Skip to content

Commit 7d8be6d

Browse files
committed
Merge branch 'master' into chore/add-auto-types-gen-and-override-for-testing
2 parents c7bdf34 + 956ed18 commit 7d8be6d

File tree

5 files changed

+152
-2
lines changed

5 files changed

+152
-2
lines changed

Diff for: src/select-query-parser/result.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,9 @@ type ProcessEmbeddedResourceResult<
372372
TablesAndViews<Schema>[CurrentTableOrView],
373373
Resolved['relation']
374374
> extends true
375-
? ProcessedChildren | null
375+
? Field extends { innerJoin: true }
376+
? ProcessedChildren
377+
: ProcessedChildren | null
376378
: ProcessedChildren
377379
}
378380
: {

Diff for: test/db/01-dummy-data.sql

+34-1
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,37 @@ INSERT INTO public.cornercase (id, array_column)
8686
VALUES
8787
(1, ARRAY['test', 'one']),
8888
(2, ARRAY['another']),
89-
(3, ARRAY['test2']);
89+
(3, ARRAY['test2']);
90+
91+
create table
92+
hotel (
93+
id bigint generated by default as identity primary key,
94+
name text null
95+
);
96+
97+
create table
98+
booking (
99+
id bigint generated by default as identity primary key,
100+
hotel_id bigint, -- nullable foreign key is needed to reproduce !inner supabase-js error
101+
foreign key (hotel_id) references hotel (id)
102+
);
103+
104+
-- Insert sample hotels
105+
INSERT INTO hotel (id, name)
106+
VALUES
107+
(1, 'Sunset Resort'),
108+
(2, 'Mountain View Hotel'),
109+
(3, 'Beachfront Inn'),
110+
(4, NULL);
111+
112+
-- Insert bookings with various relationship scenarios
113+
INSERT INTO booking (id, hotel_id)
114+
VALUES
115+
(1, 1), -- Valid booking for Sunset Resort
116+
(2, 1), -- Another booking for Sunset Resort (duplicate reference)
117+
(3, 2), -- Booking for Mountain View Hotel
118+
(4, NULL), -- Booking with no hotel (null reference)
119+
(5, 3), -- Booking for Beachfront Inn
120+
(6, 1), -- Third booking for Sunset Resort
121+
(7, NULL), -- Another booking with no hotel
122+
(8, 4); -- Booking for hotel with null name

Diff for: test/relationships.ts

+63
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ export const selectParams = {
190190
select:
191191
'msgs:messages(id, ...message_details(created_at, channel!inner(id, slug, owner:users(*))))',
192192
},
193+
innerJoinOnNullableRelationship: {
194+
from: 'booking',
195+
select: 'id, hotel!inner(id, name)',
196+
},
193197
} as const
194198

195199
export const selectQueries = {
@@ -371,6 +375,9 @@ export const selectQueries = {
371375
nestedQueryWithSelectiveFieldsAndInnerJoin: postgrest
372376
.from(selectParams.nestedQueryWithSelectiveFieldsAndInnerJoin.from)
373377
.select(selectParams.nestedQueryWithSelectiveFieldsAndInnerJoin.select),
378+
innerJoinOnNullableRelationship: postgrest
379+
.from(selectParams.innerJoinOnNullableRelationship.from)
380+
.select(selectParams.innerJoinOnNullableRelationship.select),
374381
} as const
375382

376383
test('nested query with selective fields', async () => {
@@ -518,6 +525,62 @@ test('!inner relationship', async () => {
518525
`)
519526
})
520527

528+
test('!inner relationship on nullable relation', async () => {
529+
const res = await selectQueries.innerJoinOnNullableRelationship
530+
expect(res).toMatchInlineSnapshot(`
531+
Object {
532+
"count": null,
533+
"data": Array [
534+
Object {
535+
"hotel": Object {
536+
"id": 1,
537+
"name": "Sunset Resort",
538+
},
539+
"id": 1,
540+
},
541+
Object {
542+
"hotel": Object {
543+
"id": 1,
544+
"name": "Sunset Resort",
545+
},
546+
"id": 2,
547+
},
548+
Object {
549+
"hotel": Object {
550+
"id": 2,
551+
"name": "Mountain View Hotel",
552+
},
553+
"id": 3,
554+
},
555+
Object {
556+
"hotel": Object {
557+
"id": 3,
558+
"name": "Beachfront Inn",
559+
},
560+
"id": 5,
561+
},
562+
Object {
563+
"hotel": Object {
564+
"id": 1,
565+
"name": "Sunset Resort",
566+
},
567+
"id": 6,
568+
},
569+
Object {
570+
"hotel": Object {
571+
"id": 4,
572+
"name": null,
573+
},
574+
"id": 8,
575+
},
576+
],
577+
"error": null,
578+
"status": 200,
579+
"statusText": "OK",
580+
}
581+
`)
582+
})
583+
521584
test('one-to-many relationship', async () => {
522585
const res = await selectQueries.oneToMany.limit(1).single()
523586
expect(res).toMatchInlineSnapshot(`

Diff for: test/select-query-parser/select.test-d.ts

+14
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,20 @@ type Schema = Database['public']
8585
expectType<TypeEqual<typeof result, typeof expected>>(true)
8686
}
8787

88+
// !inner relationship on nullable relation
89+
{
90+
const { data } = await selectQueries.innerJoinOnNullableRelationship
91+
let result: Exclude<typeof data, null>
92+
let expected: Array<{
93+
id: number
94+
hotel: {
95+
id: number
96+
name: string | null
97+
}
98+
}>
99+
expectType<TypeEqual<typeof result, typeof expected>>(true)
100+
}
101+
88102
// one-to-many relationship
89103
{
90104
const { data } = await selectQueries.oneToMany.limit(1).single()

Diff for: test/types.generated.ts

+38
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,29 @@ export type Database = {
130130
}
131131
]
132132
}
133+
booking: {
134+
Row: {
135+
hotel_id: number | null
136+
id: number
137+
}
138+
Insert: {
139+
hotel_id?: number | null
140+
id?: number
141+
}
142+
Update: {
143+
hotel_id?: number | null
144+
id?: number
145+
}
146+
Relationships: [
147+
{
148+
foreignKeyName: 'booking_hotel_id_fkey'
149+
columns: ['hotel_id']
150+
isOneToOne: false
151+
referencedRelation: 'hotel'
152+
referencedColumns: ['id']
153+
}
154+
]
155+
}
133156
categories: {
134157
Row: {
135158
description: string | null
@@ -233,6 +256,21 @@ export type Database = {
233256
}
234257
Relationships: []
235258
}
259+
hotel: {
260+
Row: {
261+
id: number
262+
name: string | null
263+
}
264+
Insert: {
265+
id?: number
266+
name?: string | null
267+
}
268+
Update: {
269+
id?: number
270+
name?: string | null
271+
}
272+
Relationships: []
273+
}
236274
messages: {
237275
Row: {
238276
channel_id: number

0 commit comments

Comments
 (0)