Skip to content

Commit

Permalink
Handle column name embed
Browse files Browse the repository at this point in the history
  • Loading branch information
wyozi committed Jul 26, 2023
1 parent 32e220c commit e76a0af
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 29 deletions.
83 changes: 54 additions & 29 deletions src/select-query-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,25 +66,34 @@ type EatWhitespace<Input extends string> = string extends Input
? EatWhitespace<Remainder>
: Input

type HasFKey<FKeyName, Relationships> = Relationships extends [infer R]
? R extends { foreignKeyName: FKeyName }
type InArray<Item, Array> = Array extends [infer I]
? I extends Item
? true
: false
: Relationships extends [infer R, ...infer Rest]
? HasFKey<FKeyName, [R]> extends true
: Array extends [infer I, ...infer Rest]
? InArray<Item, [I]> extends true
? true
: HasFKey<FKeyName, Rest>
: InArray<Item, Rest>
: false

type HasFKeyToFRel<FRelName, Relationships> = Relationships extends [infer R]
? R extends { referencedRelation: FRelName }
? true
: false
type HasFKey<FKeyName, Relationships> = InArray<{ foreignKeyName: FKeyName }, Relationships>

type HasFKeyToFRel<FRelName, Relationships> = InArray<
{ referencedRelation: FRelName },
Relationships
>

type ColumnForeignRelation<ColName, Relationships> = Relationships extends [infer R]
? R extends { columns: string[]; referencedRelation: string }
? InArray<ColName, R['columns']> extends true
? [R['referencedRelation']]
: null
: null
: Relationships extends [infer R, ...infer Rest]
? HasFKeyToFRel<FRelName, [R]> extends true
? true
: HasFKeyToFRel<FRelName, Rest>
: false
? ColumnForeignRelation<ColName, [R]> extends [infer Rel]
? [Rel]
: ColumnForeignRelation<ColName, Rest>
: null

/**
* Constructs a type definition for a single field of an object.
Expand Down Expand Up @@ -119,23 +128,39 @@ type ConstructFieldDefinition<
: never
}
: Field extends { name: string; original: string; children: unknown[] }
? {
[_ in Field['name']]: GetResultHelper<
Schema,
(Schema['Tables'] & Schema['Views'])[Field['original']]['Row'],
(Schema['Tables'] & Schema['Views'])[Field['original']] extends { Relationships: infer R }
? R
: unknown,
Field['children'],
unknown
> extends infer Child
? Relationships extends unknown[]
? HasFKeyToFRel<Field['original'], Relationships> extends true
? Child | null
? ColumnForeignRelation<Field['original'], Relationships> extends [infer ForeignRel]
? // handle `col:foreign_key_column`
ForeignRel extends keyof (Schema['Tables'] & Schema['Views'])
? {
[_ in Field['name']]: GetResultHelper<
Schema,
(Schema['Tables'] & Schema['Views'])[ForeignRel]['Row'],
(Schema['Tables'] & Schema['Views'])[ForeignRel] extends { Relationships: infer R }
? R
: unknown,
Field['children'],
unknown
> | null
}
: SelectQueryError<`Unknown relation in a relationship`>
: // handle `col:relation`
{
[_ in Field['name']]: GetResultHelper<
Schema,
(Schema['Tables'] & Schema['Views'])[Field['original']]['Row'],
(Schema['Tables'] & Schema['Views'])[Field['original']] extends { Relationships: infer R }
? R
: unknown,
Field['children'],
unknown
> extends infer Child
? Relationships extends unknown[]
? HasFKeyToFRel<Field['original'], Relationships> extends true
? Child | null
: Child[]
: Child[]
: Child[]
: never
}
: never
}
: Field extends { name: string; original: string }
? Field['original'] extends keyof Row
? { [K in Field['name']]: Row[Field['original']] }
Expand Down
24 changes: 24 additions & 0 deletions test/index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,30 @@ const postgrest = new PostgrestClient<Database>(REST_URL)
expectType<Database['public']['Tables']['users']['Row'] | null>(message.user)
}

// many-to-one relationship (fkey)
{
const { data: message, error } = await postgrest
.from('messages')
.select('user:users!messages_username_fkey(*)')
.single()
if (error) {
throw new Error(error.message)
}
expectType<Database['public']['Tables']['users']['Row'] | null>(message.user)
}

// many-to-one relationship (column name)
{
const { data: message, error } = await postgrest
.from('messages')
.select('user:username(*)')
.single()
if (error) {
throw new Error(error.message)
}
expectType<Database['public']['Tables']['users']['Row'] | null>(message.user)
}

// one-to-many relationship
{
const { data: user, error } = await postgrest.from('users').select('messages(*)').single()
Expand Down

0 comments on commit e76a0af

Please sign in to comment.