@casekit/orm2-config 0.0.0-20250322230249

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/build/index.d.ts +11 -0
  2. package/build/index.js +4 -0
  3. package/build/normalize/defaultZodSchema.d.ts +8 -0
  4. package/build/normalize/defaultZodSchema.js +127 -0
  5. package/build/normalize/defaultZodSchema.test.d.ts +1 -0
  6. package/build/normalize/defaultZodSchema.test.js +153 -0
  7. package/build/normalize/getColumns.d.ts +2 -0
  8. package/build/normalize/getColumns.js +8 -0
  9. package/build/normalize/getColumns.test.d.ts +1 -0
  10. package/build/normalize/getColumns.test.js +63 -0
  11. package/build/normalize/normalizeConfig.d.ts +3 -0
  12. package/build/normalize/normalizeConfig.js +20 -0
  13. package/build/normalize/normalizeConfig.test.d.ts +1 -0
  14. package/build/normalize/normalizeConfig.test.js +217 -0
  15. package/build/normalize/normalizeField.d.ts +3 -0
  16. package/build/normalize/normalizeField.js +11 -0
  17. package/build/normalize/normalizeField.test.d.ts +1 -0
  18. package/build/normalize/normalizeField.test.js +59 -0
  19. package/build/normalize/normalizeForeignKeys.d.ts +5 -0
  20. package/build/normalize/normalizeForeignKeys.js +50 -0
  21. package/build/normalize/normalizeForeignKeys.test.d.ts +1 -0
  22. package/build/normalize/normalizeForeignKeys.test.js +258 -0
  23. package/build/normalize/normalizeModel.d.ts +3 -0
  24. package/build/normalize/normalizeModel.js +18 -0
  25. package/build/normalize/normalizeModel.test.d.ts +1 -0
  26. package/build/normalize/normalizeModel.test.js +227 -0
  27. package/build/normalize/normalizePrimaryKey.d.ts +3 -0
  28. package/build/normalize/normalizePrimaryKey.js +18 -0
  29. package/build/normalize/normalizePrimaryKey.test.d.ts +1 -0
  30. package/build/normalize/normalizePrimaryKey.test.js +144 -0
  31. package/build/normalize/normalizeRelations.d.ts +3 -0
  32. package/build/normalize/normalizeRelations.js +58 -0
  33. package/build/normalize/normalizeRelations.test.d.ts +1 -0
  34. package/build/normalize/normalizeRelations.test.js +298 -0
  35. package/build/normalize/normalizeUniqueConstraints.d.ts +5 -0
  36. package/build/normalize/normalizeUniqueConstraints.js +29 -0
  37. package/build/normalize/normalizeUniqueConstraints.test.d.ts +1 -0
  38. package/build/normalize/normalizeUniqueConstraints.test.js +241 -0
  39. package/build/normalize/populateField.d.ts +3 -0
  40. package/build/normalize/populateField.js +15 -0
  41. package/build/normalize/populateField.test.d.ts +1 -0
  42. package/build/normalize/populateField.test.js +198 -0
  43. package/build/normalize/populateModels.d.ts +3 -0
  44. package/build/normalize/populateModels.js +16 -0
  45. package/build/normalize/populateModels.test.d.ts +1 -0
  46. package/build/normalize/populateModels.test.js +240 -0
  47. package/build/types/NormalizedConfig.d.ts +16 -0
  48. package/build/types/NormalizedConfig.js +1 -0
  49. package/build/types/NormalizedFieldDefinition.d.ts +10 -0
  50. package/build/types/NormalizedFieldDefinition.js +1 -0
  51. package/build/types/NormalizedForeignKeyDefinition.d.ts +14 -0
  52. package/build/types/NormalizedForeignKeyDefinition.js +1 -0
  53. package/build/types/NormalizedModelDefinition.d.ts +15 -0
  54. package/build/types/NormalizedModelDefinition.js +1 -0
  55. package/build/types/NormalizedPrimaryKey.d.ts +4 -0
  56. package/build/types/NormalizedPrimaryKey.js +1 -0
  57. package/build/types/NormalizedRelationDefinition.d.ts +42 -0
  58. package/build/types/NormalizedRelationDefinition.js +1 -0
  59. package/build/types/NormalizedUniqueConstraintDefinition.d.ts +8 -0
  60. package/build/types/NormalizedUniqueConstraintDefinition.js +1 -0
  61. package/build/types/PopulatedFieldDefinition.d.ts +4 -0
  62. package/build/types/PopulatedFieldDefinition.js +1 -0
  63. package/build/types/PopulatedModelDefinition.d.ts +6 -0
  64. package/build/types/PopulatedModelDefinition.js +1 -0
  65. package/build/util.d.ts +6 -0
  66. package/build/util.js +21 -0
  67. package/package.json +54 -0
@@ -0,0 +1,59 @@
1
+ import { snakeCase } from "es-toolkit";
2
+ import { describe, expect, test } from "vitest";
3
+ import { ZodSchema } from "zod";
4
+ import { normalizeField } from "./normalizeField.js";
5
+ import { populateModels } from "./populateModels.js";
6
+ describe("normalizeField", () => {
7
+ test("strips out references, unique, and primary key properties", () => {
8
+ const models = populateModels({
9
+ naming: {
10
+ column: snakeCase,
11
+ },
12
+ models: {
13
+ post: {
14
+ fields: {
15
+ id: { type: "serial", primaryKey: true },
16
+ slug: {
17
+ type: "text",
18
+ unique: true,
19
+ },
20
+ authorId: {
21
+ type: "integer",
22
+ references: {
23
+ model: "user",
24
+ field: "id",
25
+ },
26
+ },
27
+ },
28
+ },
29
+ },
30
+ });
31
+ expect(normalizeField(models["post"].fields["id"])).toEqual({
32
+ name: "id",
33
+ column: "id",
34
+ type: "serial",
35
+ zodSchema: expect.any(ZodSchema),
36
+ nullable: false,
37
+ default: null,
38
+ provided: false,
39
+ });
40
+ expect(normalizeField(models["post"].fields["slug"])).toEqual({
41
+ name: "slug",
42
+ column: "slug",
43
+ type: "text",
44
+ zodSchema: expect.any(ZodSchema),
45
+ nullable: false,
46
+ default: null,
47
+ provided: false,
48
+ });
49
+ expect(normalizeField(models["post"].fields["authorId"])).toEqual({
50
+ name: "authorId",
51
+ column: "author_id",
52
+ type: "integer",
53
+ zodSchema: expect.any(ZodSchema),
54
+ nullable: false,
55
+ default: null,
56
+ provided: false,
57
+ });
58
+ });
59
+ });
@@ -0,0 +1,5 @@
1
+ import { ForeignKeyDefinition } from "@casekit/orm2-schema";
2
+ import { NormalizedForeignKeyDefinition } from "#types/NormalizedForeignKeyDefinition.js";
3
+ import { PopulatedModelDefinition } from "#types/PopulatedModelDefinition.js";
4
+ export declare const normalizeForeignKeys: (models: Record<string, PopulatedModelDefinition>, model: PopulatedModelDefinition) => NormalizedForeignKeyDefinition[];
5
+ export declare const normalizeForeignKey: (models: Record<string, PopulatedModelDefinition>, model: PopulatedModelDefinition, fk: ForeignKeyDefinition) => NormalizedForeignKeyDefinition;
@@ -0,0 +1,50 @@
1
+ import { isEqual } from "es-toolkit";
2
+ import { getColumns } from "./getColumns.js";
3
+ export const normalizeForeignKeys = (models, model) => {
4
+ const columnLevelForeignKeys = Object.values(model.fields)
5
+ .filter(hasReference)
6
+ .map(referenceToForeignKey)
7
+ .map((fk) => normalizeForeignKey(models, model, fk));
8
+ const modelLevelForeignKeys = model.foreignKeys.map((fk) => normalizeForeignKey(models, model, fk));
9
+ for (const fk of columnLevelForeignKeys) {
10
+ if (modelLevelForeignKeys.some((other) => isEqual(fk.columns, other.columns))) {
11
+ throw new Error(`Duplicate foreign key defined in model "${model.name}"`);
12
+ }
13
+ }
14
+ return [...columnLevelForeignKeys, ...modelLevelForeignKeys];
15
+ };
16
+ export const normalizeForeignKey = (models, model, fk) => {
17
+ const referencedModel = models[fk.references.model];
18
+ if (!referencedModel) {
19
+ throw new Error(`Referenced model "${fk.references.model}" not found in models`);
20
+ }
21
+ const columns = getColumns(model, fk.fields);
22
+ return {
23
+ name: fk.name ?? [model.table, ...columns, "fkey"].join("_"),
24
+ fields: fk.fields,
25
+ columns: columns,
26
+ references: {
27
+ model: fk.references.model,
28
+ fields: fk.references.fields,
29
+ schema: referencedModel.schema,
30
+ table: referencedModel.table,
31
+ columns: getColumns(referencedModel, fk.references.fields),
32
+ },
33
+ onUpdate: fk.onUpdate ?? null,
34
+ onDelete: fk.onDelete ?? null,
35
+ };
36
+ };
37
+ const referenceToForeignKey = (field) => {
38
+ return {
39
+ fields: [field.name],
40
+ references: {
41
+ model: field.references.model,
42
+ fields: [field.references.field],
43
+ },
44
+ onUpdate: field.references.onUpdate,
45
+ onDelete: field.references.onDelete,
46
+ };
47
+ };
48
+ const hasReference = (field) => {
49
+ return !!field.references;
50
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,258 @@
1
+ import { snakeCase } from "es-toolkit";
2
+ import { describe, expect, test } from "vitest";
3
+ import { normalizeForeignKeys } from "./normalizeForeignKeys.js";
4
+ import { populateModels } from "./populateModels.js";
5
+ describe("normalizeForeignKeys", () => {
6
+ test("normalizes foreign keys defined at the top level", () => {
7
+ const models = populateModels({
8
+ naming: { column: snakeCase },
9
+ models: {
10
+ user: {
11
+ fields: {
12
+ id: { type: "serial", primaryKey: true },
13
+ },
14
+ },
15
+ post: {
16
+ fields: {
17
+ id: { type: "serial", primaryKey: true },
18
+ userId: {
19
+ type: "integer",
20
+ references: { model: "user", field: "id" },
21
+ },
22
+ },
23
+ },
24
+ },
25
+ });
26
+ expect(normalizeForeignKeys(models, models["post"])).toEqual([
27
+ {
28
+ name: "post_user_id_fkey",
29
+ fields: ["userId"],
30
+ columns: ["user_id"],
31
+ references: {
32
+ model: "user",
33
+ fields: ["id"],
34
+ schema: "public",
35
+ table: "user",
36
+ columns: ["id"],
37
+ },
38
+ onUpdate: null,
39
+ onDelete: null,
40
+ },
41
+ ]);
42
+ });
43
+ test("normalizes foreign keys defined in foreignKeys array", () => {
44
+ const models = populateModels({
45
+ naming: { column: snakeCase },
46
+ models: {
47
+ user: {
48
+ fields: {
49
+ id: { type: "serial", primaryKey: true },
50
+ },
51
+ },
52
+ post: {
53
+ fields: {
54
+ id: { type: "serial", primaryKey: true },
55
+ userId: { type: "integer" },
56
+ },
57
+ foreignKeys: [
58
+ {
59
+ fields: ["userId"],
60
+ references: {
61
+ model: "user",
62
+ fields: ["id"],
63
+ },
64
+ },
65
+ ],
66
+ },
67
+ },
68
+ });
69
+ expect(normalizeForeignKeys(models, models["post"])).toEqual([
70
+ {
71
+ name: "post_user_id_fkey",
72
+ fields: ["userId"],
73
+ columns: ["user_id"],
74
+ references: {
75
+ model: "user",
76
+ fields: ["id"],
77
+ schema: "public",
78
+ table: "user",
79
+ columns: ["id"],
80
+ },
81
+ onUpdate: null,
82
+ onDelete: null,
83
+ },
84
+ ]);
85
+ });
86
+ test("throws error when referenced model doesn't exist", () => {
87
+ const models = populateModels({
88
+ naming: { column: snakeCase },
89
+ models: {
90
+ post: {
91
+ fields: {
92
+ id: { type: "serial", primaryKey: true },
93
+ userId: {
94
+ type: "integer",
95
+ references: { model: "nonexistent", field: "id" },
96
+ },
97
+ },
98
+ },
99
+ },
100
+ });
101
+ expect(() => normalizeForeignKeys(models, models["post"])).toThrow('Referenced model "nonexistent" not found in models');
102
+ });
103
+ test("respects custom onDelete and onUpdate actions", () => {
104
+ const models = populateModels({
105
+ naming: { column: snakeCase },
106
+ models: {
107
+ user: {
108
+ fields: {
109
+ id: { type: "serial", primaryKey: true },
110
+ },
111
+ },
112
+ post: {
113
+ fields: {
114
+ id: { type: "serial", primaryKey: true },
115
+ userId: {
116
+ type: "integer",
117
+ references: {
118
+ model: "user",
119
+ field: "id",
120
+ onDelete: "CASCADE",
121
+ onUpdate: "SET NULL",
122
+ },
123
+ },
124
+ },
125
+ },
126
+ },
127
+ });
128
+ expect(normalizeForeignKeys(models, models["post"])).toEqual([
129
+ {
130
+ name: "post_user_id_fkey",
131
+ fields: ["userId"],
132
+ columns: ["user_id"],
133
+ references: {
134
+ model: "user",
135
+ fields: ["id"],
136
+ schema: "public",
137
+ table: "user",
138
+ columns: ["id"],
139
+ },
140
+ onUpdate: "SET NULL",
141
+ onDelete: "CASCADE",
142
+ },
143
+ ]);
144
+ });
145
+ test("throws error on duplicate foreign keys", () => {
146
+ const models = populateModels({
147
+ naming: { column: snakeCase },
148
+ models: {
149
+ user: {
150
+ fields: {
151
+ id: { type: "serial", primaryKey: true },
152
+ },
153
+ },
154
+ post: {
155
+ fields: {
156
+ id: { type: "serial", primaryKey: true },
157
+ userId: {
158
+ type: "integer",
159
+ references: { model: "user", field: "id" },
160
+ },
161
+ },
162
+ foreignKeys: [
163
+ {
164
+ fields: ["userId"],
165
+ references: {
166
+ model: "user",
167
+ fields: ["id"],
168
+ },
169
+ },
170
+ ],
171
+ },
172
+ },
173
+ });
174
+ expect(() => normalizeForeignKeys(models, models["post"])).toThrow('Duplicate foreign key defined in model "post"');
175
+ });
176
+ test("handles custom foreign key names", () => {
177
+ const models = populateModels({
178
+ naming: { column: snakeCase },
179
+ models: {
180
+ user: {
181
+ fields: {
182
+ id: { type: "serial", primaryKey: true },
183
+ },
184
+ },
185
+ post: {
186
+ fields: {
187
+ id: { type: "serial", primaryKey: true },
188
+ userId: { type: "integer" },
189
+ },
190
+ foreignKeys: [
191
+ {
192
+ name: "custom_fk_name",
193
+ fields: ["userId"],
194
+ references: {
195
+ model: "user",
196
+ fields: ["id"],
197
+ },
198
+ },
199
+ ],
200
+ },
201
+ },
202
+ });
203
+ expect(normalizeForeignKeys(models, models["post"])).toEqual([
204
+ {
205
+ name: "custom_fk_name",
206
+ fields: ["userId"],
207
+ columns: ["user_id"],
208
+ references: {
209
+ model: "user",
210
+ fields: ["id"],
211
+ schema: "public",
212
+ table: "user",
213
+ columns: ["id"],
214
+ },
215
+ onUpdate: null,
216
+ onDelete: null,
217
+ },
218
+ ]);
219
+ });
220
+ test("handles foreign keys in custom schema", () => {
221
+ const models = populateModels({
222
+ naming: { column: snakeCase },
223
+ models: {
224
+ user: {
225
+ schema: "auth",
226
+ fields: {
227
+ id: { type: "serial", primaryKey: true },
228
+ },
229
+ },
230
+ post: {
231
+ fields: {
232
+ id: { type: "serial", primaryKey: true },
233
+ userId: {
234
+ type: "integer",
235
+ references: { model: "user", field: "id" },
236
+ },
237
+ },
238
+ },
239
+ },
240
+ });
241
+ expect(normalizeForeignKeys(models, models["post"])).toEqual([
242
+ {
243
+ name: "post_user_id_fkey",
244
+ fields: ["userId"],
245
+ columns: ["user_id"],
246
+ references: {
247
+ model: "user",
248
+ fields: ["id"],
249
+ schema: "auth",
250
+ table: "user",
251
+ columns: ["id"],
252
+ },
253
+ onUpdate: null,
254
+ onDelete: null,
255
+ },
256
+ ]);
257
+ });
258
+ });
@@ -0,0 +1,3 @@
1
+ import { NormalizedModelDefinition } from "#types/NormalizedModelDefinition.js";
2
+ import { PopulatedModelDefinition } from "#types/PopulatedModelDefinition.js";
3
+ export declare const normalizeModel: (models: Record<string, PopulatedModelDefinition>, model: PopulatedModelDefinition) => NormalizedModelDefinition;
@@ -0,0 +1,18 @@
1
+ import { mapValues } from "es-toolkit";
2
+ import { normalizeField } from "./normalizeField.js";
3
+ import { normalizeForeignKeys } from "./normalizeForeignKeys.js";
4
+ import { normalizePrimaryKey } from "./normalizePrimaryKey.js";
5
+ import { normalizeRelations } from "./normalizeRelations.js";
6
+ import { normalizeUniqueConstraints } from "./normalizeUniqueConstraints.js";
7
+ export const normalizeModel = (models, model) => {
8
+ return {
9
+ name: model.name,
10
+ schema: model.schema,
11
+ table: model.table,
12
+ fields: mapValues(model.fields, (field) => normalizeField(field)),
13
+ primaryKey: normalizePrimaryKey(model),
14
+ uniqueConstraints: normalizeUniqueConstraints(model),
15
+ foreignKeys: normalizeForeignKeys(models, model),
16
+ relations: normalizeRelations(models, model),
17
+ };
18
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,227 @@
1
+ import { snakeCase } from "es-toolkit";
2
+ import { describe, expect, test } from "vitest";
3
+ import { ZodSchema, z } from "zod";
4
+ import { sql } from "@casekit/sql";
5
+ import { normalizeModel } from "./normalizeModel.js";
6
+ import { populateModels } from "./populateModels.js";
7
+ describe("normalizeModel", () => {
8
+ test("normalizes complete model definition", () => {
9
+ const models = populateModels({
10
+ naming: { column: snakeCase },
11
+ models: {
12
+ user: {
13
+ schema: "auth",
14
+ fields: {
15
+ id: {
16
+ type: "serial",
17
+ primaryKey: true,
18
+ },
19
+ email: {
20
+ type: "text",
21
+ unique: true,
22
+ zodSchema: z.string().email(),
23
+ },
24
+ name: {
25
+ type: "text",
26
+ nullable: true,
27
+ },
28
+ createdAt: {
29
+ type: "timestamp",
30
+ default: sql `NOW()`,
31
+ provided: true,
32
+ },
33
+ },
34
+ relations: {
35
+ posts: {
36
+ type: "1:N",
37
+ model: "post",
38
+ fromField: "id",
39
+ toField: "authorId",
40
+ },
41
+ likedPosts: {
42
+ type: "N:N",
43
+ model: "post",
44
+ through: {
45
+ model: "like",
46
+ fromRelation: "user",
47
+ toRelation: "post",
48
+ },
49
+ },
50
+ },
51
+ },
52
+ post: {
53
+ fields: {
54
+ id: { type: "serial", primaryKey: true },
55
+ authorId: { type: "integer" },
56
+ },
57
+ },
58
+ like: {
59
+ fields: {
60
+ userId: { type: "integer" },
61
+ postId: { type: "integer" },
62
+ },
63
+ },
64
+ },
65
+ });
66
+ const result = normalizeModel(models, models["user"]);
67
+ // Test basic model properties
68
+ expect(result.name).toBe("user");
69
+ expect(result.schema).toBe("auth");
70
+ expect(result.table).toBe("user");
71
+ // Test fields
72
+ expect(result.fields["id"]).toEqual({
73
+ name: "id",
74
+ column: "id",
75
+ type: "serial",
76
+ zodSchema: expect.any(ZodSchema),
77
+ nullable: false,
78
+ default: null,
79
+ provided: false,
80
+ });
81
+ expect(result.fields["email"]).toEqual({
82
+ name: "email",
83
+ column: "email",
84
+ type: "text",
85
+ zodSchema: expect.any(ZodSchema),
86
+ nullable: false,
87
+ default: null,
88
+ provided: false,
89
+ });
90
+ // Test primary key
91
+ expect(result.primaryKey).toEqual([{ field: "id", column: "id" }]);
92
+ // Test unique constraints
93
+ expect(result.uniqueConstraints).toEqual([
94
+ {
95
+ name: "user_email_ukey",
96
+ fields: ["email"],
97
+ columns: ["email"],
98
+ where: null,
99
+ nullsNotDistinct: false,
100
+ },
101
+ ]);
102
+ // Test relations
103
+ expect(result.relations["posts"]).toEqual({
104
+ name: "posts",
105
+ type: "1:N",
106
+ model: "post",
107
+ table: "post",
108
+ from: {
109
+ fields: ["id"],
110
+ columns: ["id"],
111
+ },
112
+ to: {
113
+ fields: ["authorId"],
114
+ columns: ["author_id"],
115
+ },
116
+ });
117
+ expect(result.relations["likedPosts"]).toEqual({
118
+ name: "likedPosts",
119
+ type: "N:N",
120
+ model: "post",
121
+ table: "post",
122
+ through: {
123
+ model: "like",
124
+ table: "like",
125
+ fromRelation: "user",
126
+ toRelation: "post",
127
+ },
128
+ });
129
+ });
130
+ test("normalizes model with column name transformations", () => {
131
+ const models = populateModels({
132
+ naming: { column: snakeCase },
133
+ models: {
134
+ userProfile: {
135
+ fields: {
136
+ userId: { type: "integer", primaryKey: true },
137
+ firstName: { type: "text" },
138
+ lastName: { type: "text" },
139
+ emailAddress: { type: "text", unique: true },
140
+ },
141
+ },
142
+ },
143
+ });
144
+ const result = normalizeModel(models, models["userProfile"]);
145
+ expect(result.fields["firstName"].column).toBe("first_name");
146
+ expect(result.fields["lastName"].column).toBe("last_name");
147
+ expect(result.fields["emailAddress"].column).toBe("email_address");
148
+ expect(result.uniqueConstraints[0].columns).toEqual(["email_address"]);
149
+ });
150
+ test("normalizes model with custom schema and table names", () => {
151
+ const models = populateModels({
152
+ models: {
153
+ user: {
154
+ schema: "custom_schema",
155
+ table: "custom_table",
156
+ fields: {
157
+ id: { type: "serial", primaryKey: true },
158
+ },
159
+ },
160
+ },
161
+ });
162
+ const result = normalizeModel(models, models["user"]);
163
+ expect(result.schema).toBe("custom_schema");
164
+ expect(result.table).toBe("custom_table");
165
+ });
166
+ test("normalizes model with composite primary key", () => {
167
+ const models = populateModels({
168
+ naming: { column: snakeCase },
169
+ models: {
170
+ orderLine: {
171
+ fields: {
172
+ orderId: { type: "integer" },
173
+ lineNumber: { type: "integer" },
174
+ },
175
+ primaryKey: ["orderId", "lineNumber"],
176
+ },
177
+ },
178
+ });
179
+ const result = normalizeModel(models, models["orderLine"]);
180
+ expect(result.primaryKey).toEqual([
181
+ { field: "orderId", column: "order_id" },
182
+ { field: "lineNumber", column: "line_number" },
183
+ ]);
184
+ });
185
+ test("normalizes model with foreign keys", () => {
186
+ const models = populateModels({
187
+ naming: { column: snakeCase },
188
+ models: {
189
+ order: {
190
+ fields: {
191
+ id: { type: "serial", primaryKey: true },
192
+ customerId: {
193
+ type: "integer",
194
+ references: {
195
+ model: "customer",
196
+ field: "id",
197
+ onDelete: "CASCADE",
198
+ },
199
+ },
200
+ },
201
+ },
202
+ customer: {
203
+ fields: {
204
+ id: { type: "serial", primaryKey: true },
205
+ },
206
+ },
207
+ },
208
+ });
209
+ const result = normalizeModel(models, models["order"]);
210
+ expect(result.foreignKeys).toEqual([
211
+ {
212
+ name: "order_customer_id_fkey",
213
+ fields: ["customerId"],
214
+ columns: ["customer_id"],
215
+ references: {
216
+ model: "customer",
217
+ fields: ["id"],
218
+ schema: "public",
219
+ table: "customer",
220
+ columns: ["id"],
221
+ },
222
+ onUpdate: null,
223
+ onDelete: "CASCADE",
224
+ },
225
+ ]);
226
+ });
227
+ });
@@ -0,0 +1,3 @@
1
+ import { NormalizedPrimaryKey } from "#types/NormalizedPrimaryKey.js";
2
+ import { PopulatedModelDefinition } from "#types/PopulatedModelDefinition.js";
3
+ export declare const normalizePrimaryKey: (model: PopulatedModelDefinition) => NormalizedPrimaryKey[];
@@ -0,0 +1,18 @@
1
+ export const normalizePrimaryKey = (model) => {
2
+ const fieldLevelPrimaryKey = Object.entries(model.fields)
3
+ .filter(([, field]) => field.primaryKey)
4
+ .map(([name]) => name);
5
+ if (model.primaryKey && fieldLevelPrimaryKey.length > 0) {
6
+ throw new Error(`Model "${model.name}" has primary key fields defined at both the model and field levels.`);
7
+ }
8
+ const fields = model.primaryKey ?? fieldLevelPrimaryKey;
9
+ return fields.map((name) => {
10
+ if (!model.fields[name]) {
11
+ throw new Error(`Primary key field "${name}" does not exist in model "${model.name}".`);
12
+ }
13
+ return {
14
+ field: name,
15
+ column: model.fields[name].column,
16
+ };
17
+ });
18
+ };
@@ -0,0 +1 @@
1
+ export {};