orchid-orm 1.3.14 → 1.3.16
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/CHANGELOG.md +15 -0
- package/dist/index.d.ts +21 -23
- package/dist/index.esm.js +678 -450
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +677 -449
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/relations/belongsTo.ts +289 -184
- package/src/relations/hasAndBelongsToMany.ts +283 -209
- package/src/relations/hasMany.ts +237 -166
- package/src/relations/hasOne.ts +205 -132
- package/src/relations/relations.ts +14 -8
- package/src/relations/utils.ts +151 -1
package/src/relations/hasMany.ts
CHANGED
|
@@ -8,8 +8,6 @@ import { Model } from '../model';
|
|
|
8
8
|
import {
|
|
9
9
|
addQueryOn,
|
|
10
10
|
getQueryAs,
|
|
11
|
-
HasManyNestedInsert,
|
|
12
|
-
HasManyNestedUpdate,
|
|
13
11
|
HasManyRelation,
|
|
14
12
|
CreateData,
|
|
15
13
|
JoinCallback,
|
|
@@ -21,8 +19,18 @@ import {
|
|
|
21
19
|
WhereResult,
|
|
22
20
|
InsertQueryData,
|
|
23
21
|
isQueryReturnsAll,
|
|
22
|
+
VirtualColumn,
|
|
23
|
+
CreateCtx,
|
|
24
|
+
UpdateCtx,
|
|
24
25
|
} from 'pqb';
|
|
25
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
getSourceRelation,
|
|
28
|
+
getThroughRelation,
|
|
29
|
+
hasRelationHandleCreate,
|
|
30
|
+
hasRelationHandleUpdate,
|
|
31
|
+
NestedInsertManyItems,
|
|
32
|
+
NestedUpdateManyItems,
|
|
33
|
+
} from './utils';
|
|
26
34
|
|
|
27
35
|
export interface HasMany extends RelationThunkBase {
|
|
28
36
|
type: 'hasMany';
|
|
@@ -56,6 +64,65 @@ export type HasManyInfo<
|
|
|
56
64
|
chainedDelete: true;
|
|
57
65
|
};
|
|
58
66
|
|
|
67
|
+
type State = {
|
|
68
|
+
query: Query;
|
|
69
|
+
primaryKey: string;
|
|
70
|
+
foreignKey: string;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export type HasManyNestedUpdate = (
|
|
74
|
+
query: Query,
|
|
75
|
+
data: Record<string, unknown>[],
|
|
76
|
+
relationData: NestedUpdateManyItems,
|
|
77
|
+
) => Promise<void>;
|
|
78
|
+
|
|
79
|
+
export type HasManyNestedInsert = (
|
|
80
|
+
query: Query,
|
|
81
|
+
data: [
|
|
82
|
+
selfData: Record<string, unknown>,
|
|
83
|
+
relationData: NestedInsertManyItems,
|
|
84
|
+
][],
|
|
85
|
+
) => Promise<void>;
|
|
86
|
+
|
|
87
|
+
class HasManyVirtualColumn extends VirtualColumn {
|
|
88
|
+
private readonly nestedInsert: HasManyNestedInsert;
|
|
89
|
+
private readonly nestedUpdate: HasManyNestedUpdate;
|
|
90
|
+
|
|
91
|
+
constructor(private key: string, private state: State) {
|
|
92
|
+
super();
|
|
93
|
+
this.nestedInsert = nestedInsert(state);
|
|
94
|
+
this.nestedUpdate = nestedUpdate(state);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
create(
|
|
98
|
+
q: Query,
|
|
99
|
+
ctx: CreateCtx,
|
|
100
|
+
item: Record<string, unknown>,
|
|
101
|
+
rowIndex: number,
|
|
102
|
+
) {
|
|
103
|
+
hasRelationHandleCreate(
|
|
104
|
+
q,
|
|
105
|
+
ctx,
|
|
106
|
+
item,
|
|
107
|
+
rowIndex,
|
|
108
|
+
this.key,
|
|
109
|
+
this.state.primaryKey,
|
|
110
|
+
this.nestedInsert,
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
update(q: Query, ctx: UpdateCtx, set: Record<string, unknown>) {
|
|
115
|
+
hasRelationHandleUpdate(
|
|
116
|
+
q,
|
|
117
|
+
ctx,
|
|
118
|
+
set,
|
|
119
|
+
this.key,
|
|
120
|
+
this.state.primaryKey,
|
|
121
|
+
this.nestedUpdate,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
59
126
|
export const makeHasManyMethod = (
|
|
60
127
|
model: Query,
|
|
61
128
|
relation: HasMany,
|
|
@@ -92,8 +159,6 @@ export const makeHasManyMethod = (
|
|
|
92
159
|
whereExistsCallback as unknown as JoinCallback<Query, Query>,
|
|
93
160
|
);
|
|
94
161
|
},
|
|
95
|
-
nestedInsert: undefined,
|
|
96
|
-
nestedUpdate: undefined,
|
|
97
162
|
joinQuery(fromQuery, toQuery) {
|
|
98
163
|
return toQuery.whereExists<Query, Query>(
|
|
99
164
|
throughRelation.joinQuery(fromQuery, throughRelation.query),
|
|
@@ -123,6 +188,7 @@ export const makeHasManyMethod = (
|
|
|
123
188
|
}
|
|
124
189
|
|
|
125
190
|
const { primaryKey, foreignKey } = relation.options;
|
|
191
|
+
const state: State = { query, primaryKey, foreignKey };
|
|
126
192
|
|
|
127
193
|
const fromQuerySelect = [{ selectAs: { [foreignKey]: primaryKey } }];
|
|
128
194
|
|
|
@@ -132,167 +198,7 @@ export const makeHasManyMethod = (
|
|
|
132
198
|
const values = { [foreignKey]: params[primaryKey] };
|
|
133
199
|
return query.where(values)._defaults(values);
|
|
134
200
|
},
|
|
135
|
-
|
|
136
|
-
const connect = data.filter(
|
|
137
|
-
(
|
|
138
|
-
item,
|
|
139
|
-
): item is [
|
|
140
|
-
Record<string, unknown>,
|
|
141
|
-
{ connect: WhereArg<QueryBase>[] },
|
|
142
|
-
] => Boolean(item[1].connect),
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
const t = query.transacting(q);
|
|
146
|
-
|
|
147
|
-
if (connect.length) {
|
|
148
|
-
await Promise.all(
|
|
149
|
-
connect.flatMap(([selfData, { connect }]) =>
|
|
150
|
-
t
|
|
151
|
-
.or<Query>(...connect)
|
|
152
|
-
._updateOrThrow({ [foreignKey]: selfData[primaryKey] }),
|
|
153
|
-
),
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const connectOrCreate = data.filter(
|
|
158
|
-
(
|
|
159
|
-
item,
|
|
160
|
-
): item is [
|
|
161
|
-
Record<string, unknown>,
|
|
162
|
-
{
|
|
163
|
-
connectOrCreate: {
|
|
164
|
-
where: WhereArg<QueryBase>;
|
|
165
|
-
create: Record<string, unknown>;
|
|
166
|
-
}[];
|
|
167
|
-
},
|
|
168
|
-
] => Boolean(item[1].connectOrCreate),
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
let connected: number[];
|
|
172
|
-
if (connectOrCreate.length) {
|
|
173
|
-
connected = await Promise.all(
|
|
174
|
-
connectOrCreate.flatMap(([selfData, { connectOrCreate }]) =>
|
|
175
|
-
connectOrCreate.map((item) =>
|
|
176
|
-
(
|
|
177
|
-
t.where(item.where) as WhereResult<Query & { hasSelect: false }>
|
|
178
|
-
)._update({
|
|
179
|
-
[foreignKey]: selfData[primaryKey],
|
|
180
|
-
}),
|
|
181
|
-
),
|
|
182
|
-
),
|
|
183
|
-
);
|
|
184
|
-
} else {
|
|
185
|
-
connected = [];
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
let connectedI = 0;
|
|
189
|
-
const create = data.filter(
|
|
190
|
-
(
|
|
191
|
-
item,
|
|
192
|
-
): item is [
|
|
193
|
-
Record<string, unknown>,
|
|
194
|
-
{
|
|
195
|
-
create?: Record<string, unknown>[];
|
|
196
|
-
connectOrCreate?: {
|
|
197
|
-
where: WhereArg<QueryBase>;
|
|
198
|
-
create: Record<string, unknown>;
|
|
199
|
-
}[];
|
|
200
|
-
},
|
|
201
|
-
] => {
|
|
202
|
-
if (item[1].connectOrCreate) {
|
|
203
|
-
const length = item[1].connectOrCreate.length;
|
|
204
|
-
connectedI += length;
|
|
205
|
-
for (let i = length; i > 0; i--) {
|
|
206
|
-
if (connected[connectedI - i] === 0) return true;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
return Boolean(item[1].create);
|
|
210
|
-
},
|
|
211
|
-
);
|
|
212
|
-
|
|
213
|
-
connectedI = 0;
|
|
214
|
-
if (create.length) {
|
|
215
|
-
await t._createMany(
|
|
216
|
-
create.flatMap(
|
|
217
|
-
([selfData, { create = [], connectOrCreate = [] }]) => {
|
|
218
|
-
return [
|
|
219
|
-
...create.map((item) => ({
|
|
220
|
-
[foreignKey]: selfData[primaryKey],
|
|
221
|
-
...item,
|
|
222
|
-
})),
|
|
223
|
-
...connectOrCreate
|
|
224
|
-
.filter(() => connected[connectedI++] === 0)
|
|
225
|
-
.map((item) => ({
|
|
226
|
-
[foreignKey]: selfData[primaryKey],
|
|
227
|
-
...item.create,
|
|
228
|
-
})),
|
|
229
|
-
];
|
|
230
|
-
},
|
|
231
|
-
) as CreateData<Query>[],
|
|
232
|
-
);
|
|
233
|
-
}
|
|
234
|
-
}) as HasManyNestedInsert,
|
|
235
|
-
nestedUpdate: (async (q, data, params) => {
|
|
236
|
-
if ((params.set || params.create) && isQueryReturnsAll(q)) {
|
|
237
|
-
const key = params.set ? 'set' : 'create';
|
|
238
|
-
throw new Error(`\`${key}\` option is not allowed in a batch update`);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
const t = query.transacting(q);
|
|
242
|
-
if (params.create) {
|
|
243
|
-
await t._count()._createMany(
|
|
244
|
-
params.create.map((create) => ({
|
|
245
|
-
...create,
|
|
246
|
-
[foreignKey]: data[0][primaryKey],
|
|
247
|
-
})),
|
|
248
|
-
);
|
|
249
|
-
delete t.query[toSqlCacheKey];
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
if (params.disconnect || params.set) {
|
|
253
|
-
await t
|
|
254
|
-
.where<Query>(
|
|
255
|
-
getWhereForNestedUpdate(
|
|
256
|
-
data,
|
|
257
|
-
params.disconnect,
|
|
258
|
-
primaryKey,
|
|
259
|
-
foreignKey,
|
|
260
|
-
),
|
|
261
|
-
)
|
|
262
|
-
._update({ [foreignKey]: null });
|
|
263
|
-
|
|
264
|
-
if (params.set) {
|
|
265
|
-
delete t.query[toSqlCacheKey];
|
|
266
|
-
await t
|
|
267
|
-
.where<Query>(
|
|
268
|
-
Array.isArray(params.set)
|
|
269
|
-
? {
|
|
270
|
-
OR: params.set,
|
|
271
|
-
}
|
|
272
|
-
: params.set,
|
|
273
|
-
)
|
|
274
|
-
._update({ [foreignKey]: data[0][primaryKey] });
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
if (params.delete || params.update) {
|
|
279
|
-
delete t.query[toSqlCacheKey];
|
|
280
|
-
const q = t._where(
|
|
281
|
-
getWhereForNestedUpdate(
|
|
282
|
-
data,
|
|
283
|
-
params.delete || params.update?.where,
|
|
284
|
-
primaryKey,
|
|
285
|
-
foreignKey,
|
|
286
|
-
),
|
|
287
|
-
);
|
|
288
|
-
|
|
289
|
-
if (params.delete) {
|
|
290
|
-
await q._delete();
|
|
291
|
-
} else if (params.update) {
|
|
292
|
-
await q._update<WhereResult<Query>>(params.update.data);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}) as HasManyNestedUpdate,
|
|
201
|
+
virtualColumn: new HasManyVirtualColumn(relationName, state),
|
|
296
202
|
joinQuery(fromQuery, toQuery) {
|
|
297
203
|
return addQueryOn(toQuery, fromQuery, toQuery, foreignKey, primaryKey);
|
|
298
204
|
},
|
|
@@ -328,3 +234,168 @@ const getWhereForNestedUpdate = (
|
|
|
328
234
|
}
|
|
329
235
|
return where;
|
|
330
236
|
};
|
|
237
|
+
|
|
238
|
+
const nestedInsert = ({ query, primaryKey, foreignKey }: State) => {
|
|
239
|
+
return (async (q, data) => {
|
|
240
|
+
const connect = data.filter(
|
|
241
|
+
(
|
|
242
|
+
item,
|
|
243
|
+
): item is [
|
|
244
|
+
Record<string, unknown>,
|
|
245
|
+
{ connect: WhereArg<QueryBase>[] },
|
|
246
|
+
] => Boolean(item[1].connect),
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
const t = query.transacting(q);
|
|
250
|
+
|
|
251
|
+
if (connect.length) {
|
|
252
|
+
await Promise.all(
|
|
253
|
+
connect.flatMap(([selfData, { connect }]) =>
|
|
254
|
+
t
|
|
255
|
+
.or<Query>(...connect)
|
|
256
|
+
._updateOrThrow({ [foreignKey]: selfData[primaryKey] }),
|
|
257
|
+
),
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const connectOrCreate = data.filter(
|
|
262
|
+
(
|
|
263
|
+
item,
|
|
264
|
+
): item is [
|
|
265
|
+
Record<string, unknown>,
|
|
266
|
+
{
|
|
267
|
+
connectOrCreate: {
|
|
268
|
+
where: WhereArg<QueryBase>;
|
|
269
|
+
create: Record<string, unknown>;
|
|
270
|
+
}[];
|
|
271
|
+
},
|
|
272
|
+
] => Boolean(item[1].connectOrCreate),
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
let connected: number[];
|
|
276
|
+
if (connectOrCreate.length) {
|
|
277
|
+
connected = await Promise.all(
|
|
278
|
+
connectOrCreate.flatMap(([selfData, { connectOrCreate }]) =>
|
|
279
|
+
connectOrCreate.map((item) =>
|
|
280
|
+
(
|
|
281
|
+
t.where(item.where) as WhereResult<Query & { hasSelect: false }>
|
|
282
|
+
)._update({
|
|
283
|
+
[foreignKey]: selfData[primaryKey],
|
|
284
|
+
}),
|
|
285
|
+
),
|
|
286
|
+
),
|
|
287
|
+
);
|
|
288
|
+
} else {
|
|
289
|
+
connected = [];
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
let connectedI = 0;
|
|
293
|
+
const create = data.filter(
|
|
294
|
+
(
|
|
295
|
+
item,
|
|
296
|
+
): item is [
|
|
297
|
+
Record<string, unknown>,
|
|
298
|
+
{
|
|
299
|
+
create?: Record<string, unknown>[];
|
|
300
|
+
connectOrCreate?: {
|
|
301
|
+
where: WhereArg<QueryBase>;
|
|
302
|
+
create: Record<string, unknown>;
|
|
303
|
+
}[];
|
|
304
|
+
},
|
|
305
|
+
] => {
|
|
306
|
+
if (item[1].connectOrCreate) {
|
|
307
|
+
const length = item[1].connectOrCreate.length;
|
|
308
|
+
connectedI += length;
|
|
309
|
+
for (let i = length; i > 0; i--) {
|
|
310
|
+
if (connected[connectedI - i] === 0) return true;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return Boolean(item[1].create);
|
|
314
|
+
},
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
connectedI = 0;
|
|
318
|
+
if (create.length) {
|
|
319
|
+
await t._createMany(
|
|
320
|
+
create.flatMap(([selfData, { create = [], connectOrCreate = [] }]) => {
|
|
321
|
+
return [
|
|
322
|
+
...create.map((item) => ({
|
|
323
|
+
[foreignKey]: selfData[primaryKey],
|
|
324
|
+
...item,
|
|
325
|
+
})),
|
|
326
|
+
...connectOrCreate
|
|
327
|
+
.filter(() => connected[connectedI++] === 0)
|
|
328
|
+
.map((item) => ({
|
|
329
|
+
[foreignKey]: selfData[primaryKey],
|
|
330
|
+
...item.create,
|
|
331
|
+
})),
|
|
332
|
+
];
|
|
333
|
+
}) as CreateData<Query>[],
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
}) as HasManyNestedInsert;
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
const nestedUpdate = ({ query, primaryKey, foreignKey }: State) => {
|
|
340
|
+
return (async (q, data, params) => {
|
|
341
|
+
if ((params.set || params.create) && isQueryReturnsAll(q)) {
|
|
342
|
+
const key = params.set ? 'set' : 'create';
|
|
343
|
+
throw new Error(`\`${key}\` option is not allowed in a batch update`);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const t = query.transacting(q);
|
|
347
|
+
if (params.create) {
|
|
348
|
+
await t._count()._createMany(
|
|
349
|
+
params.create.map((create) => ({
|
|
350
|
+
...create,
|
|
351
|
+
[foreignKey]: data[0][primaryKey],
|
|
352
|
+
})),
|
|
353
|
+
);
|
|
354
|
+
delete t.query[toSqlCacheKey];
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (params.disconnect || params.set) {
|
|
358
|
+
await t
|
|
359
|
+
.where<Query>(
|
|
360
|
+
getWhereForNestedUpdate(
|
|
361
|
+
data,
|
|
362
|
+
params.disconnect,
|
|
363
|
+
primaryKey,
|
|
364
|
+
foreignKey,
|
|
365
|
+
),
|
|
366
|
+
)
|
|
367
|
+
._update({ [foreignKey]: null });
|
|
368
|
+
|
|
369
|
+
if (params.set) {
|
|
370
|
+
delete t.query[toSqlCacheKey];
|
|
371
|
+
await t
|
|
372
|
+
.where<Query>(
|
|
373
|
+
Array.isArray(params.set)
|
|
374
|
+
? {
|
|
375
|
+
OR: params.set,
|
|
376
|
+
}
|
|
377
|
+
: params.set,
|
|
378
|
+
)
|
|
379
|
+
._update({ [foreignKey]: data[0][primaryKey] });
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (params.delete || params.update) {
|
|
384
|
+
delete t.query[toSqlCacheKey];
|
|
385
|
+
const q = t._where(
|
|
386
|
+
getWhereForNestedUpdate(
|
|
387
|
+
data,
|
|
388
|
+
params.delete || params.update?.where,
|
|
389
|
+
primaryKey,
|
|
390
|
+
foreignKey,
|
|
391
|
+
),
|
|
392
|
+
);
|
|
393
|
+
|
|
394
|
+
if (params.delete) {
|
|
395
|
+
await q._delete();
|
|
396
|
+
} else if (params.update) {
|
|
397
|
+
await q._update<WhereResult<Query>>(params.update.data);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}) as HasManyNestedUpdate;
|
|
401
|
+
};
|