Skip to content

Fix: Deterministic Referenced column sort to fix views referencing same table #903

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/server/templates/typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,10 @@ export type Database = {
.sort(
(a, b) =>
a.foreign_key_name.localeCompare(b.foreign_key_name) ||
a.referenced_relation.localeCompare(b.referenced_relation)
a.referenced_relation.localeCompare(b.referenced_relation) ||
JSON.stringify(a.referenced_columns).localeCompare(
JSON.stringify(b.referenced_columns)
)
)
.map(
(relationship) => `{
Expand Down Expand Up @@ -235,7 +238,10 @@ export type Database = {
.sort(
(a, b) =>
a.foreign_key_name.localeCompare(b.foreign_key_name) ||
a.referenced_relation.localeCompare(b.referenced_relation)
a.referenced_relation.localeCompare(b.referenced_relation) ||
JSON.stringify(a.referenced_columns).localeCompare(
JSON.stringify(b.referenced_columns)
)
)
.map(
(relationship) => `{
Expand Down
18 changes: 18 additions & 0 deletions test/db/00-init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,21 @@ create table table_with_primary_key_other_than_id (
create type composite_type_with_record_attribute as (
todo todos
);

create view users_view_with_multiple_refs_to_users as
WITH initial_user AS (
SELECT
u.id as initial_id,
u.name as initial_name
FROM users u
where u.id = 1
),
second_user AS (
SELECT
u.id as second_id,
u.name as second_name
FROM users u
where u.id = 2
)
SELECT * from initial_user iu
cross join second_user su;
218 changes: 218 additions & 0 deletions test/server/typegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,18 @@ test('typegen: typescript', async () => {
referencedRelation: "users_view"
referencedColumns: ["id"]
},
{
foreignKeyName: "todos_user-id_fkey"
columns: ["user-id"]
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["initial_id"]
},
{
foreignKeyName: "todos_user-id_fkey"
columns: ["user-id"]
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["second_id"]
},
]
}
user_details: {
Expand Down Expand Up @@ -192,6 +204,18 @@ test('typegen: typescript', async () => {
referencedRelation: "users_view"
referencedColumns: ["id"]
},
{
foreignKeyName: "user_details_user_id_fkey"
columns: ["user_id"]
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["initial_id"]
},
{
foreignKeyName: "user_details_user_id_fkey"
columns: ["user_id"]
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["second_id"]
},
]
}
users: {
Expand Down Expand Up @@ -272,6 +296,18 @@ test('typegen: typescript', async () => {
referencedRelation: "users_view"
referencedColumns: ["id"]
},
{
foreignKeyName: "todos_user-id_fkey"
columns: ["user-id"]
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["initial_id"]
},
{
foreignKeyName: "todos_user-id_fkey"
columns: ["user-id"]
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["second_id"]
},
]
}
todos_view: {
Expand Down Expand Up @@ -309,6 +345,18 @@ test('typegen: typescript', async () => {
referencedRelation: "users_view"
referencedColumns: ["id"]
},
{
foreignKeyName: "todos_user-id_fkey"
columns: ["user-id"]
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["initial_id"]
},
{
foreignKeyName: "todos_user-id_fkey"
columns: ["user-id"]
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["second_id"]
},
]
}
users_view: {
Expand All @@ -329,6 +377,15 @@ test('typegen: typescript', async () => {
}
Relationships: []
}
users_view_with_multiple_refs_to_users: {
Row: {
initial_id: number | null
initial_name: string | null
second_id: number | null
second_name: string | null
}
Relationships: []
}
}
Functions: {
blurb: {
Expand Down Expand Up @@ -713,6 +770,20 @@ test('typegen w/ one-to-one relationships', async () => {
referencedRelation: "users_view"
referencedColumns: ["id"]
},
{
foreignKeyName: "todos_user-id_fkey"
columns: ["user-id"]
isOneToOne: false
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["initial_id"]
},
{
foreignKeyName: "todos_user-id_fkey"
columns: ["user-id"]
isOneToOne: false
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["second_id"]
},
]
}
user_details: {
Expand Down Expand Up @@ -750,6 +821,20 @@ test('typegen w/ one-to-one relationships', async () => {
referencedRelation: "users_view"
referencedColumns: ["id"]
},
{
foreignKeyName: "user_details_user_id_fkey"
columns: ["user_id"]
isOneToOne: true
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["initial_id"]
},
{
foreignKeyName: "user_details_user_id_fkey"
columns: ["user_id"]
isOneToOne: true
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["second_id"]
},
]
}
users: {
Expand Down Expand Up @@ -833,6 +918,20 @@ test('typegen w/ one-to-one relationships', async () => {
referencedRelation: "users_view"
referencedColumns: ["id"]
},
{
foreignKeyName: "todos_user-id_fkey"
columns: ["user-id"]
isOneToOne: false
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["initial_id"]
},
{
foreignKeyName: "todos_user-id_fkey"
columns: ["user-id"]
isOneToOne: false
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["second_id"]
},
]
}
todos_view: {
Expand Down Expand Up @@ -873,6 +972,20 @@ test('typegen w/ one-to-one relationships', async () => {
referencedRelation: "users_view"
referencedColumns: ["id"]
},
{
foreignKeyName: "todos_user-id_fkey"
columns: ["user-id"]
isOneToOne: false
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["initial_id"]
},
{
foreignKeyName: "todos_user-id_fkey"
columns: ["user-id"]
isOneToOne: false
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["second_id"]
},
]
}
users_view: {
Expand All @@ -893,6 +1006,15 @@ test('typegen w/ one-to-one relationships', async () => {
}
Relationships: []
}
users_view_with_multiple_refs_to_users: {
Row: {
initial_id: number | null
initial_name: string | null
second_id: number | null
second_name: string | null
}
Relationships: []
}
}
Functions: {
blurb: {
Expand Down Expand Up @@ -1277,6 +1399,20 @@ test('typegen: typescript w/ one-to-one relationships', async () => {
referencedRelation: "users_view"
referencedColumns: ["id"]
},
{
foreignKeyName: "todos_user-id_fkey"
columns: ["user-id"]
isOneToOne: false
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["initial_id"]
},
{
foreignKeyName: "todos_user-id_fkey"
columns: ["user-id"]
isOneToOne: false
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["second_id"]
},
]
}
user_details: {
Expand Down Expand Up @@ -1314,6 +1450,20 @@ test('typegen: typescript w/ one-to-one relationships', async () => {
referencedRelation: "users_view"
referencedColumns: ["id"]
},
{
foreignKeyName: "user_details_user_id_fkey"
columns: ["user_id"]
isOneToOne: true
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["initial_id"]
},
{
foreignKeyName: "user_details_user_id_fkey"
columns: ["user_id"]
isOneToOne: true
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["second_id"]
},
]
}
users: {
Expand Down Expand Up @@ -1397,6 +1547,20 @@ test('typegen: typescript w/ one-to-one relationships', async () => {
referencedRelation: "users_view"
referencedColumns: ["id"]
},
{
foreignKeyName: "todos_user-id_fkey"
columns: ["user-id"]
isOneToOne: false
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["initial_id"]
},
{
foreignKeyName: "todos_user-id_fkey"
columns: ["user-id"]
isOneToOne: false
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["second_id"]
},
]
}
todos_view: {
Expand Down Expand Up @@ -1437,6 +1601,20 @@ test('typegen: typescript w/ one-to-one relationships', async () => {
referencedRelation: "users_view"
referencedColumns: ["id"]
},
{
foreignKeyName: "todos_user-id_fkey"
columns: ["user-id"]
isOneToOne: false
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["initial_id"]
},
{
foreignKeyName: "todos_user-id_fkey"
columns: ["user-id"]
isOneToOne: false
referencedRelation: "users_view_with_multiple_refs_to_users"
referencedColumns: ["second_id"]
},
]
}
users_view: {
Expand All @@ -1457,6 +1635,15 @@ test('typegen: typescript w/ one-to-one relationships', async () => {
}
Relationships: []
}
users_view_with_multiple_refs_to_users: {
Row: {
initial_id: number | null
initial_name: string | null
second_id: number | null
second_name: string | null
}
Relationships: []
}
}
Functions: {
blurb: {
Expand Down Expand Up @@ -1853,6 +2040,13 @@ type PublicAViewSelect struct {
Id *int64 \`json:"id"\`
}

type PublicUsersViewWithMultipleRefsToUsersSelect struct {
InitialId *int64 \`json:"initial_id"\`
InitialName *string \`json:"initial_name"\`
SecondId *int64 \`json:"second_id"\`
SecondName *string \`json:"second_name"\`
}

type PublicTodosMatviewSelect struct {
Details *string \`json:"details"\`
Id *int64 \`json:"id"\`
Expand Down Expand Up @@ -2200,6 +2394,18 @@ test('typegen: swift', async () => {
case status = "status"
}
}
internal struct UsersViewWithMultipleRefsToUsersSelect: Codable, Hashable, Sendable {
internal let initialId: Int64?
internal let initialName: String?
internal let secondId: Int64?
internal let secondName: String?
internal enum CodingKeys: String, CodingKey {
case initialId = "initial_id"
case initialName = "initial_name"
case secondId = "second_id"
case secondName = "second_name"
}
}
internal struct CompositeTypeWithArrayAttribute: Codable, Hashable, Sendable {
internal let MyTextArray: AnyJSON
internal enum CodingKeys: String, CodingKey {
Expand Down Expand Up @@ -2551,6 +2757,18 @@ test('typegen: swift w/ public access control', async () => {
case status = "status"
}
}
public struct UsersViewWithMultipleRefsToUsersSelect: Codable, Hashable, Sendable {
public let initialId: Int64?
public let initialName: String?
public let secondId: Int64?
public let secondName: String?
public enum CodingKeys: String, CodingKey {
case initialId = "initial_id"
case initialName = "initial_name"
case secondId = "second_id"
case secondName = "second_name"
}
}
public struct CompositeTypeWithArrayAttribute: Codable, Hashable, Sendable {
public let MyTextArray: AnyJSON
public enum CodingKeys: String, CodingKey {
Expand Down