Skip to content

Commit

Permalink
fix(types): add deduplication helpers for retro-compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
avallete committed Nov 7, 2024
1 parent cc9344a commit fe72d45
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 7 deletions.
44 changes: 37 additions & 7 deletions src/select-query-parser/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,23 @@ export type IsAny<T> = 0 extends 1 & T ? true : false

export type SelectQueryError<Message extends string> = { error: true } & Message

/*
** Because of pg-meta types generation there is some cases where a same relationship can be duplicated
** if the relation is across schemas and views this ensure that we dedup those relations and treat them
** as postgrest would.
** This is no longer the case and has been patched here: https://github.com/supabase/postgres-meta/pull/809
** But we still need this for retro-compatibilty with older generated types
** TODO: Remove this in next major version
*/
export type DeduplicateRelationships<T extends readonly unknown[]> = T extends readonly [
infer First,
...infer Rest
]
? First extends Rest[number]
? DeduplicateRelationships<Rest extends readonly unknown[] ? Rest : []>
: [First, ...DeduplicateRelationships<Rest extends readonly unknown[] ? Rest : []>]
: T

export type GetFieldNodeResultName<Field extends Ast.FieldNode> = Field['alias'] extends string
? Field['alias']
: Field['aggregateFunction'] extends AggregateFunctions
Expand Down Expand Up @@ -87,10 +104,14 @@ type CheckDuplicates<Arr extends any[], Current> = Arr extends [infer Head, ...i
/**
* Iterates over the elements of the array to find duplicates
*/
type FindDuplicates<Arr extends any[]> = Arr extends [infer Head, ...infer Tail]
? CheckDuplicates<Tail, Head> | FindDuplicates<Tail>
type FindDuplicatesWithinDeduplicated<Arr extends any[]> = Arr extends [infer Head, ...infer Tail]
? CheckDuplicates<Tail, Head> | FindDuplicatesWithinDeduplicated<Tail>
: never

type FindDuplicates<Arr extends any[]> = FindDuplicatesWithinDeduplicated<
DeduplicateRelationships<Arr>
>

export type CheckDuplicateEmbededReference<
Schema extends GenericSchema,
RelationName extends string,
Expand Down Expand Up @@ -137,17 +158,22 @@ type HasFKeyToFRel<FRelName, Relationships> = Relationships extends [infer R]
/**
* Checks if there is more than one relation to a given foreign relation name in the Relationships.
*/
type HasMultipleFKeysToFRel<FRelName, Relationships> = Relationships extends [
type HasMultipleFKeysToFRelDeduplicated<FRelName, Relationships> = Relationships extends [
infer R,
...infer Rest
]
? R extends { referencedRelation: FRelName }
? HasFKeyToFRel<FRelName, Rest> extends true
? true
: HasMultipleFKeysToFRel<FRelName, Rest>
: HasMultipleFKeysToFRel<FRelName, Rest>
: HasMultipleFKeysToFRelDeduplicated<FRelName, Rest>
: HasMultipleFKeysToFRelDeduplicated<FRelName, Rest>
: false

type HasMultipleFKeysToFRel<
FRelName,
Relationships extends unknown[]
> = HasMultipleFKeysToFRelDeduplicated<FRelName, DeduplicateRelationships<Relationships>>

type CheckRelationshipError<
Schema extends GenericSchema,
Relationships extends GenericRelationship[],
Expand Down Expand Up @@ -454,9 +480,13 @@ type ResolveJoinTableRelationship<
CurrentTableOrView extends keyof TablesAndViews<Schema> & string,
FieldName extends string
> = {
[TableName in keyof TablesAndViews<Schema>]: TablesAndViews<Schema>[TableName]['Relationships'] extends readonly (infer Rel)[]
[TableName in keyof TablesAndViews<Schema>]: DeduplicateRelationships<
TablesAndViews<Schema>[TableName]['Relationships']
> extends readonly (infer Rel)[]
? Rel extends { referencedRelation: CurrentTableOrView }
? TablesAndViews<Schema>[TableName]['Relationships'] extends readonly (infer OtherRel)[]
? DeduplicateRelationships<
TablesAndViews<Schema>[TableName]['Relationships']
> extends readonly (infer OtherRel)[]
? OtherRel extends { referencedRelation: FieldName }
? OtherRel
: never
Expand Down
55 changes: 55 additions & 0 deletions test/select-query-parser/types.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { expectType } from 'tsd'
import { TypeEqual } from 'ts-expect'
import { DeduplicateRelationships } from '../../src/select-query-parser/utils'
// Deduplicate exact sames relationships
{
type rels = [
{
foreignKeyName: 'test_fkey'
columns: ['project_id']
referencedRelation: 'project_subscriptions'
referencedColumns: ['project_id']
},
{
foreignKeyName: 'test_fkey'
columns: ['project_id']
referencedRelation: 'projects'
referencedColumns: ['id']
},
{
foreignKeyName: 'test_fkey'
columns: ['project_id']
referencedRelation: 'projects'
referencedColumns: ['id']
},
{
foreignKeyName: 'test_fkey'
columns: ['project_id']
referencedRelation: 'sls_physical_backups_monitoring'
referencedColumns: ['project_id']
}
]
type expected = [
{
foreignKeyName: 'test_fkey'
columns: ['project_id']
referencedRelation: 'project_subscriptions'
referencedColumns: ['project_id']
},
{
foreignKeyName: 'test_fkey'
columns: ['project_id']
referencedRelation: 'projects'
referencedColumns: ['id']
},
{
foreignKeyName: 'test_fkey'
columns: ['project_id']
referencedRelation: 'sls_physical_backups_monitoring'
referencedColumns: ['project_id']
}
]

type result = DeduplicateRelationships<rels>
expectType<TypeEqual<result, expected>>(true)
}
70 changes: 70 additions & 0 deletions test/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ export type Database = {
referencedRelation: 'users'
referencedColumns: ['username']
},
{
foreignKeyName: 'best_friends_first_user_fkey'
columns: ['first_user']
isOneToOne: false
referencedRelation: 'users'
referencedColumns: ['username']
},
{
foreignKeyName: 'best_friends_second_user_fkey'
columns: ['second_user']
Expand All @@ -107,6 +114,13 @@ export type Database = {
referencedRelation: 'users'
referencedColumns: ['username']
},
{
foreignKeyName: 'best_friends_second_user_fkey'
columns: ['second_user']
isOneToOne: false
referencedRelation: 'users'
referencedColumns: ['username']
},
{
foreignKeyName: 'best_friends_third_wheel_fkey'
columns: ['third_wheel']
Expand All @@ -121,6 +135,13 @@ export type Database = {
referencedRelation: 'updatable_view'
referencedColumns: ['username']
},
{
foreignKeyName: 'best_friends_third_wheel_fkey'
columns: ['third_wheel']
isOneToOne: false
referencedRelation: 'users'
referencedColumns: ['username']
},
{
foreignKeyName: 'best_friends_third_wheel_fkey'
columns: ['third_wheel']
Expand All @@ -144,6 +165,13 @@ export type Database = {
id?: number
}
Relationships: [
{
foreignKeyName: 'channel_details_id_fkey'
columns: ['id']
isOneToOne: true
referencedRelation: 'channels'
referencedColumns: ['id']
},
{
foreignKeyName: 'channel_details_id_fkey'
columns: ['id']
Expand Down Expand Up @@ -188,6 +216,13 @@ export type Database = {
parent_id?: number | null
}
Relationships: [
{
foreignKeyName: 'collections_parent_id_fkey'
columns: ['parent_id']
isOneToOne: false
referencedRelation: 'collections'
referencedColumns: ['id']
},
{
foreignKeyName: 'collections_parent_id_fkey'
columns: ['parent_id']
Expand Down Expand Up @@ -220,6 +255,13 @@ export type Database = {
username?: string
}
Relationships: [
{
foreignKeyName: 'messages_channel_id_fkey'
columns: ['channel_id']
isOneToOne: false
referencedRelation: 'channels'
referencedColumns: ['id']
},
{
foreignKeyName: 'messages_channel_id_fkey'
columns: ['channel_id']
Expand All @@ -241,6 +283,13 @@ export type Database = {
referencedRelation: 'updatable_view'
referencedColumns: ['username']
},
{
foreignKeyName: 'messages_username_fkey'
columns: ['username']
isOneToOne: false
referencedRelation: 'users'
referencedColumns: ['username']
},
{
foreignKeyName: 'messages_username_fkey'
columns: ['username']
Expand All @@ -264,6 +313,20 @@ export type Database = {
product_id?: number
}
Relationships: [
{
foreignKeyName: 'product_categories_category_id_fkey'
columns: ['category_id']
isOneToOne: false
referencedRelation: 'categories'
referencedColumns: ['id']
},
{
foreignKeyName: 'product_categories_product_id_fkey'
columns: ['product_id']
isOneToOne: false
referencedRelation: 'products'
referencedColumns: ['id']
},
{
foreignKeyName: 'product_categories_category_id_fkey'
columns: ['category_id']
Expand Down Expand Up @@ -389,6 +452,13 @@ export type Database = {
referencedRelation: 'updatable_view'
referencedColumns: ['username']
},
{
foreignKeyName: 'user_profiles_username_fkey'
columns: ['username']
isOneToOne: false
referencedRelation: 'users'
referencedColumns: ['username']
},
{
foreignKeyName: 'user_profiles_username_fkey'
columns: ['username']
Expand Down

0 comments on commit fe72d45

Please sign in to comment.