@casekit/orm2-config 1.0.0 → 1.0.2
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.
- package/{src/index.ts → build/index.d.ts} +1 -7
- package/build/index.js +4 -0
- package/build/normalize/defaultZodSchema.d.ts +8 -0
- package/{src/normalize/defaultZodSchema.ts → build/normalize/defaultZodSchema.js} +28 -20
- package/build/normalize/defaultZodSchema.test.d.ts +1 -0
- package/{src/normalize/defaultZodSchema.test.ts → build/normalize/defaultZodSchema.test.js} +5 -13
- package/build/normalize/getColumns.d.ts +2 -0
- package/{src/normalize/getColumns.ts → build/normalize/getColumns.js} +1 -6
- package/build/normalize/getColumns.test.d.ts +1 -0
- package/{src/normalize/getColumns.test.ts → build/normalize/getColumns.test.js} +4 -17
- package/build/normalize/normalizeConfig.d.ts +3 -0
- package/{src/normalize/normalizeConfig.ts → build/normalize/normalizeConfig.js} +1 -6
- package/build/normalize/normalizeConfig.test.d.ts +1 -0
- package/{src/normalize/normalizeConfig.test.ts → build/normalize/normalizeConfig.test.js} +22 -68
- package/build/normalize/normalizeField.d.ts +3 -0
- package/build/normalize/normalizeField.js +11 -0
- package/build/normalize/normalizeField.test.d.ts +1 -0
- package/{src/normalize/normalizeField.test.ts → build/normalize/normalizeField.test.js} +3 -8
- package/build/normalize/normalizeForeignKeys.d.ts +5 -0
- package/build/normalize/normalizeForeignKeys.js +50 -0
- package/build/normalize/normalizeForeignKeys.test.d.ts +1 -0
- package/{src/normalize/normalizeForeignKeys.test.ts → build/normalize/normalizeForeignKeys.test.js} +7 -26
- package/build/normalize/normalizeModel.d.ts +3 -0
- package/{src/normalize/normalizeModel.ts → build/normalize/normalizeModel.js} +1 -8
- package/build/normalize/normalizeModel.test.d.ts +1 -0
- package/{src/normalize/normalizeModel.test.ts → build/normalize/normalizeModel.test.js} +14 -38
- package/build/normalize/normalizePrimaryKey.d.ts +3 -0
- package/build/normalize/normalizePrimaryKey.js +18 -0
- package/build/normalize/normalizePrimaryKey.test.d.ts +1 -0
- package/{src/normalize/normalizePrimaryKey.test.ts → build/normalize/normalizePrimaryKey.test.js} +7 -31
- package/build/normalize/normalizeRelations.d.ts +3 -0
- package/{src/normalize/normalizeRelations.ts → build/normalize/normalizeRelations.js} +12 -34
- package/build/normalize/normalizeRelations.test.d.ts +1 -0
- package/{src/normalize/normalizeRelations.test.ts → build/normalize/normalizeRelations.test.js} +9 -38
- package/build/normalize/normalizeUniqueConstraints.d.ts +5 -0
- package/build/normalize/normalizeUniqueConstraints.js +29 -0
- package/build/normalize/normalizeUniqueConstraints.test.d.ts +1 -0
- package/{src/normalize/normalizeUniqueConstraints.test.ts → build/normalize/normalizeUniqueConstraints.test.js} +15 -46
- package/build/normalize/populateField.d.ts +3 -0
- package/{src/normalize/populateField.ts → build/normalize/populateField.js} +1 -9
- package/build/normalize/populateField.test.d.ts +1 -0
- package/build/normalize/populateField.test.js +198 -0
- package/build/normalize/populateModels.d.ts +3 -0
- package/{src/normalize/populateModels.ts → build/normalize/populateModels.js} +2 -11
- package/build/normalize/populateModels.test.d.ts +1 -0
- package/{src/normalize/populateModels.test.ts → build/normalize/populateModels.test.js} +11 -32
- package/{src/types/NormalizedConfig.ts → build/types/NormalizedConfig.d.ts} +1 -8
- package/build/types/NormalizedConfig.js +1 -0
- package/{src/types/NormalizedFieldDefinition.ts → build/types/NormalizedFieldDefinition.d.ts} +0 -1
- package/build/types/NormalizedFieldDefinition.js +1 -0
- package/build/types/NormalizedForeignKeyDefinition.js +1 -0
- package/{src/types/NormalizedModelDefinition.ts → build/types/NormalizedModelDefinition.d.ts} +0 -1
- package/build/types/NormalizedModelDefinition.js +1 -0
- package/build/types/NormalizedPrimaryKey.js +1 -0
- package/{src/types/NormalizedRelationDefinition.ts → build/types/NormalizedRelationDefinition.d.ts} +1 -7
- package/build/types/NormalizedRelationDefinition.js +1 -0
- package/{src/types/NormalizedUniqueConstraintDefinition.ts → build/types/NormalizedUniqueConstraintDefinition.d.ts} +0 -1
- package/build/types/NormalizedUniqueConstraintDefinition.js +1 -0
- package/{src/types/PopulatedFieldDefinition.ts → build/types/PopulatedFieldDefinition.d.ts} +0 -1
- package/build/types/PopulatedFieldDefinition.js +1 -0
- package/{src/types/PopulatedModelDefinition.ts → build/types/PopulatedModelDefinition.d.ts} +0 -2
- package/build/types/PopulatedModelDefinition.js +1 -0
- package/build/util.d.ts +6 -0
- package/build/util.js +21 -0
- package/package.json +10 -10
- package/src/normalize/normalizeField.ts +0 -16
- package/src/normalize/normalizeForeignKeys.ts +0 -89
- package/src/normalize/normalizePrimaryKey.ts +0 -30
- package/src/normalize/normalizeUniqueConstraints.ts +0 -58
- package/src/normalize/populateField.test.ts +0 -253
- package/src/util.ts +0 -38
- /package/{src/types/NormalizedForeignKeyDefinition.ts → build/types/NormalizedForeignKeyDefinition.d.ts} +0 -0
- /package/{src/types/NormalizedPrimaryKey.ts → build/types/NormalizedPrimaryKey.d.ts} +0 -0
package/{src/normalize/normalizeForeignKeys.test.ts → build/normalize/normalizeForeignKeys.test.js}
RENAMED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { snakeCase } from "es-toolkit";
|
|
2
2
|
import { describe, expect, test } from "vitest";
|
|
3
|
-
|
|
4
3
|
import { normalizeForeignKeys } from "./normalizeForeignKeys.js";
|
|
5
4
|
import { populateModels } from "./populateModels.js";
|
|
6
|
-
|
|
7
5
|
describe("normalizeForeignKeys", () => {
|
|
8
6
|
test("normalizes foreign keys defined at the top level", () => {
|
|
9
7
|
const models = populateModels({
|
|
@@ -25,8 +23,7 @@ describe("normalizeForeignKeys", () => {
|
|
|
25
23
|
},
|
|
26
24
|
},
|
|
27
25
|
});
|
|
28
|
-
|
|
29
|
-
expect(normalizeForeignKeys(models, models["post"]!)).toEqual([
|
|
26
|
+
expect(normalizeForeignKeys(models, models["post"])).toEqual([
|
|
30
27
|
{
|
|
31
28
|
name: "post_user_id_fkey",
|
|
32
29
|
fields: ["userId"],
|
|
@@ -43,7 +40,6 @@ describe("normalizeForeignKeys", () => {
|
|
|
43
40
|
},
|
|
44
41
|
]);
|
|
45
42
|
});
|
|
46
|
-
|
|
47
43
|
test("normalizes foreign keys defined in foreignKeys array", () => {
|
|
48
44
|
const models = populateModels({
|
|
49
45
|
naming: { column: snakeCase },
|
|
@@ -70,8 +66,7 @@ describe("normalizeForeignKeys", () => {
|
|
|
70
66
|
},
|
|
71
67
|
},
|
|
72
68
|
});
|
|
73
|
-
|
|
74
|
-
expect(normalizeForeignKeys(models, models["post"]!)).toEqual([
|
|
69
|
+
expect(normalizeForeignKeys(models, models["post"])).toEqual([
|
|
75
70
|
{
|
|
76
71
|
name: "post_user_id_fkey",
|
|
77
72
|
fields: ["userId"],
|
|
@@ -88,7 +83,6 @@ describe("normalizeForeignKeys", () => {
|
|
|
88
83
|
},
|
|
89
84
|
]);
|
|
90
85
|
});
|
|
91
|
-
|
|
92
86
|
test("throws error when referenced model doesn't exist", () => {
|
|
93
87
|
const models = populateModels({
|
|
94
88
|
naming: { column: snakeCase },
|
|
@@ -104,12 +98,8 @@ describe("normalizeForeignKeys", () => {
|
|
|
104
98
|
},
|
|
105
99
|
},
|
|
106
100
|
});
|
|
107
|
-
|
|
108
|
-
expect(() => normalizeForeignKeys(models, models["post"]!)).toThrow(
|
|
109
|
-
'Referenced model "nonexistent" not found in models',
|
|
110
|
-
);
|
|
101
|
+
expect(() => normalizeForeignKeys(models, models["post"])).toThrow('Referenced model "nonexistent" not found in models');
|
|
111
102
|
});
|
|
112
|
-
|
|
113
103
|
test("respects custom onDelete and onUpdate actions", () => {
|
|
114
104
|
const models = populateModels({
|
|
115
105
|
naming: { column: snakeCase },
|
|
@@ -135,8 +125,7 @@ describe("normalizeForeignKeys", () => {
|
|
|
135
125
|
},
|
|
136
126
|
},
|
|
137
127
|
});
|
|
138
|
-
|
|
139
|
-
expect(normalizeForeignKeys(models, models["post"]!)).toEqual([
|
|
128
|
+
expect(normalizeForeignKeys(models, models["post"])).toEqual([
|
|
140
129
|
{
|
|
141
130
|
name: "post_user_id_fkey",
|
|
142
131
|
fields: ["userId"],
|
|
@@ -153,7 +142,6 @@ describe("normalizeForeignKeys", () => {
|
|
|
153
142
|
},
|
|
154
143
|
]);
|
|
155
144
|
});
|
|
156
|
-
|
|
157
145
|
test("throws error on duplicate foreign keys", () => {
|
|
158
146
|
const models = populateModels({
|
|
159
147
|
naming: { column: snakeCase },
|
|
@@ -183,12 +171,8 @@ describe("normalizeForeignKeys", () => {
|
|
|
183
171
|
},
|
|
184
172
|
},
|
|
185
173
|
});
|
|
186
|
-
|
|
187
|
-
expect(() => normalizeForeignKeys(models, models["post"]!)).toThrow(
|
|
188
|
-
'Duplicate foreign key defined in model "post"',
|
|
189
|
-
);
|
|
174
|
+
expect(() => normalizeForeignKeys(models, models["post"])).toThrow('Duplicate foreign key defined in model "post"');
|
|
190
175
|
});
|
|
191
|
-
|
|
192
176
|
test("handles custom foreign key names", () => {
|
|
193
177
|
const models = populateModels({
|
|
194
178
|
naming: { column: snakeCase },
|
|
@@ -216,8 +200,7 @@ describe("normalizeForeignKeys", () => {
|
|
|
216
200
|
},
|
|
217
201
|
},
|
|
218
202
|
});
|
|
219
|
-
|
|
220
|
-
expect(normalizeForeignKeys(models, models["post"]!)).toEqual([
|
|
203
|
+
expect(normalizeForeignKeys(models, models["post"])).toEqual([
|
|
221
204
|
{
|
|
222
205
|
name: "custom_fk_name",
|
|
223
206
|
fields: ["userId"],
|
|
@@ -234,7 +217,6 @@ describe("normalizeForeignKeys", () => {
|
|
|
234
217
|
},
|
|
235
218
|
]);
|
|
236
219
|
});
|
|
237
|
-
|
|
238
220
|
test("handles foreign keys in custom schema", () => {
|
|
239
221
|
const models = populateModels({
|
|
240
222
|
naming: { column: snakeCase },
|
|
@@ -256,8 +238,7 @@ describe("normalizeForeignKeys", () => {
|
|
|
256
238
|
},
|
|
257
239
|
},
|
|
258
240
|
});
|
|
259
|
-
|
|
260
|
-
expect(normalizeForeignKeys(models, models["post"]!)).toEqual([
|
|
241
|
+
expect(normalizeForeignKeys(models, models["post"])).toEqual([
|
|
261
242
|
{
|
|
262
243
|
name: "post_user_id_fkey",
|
|
263
244
|
fields: ["userId"],
|
|
@@ -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;
|
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
import { mapValues } from "es-toolkit";
|
|
2
|
-
|
|
3
|
-
import { NormalizedModelDefinition } from "#types/NormalizedModelDefinition.js";
|
|
4
|
-
import { PopulatedModelDefinition } from "#types/PopulatedModelDefinition.js";
|
|
5
2
|
import { normalizeField } from "./normalizeField.js";
|
|
6
3
|
import { normalizeForeignKeys } from "./normalizeForeignKeys.js";
|
|
7
4
|
import { normalizePrimaryKey } from "./normalizePrimaryKey.js";
|
|
8
5
|
import { normalizeRelations } from "./normalizeRelations.js";
|
|
9
6
|
import { normalizeUniqueConstraints } from "./normalizeUniqueConstraints.js";
|
|
10
|
-
|
|
11
|
-
export const normalizeModel = (
|
|
12
|
-
models: Record<string, PopulatedModelDefinition>,
|
|
13
|
-
model: PopulatedModelDefinition,
|
|
14
|
-
): NormalizedModelDefinition => {
|
|
7
|
+
export const normalizeModel = (models, model) => {
|
|
15
8
|
return {
|
|
16
9
|
name: model.name,
|
|
17
10
|
schema: model.schema,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import { snakeCase } from "es-toolkit";
|
|
2
2
|
import { describe, expect, test } from "vitest";
|
|
3
3
|
import { ZodType, z } from "zod";
|
|
4
|
-
|
|
5
4
|
import { sql } from "@casekit/sql";
|
|
6
|
-
|
|
7
5
|
import { normalizeModel } from "./normalizeModel.js";
|
|
8
6
|
import { populateModels } from "./populateModels.js";
|
|
9
|
-
|
|
10
7
|
describe("normalizeModel", () => {
|
|
11
8
|
test("normalizes complete model definition", () => {
|
|
12
9
|
const models = populateModels({
|
|
@@ -30,7 +27,7 @@ describe("normalizeModel", () => {
|
|
|
30
27
|
},
|
|
31
28
|
createdAt: {
|
|
32
29
|
type: "timestamp",
|
|
33
|
-
default: sql`NOW()`,
|
|
30
|
+
default: sql `NOW()`,
|
|
34
31
|
provided: true,
|
|
35
32
|
},
|
|
36
33
|
},
|
|
@@ -66,16 +63,13 @@ describe("normalizeModel", () => {
|
|
|
66
63
|
},
|
|
67
64
|
},
|
|
68
65
|
});
|
|
69
|
-
|
|
70
|
-
const result = normalizeModel(models, models["user"]!);
|
|
71
|
-
|
|
66
|
+
const result = normalizeModel(models, models["user"]);
|
|
72
67
|
// Test basic model properties
|
|
73
68
|
expect(result.name).toBe("user");
|
|
74
69
|
expect(result.schema).toBe("auth");
|
|
75
70
|
expect(result.table).toBe("user");
|
|
76
|
-
|
|
77
71
|
// Test fields
|
|
78
|
-
expect(result.fields["id"]
|
|
72
|
+
expect(result.fields["id"]).toEqual({
|
|
79
73
|
name: "id",
|
|
80
74
|
column: "id",
|
|
81
75
|
type: "serial",
|
|
@@ -84,8 +78,7 @@ describe("normalizeModel", () => {
|
|
|
84
78
|
default: null,
|
|
85
79
|
provided: false,
|
|
86
80
|
});
|
|
87
|
-
|
|
88
|
-
expect(result.fields["email"]!).toEqual({
|
|
81
|
+
expect(result.fields["email"]).toEqual({
|
|
89
82
|
name: "email",
|
|
90
83
|
column: "email",
|
|
91
84
|
type: "text",
|
|
@@ -94,10 +87,8 @@ describe("normalizeModel", () => {
|
|
|
94
87
|
default: null,
|
|
95
88
|
provided: false,
|
|
96
89
|
});
|
|
97
|
-
|
|
98
90
|
// Test primary key
|
|
99
91
|
expect(result.primaryKey).toEqual([{ field: "id", column: "id" }]);
|
|
100
|
-
|
|
101
92
|
// Test unique constraints
|
|
102
93
|
expect(result.uniqueConstraints).toEqual([
|
|
103
94
|
{
|
|
@@ -108,9 +99,8 @@ describe("normalizeModel", () => {
|
|
|
108
99
|
nullsNotDistinct: false,
|
|
109
100
|
},
|
|
110
101
|
]);
|
|
111
|
-
|
|
112
102
|
// Test relations
|
|
113
|
-
expect(result.relations["posts"]
|
|
103
|
+
expect(result.relations["posts"]).toEqual({
|
|
114
104
|
name: "posts",
|
|
115
105
|
type: "1:N",
|
|
116
106
|
model: "post",
|
|
@@ -124,8 +114,7 @@ describe("normalizeModel", () => {
|
|
|
124
114
|
columns: ["author_id"],
|
|
125
115
|
},
|
|
126
116
|
});
|
|
127
|
-
|
|
128
|
-
expect(result.relations["likedPosts"]!).toEqual({
|
|
117
|
+
expect(result.relations["likedPosts"]).toEqual({
|
|
129
118
|
name: "likedPosts",
|
|
130
119
|
type: "N:N",
|
|
131
120
|
model: "post",
|
|
@@ -138,7 +127,6 @@ describe("normalizeModel", () => {
|
|
|
138
127
|
},
|
|
139
128
|
});
|
|
140
129
|
});
|
|
141
|
-
|
|
142
130
|
test("normalizes model with column name transformations", () => {
|
|
143
131
|
const models = populateModels({
|
|
144
132
|
naming: { column: snakeCase },
|
|
@@ -153,16 +141,12 @@ describe("normalizeModel", () => {
|
|
|
153
141
|
},
|
|
154
142
|
},
|
|
155
143
|
});
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
expect(result.fields["
|
|
160
|
-
expect(result.
|
|
161
|
-
expect(result.fields["emailAddress"]!.column).toBe("email_address");
|
|
162
|
-
|
|
163
|
-
expect(result.uniqueConstraints[0]!.columns).toEqual(["email_address"]);
|
|
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"]);
|
|
164
149
|
});
|
|
165
|
-
|
|
166
150
|
test("normalizes model with custom schema and table names", () => {
|
|
167
151
|
const models = populateModels({
|
|
168
152
|
models: {
|
|
@@ -175,13 +159,10 @@ describe("normalizeModel", () => {
|
|
|
175
159
|
},
|
|
176
160
|
},
|
|
177
161
|
});
|
|
178
|
-
|
|
179
|
-
const result = normalizeModel(models, models["user"]!);
|
|
180
|
-
|
|
162
|
+
const result = normalizeModel(models, models["user"]);
|
|
181
163
|
expect(result.schema).toBe("custom_schema");
|
|
182
164
|
expect(result.table).toBe("custom_table");
|
|
183
165
|
});
|
|
184
|
-
|
|
185
166
|
test("normalizes model with composite primary key", () => {
|
|
186
167
|
const models = populateModels({
|
|
187
168
|
naming: { column: snakeCase },
|
|
@@ -195,15 +176,12 @@ describe("normalizeModel", () => {
|
|
|
195
176
|
},
|
|
196
177
|
},
|
|
197
178
|
});
|
|
198
|
-
|
|
199
|
-
const result = normalizeModel(models, models["orderLine"]!);
|
|
200
|
-
|
|
179
|
+
const result = normalizeModel(models, models["orderLine"]);
|
|
201
180
|
expect(result.primaryKey).toEqual([
|
|
202
181
|
{ field: "orderId", column: "order_id" },
|
|
203
182
|
{ field: "lineNumber", column: "line_number" },
|
|
204
183
|
]);
|
|
205
184
|
});
|
|
206
|
-
|
|
207
185
|
test("normalizes model with foreign keys", () => {
|
|
208
186
|
const models = populateModels({
|
|
209
187
|
naming: { column: snakeCase },
|
|
@@ -228,9 +206,7 @@ describe("normalizeModel", () => {
|
|
|
228
206
|
},
|
|
229
207
|
},
|
|
230
208
|
});
|
|
231
|
-
|
|
232
|
-
const result = normalizeModel(models, models["order"]!);
|
|
233
|
-
|
|
209
|
+
const result = normalizeModel(models, models["order"]);
|
|
234
210
|
expect(result.foreignKeys).toEqual([
|
|
235
211
|
{
|
|
236
212
|
name: "order_customer_id_fkey",
|
|
@@ -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 {};
|
package/{src/normalize/normalizePrimaryKey.test.ts → build/normalize/normalizePrimaryKey.test.js}
RENAMED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { snakeCase } from "es-toolkit";
|
|
2
2
|
import { describe, expect, test } from "vitest";
|
|
3
|
-
|
|
4
3
|
import { normalizePrimaryKey } from "./normalizePrimaryKey.js";
|
|
5
4
|
import { populateModels } from "./populateModels.js";
|
|
6
|
-
|
|
7
5
|
describe("normalizePrimaryKey", () => {
|
|
8
6
|
test("normalizes field-level primary key", () => {
|
|
9
7
|
const models = populateModels({
|
|
@@ -16,9 +14,7 @@ describe("normalizePrimaryKey", () => {
|
|
|
16
14
|
},
|
|
17
15
|
},
|
|
18
16
|
});
|
|
19
|
-
|
|
20
|
-
const result = normalizePrimaryKey(models["user"]!);
|
|
21
|
-
|
|
17
|
+
const result = normalizePrimaryKey(models["user"]);
|
|
22
18
|
expect(result).toEqual([
|
|
23
19
|
{
|
|
24
20
|
field: "id",
|
|
@@ -26,7 +22,6 @@ describe("normalizePrimaryKey", () => {
|
|
|
26
22
|
},
|
|
27
23
|
]);
|
|
28
24
|
});
|
|
29
|
-
|
|
30
25
|
test("normalizes model-level primary key", () => {
|
|
31
26
|
const models = populateModels({
|
|
32
27
|
models: {
|
|
@@ -40,9 +35,7 @@ describe("normalizePrimaryKey", () => {
|
|
|
40
35
|
},
|
|
41
36
|
},
|
|
42
37
|
});
|
|
43
|
-
|
|
44
|
-
const result = normalizePrimaryKey(models["userRole"]!);
|
|
45
|
-
|
|
38
|
+
const result = normalizePrimaryKey(models["userRole"]);
|
|
46
39
|
expect(result).toEqual([
|
|
47
40
|
{
|
|
48
41
|
field: "userId",
|
|
@@ -54,7 +47,6 @@ describe("normalizePrimaryKey", () => {
|
|
|
54
47
|
},
|
|
55
48
|
]);
|
|
56
49
|
});
|
|
57
|
-
|
|
58
50
|
test("throws error when primary key is defined at both levels", () => {
|
|
59
51
|
const models = populateModels({
|
|
60
52
|
models: {
|
|
@@ -67,12 +59,8 @@ describe("normalizePrimaryKey", () => {
|
|
|
67
59
|
},
|
|
68
60
|
},
|
|
69
61
|
});
|
|
70
|
-
|
|
71
|
-
expect(() => normalizePrimaryKey(models["user"]!)).toThrow(
|
|
72
|
-
'Model "user" has primary key fields defined at both the model and field levels.',
|
|
73
|
-
);
|
|
62
|
+
expect(() => normalizePrimaryKey(models["user"])).toThrow('Model "user" has primary key fields defined at both the model and field levels.');
|
|
74
63
|
});
|
|
75
|
-
|
|
76
64
|
test("handles column name transformations", () => {
|
|
77
65
|
const models = populateModels({
|
|
78
66
|
naming: { column: snakeCase },
|
|
@@ -85,9 +73,7 @@ describe("normalizePrimaryKey", () => {
|
|
|
85
73
|
},
|
|
86
74
|
},
|
|
87
75
|
});
|
|
88
|
-
|
|
89
|
-
const result = normalizePrimaryKey(models["user"]!);
|
|
90
|
-
|
|
76
|
+
const result = normalizePrimaryKey(models["user"]);
|
|
91
77
|
expect(result).toEqual([
|
|
92
78
|
{
|
|
93
79
|
field: "userId",
|
|
@@ -95,7 +81,6 @@ describe("normalizePrimaryKey", () => {
|
|
|
95
81
|
},
|
|
96
82
|
]);
|
|
97
83
|
});
|
|
98
|
-
|
|
99
84
|
test("handles custom column names", () => {
|
|
100
85
|
const models = populateModels({
|
|
101
86
|
models: {
|
|
@@ -110,9 +95,7 @@ describe("normalizePrimaryKey", () => {
|
|
|
110
95
|
},
|
|
111
96
|
},
|
|
112
97
|
});
|
|
113
|
-
|
|
114
|
-
const result = normalizePrimaryKey(models["user"]!);
|
|
115
|
-
|
|
98
|
+
const result = normalizePrimaryKey(models["user"]);
|
|
116
99
|
expect(result).toEqual([
|
|
117
100
|
{
|
|
118
101
|
field: "id",
|
|
@@ -120,7 +103,6 @@ describe("normalizePrimaryKey", () => {
|
|
|
120
103
|
},
|
|
121
104
|
]);
|
|
122
105
|
});
|
|
123
|
-
|
|
124
106
|
test("throws error for non-existent primary key field in model-level definition", () => {
|
|
125
107
|
const models = populateModels({
|
|
126
108
|
models: {
|
|
@@ -133,12 +115,8 @@ describe("normalizePrimaryKey", () => {
|
|
|
133
115
|
},
|
|
134
116
|
},
|
|
135
117
|
});
|
|
136
|
-
|
|
137
|
-
expect(() => normalizePrimaryKey(models["user"]!)).toThrow(
|
|
138
|
-
'Primary key field "nonexistent" does not exist in model "user".',
|
|
139
|
-
);
|
|
118
|
+
expect(() => normalizePrimaryKey(models["user"])).toThrow('Primary key field "nonexistent" does not exist in model "user".');
|
|
140
119
|
});
|
|
141
|
-
|
|
142
120
|
test("handles multiple field-level primary keys", () => {
|
|
143
121
|
const models = populateModels({
|
|
144
122
|
models: {
|
|
@@ -151,9 +129,7 @@ describe("normalizePrimaryKey", () => {
|
|
|
151
129
|
},
|
|
152
130
|
},
|
|
153
131
|
});
|
|
154
|
-
|
|
155
|
-
const result = normalizePrimaryKey(models["userRole"]!);
|
|
156
|
-
|
|
132
|
+
const result = normalizePrimaryKey(models["userRole"]);
|
|
157
133
|
expect(result).toEqual([
|
|
158
134
|
{
|
|
159
135
|
field: "userId",
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { NormalizedRelationDefinition } from "#types/NormalizedRelationDefinition.js";
|
|
2
|
+
import { PopulatedModelDefinition } from "#types/PopulatedModelDefinition.js";
|
|
3
|
+
export declare const normalizeRelations: (models: Record<string, PopulatedModelDefinition>, model: PopulatedModelDefinition) => Record<string, NormalizedRelationDefinition>;
|
|
@@ -1,49 +1,25 @@
|
|
|
1
1
|
import { mapValues } from "es-toolkit";
|
|
2
2
|
import { castArray } from "es-toolkit/compat";
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
NormalizedManyToManyRelationDefinition,
|
|
6
|
-
NormalizedManyToOneRelationDefinition,
|
|
7
|
-
NormalizedOneToManyRelationDefinition,
|
|
8
|
-
NormalizedRelationDefinition,
|
|
9
|
-
} from "#types/NormalizedRelationDefinition.js";
|
|
10
|
-
import { PopulatedModelDefinition } from "#types/PopulatedModelDefinition.js";
|
|
11
|
-
|
|
12
|
-
const normalizeRelationKeys = (
|
|
13
|
-
model: PopulatedModelDefinition,
|
|
14
|
-
fields: string | string[],
|
|
15
|
-
) => {
|
|
3
|
+
const normalizeRelationKeys = (model, fields) => {
|
|
16
4
|
const columns = castArray(fields).map((field) => {
|
|
17
5
|
if (!model.fields[field]) {
|
|
18
|
-
throw new Error(
|
|
19
|
-
`Model "${model.name}" has relation with non-existent field "${field}".`,
|
|
20
|
-
);
|
|
6
|
+
throw new Error(`Model "${model.name}" has relation with non-existent field "${field}".`);
|
|
21
7
|
}
|
|
22
8
|
return model.fields[field].column;
|
|
23
9
|
});
|
|
24
10
|
return { fields: castArray(fields), columns };
|
|
25
11
|
};
|
|
26
|
-
|
|
27
|
-
export const normalizeRelations = (
|
|
28
|
-
models: Record<string, PopulatedModelDefinition>,
|
|
29
|
-
model: PopulatedModelDefinition,
|
|
30
|
-
): Record<string, NormalizedRelationDefinition> => {
|
|
12
|
+
export const normalizeRelations = (models, model) => {
|
|
31
13
|
return mapValues(model.relations, (relation, name) => {
|
|
32
14
|
const relatedModel = models[relation.model];
|
|
33
15
|
if (!relatedModel) {
|
|
34
|
-
throw new Error(
|
|
35
|
-
`Model "${model.name}" has relation "${name}" that references non-existent model "${relation.model}".`,
|
|
36
|
-
);
|
|
16
|
+
throw new Error(`Model "${model.name}" has relation "${name}" that references non-existent model "${relation.model}".`);
|
|
37
17
|
}
|
|
38
|
-
|
|
39
18
|
if (relation.type === "N:N") {
|
|
40
19
|
const joinModel = models[relation.through.model];
|
|
41
20
|
if (!joinModel) {
|
|
42
|
-
throw new Error(
|
|
43
|
-
`Model "${model.name}" has relation "${name}" with join model "${relation.through.model}" that does not exist.`,
|
|
44
|
-
);
|
|
21
|
+
throw new Error(`Model "${model.name}" has relation "${name}" with join model "${relation.through.model}" that does not exist.`);
|
|
45
22
|
}
|
|
46
|
-
|
|
47
23
|
return {
|
|
48
24
|
name,
|
|
49
25
|
type: relation.type,
|
|
@@ -55,8 +31,9 @@ export const normalizeRelations = (
|
|
|
55
31
|
fromRelation: relation.through.fromRelation,
|
|
56
32
|
toRelation: relation.through.toRelation,
|
|
57
33
|
},
|
|
58
|
-
}
|
|
59
|
-
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
else if (relation.type === "1:N") {
|
|
60
37
|
return {
|
|
61
38
|
name,
|
|
62
39
|
type: relation.type,
|
|
@@ -64,8 +41,9 @@ export const normalizeRelations = (
|
|
|
64
41
|
table: relatedModel.table,
|
|
65
42
|
from: normalizeRelationKeys(model, relation.fromField),
|
|
66
43
|
to: normalizeRelationKeys(relatedModel, relation.toField),
|
|
67
|
-
}
|
|
68
|
-
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
69
47
|
return {
|
|
70
48
|
name,
|
|
71
49
|
type: relation.type,
|
|
@@ -74,7 +52,7 @@ export const normalizeRelations = (
|
|
|
74
52
|
optional: relation.optional ?? false,
|
|
75
53
|
from: normalizeRelationKeys(model, relation.fromField),
|
|
76
54
|
to: normalizeRelationKeys(relatedModel, relation.toField),
|
|
77
|
-
}
|
|
55
|
+
};
|
|
78
56
|
}
|
|
79
57
|
});
|
|
80
58
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/{src/normalize/normalizeRelations.test.ts → build/normalize/normalizeRelations.test.js}
RENAMED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { snakeCase } from "es-toolkit";
|
|
2
2
|
import { describe, expect, test } from "vitest";
|
|
3
|
-
|
|
4
|
-
import { NormalizedOneToManyRelationDefinition } from "../types/NormalizedRelationDefinition.js";
|
|
5
3
|
import { normalizeRelations } from "./normalizeRelations.js";
|
|
6
4
|
import { populateModels } from "./populateModels.js";
|
|
7
|
-
|
|
8
5
|
describe("normalizeRelations", () => {
|
|
9
6
|
test("normalizes one-to-many relation", () => {
|
|
10
7
|
const models = populateModels({
|
|
@@ -31,9 +28,7 @@ describe("normalizeRelations", () => {
|
|
|
31
28
|
},
|
|
32
29
|
},
|
|
33
30
|
});
|
|
34
|
-
|
|
35
|
-
const result = normalizeRelations(models, models["user"]!);
|
|
36
|
-
|
|
31
|
+
const result = normalizeRelations(models, models["user"]);
|
|
37
32
|
expect(result).toEqual({
|
|
38
33
|
posts: {
|
|
39
34
|
name: "posts",
|
|
@@ -51,7 +46,6 @@ describe("normalizeRelations", () => {
|
|
|
51
46
|
},
|
|
52
47
|
});
|
|
53
48
|
});
|
|
54
|
-
|
|
55
49
|
test("normalizes many-to-one relation", () => {
|
|
56
50
|
const models = populateModels({
|
|
57
51
|
naming: { column: snakeCase },
|
|
@@ -77,9 +71,7 @@ describe("normalizeRelations", () => {
|
|
|
77
71
|
},
|
|
78
72
|
},
|
|
79
73
|
});
|
|
80
|
-
|
|
81
|
-
const result = normalizeRelations(models, models["post"]!);
|
|
82
|
-
|
|
74
|
+
const result = normalizeRelations(models, models["post"]);
|
|
83
75
|
expect(result).toEqual({
|
|
84
76
|
author: {
|
|
85
77
|
name: "author",
|
|
@@ -98,7 +90,6 @@ describe("normalizeRelations", () => {
|
|
|
98
90
|
},
|
|
99
91
|
});
|
|
100
92
|
});
|
|
101
|
-
|
|
102
93
|
test("normalizes many-to-many relation", () => {
|
|
103
94
|
const models = populateModels({
|
|
104
95
|
naming: { column: snakeCase },
|
|
@@ -132,9 +123,7 @@ describe("normalizeRelations", () => {
|
|
|
132
123
|
},
|
|
133
124
|
},
|
|
134
125
|
});
|
|
135
|
-
|
|
136
|
-
const result = normalizeRelations(models, models["user"]!);
|
|
137
|
-
|
|
126
|
+
const result = normalizeRelations(models, models["user"]);
|
|
138
127
|
expect(result).toEqual({
|
|
139
128
|
likedPosts: {
|
|
140
129
|
model: "post",
|
|
@@ -150,7 +139,6 @@ describe("normalizeRelations", () => {
|
|
|
150
139
|
},
|
|
151
140
|
});
|
|
152
141
|
});
|
|
153
|
-
|
|
154
142
|
test("handles composite keys in relations", () => {
|
|
155
143
|
const models = populateModels({
|
|
156
144
|
naming: { column: snakeCase },
|
|
@@ -179,9 +167,7 @@ describe("normalizeRelations", () => {
|
|
|
179
167
|
},
|
|
180
168
|
},
|
|
181
169
|
});
|
|
182
|
-
|
|
183
|
-
const result = normalizeRelations(models, models["order"]!);
|
|
184
|
-
|
|
170
|
+
const result = normalizeRelations(models, models["order"]);
|
|
185
171
|
expect(result).toEqual({
|
|
186
172
|
product: {
|
|
187
173
|
name: "product",
|
|
@@ -200,7 +186,6 @@ describe("normalizeRelations", () => {
|
|
|
200
186
|
},
|
|
201
187
|
});
|
|
202
188
|
});
|
|
203
|
-
|
|
204
189
|
test("throws error for non-existent related model", () => {
|
|
205
190
|
const models = populateModels({
|
|
206
191
|
models: {
|
|
@@ -219,12 +204,8 @@ describe("normalizeRelations", () => {
|
|
|
219
204
|
},
|
|
220
205
|
},
|
|
221
206
|
});
|
|
222
|
-
|
|
223
|
-
expect(() => normalizeRelations(models, models["user"]!)).toThrow(
|
|
224
|
-
'Model "user" has relation "posts" that references non-existent model "nonexistent".',
|
|
225
|
-
);
|
|
207
|
+
expect(() => normalizeRelations(models, models["user"])).toThrow('Model "user" has relation "posts" that references non-existent model "nonexistent".');
|
|
226
208
|
});
|
|
227
|
-
|
|
228
209
|
test("throws error for non-existent join model", () => {
|
|
229
210
|
const models = populateModels({
|
|
230
211
|
models: {
|
|
@@ -251,12 +232,8 @@ describe("normalizeRelations", () => {
|
|
|
251
232
|
},
|
|
252
233
|
},
|
|
253
234
|
});
|
|
254
|
-
|
|
255
|
-
expect(() => normalizeRelations(models, models["user"]!)).toThrow(
|
|
256
|
-
'Model "user" has relation "likedPosts" with join model "nonexistent" that does not exist.',
|
|
257
|
-
);
|
|
235
|
+
expect(() => normalizeRelations(models, models["user"])).toThrow('Model "user" has relation "likedPosts" with join model "nonexistent" that does not exist.');
|
|
258
236
|
});
|
|
259
|
-
|
|
260
237
|
test("throws error for non-existent field in relation", () => {
|
|
261
238
|
const models = populateModels({
|
|
262
239
|
models: {
|
|
@@ -281,12 +258,8 @@ describe("normalizeRelations", () => {
|
|
|
281
258
|
},
|
|
282
259
|
},
|
|
283
260
|
});
|
|
284
|
-
|
|
285
|
-
expect(() => normalizeRelations(models, models["user"]!)).toThrow(
|
|
286
|
-
'Model "user" has relation with non-existent field "nonexistent".',
|
|
287
|
-
);
|
|
261
|
+
expect(() => normalizeRelations(models, models["user"])).toThrow('Model "user" has relation with non-existent field "nonexistent".');
|
|
288
262
|
});
|
|
289
|
-
|
|
290
263
|
test("handles custom column names", () => {
|
|
291
264
|
const models = populateModels({
|
|
292
265
|
models: {
|
|
@@ -317,10 +290,8 @@ describe("normalizeRelations", () => {
|
|
|
317
290
|
},
|
|
318
291
|
},
|
|
319
292
|
});
|
|
320
|
-
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
const posts = result["posts"]! as NormalizedOneToManyRelationDefinition;
|
|
293
|
+
const result = normalizeRelations(models, models["user"]);
|
|
294
|
+
const posts = result["posts"];
|
|
324
295
|
expect(posts.from.columns).toEqual(["user_identifier"]);
|
|
325
296
|
expect(posts.to.columns).toEqual(["created_by_user"]);
|
|
326
297
|
});
|