orchid-orm 1.67.1 → 1.68.1

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/dist/index.mjs CHANGED
@@ -1,2386 +1,1479 @@
1
- import { makeColumnTypes, defaultSchemaConfig, getStackTrace, _createDbSqlMethod, applyMixins, QueryHooks, emptyArray, emptyObject, getCallerFilePath, snakeCaseKey, getColumnTypes, parseTableData, toSnakeCase, getQueryAs, setQueryObjectValueImmutable, pushQueryOnForOuter, _queryHookAfterCreate, _queryHookAfterUpdate, isExpression, cloneQueryBaseUnscoped, DynamicRawSQL, RawSql, getShapeFromSelect, _queryWhere, _queryDefaults, getPrimaryKeys, VirtualColumn, _prependWith, _queryInsertMany, getFreeAlias, _orCreate, _querySelect, _queryCreate, _hookSelectColumns, _queryUpdate, _queryWhereIn, _appendQuery, isQueryReturnsAll, _queryUpsert, noop, _queryDelete, _queryFindBy, prepareSubQueryForSql, _clone, _queryUpdateOrThrow, _queryInsert, _queryCreateMany, toArray, objectHasValues, _queryCreateManyFrom, _queryJoinOn, _queryWhereExists, _queryFindByOptional, _queryRows, pick, _queryTake, _queryTakeOptional, _initQueryBuilder, getClonedQueryData } from 'pqb/internal';
2
- import { OrchidOrmInternalError, NotFoundError, Db } from 'pqb';
3
- export * from 'pqb';
4
- import { AsyncLocalStorage } from 'node:async_hooks';
5
-
6
- function createBaseTable({
7
- schemaConfig = defaultSchemaConfig,
8
- columnTypes: columnTypesArg,
9
- snakeCase,
10
- filePath: filePathArg,
11
- nowSQL,
12
- exportAs = "BaseTable",
13
- language,
14
- autoForeignKeys
15
- } = {}) {
16
- var _a;
17
- const columnTypes = typeof columnTypesArg === "function" ? columnTypesArg(makeColumnTypes(schemaConfig)) : columnTypesArg || makeColumnTypes(schemaConfig);
18
- const filePathOrStack = filePathArg || getStackTrace();
19
- let filePath;
20
- const defaultColumns = {
21
- shape: emptyObject,
22
- data: emptyArray
23
- };
24
- const instances = /* @__PURE__ */ new WeakMap();
25
- const base = (_a = class {
26
- constructor() {
27
- this.columns = defaultColumns;
28
- this.snakeCase = snakeCase;
29
- this.types = columnTypes;
30
- this.q = {};
31
- this.language = language;
32
- }
33
- static inputSchema() {
34
- this.instance();
35
- return this._inputSchema === void 0 ? this._inputSchema = schemaConfig.inputSchema.call(this) : this._inputSchema;
36
- }
37
- static outputSchema() {
38
- this.instance();
39
- return this._outputSchema === void 0 ? this._outputSchema = schemaConfig.outputSchema.call(this) : this._outputSchema;
40
- }
41
- static querySchema() {
42
- this.instance();
43
- return this._querySchema === void 0 ? this._querySchema = schemaConfig.querySchema.call(this) : this._querySchema;
44
- }
45
- static createSchema() {
46
- this.instance();
47
- return this._createSchema === void 0 ? this._createSchema = schemaConfig.createSchema.call(this) : this._createSchema;
48
- }
49
- static updateSchema() {
50
- this.instance();
51
- return this._updateSchema === void 0 ? this._updateSchema = schemaConfig.updateSchema.call(this) : this._updateSchema;
52
- }
53
- static pkeySchema() {
54
- this.instance();
55
- return this._pkeySchema === void 0 ? this._pkeySchema = schemaConfig.pkeySchema.call(this) : this._pkeySchema;
56
- }
57
- static getFilePath() {
58
- if (filePath) return filePath;
59
- if (typeof filePathOrStack === "string") {
60
- return filePath = filePathOrStack;
61
- }
62
- filePath = getCallerFilePath(filePathOrStack);
63
- if (filePath) return filePath;
64
- throw new Error(
65
- `Failed to determine file path of a base table. Please set the \`filePath\` option of \`createBaseTable\` manually.`
66
- );
67
- }
68
- static instance() {
69
- let instance = instances.get(this);
70
- if (!instance) {
71
- instance = new this();
72
- instances.set(this, instance);
73
- }
74
- return instance;
75
- }
76
- clone() {
77
- return this;
78
- }
79
- getFilePath() {
80
- if (this.filePath) return this.filePath;
81
- if (typeof filePathOrStack === "string")
82
- return this.filePath = filePathOrStack;
83
- const filePath2 = getCallerFilePath(filePathOrStack);
84
- if (filePath2) return this.filePath = filePath2;
85
- throw new Error(
86
- `Failed to determine file path for table ${this.constructor.name}. Please set \`filePath\` property manually`
87
- );
88
- }
89
- setColumns(fn, dataFn) {
90
- columnTypes[snakeCaseKey] = this.snakeCase;
91
- const shape = getColumnTypes(columnTypes, fn, nowSQL, this.language);
92
- const tableData = parseTableData(dataFn);
93
- if (this.snakeCase) {
94
- for (const key in shape) {
95
- const column = shape[key];
96
- if (column.data.name) continue;
97
- const snakeName = toSnakeCase(key);
98
- if (snakeName !== key) {
99
- column.data.name = snakeName;
100
- }
101
- }
102
- }
103
- return this.constructor.prototype.columns = {
104
- shape,
105
- data: tableData
106
- };
107
- }
108
- setComputed(computed) {
109
- return computed;
110
- }
111
- setScopes(scopes) {
112
- return scopes;
113
- }
114
- belongsTo(fn, options) {
115
- return {
116
- type: "belongsTo",
117
- fn,
118
- options
119
- };
120
- }
121
- hasOne(fn, options) {
122
- return {
123
- type: "hasOne",
124
- fn,
125
- options
126
- };
127
- }
128
- hasMany(fn, options) {
129
- return {
130
- type: "hasMany",
131
- fn,
132
- options
133
- };
134
- }
135
- hasAndBelongsToMany(fn, options) {
136
- return {
137
- type: "hasAndBelongsToMany",
138
- fn,
139
- options
140
- };
141
- }
142
- }, _a.nowSQL = nowSQL, _a.exportAs = exportAs, _a.columnTypes = columnTypes, _a.sql = _createDbSqlMethod(columnTypes), _a);
143
- applyMixins(base, [QueryHooks]);
144
- base.prototype.types = columnTypes;
145
- base.prototype.snakeCase = snakeCase;
146
- base.prototype.language = language;
147
- base.prototype.autoForeignKeys = autoForeignKeys === true ? {} : autoForeignKeys || void 0;
148
- return base;
1
+ import { DynamicRawSQL, QueryHooks, RawSql, VirtualColumn, _appendQuery, _clone, _createDbSqlMethod, _hookSelectColumns, _initQueryBuilder, _orCreate, _prependWith, _queryCreate, _queryCreateMany, _queryCreateManyFrom, _queryDefaults, _queryDelete, _queryFindBy, _queryFindByOptional, _queryHookAfterCreate, _queryHookAfterUpdate, _queryInsert, _queryInsertMany, _queryJoinOn, _queryRows, _querySelect, _queryTake, _queryTakeOptional, _queryUpdate, _queryUpdateOrThrow, _queryUpsert, _queryWhere, _queryWhereExists, _queryWhereIn, applyMixins, cloneQueryBaseUnscoped, defaultSchemaConfig, emptyArray, emptyObject, getCallerFilePath, getClonedQueryData, getColumnTypes, getFreeAlias, getPrimaryKeys, getQueryAs, getShapeFromSelect, getStackTrace, isExpression, isQueryReturnsAll, makeColumnTypes, noop, objectHasValues, parseTableData, pick, prepareSubQueryForSql, pushQueryOnForOuter, setQueryObjectValueImmutable, snakeCaseKey, toArray, toSnakeCase } from "pqb/internal";
2
+ import { Db, NotFoundError, OrchidOrmInternalError } from "pqb";
3
+ import { AsyncLocalStorage } from "node:async_hooks";
4
+ export * from "pqb";
5
+ function createBaseTable({ schemaConfig = defaultSchemaConfig, columnTypes: columnTypesArg, snakeCase, filePath: filePathArg, nowSQL, exportAs = "BaseTable", language, autoForeignKeys } = {}) {
6
+ const columnTypes = typeof columnTypesArg === "function" ? columnTypesArg(makeColumnTypes(schemaConfig)) : columnTypesArg || makeColumnTypes(schemaConfig);
7
+ const filePathOrStack = filePathArg || getStackTrace();
8
+ let filePath;
9
+ const defaultColumns = {
10
+ shape: emptyObject,
11
+ data: emptyArray
12
+ };
13
+ const instances = /* @__PURE__ */ new WeakMap();
14
+ const base = class BaseTable {
15
+ constructor() {
16
+ this.columns = defaultColumns;
17
+ this.snakeCase = snakeCase;
18
+ this.types = columnTypes;
19
+ this.q = {};
20
+ this.language = language;
21
+ }
22
+ static {
23
+ this.nowSQL = nowSQL;
24
+ }
25
+ static {
26
+ this.exportAs = exportAs;
27
+ }
28
+ static {
29
+ this.columnTypes = columnTypes;
30
+ }
31
+ static {
32
+ this.sql = _createDbSqlMethod(columnTypes);
33
+ }
34
+ static inputSchema() {
35
+ this.instance();
36
+ return this._inputSchema === void 0 ? this._inputSchema = schemaConfig.inputSchema.call(this) : this._inputSchema;
37
+ }
38
+ static outputSchema() {
39
+ this.instance();
40
+ return this._outputSchema === void 0 ? this._outputSchema = schemaConfig.outputSchema.call(this) : this._outputSchema;
41
+ }
42
+ static querySchema() {
43
+ this.instance();
44
+ return this._querySchema === void 0 ? this._querySchema = schemaConfig.querySchema.call(this) : this._querySchema;
45
+ }
46
+ static createSchema() {
47
+ this.instance();
48
+ return this._createSchema === void 0 ? this._createSchema = schemaConfig.createSchema.call(this) : this._createSchema;
49
+ }
50
+ static updateSchema() {
51
+ this.instance();
52
+ return this._updateSchema === void 0 ? this._updateSchema = schemaConfig.updateSchema.call(this) : this._updateSchema;
53
+ }
54
+ static pkeySchema() {
55
+ this.instance();
56
+ return this._pkeySchema === void 0 ? this._pkeySchema = schemaConfig.pkeySchema.call(this) : this._pkeySchema;
57
+ }
58
+ static getFilePath() {
59
+ if (filePath) return filePath;
60
+ if (typeof filePathOrStack === "string") return filePath = filePathOrStack;
61
+ filePath = getCallerFilePath(filePathOrStack);
62
+ if (filePath) return filePath;
63
+ throw new Error(`Failed to determine file path of a base table. Please set the \`filePath\` option of \`createBaseTable\` manually.`);
64
+ }
65
+ static instance() {
66
+ let instance = instances.get(this);
67
+ if (!instance) {
68
+ instance = new this();
69
+ instances.set(this, instance);
70
+ }
71
+ return instance;
72
+ }
73
+ clone() {
74
+ return this;
75
+ }
76
+ getFilePath() {
77
+ if (this.filePath) return this.filePath;
78
+ if (typeof filePathOrStack === "string") return this.filePath = filePathOrStack;
79
+ const filePath = getCallerFilePath(filePathOrStack);
80
+ if (filePath) return this.filePath = filePath;
81
+ throw new Error(`Failed to determine file path for table ${this.constructor.name}. Please set \`filePath\` property manually`);
82
+ }
83
+ setColumns(fn, dataFn) {
84
+ columnTypes[snakeCaseKey] = this.snakeCase;
85
+ const shape = getColumnTypes(columnTypes, fn, nowSQL, this.language);
86
+ const tableData = parseTableData(dataFn);
87
+ if (this.snakeCase) for (const key in shape) {
88
+ const column = shape[key];
89
+ if (column.data.name) continue;
90
+ const snakeName = toSnakeCase(key);
91
+ if (snakeName !== key) column.data.name = snakeName;
92
+ }
93
+ return this.constructor.prototype.columns = {
94
+ shape,
95
+ data: tableData
96
+ };
97
+ }
98
+ setComputed(computed) {
99
+ return computed;
100
+ }
101
+ setScopes(scopes) {
102
+ return scopes;
103
+ }
104
+ belongsTo(fn, options) {
105
+ return {
106
+ type: "belongsTo",
107
+ fn,
108
+ options
109
+ };
110
+ }
111
+ hasOne(fn, options) {
112
+ return {
113
+ type: "hasOne",
114
+ fn,
115
+ options
116
+ };
117
+ }
118
+ hasMany(fn, options) {
119
+ return {
120
+ type: "hasMany",
121
+ fn,
122
+ options
123
+ };
124
+ }
125
+ hasAndBelongsToMany(fn, options) {
126
+ return {
127
+ type: "hasAndBelongsToMany",
128
+ fn,
129
+ options
130
+ };
131
+ }
132
+ };
133
+ applyMixins(base, [QueryHooks]);
134
+ base.prototype.types = columnTypes;
135
+ base.prototype.snakeCase = snakeCase;
136
+ base.prototype.language = language;
137
+ base.prototype.autoForeignKeys = autoForeignKeys === true ? {} : autoForeignKeys || void 0;
138
+ return base;
149
139
  }
150
-
151
140
  const getThroughRelation = (table, through) => {
152
- return table.relations[through];
141
+ return table.relations[through];
153
142
  };
154
143
  const getSourceRelation = (throughRelation, source) => {
155
- return throughRelation.query.relations[source];
144
+ return throughRelation.query.relations[source];
156
145
  };
157
146
  const hasRelationHandleCreate = (q, ctx, items, rowIndexes, key, primaryKeys, nestedInsert) => {
158
- q.q.wrapInTransaction = true;
159
- items.forEach((item, i) => {
160
- const value = item[key];
161
- if ((!value.create || Array.isArray(value.create) && value.create.length === 0) && (!value.connect || Array.isArray(value.connect) && value.connect.length === 0) && (!value.connectOrCreate || Array.isArray(value.connectOrCreate) && value.connectOrCreate.length === 0))
162
- return;
163
- const store = ctx;
164
- if (!store.hasRelation) store.hasRelation = {};
165
- const values = [rowIndexes[i], value];
166
- if (store.hasRelation[key]) {
167
- store.hasRelation[key].push(values);
168
- return;
169
- }
170
- const relationData = [values];
171
- store.hasRelation[key] = relationData;
172
- _queryHookAfterCreate(
173
- q,
174
- primaryKeys,
175
- (rows, q2) => nestedInsert(
176
- q2,
177
- relationData.map(([rowIndex, data]) => [
178
- rows[rowIndex],
179
- data
180
- ])
181
- )
182
- );
183
- });
147
+ q.q.wrapInTransaction = true;
148
+ items.forEach((item, i) => {
149
+ const value = item[key];
150
+ if ((!value.create || Array.isArray(value.create) && value.create.length === 0) && (!value.connect || Array.isArray(value.connect) && value.connect.length === 0) && (!value.connectOrCreate || Array.isArray(value.connectOrCreate) && value.connectOrCreate.length === 0)) return;
151
+ const store = ctx;
152
+ if (!store.hasRelation) store.hasRelation = {};
153
+ const values = [rowIndexes[i], value];
154
+ if (store.hasRelation[key]) {
155
+ store.hasRelation[key].push(values);
156
+ return;
157
+ }
158
+ const relationData = [values];
159
+ store.hasRelation[key] = relationData;
160
+ _queryHookAfterCreate(q, primaryKeys, (rows, q) => nestedInsert(q, relationData.map(([rowIndex, data]) => [rows[rowIndex], data])));
161
+ });
184
162
  };
185
163
  const hasRelationHandleUpdate = (q, set, key, primaryKeys, nestedUpdate) => {
186
- const value = set[key];
187
- if (!value.set && !("upsert" in value) && (!value.add || Array.isArray(value.add) && value.add.length === 0) && (!value.disconnect || Array.isArray(value.disconnect) && value.disconnect.length === 0) && (!value.delete || Array.isArray(value.delete) && value.delete.length === 0) && (!value.update || Array.isArray(value.update.where) && value.update.where.length === 0) && (!value.create || Array.isArray(value.create) && value.create.length === 0))
188
- return;
189
- q.q.wrapInTransaction = true;
190
- _queryHookAfterUpdate(q, primaryKeys, (rows, q2) => {
191
- return nestedUpdate(
192
- q2,
193
- rows,
194
- value
195
- );
196
- });
164
+ const value = set[key];
165
+ if (!value.set && !("upsert" in value) && (!value.add || Array.isArray(value.add) && value.add.length === 0) && (!value.disconnect || Array.isArray(value.disconnect) && value.disconnect.length === 0) && (!value.delete || Array.isArray(value.delete) && value.delete.length === 0) && (!value.update || Array.isArray(value.update.where) && value.update.where.length === 0) && (!value.create || Array.isArray(value.create) && value.create.length === 0)) return;
166
+ q.q.wrapInTransaction = true;
167
+ _queryHookAfterUpdate(q, primaryKeys, (rows, q) => {
168
+ return nestedUpdate(q, rows, value);
169
+ });
197
170
  };
198
171
  function joinHasThrough(q, baseQuery, joiningQuery, throughRelation, sourceRelation) {
199
- return q.whereExists(
200
- throughRelation.joinQuery(
201
- throughRelation.query,
202
- baseQuery
203
- ),
204
- () => {
205
- const as = getQueryAs(joiningQuery);
206
- return sourceRelation.joinQuery(
207
- sourceRelation.query.as(as),
208
- throughRelation.query
209
- );
210
- }
211
- );
172
+ return q.whereExists(throughRelation.joinQuery(throughRelation.query, baseQuery), (() => {
173
+ const as = getQueryAs(joiningQuery);
174
+ return sourceRelation.joinQuery(sourceRelation.query.as(as), throughRelation.query);
175
+ }));
212
176
  }
213
177
  function joinHasRelation(baseQuery, joiningQuery, primaryKeys, foreignKeys, len) {
214
- const baseAs = getQueryAs(baseQuery);
215
- const q = joiningQuery.clone();
216
- setQueryObjectValueImmutable(q, "joinedShapes", baseAs, baseQuery.q.shape);
217
- for (let i = 0; i < len; i++) {
218
- pushQueryOnForOuter(
219
- q,
220
- baseQuery,
221
- joiningQuery,
222
- foreignKeys[i],
223
- `${baseAs}.${primaryKeys[i]}`
224
- );
225
- }
226
- return q;
178
+ const baseAs = getQueryAs(baseQuery);
179
+ const q = joiningQuery.clone();
180
+ setQueryObjectValueImmutable(q, "joinedShapes", baseAs, baseQuery.q.shape);
181
+ for (let i = 0; i < len; i++) pushQueryOnForOuter(q, baseQuery, joiningQuery, foreignKeys[i], `${baseAs}.${primaryKeys[i]}`);
182
+ return q;
227
183
  }
228
184
  const addAutoForeignKey = (tableConfig, from, to, primaryKeys, foreignKeys, options, originalForeignKeys) => {
229
- var _a;
230
- const toTable = to.table;
231
- let fkeyOptions = options.foreignKey !== void 0 ? options.foreignKey : tableConfig.autoForeignKeys;
232
- if (!fkeyOptions) return;
233
- if (fkeyOptions === true) {
234
- fkeyOptions = tableConfig.autoForeignKeys || emptyObject;
235
- }
236
- if (foreignKeys.length === 1) {
237
- const column = from.shape[foreignKeys[0]];
238
- if (column.data.foreignKeys) {
239
- const pkey = primaryKeys[0];
240
- for (const fkey of column.data.foreignKeys) {
241
- let fkeyTable;
242
- let fkeyColumn = fkey.foreignColumns[0];
243
- if (typeof fkey.fnOrTable === "string") {
244
- fkeyTable = fkey.fnOrTable;
245
- fkeyColumn = getColumnKeyFromDbName(to, fkeyColumn);
246
- } else {
247
- fkeyTable = fkey.fnOrTable().instance().table;
248
- }
249
- if (toTable === fkeyTable && pkey === fkeyColumn) return;
250
- }
251
- }
252
- }
253
- const { constraints } = from.internal.tableData;
254
- if (constraints) {
255
- const sortedPkeys = [...primaryKeys].sort();
256
- const sortedFkeys = [...foreignKeys].sort();
257
- for (const { references: refs } of constraints) {
258
- if (!refs) continue;
259
- if (refs.columns.length === sortedFkeys.length && refs.columns.every((column, i) => column === sortedFkeys[i]) && refs.foreignColumns.length === sortedPkeys.length && (typeof refs.fnOrTable === "string" ? refs.fnOrTable === toTable && refs.foreignColumns.every(
260
- (column, i) => getColumnKeyFromDbName(to, column) === sortedPkeys[i]
261
- ) : refs.fnOrTable().instance().table === toTable && refs.foreignColumns.every((column, i) => column === sortedPkeys[i])))
262
- return;
263
- }
264
- }
265
- ((_a = from.internal.tableData).constraints ?? (_a.constraints = [])).push({
266
- references: {
267
- columns: originalForeignKeys || foreignKeys,
268
- fnOrTable: toTable,
269
- foreignColumns: primaryKeys,
270
- options: fkeyOptions
271
- },
272
- dropMode: fkeyOptions.dropMode
273
- });
185
+ const toTable = to.table;
186
+ let fkeyOptions = options.foreignKey !== void 0 ? options.foreignKey : tableConfig.autoForeignKeys;
187
+ if (!fkeyOptions) return;
188
+ if (fkeyOptions === true) fkeyOptions = tableConfig.autoForeignKeys || emptyObject;
189
+ if (foreignKeys.length === 1) {
190
+ const column = from.shape[foreignKeys[0]];
191
+ if (column.data.foreignKeys) {
192
+ const pkey = primaryKeys[0];
193
+ for (const fkey of column.data.foreignKeys) {
194
+ let fkeyTable;
195
+ let fkeyColumn = fkey.foreignColumns[0];
196
+ if (typeof fkey.fnOrTable === "string") {
197
+ fkeyTable = fkey.fnOrTable;
198
+ fkeyColumn = getColumnKeyFromDbName(to, fkeyColumn);
199
+ } else fkeyTable = fkey.fnOrTable().instance().table;
200
+ if (toTable === fkeyTable && pkey === fkeyColumn) return;
201
+ }
202
+ }
203
+ }
204
+ const { constraints } = from.internal.tableData;
205
+ if (constraints) {
206
+ const sortedPkeys = [...primaryKeys].sort();
207
+ const sortedFkeys = [...foreignKeys].sort();
208
+ for (const { references: refs } of constraints) {
209
+ if (!refs) continue;
210
+ if (refs.columns.length === sortedFkeys.length && refs.columns.every((column, i) => column === sortedFkeys[i]) && refs.foreignColumns.length === sortedPkeys.length && (typeof refs.fnOrTable === "string" ? refs.fnOrTable === toTable && refs.foreignColumns.every((column, i) => getColumnKeyFromDbName(to, column) === sortedPkeys[i]) : refs.fnOrTable().instance().table === toTable && refs.foreignColumns.every((column, i) => column === sortedPkeys[i]))) return;
211
+ }
212
+ }
213
+ (from.internal.tableData.constraints ??= []).push({
214
+ references: {
215
+ columns: originalForeignKeys || foreignKeys,
216
+ fnOrTable: toTable,
217
+ foreignColumns: primaryKeys,
218
+ options: fkeyOptions
219
+ },
220
+ dropMode: fkeyOptions.dropMode
221
+ });
274
222
  };
275
223
  const getColumnKeyFromDbName = (query, name) => {
276
- for (const k in query.shape) {
277
- if (query.shape[k].data.name === name) {
278
- return k;
279
- }
280
- }
281
- return name;
224
+ for (const k in query.shape) if (query.shape[k].data.name === name) return k;
225
+ return name;
282
226
  };
283
227
  const selectCteColumnsSql = (cteAs, columns) => `(SELECT ${columns.map((c) => `"${cteAs}"."${c}"`).join(", ")} FROM "${cteAs}")`;
284
228
  const selectCteColumnSql = (cteAs, column) => `(SELECT "${cteAs}"."${column}" FROM "${cteAs}")`;
285
229
  const selectCteColumnFromManySql = (cteAs, column, rowIndex, count) => {
286
- let sql = `(SELECT "${cteAs}"."${column}" FROM "${cteAs}"`;
287
- if (count > 1) {
288
- sql += ` LIMIT 1`;
289
- if (rowIndex) sql += ` OFFSET ${rowIndex}`;
290
- }
291
- return sql + ")";
230
+ let sql = `(SELECT "${cteAs}"."${column}" FROM "${cteAs}"`;
231
+ if (count > 1) {
232
+ sql += ` LIMIT 1`;
233
+ if (rowIndex) sql += ` OFFSET ${rowIndex}`;
234
+ }
235
+ return sql + ")";
292
236
  };
293
-
294
237
  const joinQueryChainHOF = (relPKeys, reverseJoin, joinQuery) => (joiningQuery, baseQuery) => {
295
- const jq = joiningQuery;
296
- const chain = jq.q.relChain;
297
- if (!chain || chain.length === 1) {
298
- return joinQuery(jq, baseQuery);
299
- }
300
- const last = chain[chain.length - 1];
301
- const prev = chain[chain.length - 2];
302
- const query = prev.rel.joinQuery(last.query, baseQuery);
303
- let useWhereExist = true;
304
- if (jq.q.returnType !== "value" && jq.q.returnType !== "valueOrThrow") {
305
- let tablePrefix;
306
- if (jq.q.order) {
307
- const prefix = tablePrefix = getQueryAs(jq) + ".";
308
- useWhereExist = jq.q.order.every((o) => {
309
- if (typeof o === "string") {
310
- return isOwnColumn(prefix, o);
311
- } else if (isExpression(o)) {
312
- return false;
313
- } else {
314
- for (const key in o) {
315
- if (!isOwnColumn(prefix, key)) {
316
- return false;
317
- }
318
- }
319
- return true;
320
- }
321
- });
322
- }
323
- if (useWhereExist && jq.q.select) {
324
- const prefix = tablePrefix || getQueryAs(jq) + ".";
325
- useWhereExist = jq.q.select.every((s) => {
326
- if (typeof s === "string") {
327
- return isOwnColumn(prefix, s);
328
- } else if (isExpression(s)) {
329
- return false;
330
- } else if (!s) {
331
- return false;
332
- } else {
333
- for (const key in s.selectAs) {
334
- const value = s.selectAs[key];
335
- if (typeof value !== "string" || !isOwnColumn(prefix, value)) {
336
- return false;
337
- }
338
- }
339
- return true;
340
- }
341
- });
342
- }
343
- }
344
- if (useWhereExist) {
345
- return jq.where({
346
- EXISTS: { q: reverseJoin(query, jq) }
347
- });
348
- }
349
- const result = jq.join(
350
- { _internalJoin: reverseJoin(query, jq) },
351
- void 0
352
- );
353
- if (!query.q.chainMultiple) {
354
- return result;
355
- }
356
- const item = selectRowNumber(result, relPKeys);
357
- combineOrdering(result, query);
358
- if (!result.q.select) result.q.select = ["*"];
359
- return wrapQuery(jq, result, item);
238
+ const jq = joiningQuery;
239
+ const chain = jq.q.relChain;
240
+ if (!chain || chain.length === 1) return joinQuery(jq, baseQuery);
241
+ const last = chain[chain.length - 1];
242
+ const query = chain[chain.length - 2].rel.joinQuery(last.query, baseQuery);
243
+ let useWhereExist = true;
244
+ if (jq.q.returnType !== "value" && jq.q.returnType !== "valueOrThrow") {
245
+ let tablePrefix;
246
+ if (jq.q.order) {
247
+ const prefix = tablePrefix = getQueryAs(jq) + ".";
248
+ useWhereExist = jq.q.order.every((o) => {
249
+ if (typeof o === "string") return isOwnColumn(prefix, o);
250
+ else if (isExpression(o)) return false;
251
+ else {
252
+ for (const key in o) if (!isOwnColumn(prefix, key)) return false;
253
+ return true;
254
+ }
255
+ });
256
+ }
257
+ if (useWhereExist && jq.q.select) {
258
+ const prefix = tablePrefix || getQueryAs(jq) + ".";
259
+ useWhereExist = jq.q.select.every((s) => {
260
+ if (typeof s === "string") return isOwnColumn(prefix, s);
261
+ else if (isExpression(s)) return false;
262
+ else if (!s) return false;
263
+ else {
264
+ for (const key in s.selectAs) {
265
+ const value = s.selectAs[key];
266
+ if (typeof value !== "string" || !isOwnColumn(prefix, value)) return false;
267
+ }
268
+ return true;
269
+ }
270
+ });
271
+ }
272
+ }
273
+ if (useWhereExist) return jq.where({ EXISTS: { q: reverseJoin(query, jq) } });
274
+ const result = jq.join({ _internalJoin: reverseJoin(query, jq) }, void 0);
275
+ if (!query.q.chainMultiple) return result;
276
+ const item = selectRowNumber(result, relPKeys);
277
+ combineOrdering(result, query);
278
+ if (!result.q.select) result.q.select = ["*"];
279
+ return wrapQuery(jq, result, item);
360
280
  };
361
281
  const isOwnColumn = (prefix, column) => !column.includes(".") || column.startsWith(prefix);
362
282
  const selectRowNumber = (result, relPKeys) => {
363
- const hookSelect = result.q.hookSelect = new Map(
364
- result.q.hookSelect && [...result.q.hookSelect]
365
- );
366
- const as = `"${getQueryAs(result)}"`;
367
- const partitionColumns = relPKeys.map(
368
- (key) => `${as}."${result.shape[key]?.data.name || key}"`
369
- );
370
- const item = {
371
- select: {
372
- sql: `row_number() OVER (PARTITION BY ${partitionColumns.join(", ")})`
373
- }
374
- };
375
- hookSelect.set("r", item);
376
- return item;
283
+ const hookSelect = result.q.hookSelect = new Map(result.q.hookSelect && [...result.q.hookSelect]);
284
+ const as = `"${getQueryAs(result)}"`;
285
+ const item = { select: { sql: `row_number() OVER (PARTITION BY ${relPKeys.map((key) => `${as}."${result.shape[key]?.data.name || key}"`).join(", ")})` } };
286
+ hookSelect.set("r", item);
287
+ return item;
377
288
  };
378
289
  const combineOrdering = (result, joined) => {
379
- const { order } = joined.q;
380
- if (order) {
381
- const as = getQueryAs(joined);
382
- const add = order.map(
383
- (o) => typeof o === "string" ? `${as}.${o}` : isExpression(o) ? o : Object.fromEntries(
384
- Object.entries(o).map(([key, value]) => [`${as}.${key}`, value])
385
- )
386
- );
387
- const arr = result.q.order;
388
- result.q.order = arr ? [...add, ...arr] : add;
389
- }
290
+ const { order } = joined.q;
291
+ if (order) {
292
+ const as = getQueryAs(joined);
293
+ const add = order.map((o) => typeof o === "string" ? `${as}.${o}` : isExpression(o) ? o : Object.fromEntries(Object.entries(o).map(([key, value]) => [`${as}.${key}`, value])));
294
+ const arr = result.q.order;
295
+ result.q.order = arr ? [...add, ...arr] : add;
296
+ }
390
297
  };
391
298
  const wrapQuery = (joiningQuery, result, item) => {
392
- const baseOuterQuery = cloneQueryBaseUnscoped(joiningQuery);
393
- const outer = baseOuterQuery.clone();
394
- outer.q.and = [new DynamicRawSQL(() => new RawSql(`${item.as || "r"} = 1`))];
395
- outer.q.useFromLimitOffset = true;
396
- outer.shape = getShapeFromSelect(result, true);
397
- outer.q.select = Object.keys(outer.shape);
398
- outer.q.returnType = result.q.returnType;
399
- result.q.returnsOne = true;
400
- return result.wrap(outer);
299
+ const outer = cloneQueryBaseUnscoped(joiningQuery).clone();
300
+ outer.q.and = [new DynamicRawSQL(() => new RawSql(`${item.as || "r"} = 1`))];
301
+ outer.q.useFromLimitOffset = true;
302
+ outer.shape = getShapeFromSelect(result, true);
303
+ outer.q.select = Object.keys(outer.shape);
304
+ outer.q.returnType = result.q.returnType;
305
+ result.q.returnsOne = true;
306
+ return result.wrap(outer);
307
+ };
308
+ var BelongsToVirtualColumn = class extends VirtualColumn {
309
+ constructor(schema, key, state) {
310
+ super(schema);
311
+ this.key = key;
312
+ this.state = state;
313
+ this.nestedUpdate = nestedUpdate$2(this.state);
314
+ }
315
+ create(q, ctx, items) {
316
+ const { key, state: { query, primaryKeys, foreignKeys } } = this;
317
+ let nestedCreateItems;
318
+ items.forEach((item) => {
319
+ const value = item[key];
320
+ const kind = value.create ? "create" : value.connect ? "connect" : "connectOrCreate";
321
+ if (kind) {
322
+ const nestedCreateItem = (nestedCreateItems ??= {})[kind] ??= {
323
+ items: [],
324
+ values: []
325
+ };
326
+ nestedCreateItem.items.push(item);
327
+ nestedCreateItem.values.push(value[kind]);
328
+ if (kind !== "connect") for (const key of foreignKeys) item[key] = new RawSql("");
329
+ }
330
+ });
331
+ if (!nestedCreateItems) return;
332
+ for (const key of foreignKeys) if (!ctx.columns.has(key)) ctx.columns.set(key, ctx.columns.size);
333
+ const { create, connect, connectOrCreate } = nestedCreateItems;
334
+ if (create) _prependWith(q, (as) => {
335
+ const count = create.items.length;
336
+ foreignKeys.forEach((foreignKey, i) => {
337
+ const primaryKey = primaryKeys[i];
338
+ create.items.forEach((item, i) => {
339
+ item[foreignKey]._sql = selectCteColumnFromManySql(as, primaryKey, i, count);
340
+ });
341
+ });
342
+ }, _queryInsertMany(query.select(...primaryKeys), create.values));
343
+ if (connect) connect.values.forEach((value, itemI) => {
344
+ const as = getFreeAlias(q.q.withShapes, "q");
345
+ _prependWith(q, as, query.select(...primaryKeys).findBy(value));
346
+ foreignKeys.map((foreignKey, i) => {
347
+ connect.items[itemI][foreignKey] = new RawSql(selectCteColumnMustExistSql(i, as, primaryKeys[i]));
348
+ });
349
+ });
350
+ if (connectOrCreate) connectOrCreate.values.forEach((value, itemI) => {
351
+ _prependWith(q, setForeignKeysFromCte(connectOrCreate.items[itemI], primaryKeys, foreignKeys), _orCreate(_queryWhere(query.select(...primaryKeys), [value.where]), value.create));
352
+ });
353
+ }
354
+ update(q, set) {
355
+ q.q.wrapInTransaction = true;
356
+ const data = set[this.key];
357
+ this.nestedUpdate(q, set, data);
358
+ }
401
359
  };
402
-
403
- class BelongsToVirtualColumn extends VirtualColumn {
404
- constructor(schema, key, state) {
405
- super(schema);
406
- this.key = key;
407
- this.state = state;
408
- this.nestedUpdate = nestedUpdate$2(this.state);
409
- }
410
- create(q, ctx, items) {
411
- const {
412
- key,
413
- state: { query, primaryKeys, foreignKeys }
414
- } = this;
415
- let nestedCreateItems;
416
- items.forEach((item) => {
417
- var _a;
418
- const value = item[key];
419
- const kind = value.create ? "create" : value.connect ? "connect" : "connectOrCreate";
420
- {
421
- const nestedCreateItem = (_a = nestedCreateItems ?? (nestedCreateItems = {}))[kind] ?? (_a[kind] = {
422
- items: [],
423
- values: []
424
- });
425
- nestedCreateItem.items.push(item);
426
- nestedCreateItem.values.push(value[kind]);
427
- if (kind !== "connect") {
428
- for (const key2 of foreignKeys) {
429
- item[key2] = new RawSql("");
430
- }
431
- }
432
- }
433
- });
434
- if (!nestedCreateItems) {
435
- return;
436
- }
437
- for (const key2 of foreignKeys) {
438
- if (!ctx.columns.has(key2)) {
439
- ctx.columns.set(key2, ctx.columns.size);
440
- }
441
- }
442
- const { create, connect, connectOrCreate } = nestedCreateItems;
443
- if (create) {
444
- const selectPKeys = query.select(...primaryKeys);
445
- _prependWith(
446
- q,
447
- (as) => {
448
- const count = create.items.length;
449
- foreignKeys.forEach((foreignKey, i) => {
450
- const primaryKey = primaryKeys[i];
451
- create.items.forEach((item, i2) => {
452
- item[foreignKey]._sql = selectCteColumnFromManySql(
453
- as,
454
- primaryKey,
455
- i2,
456
- count
457
- );
458
- });
459
- });
460
- },
461
- _queryInsertMany(selectPKeys, create.values)
462
- );
463
- }
464
- if (connect) {
465
- connect.values.forEach((value, itemI) => {
466
- const as = getFreeAlias(q.q.withShapes, "q");
467
- _prependWith(q, as, query.select(...primaryKeys).findBy(value));
468
- foreignKeys.map((foreignKey, i) => {
469
- connect.items[itemI][foreignKey] = new RawSql(
470
- selectCteColumnMustExistSql(i, as, primaryKeys[i])
471
- );
472
- });
473
- });
474
- }
475
- if (connectOrCreate) {
476
- connectOrCreate.values.forEach((value, itemI) => {
477
- const asFn = setForeignKeysFromCte(
478
- connectOrCreate.items[itemI],
479
- primaryKeys,
480
- foreignKeys
481
- );
482
- const selectPKeys = query.select(...primaryKeys);
483
- _prependWith(
484
- q,
485
- asFn,
486
- _orCreate(
487
- _queryWhere(selectPKeys, [value.where]),
488
- value.create
489
- )
490
- );
491
- });
492
- }
493
- }
494
- update(q, set) {
495
- q.q.wrapInTransaction = true;
496
- const data = set[this.key];
497
- this.nestedUpdate(q, set, data);
498
- }
499
- }
500
360
  const makeBelongsToMethod = (tableConfig, table, relation, relationName, query) => {
501
- const primaryKeys = relation.options.references;
502
- const foreignKeys = relation.options.columns;
503
- const { on } = relation.options;
504
- if (on) {
505
- _queryWhere(query, [on]);
506
- _queryDefaults(query, on);
507
- }
508
- const len = primaryKeys.length;
509
- const state = { query, primaryKeys, foreignKeys, len, on };
510
- addAutoForeignKey(
511
- tableConfig,
512
- table,
513
- query,
514
- primaryKeys,
515
- foreignKeys,
516
- relation.options
517
- );
518
- const join = (baseQuery, joiningQuery, primaryKeys2, foreignKeys2) => {
519
- const baseAs = getQueryAs(baseQuery);
520
- const q = joiningQuery.clone();
521
- setQueryObjectValueImmutable(q, "joinedShapes", baseAs, baseQuery.q.shape);
522
- for (let i = 0; i < len; i++) {
523
- pushQueryOnForOuter(
524
- q,
525
- baseQuery,
526
- joiningQuery,
527
- primaryKeys2[i],
528
- `${baseAs}.${foreignKeys2[i]}`
529
- );
530
- }
531
- return q;
532
- };
533
- const reverseJoin = (baseQuery, joiningQuery) => {
534
- return join(
535
- joiningQuery,
536
- baseQuery,
537
- foreignKeys,
538
- primaryKeys
539
- );
540
- };
541
- return {
542
- returns: "one",
543
- queryRelated(params) {
544
- const obj = {};
545
- for (let i = 0; i < len; i++) {
546
- obj[primaryKeys[i]] = params[foreignKeys[i]];
547
- }
548
- return query.where(obj);
549
- },
550
- virtualColumn: new BelongsToVirtualColumn(
551
- defaultSchemaConfig,
552
- relationName,
553
- state
554
- ),
555
- joinQuery: joinQueryChainHOF(
556
- getPrimaryKeys(query),
557
- reverseJoin,
558
- (joiningQuery, baseQuery) => join(
559
- baseQuery,
560
- joiningQuery,
561
- primaryKeys,
562
- foreignKeys
563
- )
564
- ),
565
- reverseJoin
566
- };
361
+ const primaryKeys = relation.options.references;
362
+ const foreignKeys = relation.options.columns;
363
+ const { on } = relation.options;
364
+ if (on) {
365
+ _queryWhere(query, [on]);
366
+ _queryDefaults(query, on);
367
+ }
368
+ const len = primaryKeys.length;
369
+ const state = {
370
+ query,
371
+ primaryKeys,
372
+ foreignKeys,
373
+ len,
374
+ on
375
+ };
376
+ addAutoForeignKey(tableConfig, table, query, primaryKeys, foreignKeys, relation.options);
377
+ const join = (baseQuery, joiningQuery, primaryKeys, foreignKeys) => {
378
+ const baseAs = getQueryAs(baseQuery);
379
+ const q = joiningQuery.clone();
380
+ setQueryObjectValueImmutable(q, "joinedShapes", baseAs, baseQuery.q.shape);
381
+ for (let i = 0; i < len; i++) pushQueryOnForOuter(q, baseQuery, joiningQuery, primaryKeys[i], `${baseAs}.${foreignKeys[i]}`);
382
+ return q;
383
+ };
384
+ const reverseJoin = (baseQuery, joiningQuery) => {
385
+ return join(joiningQuery, baseQuery, foreignKeys, primaryKeys);
386
+ };
387
+ return {
388
+ returns: "one",
389
+ queryRelated(params) {
390
+ const obj = {};
391
+ for (let i = 0; i < len; i++) obj[primaryKeys[i]] = params[foreignKeys[i]];
392
+ return query.where(obj);
393
+ },
394
+ virtualColumn: new BelongsToVirtualColumn(defaultSchemaConfig, relationName, state),
395
+ joinQuery: joinQueryChainHOF(getPrimaryKeys(query), reverseJoin, (joiningQuery, baseQuery) => join(baseQuery, joiningQuery, primaryKeys, foreignKeys)),
396
+ reverseJoin
397
+ };
567
398
  };
568
399
  const nestedUpdate$2 = ({ query, primaryKeys, foreignKeys, len }) => {
569
- return (self, update, params) => {
570
- if (params.create) {
571
- const createQuery = _querySelect(
572
- _queryCreate(query.clone(), params.create),
573
- primaryKeys
574
- );
575
- const asFn = setForeignKeysFromCte(update, primaryKeys, foreignKeys);
576
- _prependWith(self, asFn, createQuery);
577
- } else if (params.update) {
578
- let appendedAs;
579
- _hookSelectColumns(self, foreignKeys, (aliasedForeignKeys) => {
580
- selectIdsSql._sql = selectCteColumnsSql(
581
- appendedAs,
582
- aliasedForeignKeys
583
- );
584
- });
585
- const selectIdsSql = new RawSql("");
586
- const updateQuery = _queryUpdate(
587
- _queryWhereIn(query.clone(), true, primaryKeys, selectIdsSql),
588
- params.update
589
- );
590
- updateQuery.q.returnType = "value";
591
- _appendQuery(self, updateQuery, (as) => appendedAs = as);
592
- } else if (params.upsert) {
593
- if (isQueryReturnsAll(self)) {
594
- throw new Error("`upsert` option is not allowed in a batch update");
595
- }
596
- const { relQuery } = relWithSelectIds(
597
- self,
598
- query,
599
- primaryKeys,
600
- foreignKeys
601
- );
602
- const upsertQuery = _querySelect(
603
- _queryUpsert(
604
- relQuery,
605
- params.upsert
606
- ),
607
- primaryKeys
608
- );
609
- const asFn = setForeignKeysFromCte(update, primaryKeys, foreignKeys);
610
- _prependWith(self, asFn, upsertQuery);
611
- } else if (params.delete) {
612
- _hookSelectColumns(self, foreignKeys, noop);
613
- disconnect(update, foreignKeys);
614
- const { selectIdsSql, relQuery } = relWithSelectIds(
615
- self,
616
- query,
617
- primaryKeys,
618
- foreignKeys
619
- );
620
- self.q.and = self.q.or = void 0;
621
- _queryWhereIn(self, true, foreignKeys, selectIdsSql);
622
- const deleteQuery = _queryDelete(relQuery);
623
- deleteQuery.q.returnType = "value";
624
- _appendQuery(self, deleteQuery, noop);
625
- } else if (params.disconnect) {
626
- disconnect(update, foreignKeys);
627
- } else if (params.set) {
628
- let loadPrimaryKeys;
629
- let loadForeignKeys;
630
- for (let i = 0; i < len; i++) {
631
- const primaryKey = primaryKeys[i];
632
- if (primaryKey in params.set) {
633
- update[foreignKeys[i]] = params.set[primaryKey];
634
- } else {
635
- (loadPrimaryKeys ?? (loadPrimaryKeys = [])).push(primaryKey);
636
- (loadForeignKeys ?? (loadForeignKeys = [])).push(foreignKeys[i]);
637
- }
638
- }
639
- if (loadPrimaryKeys) {
640
- const asFn = setForeignKeysFromCte(
641
- update,
642
- loadPrimaryKeys,
643
- loadForeignKeys,
644
- true
645
- );
646
- _prependWith(
647
- self,
648
- asFn,
649
- _queryFindBy(query.select(...loadPrimaryKeys), params.set)
650
- );
651
- }
652
- }
653
- };
400
+ return ((self, update, params) => {
401
+ if (params.create) {
402
+ const createQuery = _querySelect(_queryCreate(query.clone(), params.create), primaryKeys);
403
+ _prependWith(self, setForeignKeysFromCte(update, primaryKeys, foreignKeys), createQuery);
404
+ } else if (params.update) {
405
+ let appendedAs;
406
+ _hookSelectColumns(self, foreignKeys, (aliasedForeignKeys) => {
407
+ selectIdsSql._sql = selectCteColumnsSql(appendedAs, aliasedForeignKeys);
408
+ });
409
+ const selectIdsSql = new RawSql("");
410
+ const updateQuery = _queryUpdate(_queryWhereIn(query.clone(), true, primaryKeys, selectIdsSql), params.update);
411
+ updateQuery.q.returnType = "value";
412
+ _appendQuery(self, updateQuery, (as) => appendedAs = as);
413
+ } else if (params.upsert) {
414
+ if (isQueryReturnsAll(self)) throw new Error("`upsert` option is not allowed in a batch update");
415
+ const { relQuery } = relWithSelectIds(self, query, primaryKeys, foreignKeys);
416
+ const upsertQuery = _querySelect(_queryUpsert(relQuery, params.upsert), primaryKeys);
417
+ _prependWith(self, setForeignKeysFromCte(update, primaryKeys, foreignKeys), upsertQuery);
418
+ } else if (params.delete) {
419
+ _hookSelectColumns(self, foreignKeys, noop);
420
+ disconnect(update, foreignKeys);
421
+ const { selectIdsSql, relQuery } = relWithSelectIds(self, query, primaryKeys, foreignKeys);
422
+ self.q.and = self.q.or = void 0;
423
+ _queryWhereIn(self, true, foreignKeys, selectIdsSql);
424
+ const deleteQuery = _queryDelete(relQuery);
425
+ deleteQuery.q.returnType = "value";
426
+ _appendQuery(self, deleteQuery, noop);
427
+ } else if (params.disconnect) disconnect(update, foreignKeys);
428
+ else if (params.set) {
429
+ let loadPrimaryKeys;
430
+ let loadForeignKeys;
431
+ for (let i = 0; i < len; i++) {
432
+ const primaryKey = primaryKeys[i];
433
+ if (primaryKey in params.set) update[foreignKeys[i]] = params.set[primaryKey];
434
+ else {
435
+ (loadPrimaryKeys ??= []).push(primaryKey);
436
+ (loadForeignKeys ??= []).push(foreignKeys[i]);
437
+ }
438
+ }
439
+ if (loadPrimaryKeys) _prependWith(self, setForeignKeysFromCte(update, loadPrimaryKeys, loadForeignKeys, true), _queryFindBy(query.select(...loadPrimaryKeys), params.set));
440
+ }
441
+ });
654
442
  };
655
443
  const disconnect = (update, foreignKeys) => {
656
- for (const foreignKey of foreignKeys) {
657
- update[foreignKey] = null;
658
- }
444
+ for (const foreignKey of foreignKeys) update[foreignKey] = null;
659
445
  };
660
446
  const relWithSelectIds = (self, rel, primaryKeys, foreignKeys) => {
661
- const selectIdsQuery = makeSelectIdsQuery(self, foreignKeys);
662
- const selectIdsSql = new RawSql("");
663
- _prependWith(
664
- self,
665
- (as) => {
666
- selectIdsSql._sql = selectCteColumnsSql(as, foreignKeys);
667
- },
668
- selectIdsQuery
669
- );
670
- return {
671
- selectIdsSql,
672
- relQuery: _queryWhereIn(rel.clone(), true, primaryKeys, selectIdsSql)
673
- };
447
+ const selectIdsQuery = makeSelectIdsQuery(self, foreignKeys);
448
+ const selectIdsSql = new RawSql("");
449
+ _prependWith(self, (as) => {
450
+ selectIdsSql._sql = selectCteColumnsSql(as, foreignKeys);
451
+ }, selectIdsQuery);
452
+ return {
453
+ selectIdsSql,
454
+ relQuery: _queryWhereIn(rel.clone(), true, primaryKeys, selectIdsSql)
455
+ };
674
456
  };
675
457
  const makeSelectIdsQuery = (self, foreignKeys) => {
676
- const selectIdsQuery = self.baseQuery.clone();
677
- selectIdsQuery.q.distinct = emptyArray;
678
- selectIdsQuery.q.select = foreignKeys;
679
- selectIdsQuery.q.and = self.q.and;
680
- selectIdsQuery.q.or = self.q.or;
681
- return selectIdsQuery;
458
+ const selectIdsQuery = self.baseQuery.clone();
459
+ selectIdsQuery.q.distinct = emptyArray;
460
+ selectIdsQuery.q.select = foreignKeys;
461
+ selectIdsQuery.q.and = self.q.and;
462
+ selectIdsQuery.q.or = self.q.or;
463
+ return selectIdsQuery;
682
464
  };
683
465
  const setForeignKeysFromCte = (record, primaryKeys, foreignKeys, mustExist) => {
684
- for (const key of foreignKeys) {
685
- record[key] = new RawSql("");
686
- }
687
- return (as) => {
688
- foreignKeys.forEach(
689
- mustExist ? (foreignKey, i) => {
690
- record[foreignKey]._sql = selectCteColumnMustExistSql(
691
- i,
692
- as,
693
- primaryKeys[i]
694
- );
695
- } : (foreignKey, i) => {
696
- record[foreignKey]._sql = selectCteColumnSql(
697
- as,
698
- primaryKeys[i]
699
- );
700
- }
701
- );
702
- };
466
+ for (const key of foreignKeys) record[key] = new RawSql("");
467
+ return (as) => {
468
+ foreignKeys.forEach(mustExist ? (foreignKey, i) => {
469
+ record[foreignKey]._sql = selectCteColumnMustExistSql(i, as, primaryKeys[i]);
470
+ } : (foreignKey, i) => {
471
+ record[foreignKey]._sql = selectCteColumnSql(as, primaryKeys[i]);
472
+ });
473
+ };
703
474
  };
704
475
  const selectCteColumnMustExistSql = (i, cteAs, column) => {
705
- const selectColumn = selectCteColumnSql(cteAs, column);
706
- return i === 0 ? `CASE WHEN (SELECT count(*) FROM "${cteAs}") = 0 AND (SELECT 'not-found')::int = 0 THEN NULL ELSE ${selectColumn} END` : selectColumn;
476
+ const selectColumn = selectCteColumnSql(cteAs, column);
477
+ return i === 0 ? `CASE WHEN (SELECT count(*) FROM "${cteAs}") = 0 AND (SELECT 'not-found')::int = 0 THEN NULL ELSE ${selectColumn} END` : selectColumn;
478
+ };
479
+ var HasOneVirtualColumn = class extends VirtualColumn {
480
+ constructor(schema, key, state) {
481
+ super(schema);
482
+ this.key = key;
483
+ this.state = state;
484
+ this.nestedInsert = nestedInsert$2(state);
485
+ this.setNulls = {};
486
+ for (const foreignKey of state.foreignKeys) this.setNulls[foreignKey] = null;
487
+ }
488
+ create(self, ctx, items, rowIndexes, count) {
489
+ if (count <= self.qb.internal.nestedCreateBatchMax) {
490
+ const { query: rel, primaryKeys, foreignKeys } = this.state;
491
+ let nestedCreateItems;
492
+ items.forEach((item, i) => {
493
+ const value = item[this.key];
494
+ const kind = value.create ? "create" : value.connect ? "connect" : "connectOrCreate";
495
+ if (kind) {
496
+ const nestedCreateItem = (nestedCreateItems ??= {})[kind] ??= {
497
+ indexes: [],
498
+ items: [],
499
+ values: []
500
+ };
501
+ nestedCreateItem.indexes.push(rowIndexes[i]);
502
+ nestedCreateItem.values.push(value[kind]);
503
+ const data = value.create ? { ...value.create } : {};
504
+ for (const key of foreignKeys) data[key] = new RawSql("");
505
+ nestedCreateItem.items.push(data);
506
+ }
507
+ });
508
+ if (!nestedCreateItems) return;
509
+ let createAs;
510
+ let connectAs;
511
+ let connectOrCreateAs;
512
+ _hookSelectColumns(self, primaryKeys, (aliasedPrimaryKeys) => {
513
+ foreignKeys.forEach((key, keyI) => {
514
+ const primaryKey = aliasedPrimaryKeys[keyI];
515
+ if (create && createAs) for (let i = 0; i < create.items.length; i++) create.items[i][key]._sql = selectCteColumnFromManySql(createAs, primaryKey, create.indexes[i], count);
516
+ if (connect && connectAs) for (let i = 0; i < connect.items.length; i++) connect.items[i][key]._sql = selectCteColumnFromManySql(connectAs, primaryKey, connect.indexes[i], count);
517
+ if (connectOrCreate && connectOrCreateAs) for (let i = 0; i < connectOrCreate.items.length; i++) connectOrCreate.items[i][key]._sql = selectCteColumnFromManySql(connectOrCreateAs, primaryKey, connectOrCreate.indexes[i], count);
518
+ });
519
+ });
520
+ const { create, connect, connectOrCreate } = nestedCreateItems;
521
+ if (create) _appendQuery(self, _queryInsertMany(_clone(rel), create.items), (as) => createAs = as);
522
+ if (connect) connect.values.forEach((value, i) => {
523
+ const query = _queryUpdateOrThrow(rel.where(value), connect.items[i]);
524
+ query.q.ensureCount = 1;
525
+ _appendQuery(self, query, (as) => connectAs = as);
526
+ });
527
+ if (connectOrCreate) connectOrCreate.values.forEach((value, i) => {
528
+ _appendQuery(self, _queryUpsert(rel.where(value.where), {
529
+ update: connectOrCreate.items[i],
530
+ create: {
531
+ ...value.create,
532
+ ...connectOrCreate.items[i]
533
+ }
534
+ }), (as) => connectOrCreateAs = as);
535
+ });
536
+ } else hasRelationHandleCreate(self, ctx, items, rowIndexes, this.key, this.state.primaryKeys, this.nestedInsert);
537
+ }
538
+ update(self, set) {
539
+ const params = set[this.key];
540
+ if ((params.set || params.create || params.upsert) && isQueryReturnsAll(self)) {
541
+ const key = params.set ? "set" : params.create ? "create" : "upsert";
542
+ throw new Error(`\`${key}\` option is not allowed in a batch update`);
543
+ }
544
+ const { primaryKeys, foreignKeys, query: relQuery } = this.state;
545
+ if (params.create || params.update || params.upsert || params.disconnect || params.set || params.delete) {
546
+ let appendedAs;
547
+ _hookSelectColumns(self, primaryKeys, (aliasedPrimaryKeys) => {
548
+ selectIdsSql._sql = selectCteColumnsSql(appendedAs, aliasedPrimaryKeys);
549
+ if (params.create || params.set || params.upsert) foreignKeys.forEach((foreignKey, i) => {
550
+ setIds[foreignKey]._sql = selectCteColumnSql(appendedAs, aliasedPrimaryKeys[i]);
551
+ });
552
+ });
553
+ const selectIdsSql = new RawSql("");
554
+ const existingRelQuery = _queryWhereIn(_clone(relQuery), true, foreignKeys, selectIdsSql);
555
+ let setIds = void 0;
556
+ if (params.create || params.set || params.upsert) {
557
+ setIds = {};
558
+ foreignKeys.forEach((foreignKey) => {
559
+ setIds[foreignKey] = new RawSql("");
560
+ });
561
+ }
562
+ const nullifyOrDeleteQuery = params.update ? _queryUpdate(existingRelQuery, params.update) : params.upsert ? _queryUpsert(existingRelQuery, {
563
+ update: params.upsert.update,
564
+ create: {
565
+ ...typeof params.upsert.create === "function" ? params.upsert.create() : params.upsert.create,
566
+ ...setIds
567
+ }
568
+ }) : params.delete ? _queryDelete(existingRelQuery) : _queryUpdate(existingRelQuery, this.setNulls);
569
+ nullifyOrDeleteQuery.q.returnType = "void";
570
+ _appendQuery(self, nullifyOrDeleteQuery, (as) => appendedAs = as);
571
+ if (params.create) _appendQuery(self, _queryInsert(_clone(relQuery), {
572
+ ...params.create,
573
+ ...setIds
574
+ }), noop);
575
+ else if (params.set) {
576
+ const setQuery = _queryUpdate(_queryWhere(_clone(relQuery), [params.set]), setIds);
577
+ setQuery.q.returnType = "void";
578
+ _appendQuery(self, setQuery, noop);
579
+ }
580
+ }
581
+ }
707
582
  };
708
-
709
- class HasOneVirtualColumn extends VirtualColumn {
710
- constructor(schema, key, state) {
711
- super(schema);
712
- this.key = key;
713
- this.state = state;
714
- this.nestedInsert = nestedInsert$2(state);
715
- this.setNulls = {};
716
- for (const foreignKey of state.foreignKeys) {
717
- this.setNulls[foreignKey] = null;
718
- }
719
- }
720
- create(self, ctx, items, rowIndexes, count) {
721
- if (count <= self.qb.internal.nestedCreateBatchMax) {
722
- const { query: rel, primaryKeys, foreignKeys } = this.state;
723
- let nestedCreateItems;
724
- items.forEach((item, i) => {
725
- var _a;
726
- const value = item[this.key];
727
- const kind = value.create ? "create" : value.connect ? "connect" : "connectOrCreate";
728
- {
729
- const nestedCreateItem = (_a = nestedCreateItems ?? (nestedCreateItems = {}))[kind] ?? (_a[kind] = {
730
- indexes: [],
731
- items: [],
732
- values: []
733
- });
734
- nestedCreateItem.indexes.push(rowIndexes[i]);
735
- nestedCreateItem.values.push(value[kind]);
736
- const data = value.create ? { ...value.create } : {};
737
- for (const key of foreignKeys) {
738
- data[key] = new RawSql("");
739
- }
740
- nestedCreateItem.items.push(data);
741
- }
742
- });
743
- if (!nestedCreateItems) {
744
- return;
745
- }
746
- let createAs;
747
- let connectAs;
748
- let connectOrCreateAs;
749
- _hookSelectColumns(self, primaryKeys, (aliasedPrimaryKeys) => {
750
- foreignKeys.forEach((key, keyI) => {
751
- const primaryKey = aliasedPrimaryKeys[keyI];
752
- if (create && createAs) {
753
- for (let i = 0; i < create.items.length; i++) {
754
- create.items[i][key]._sql = selectCteColumnFromManySql(
755
- createAs,
756
- primaryKey,
757
- create.indexes[i],
758
- count
759
- );
760
- }
761
- }
762
- if (connect && connectAs) {
763
- for (let i = 0; i < connect.items.length; i++) {
764
- connect.items[i][key]._sql = selectCteColumnFromManySql(
765
- connectAs,
766
- primaryKey,
767
- connect.indexes[i],
768
- count
769
- );
770
- }
771
- }
772
- if (connectOrCreate && connectOrCreateAs) {
773
- for (let i = 0; i < connectOrCreate.items.length; i++) {
774
- connectOrCreate.items[i][key]._sql = selectCteColumnFromManySql(
775
- connectOrCreateAs,
776
- primaryKey,
777
- connectOrCreate.indexes[i],
778
- count
779
- );
780
- }
781
- }
782
- });
783
- });
784
- const { create, connect, connectOrCreate } = nestedCreateItems;
785
- if (create) {
786
- const query = _queryInsertMany(_clone(rel), create.items);
787
- _appendQuery(self, query, (as) => createAs = as);
788
- }
789
- if (connect) {
790
- connect.values.forEach((value, i) => {
791
- const query = _queryUpdateOrThrow(
792
- rel.where(value),
793
- connect.items[i]
794
- );
795
- query.q.ensureCount = 1;
796
- _appendQuery(self, query, (as) => connectAs = as);
797
- });
798
- }
799
- if (connectOrCreate) {
800
- connectOrCreate.values.forEach((value, i) => {
801
- const query = _queryUpsert(rel.where(value.where), {
802
- update: connectOrCreate.items[i],
803
- create: {
804
- ...value.create,
805
- ...connectOrCreate.items[i]
806
- }
807
- });
808
- _appendQuery(self, query, (as) => connectOrCreateAs = as);
809
- });
810
- }
811
- } else {
812
- hasRelationHandleCreate(
813
- self,
814
- ctx,
815
- items,
816
- rowIndexes,
817
- this.key,
818
- this.state.primaryKeys,
819
- this.nestedInsert
820
- );
821
- }
822
- }
823
- update(self, set) {
824
- const params = set[this.key];
825
- if ((params.set || params.create || params.upsert) && isQueryReturnsAll(self)) {
826
- const key = params.set ? "set" : params.create ? "create" : "upsert";
827
- throw new Error(`\`${key}\` option is not allowed in a batch update`);
828
- }
829
- const { primaryKeys, foreignKeys, query: relQuery } = this.state;
830
- if (params.create || params.update || params.upsert || params.disconnect || params.set || params.delete) {
831
- let appendedAs;
832
- _hookSelectColumns(self, primaryKeys, (aliasedPrimaryKeys) => {
833
- selectIdsSql._sql = selectCteColumnsSql(
834
- appendedAs,
835
- aliasedPrimaryKeys
836
- );
837
- if (params.create || params.set || params.upsert) {
838
- foreignKeys.forEach((foreignKey, i) => {
839
- setIds[foreignKey]._sql = selectCteColumnSql(
840
- appendedAs,
841
- aliasedPrimaryKeys[i]
842
- );
843
- });
844
- }
845
- });
846
- const selectIdsSql = new RawSql("");
847
- const existingRelQuery = _queryWhereIn(
848
- _clone(relQuery),
849
- true,
850
- foreignKeys,
851
- selectIdsSql
852
- );
853
- let setIds = void 0;
854
- if (params.create || params.set || params.upsert) {
855
- setIds = {};
856
- foreignKeys.forEach((foreignKey) => {
857
- setIds[foreignKey] = new RawSql("");
858
- });
859
- }
860
- const nullifyOrDeleteQuery = params.update ? _queryUpdate(existingRelQuery, params.update) : params.upsert ? _queryUpsert(existingRelQuery, {
861
- update: params.upsert.update,
862
- create: {
863
- ...typeof params.upsert.create === "function" ? params.upsert.create() : params.upsert.create,
864
- ...setIds
865
- }
866
- }) : params.delete ? _queryDelete(existingRelQuery) : _queryUpdate(existingRelQuery, this.setNulls);
867
- nullifyOrDeleteQuery.q.returnType = "void";
868
- _appendQuery(self, nullifyOrDeleteQuery, (as) => appendedAs = as);
869
- if (params.create) {
870
- const createQuery = _queryInsert(_clone(relQuery), {
871
- ...params.create,
872
- ...setIds
873
- });
874
- _appendQuery(self, createQuery, noop);
875
- } else if (params.set) {
876
- const setQuery = _queryUpdate(
877
- _queryWhere(_clone(relQuery), [params.set]),
878
- setIds
879
- );
880
- setQuery.q.returnType = "void";
881
- _appendQuery(self, setQuery, noop);
882
- }
883
- }
884
- }
885
- }
886
583
  const makeHasOneMethod = (tableConfig, table, relation, relationName, query) => {
887
- const relPKeys = getPrimaryKeys(query);
888
- if ("through" in relation.options) {
889
- const { through, source } = relation.options;
890
- const throughRelation = getThroughRelation(table, through);
891
- const sourceRelation = getSourceRelation(throughRelation, source);
892
- const sourceRelationQuery = sourceRelation.query.as(
893
- relationName
894
- );
895
- const sourceQuery = sourceRelation.joinQuery(
896
- sourceRelationQuery,
897
- throughRelation.query
898
- );
899
- const whereExistsCallback = () => sourceQuery;
900
- const reverseJoin2 = (baseQuery, joiningQuery) => {
901
- return joinHasThrough(
902
- baseQuery,
903
- baseQuery,
904
- joiningQuery,
905
- throughRelation,
906
- sourceRelation
907
- );
908
- };
909
- return {
910
- returns: "one",
911
- queryRelated: (params) => {
912
- const throughQuery = table.queryRelated(through, params);
913
- return query.whereExists(throughQuery, whereExistsCallback);
914
- },
915
- joinQuery: joinQueryChainHOF(
916
- relPKeys,
917
- reverseJoin2,
918
- (joiningQuery, baseQuery) => joinHasThrough(
919
- joiningQuery,
920
- baseQuery,
921
- joiningQuery,
922
- throughRelation,
923
- sourceRelation
924
- )
925
- ),
926
- reverseJoin: reverseJoin2
927
- };
928
- }
929
- const primaryKeys = relation.options.columns;
930
- const foreignKeys = relation.options.references;
931
- const { on } = relation.options;
932
- if (on) {
933
- _queryWhere(query, [on]);
934
- _queryDefaults(query, on);
935
- }
936
- addAutoForeignKey(
937
- tableConfig,
938
- query,
939
- table,
940
- primaryKeys,
941
- foreignKeys,
942
- relation.options
943
- );
944
- const state = { query, primaryKeys, foreignKeys, on };
945
- const len = primaryKeys.length;
946
- const reversedOn = {};
947
- for (let i = 0; i < len; i++) {
948
- reversedOn[foreignKeys[i]] = primaryKeys[i];
949
- }
950
- const fromQuerySelect = [{ selectAs: reversedOn }];
951
- const reverseJoin = (baseQuery, joiningQuery) => {
952
- return joinHasRelation(
953
- joiningQuery,
954
- baseQuery,
955
- foreignKeys,
956
- primaryKeys,
957
- len
958
- );
959
- };
960
- return {
961
- returns: "one",
962
- queryRelated: (params) => {
963
- const values = {};
964
- for (let i = 0; i < len; i++) {
965
- values[foreignKeys[i]] = params[primaryKeys[i]];
966
- }
967
- return _queryDefaults(query.where(values), { ...on, ...values });
968
- },
969
- virtualColumn: new HasOneVirtualColumn(
970
- defaultSchemaConfig,
971
- relationName,
972
- state
973
- ),
974
- joinQuery: joinQueryChainHOF(
975
- relPKeys,
976
- reverseJoin,
977
- (joiningQuery, baseQuery) => joinHasRelation(
978
- baseQuery,
979
- joiningQuery,
980
- primaryKeys,
981
- foreignKeys,
982
- len
983
- )
984
- ),
985
- reverseJoin,
986
- modifyRelatedQuery(relationQuery) {
987
- return (query2) => {
988
- const baseQuery = query2.clone();
989
- baseQuery.q.select = fromQuerySelect;
990
- const q = relationQuery.q;
991
- q.insertFrom = prepareSubQueryForSql(q, baseQuery);
992
- q.values = [];
993
- };
994
- }
995
- };
584
+ const relPKeys = getPrimaryKeys(query);
585
+ if ("through" in relation.options) {
586
+ const { through, source } = relation.options;
587
+ const throughRelation = getThroughRelation(table, through);
588
+ const sourceRelation = getSourceRelation(throughRelation, source);
589
+ const sourceRelationQuery = sourceRelation.query.as(relationName);
590
+ const sourceQuery = sourceRelation.joinQuery(sourceRelationQuery, throughRelation.query);
591
+ const whereExistsCallback = () => sourceQuery;
592
+ const reverseJoin = (baseQuery, joiningQuery) => {
593
+ return joinHasThrough(baseQuery, baseQuery, joiningQuery, throughRelation, sourceRelation);
594
+ };
595
+ return {
596
+ returns: "one",
597
+ queryRelated: (params) => {
598
+ const throughQuery = table.queryRelated(through, params);
599
+ return query.whereExists(throughQuery, whereExistsCallback);
600
+ },
601
+ joinQuery: joinQueryChainHOF(relPKeys, reverseJoin, (joiningQuery, baseQuery) => joinHasThrough(joiningQuery, baseQuery, joiningQuery, throughRelation, sourceRelation)),
602
+ reverseJoin
603
+ };
604
+ }
605
+ const primaryKeys = relation.options.columns;
606
+ const foreignKeys = relation.options.references;
607
+ const { on } = relation.options;
608
+ if (on) {
609
+ _queryWhere(query, [on]);
610
+ _queryDefaults(query, on);
611
+ }
612
+ addAutoForeignKey(tableConfig, query, table, primaryKeys, foreignKeys, relation.options);
613
+ const state = {
614
+ query,
615
+ primaryKeys,
616
+ foreignKeys,
617
+ on
618
+ };
619
+ const len = primaryKeys.length;
620
+ const reversedOn = {};
621
+ for (let i = 0; i < len; i++) reversedOn[foreignKeys[i]] = primaryKeys[i];
622
+ const fromQuerySelect = [{ selectAs: reversedOn }];
623
+ const reverseJoin = (baseQuery, joiningQuery) => {
624
+ return joinHasRelation(joiningQuery, baseQuery, foreignKeys, primaryKeys, len);
625
+ };
626
+ return {
627
+ returns: "one",
628
+ queryRelated: (params) => {
629
+ const values = {};
630
+ for (let i = 0; i < len; i++) values[foreignKeys[i]] = params[primaryKeys[i]];
631
+ return _queryDefaults(query.where(values), {
632
+ ...on,
633
+ ...values
634
+ });
635
+ },
636
+ virtualColumn: new HasOneVirtualColumn(defaultSchemaConfig, relationName, state),
637
+ joinQuery: joinQueryChainHOF(relPKeys, reverseJoin, (joiningQuery, baseQuery) => joinHasRelation(baseQuery, joiningQuery, primaryKeys, foreignKeys, len)),
638
+ reverseJoin,
639
+ modifyRelatedQuery(relationQuery) {
640
+ return (query) => {
641
+ const baseQuery = query.clone();
642
+ baseQuery.q.select = fromQuerySelect;
643
+ const q = relationQuery.q;
644
+ q.insertFrom = prepareSubQueryForSql(q, baseQuery);
645
+ q.values = [];
646
+ };
647
+ }
648
+ };
996
649
  };
997
650
  const nestedInsert$2 = ({ query, primaryKeys, foreignKeys }) => {
998
- return async (_, data) => {
999
- const t = query.clone();
1000
- const items = [];
1001
- for (const item of data) {
1002
- if (item[1].connect || item[1].connectOrCreate) {
1003
- items.push(item);
1004
- }
1005
- }
1006
- let connected;
1007
- if (items.length) {
1008
- for (let i = 0, len = items.length; i < len; i++) {
1009
- const [selfData, item] = items[i];
1010
- const data2 = {};
1011
- primaryKeys.forEach((primaryKey, i2) => {
1012
- data2[foreignKeys[i2]] = selfData[primaryKey];
1013
- });
1014
- items[i] = "connect" in item ? _queryUpdateOrThrow(
1015
- t.where(item.connect),
1016
- data2
1017
- ) : _queryUpdate(
1018
- t.where(
1019
- item.connectOrCreate.where
1020
- ),
1021
- data2
1022
- );
1023
- }
1024
- connected = await Promise.all(items);
1025
- } else {
1026
- connected = [];
1027
- }
1028
- let connectedI = 0;
1029
- items.length = 0;
1030
- for (const item of data) {
1031
- if (item[1].connectOrCreate) {
1032
- if (!connected[connectedI++]) {
1033
- items.push(item);
1034
- }
1035
- } else if (item[1].create) {
1036
- items.push(item);
1037
- }
1038
- }
1039
- if (items.length) {
1040
- for (let i = 0, len = items.length; i < len; i++) {
1041
- const [selfData, item] = items[i];
1042
- const data2 = {
1043
- ..."create" in item ? item.create : item.connectOrCreate.create
1044
- };
1045
- for (let i2 = 0; i2 < primaryKeys.length; i2++) {
1046
- data2[foreignKeys[i2]] = selfData[primaryKeys[i2]];
1047
- }
1048
- items[i] = data2;
1049
- }
1050
- await t.insertMany(items);
1051
- }
1052
- };
651
+ return (async (_, data) => {
652
+ const t = query.clone();
653
+ const items = [];
654
+ for (const item of data) if (item[1].connect || item[1].connectOrCreate) items.push(item);
655
+ let connected;
656
+ if (items.length) {
657
+ for (let i = 0, len = items.length; i < len; i++) {
658
+ const [selfData, item] = items[i];
659
+ const data = {};
660
+ primaryKeys.forEach((primaryKey, i) => {
661
+ data[foreignKeys[i]] = selfData[primaryKey];
662
+ });
663
+ items[i] = "connect" in item ? _queryUpdateOrThrow(t.where(item.connect), data) : _queryUpdate(t.where(item.connectOrCreate.where), data);
664
+ }
665
+ connected = await Promise.all(items);
666
+ } else connected = [];
667
+ let connectedI = 0;
668
+ items.length = 0;
669
+ for (const item of data) if (item[1].connectOrCreate) {
670
+ if (!connected[connectedI++]) items.push(item);
671
+ } else if (item[1].create) items.push(item);
672
+ if (items.length) {
673
+ for (let i = 0, len = items.length; i < len; i++) {
674
+ const [selfData, item] = items[i];
675
+ const data = { ..."create" in item ? item.create : item.connectOrCreate.create };
676
+ for (let i = 0; i < primaryKeys.length; i++) data[foreignKeys[i]] = selfData[primaryKeys[i]];
677
+ items[i] = data;
678
+ }
679
+ await t.insertMany(items);
680
+ }
681
+ });
682
+ };
683
+ var HasManyVirtualColumn = class extends VirtualColumn {
684
+ constructor(schema, key, state) {
685
+ super(schema);
686
+ this.key = key;
687
+ this.state = state;
688
+ this.nestedInsert = nestedInsert$1(state);
689
+ this.nestedUpdate = nestedUpdate$1(state);
690
+ }
691
+ create(self, ctx, items, rowIndexes, count) {
692
+ if (count <= self.qb.internal.nestedCreateBatchMax) {
693
+ const { query: rel, primaryKeys, foreignKeys } = this.state;
694
+ let nestedCreateItems;
695
+ items.forEach((item, i) => {
696
+ const value = item[this.key];
697
+ if (value.create?.length) {
698
+ const nestedCreateItem = (nestedCreateItems ??= {}).create ??= {
699
+ indexes: [],
700
+ items: []
701
+ };
702
+ nestedCreateItem.indexes.push(rowIndexes[i]);
703
+ const data = value.create.map((obj) => {
704
+ const data = { ...obj };
705
+ for (const key of foreignKeys) data[key] = new RawSql("");
706
+ return data;
707
+ });
708
+ nestedCreateItem.items.push(data);
709
+ } else {
710
+ const kind = value.connect?.length ? "connect" : value.connectOrCreate?.length ? "connectOrCreate" : void 0;
711
+ if (kind) {
712
+ const nestedCreateItem = (nestedCreateItems ??= {})[kind] ??= {
713
+ indexes: [],
714
+ items: [],
715
+ values: []
716
+ };
717
+ nestedCreateItem.indexes.push(rowIndexes[i]);
718
+ nestedCreateItem.values.push(value[kind]);
719
+ const data = {};
720
+ for (const key of foreignKeys) data[key] = new RawSql("");
721
+ nestedCreateItem.items.push(data);
722
+ }
723
+ }
724
+ });
725
+ if (!nestedCreateItems) return;
726
+ let createAs;
727
+ let connectAs;
728
+ let connectOrCreateAs;
729
+ _hookSelectColumns(self, primaryKeys, (aliasedPrimaryKeys) => {
730
+ foreignKeys.forEach((key, keyI) => {
731
+ const primaryKey = aliasedPrimaryKeys[keyI];
732
+ if (create && createAs) for (let i = 0; i < create.items.length; i++) {
733
+ const sql = selectCteColumnFromManySql(createAs, primaryKey, create.indexes[i], count);
734
+ for (const item of create.items[i]) item[key]._sql = sql;
735
+ }
736
+ if (connect && connectAs) for (let i = 0; i < connect.items.length; i++) connect.items[i][key]._sql = selectCteColumnFromManySql(connectAs, primaryKey, connect.indexes[i], count);
737
+ if (connectOrCreate && connectOrCreateAs) for (let i = 0; i < connectOrCreate.items.length; i++) connectOrCreate.items[i][key]._sql = selectCteColumnFromManySql(connectOrCreateAs, primaryKey, connectOrCreate.indexes[i], count);
738
+ });
739
+ });
740
+ const { create, connect, connectOrCreate } = nestedCreateItems;
741
+ if (create) _appendQuery(self, _queryInsertMany(_clone(rel), create.items.flat()), (as) => createAs = as);
742
+ if (connect) connect.values.forEach((value, i) => {
743
+ const query = _queryUpdateOrThrow(rel.whereOneOf(...value), connect.items[i]);
744
+ query.q.ensureCount = value.length;
745
+ _appendQuery(self, query, (as) => connectAs = as);
746
+ });
747
+ if (connectOrCreate) connectOrCreate.values.forEach((array, i) => {
748
+ const foreignKeyValues = connectOrCreate.items[i];
749
+ for (const value of array) _appendQuery(self, _queryUpsert(rel.where(value.where), {
750
+ update: foreignKeyValues,
751
+ create: {
752
+ ...value.create,
753
+ ...foreignKeyValues
754
+ }
755
+ }), (as) => connectOrCreateAs = as);
756
+ });
757
+ } else hasRelationHandleCreate(self, ctx, items, rowIndexes, this.key, this.state.primaryKeys, this.nestedInsert);
758
+ }
759
+ update(q, set) {
760
+ const params = set[this.key];
761
+ if ((params.set || params.create) && isQueryReturnsAll(q)) {
762
+ const key = params.set ? "set" : "create";
763
+ throw new Error(`\`${key}\` option is not allowed in a batch update`);
764
+ }
765
+ hasRelationHandleUpdate(q, set, this.key, this.state.primaryKeys, this.nestedUpdate);
766
+ }
1053
767
  };
1054
-
1055
- class HasManyVirtualColumn extends VirtualColumn {
1056
- constructor(schema, key, state) {
1057
- super(schema);
1058
- this.key = key;
1059
- this.state = state;
1060
- this.nestedInsert = nestedInsert$1(state);
1061
- this.nestedUpdate = nestedUpdate$1(state);
1062
- }
1063
- create(self, ctx, items, rowIndexes, count) {
1064
- if (count <= self.qb.internal.nestedCreateBatchMax) {
1065
- const { query: rel, primaryKeys, foreignKeys } = this.state;
1066
- let nestedCreateItems;
1067
- items.forEach((item, i) => {
1068
- var _a, _b;
1069
- const value = item[this.key];
1070
- if (value.create?.length) {
1071
- const nestedCreateItem = (_a = nestedCreateItems ?? (nestedCreateItems = {})).create ?? (_a.create = {
1072
- indexes: [],
1073
- items: []
1074
- });
1075
- nestedCreateItem.indexes.push(rowIndexes[i]);
1076
- const data = value.create.map((obj) => {
1077
- const data2 = { ...obj };
1078
- for (const key of foreignKeys) {
1079
- data2[key] = new RawSql("");
1080
- }
1081
- return data2;
1082
- });
1083
- nestedCreateItem.items.push(data);
1084
- } else {
1085
- const kind = value.connect?.length ? "connect" : value.connectOrCreate?.length ? "connectOrCreate" : void 0;
1086
- if (kind) {
1087
- const nestedCreateItem = (_b = nestedCreateItems ?? (nestedCreateItems = {}))[kind] ?? (_b[kind] = {
1088
- indexes: [],
1089
- items: [],
1090
- values: []
1091
- });
1092
- nestedCreateItem.indexes.push(rowIndexes[i]);
1093
- nestedCreateItem.values.push(value[kind]);
1094
- const data = {};
1095
- for (const key of foreignKeys) {
1096
- data[key] = new RawSql("");
1097
- }
1098
- nestedCreateItem.items.push(data);
1099
- }
1100
- }
1101
- });
1102
- if (!nestedCreateItems) {
1103
- return;
1104
- }
1105
- let createAs;
1106
- let connectAs;
1107
- let connectOrCreateAs;
1108
- _hookSelectColumns(self, primaryKeys, (aliasedPrimaryKeys) => {
1109
- foreignKeys.forEach((key, keyI) => {
1110
- const primaryKey = aliasedPrimaryKeys[keyI];
1111
- if (create && createAs) {
1112
- for (let i = 0; i < create.items.length; i++) {
1113
- const sql = selectCteColumnFromManySql(
1114
- createAs,
1115
- primaryKey,
1116
- create.indexes[i],
1117
- count
1118
- );
1119
- for (const item of create.items[i]) {
1120
- item[key]._sql = sql;
1121
- }
1122
- }
1123
- }
1124
- if (connect && connectAs) {
1125
- for (let i = 0; i < connect.items.length; i++) {
1126
- connect.items[i][key]._sql = selectCteColumnFromManySql(
1127
- connectAs,
1128
- primaryKey,
1129
- connect.indexes[i],
1130
- count
1131
- );
1132
- }
1133
- }
1134
- if (connectOrCreate && connectOrCreateAs) {
1135
- for (let i = 0; i < connectOrCreate.items.length; i++) {
1136
- connectOrCreate.items[i][key]._sql = selectCteColumnFromManySql(
1137
- connectOrCreateAs,
1138
- primaryKey,
1139
- connectOrCreate.indexes[i],
1140
- count
1141
- );
1142
- }
1143
- }
1144
- });
1145
- });
1146
- const { create, connect, connectOrCreate } = nestedCreateItems;
1147
- if (create) {
1148
- const query = _queryInsertMany(
1149
- _clone(rel),
1150
- create.items.flat()
1151
- );
1152
- _appendQuery(self, query, (as) => createAs = as);
1153
- }
1154
- if (connect) {
1155
- connect.values.forEach((value, i) => {
1156
- const query = _queryUpdateOrThrow(
1157
- rel.whereOneOf(...value),
1158
- connect.items[i]
1159
- );
1160
- query.q.ensureCount = value.length;
1161
- _appendQuery(self, query, (as) => connectAs = as);
1162
- });
1163
- }
1164
- if (connectOrCreate) {
1165
- connectOrCreate.values.forEach((array, i) => {
1166
- const foreignKeyValues = connectOrCreate.items[i];
1167
- for (const value of array) {
1168
- const query = _queryUpsert(rel.where(value.where), {
1169
- update: foreignKeyValues,
1170
- create: {
1171
- ...value.create,
1172
- ...foreignKeyValues
1173
- }
1174
- });
1175
- _appendQuery(self, query, (as) => connectOrCreateAs = as);
1176
- }
1177
- });
1178
- }
1179
- } else {
1180
- hasRelationHandleCreate(
1181
- self,
1182
- ctx,
1183
- items,
1184
- rowIndexes,
1185
- this.key,
1186
- this.state.primaryKeys,
1187
- this.nestedInsert
1188
- );
1189
- }
1190
- }
1191
- update(q, set) {
1192
- const params = set[this.key];
1193
- if ((params.set || params.create) && isQueryReturnsAll(q)) {
1194
- const key = params.set ? "set" : "create";
1195
- throw new Error(`\`${key}\` option is not allowed in a batch update`);
1196
- }
1197
- hasRelationHandleUpdate(
1198
- q,
1199
- set,
1200
- this.key,
1201
- this.state.primaryKeys,
1202
- this.nestedUpdate
1203
- );
1204
- }
1205
- }
1206
768
  const makeHasManyMethod = (tableConfig, table, relation, relationName, query) => {
1207
- const relPKeys = getPrimaryKeys(query);
1208
- if ("through" in relation.options) {
1209
- const { through, source } = relation.options;
1210
- const throughRelation = getThroughRelation(table, through);
1211
- const sourceRelation = getSourceRelation(throughRelation, source);
1212
- const sourceRelationQuery = sourceRelation.query.as(
1213
- relationName
1214
- );
1215
- const sourceQuery = sourceRelation.joinQuery(
1216
- sourceRelationQuery,
1217
- throughRelation.query
1218
- );
1219
- const whereExistsCallback = () => sourceQuery;
1220
- const reverseJoin2 = (baseQuery, joiningQuery) => {
1221
- return joinHasThrough(
1222
- baseQuery,
1223
- baseQuery,
1224
- joiningQuery,
1225
- throughRelation,
1226
- sourceRelation
1227
- );
1228
- };
1229
- return {
1230
- returns: "many",
1231
- queryRelated: (params) => {
1232
- const throughQuery = table.queryRelated(through, params);
1233
- return query.whereExists(
1234
- throughQuery,
1235
- whereExistsCallback
1236
- );
1237
- },
1238
- joinQuery: joinQueryChainHOF(
1239
- relPKeys,
1240
- reverseJoin2,
1241
- (joiningQuery, baseQuery) => joinHasThrough(
1242
- joiningQuery,
1243
- baseQuery,
1244
- joiningQuery,
1245
- throughRelation,
1246
- sourceRelation
1247
- )
1248
- ),
1249
- reverseJoin: reverseJoin2
1250
- };
1251
- }
1252
- const primaryKeys = relation.options.columns;
1253
- const foreignKeys = relation.options.references;
1254
- const { on } = relation.options;
1255
- if (on) {
1256
- _queryWhere(query, [on]);
1257
- _queryDefaults(query, on);
1258
- }
1259
- addAutoForeignKey(
1260
- tableConfig,
1261
- query,
1262
- table,
1263
- primaryKeys,
1264
- foreignKeys,
1265
- relation.options
1266
- );
1267
- const state = { query, primaryKeys, foreignKeys, on };
1268
- const len = primaryKeys.length;
1269
- const reversedOn = {};
1270
- for (let i = 0; i < len; i++) {
1271
- reversedOn[foreignKeys[i]] = primaryKeys[i];
1272
- }
1273
- const fromQuerySelect = [{ selectAs: reversedOn }];
1274
- const reverseJoin = (baseQuery, joiningQuery) => {
1275
- return joinHasRelation(
1276
- joiningQuery,
1277
- baseQuery,
1278
- foreignKeys,
1279
- primaryKeys,
1280
- len
1281
- );
1282
- };
1283
- return {
1284
- returns: "many",
1285
- queryRelated: (params) => {
1286
- const values = {};
1287
- for (let i = 0; i < len; i++) {
1288
- values[foreignKeys[i]] = params[primaryKeys[i]];
1289
- }
1290
- return _queryDefaults(query.where(values), { ...on, ...values });
1291
- },
1292
- virtualColumn: new HasManyVirtualColumn(
1293
- defaultSchemaConfig,
1294
- relationName,
1295
- state
1296
- ),
1297
- joinQuery: joinQueryChainHOF(
1298
- relPKeys,
1299
- reverseJoin,
1300
- (joiningQuery, baseQuery) => joinHasRelation(
1301
- baseQuery,
1302
- joiningQuery,
1303
- primaryKeys,
1304
- foreignKeys,
1305
- len
1306
- )
1307
- ),
1308
- reverseJoin,
1309
- modifyRelatedQuery(relationQuery) {
1310
- return (query2) => {
1311
- const baseQuery = query2.clone();
1312
- baseQuery.q.select = fromQuerySelect;
1313
- const q = relationQuery.q;
1314
- q.insertFrom = prepareSubQueryForSql(q, baseQuery);
1315
- q.values = [];
1316
- };
1317
- }
1318
- };
769
+ const relPKeys = getPrimaryKeys(query);
770
+ if ("through" in relation.options) {
771
+ const { through, source } = relation.options;
772
+ const throughRelation = getThroughRelation(table, through);
773
+ const sourceRelation = getSourceRelation(throughRelation, source);
774
+ const sourceRelationQuery = sourceRelation.query.as(relationName);
775
+ const sourceQuery = sourceRelation.joinQuery(sourceRelationQuery, throughRelation.query);
776
+ const whereExistsCallback = () => sourceQuery;
777
+ const reverseJoin = (baseQuery, joiningQuery) => {
778
+ return joinHasThrough(baseQuery, baseQuery, joiningQuery, throughRelation, sourceRelation);
779
+ };
780
+ return {
781
+ returns: "many",
782
+ queryRelated: (params) => {
783
+ const throughQuery = table.queryRelated(through, params);
784
+ return query.whereExists(throughQuery, whereExistsCallback);
785
+ },
786
+ joinQuery: joinQueryChainHOF(relPKeys, reverseJoin, (joiningQuery, baseQuery) => joinHasThrough(joiningQuery, baseQuery, joiningQuery, throughRelation, sourceRelation)),
787
+ reverseJoin
788
+ };
789
+ }
790
+ const primaryKeys = relation.options.columns;
791
+ const foreignKeys = relation.options.references;
792
+ const { on } = relation.options;
793
+ if (on) {
794
+ _queryWhere(query, [on]);
795
+ _queryDefaults(query, on);
796
+ }
797
+ addAutoForeignKey(tableConfig, query, table, primaryKeys, foreignKeys, relation.options);
798
+ const state = {
799
+ query,
800
+ primaryKeys,
801
+ foreignKeys,
802
+ on
803
+ };
804
+ const len = primaryKeys.length;
805
+ const reversedOn = {};
806
+ for (let i = 0; i < len; i++) reversedOn[foreignKeys[i]] = primaryKeys[i];
807
+ const fromQuerySelect = [{ selectAs: reversedOn }];
808
+ const reverseJoin = (baseQuery, joiningQuery) => {
809
+ return joinHasRelation(joiningQuery, baseQuery, foreignKeys, primaryKeys, len);
810
+ };
811
+ return {
812
+ returns: "many",
813
+ queryRelated: (params) => {
814
+ const values = {};
815
+ for (let i = 0; i < len; i++) values[foreignKeys[i]] = params[primaryKeys[i]];
816
+ return _queryDefaults(query.where(values), {
817
+ ...on,
818
+ ...values
819
+ });
820
+ },
821
+ virtualColumn: new HasManyVirtualColumn(defaultSchemaConfig, relationName, state),
822
+ joinQuery: joinQueryChainHOF(relPKeys, reverseJoin, (joiningQuery, baseQuery) => joinHasRelation(baseQuery, joiningQuery, primaryKeys, foreignKeys, len)),
823
+ reverseJoin,
824
+ modifyRelatedQuery(relationQuery) {
825
+ return (query) => {
826
+ const baseQuery = query.clone();
827
+ baseQuery.q.select = fromQuerySelect;
828
+ const q = relationQuery.q;
829
+ q.insertFrom = prepareSubQueryForSql(q, baseQuery);
830
+ q.values = [];
831
+ };
832
+ }
833
+ };
1319
834
  };
1320
835
  const getWhereForNestedUpdate = (t, data, params, primaryKeys, foreignKeys) => {
1321
- return t.where({
1322
- IN: {
1323
- columns: foreignKeys,
1324
- values: data.map((item) => primaryKeys.map((key) => item[key]))
1325
- },
1326
- OR: params ? toArray(params) : void 0
1327
- });
836
+ return t.where({
837
+ IN: {
838
+ columns: foreignKeys,
839
+ values: data.map((item) => primaryKeys.map((key) => item[key]))
840
+ },
841
+ OR: params ? toArray(params) : void 0
842
+ });
1328
843
  };
1329
844
  const nestedInsert$1 = ({ query, primaryKeys, foreignKeys }) => {
1330
- const len = primaryKeys.length;
1331
- return async (_, data) => {
1332
- const t = query.clone();
1333
- const items = [];
1334
- for (const item of data) {
1335
- if (item[1].connect) {
1336
- items.push(item);
1337
- }
1338
- }
1339
- if (items.length) {
1340
- for (let i = 0, len2 = items.length; i < len2; i++) {
1341
- const [selfData, { connect }] = items[i];
1342
- const obj = {};
1343
- for (let i2 = 0; i2 < len2; i2++) {
1344
- obj[foreignKeys[i2]] = selfData[primaryKeys[i2]];
1345
- }
1346
- items[i] = _queryUpdateOrThrow(
1347
- t.where({ OR: connect }),
1348
- obj
1349
- );
1350
- }
1351
- await Promise.all(items);
1352
- }
1353
- items.length = 0;
1354
- for (const item of data) {
1355
- if (item[1].connectOrCreate) {
1356
- items.push(item);
1357
- }
1358
- }
1359
- let connected;
1360
- if (items.length) {
1361
- const queries = [];
1362
- for (let i = 0, len2 = items.length; i < len2; i++) {
1363
- const [selfData, { connectOrCreate }] = items[i];
1364
- for (const item of connectOrCreate) {
1365
- const obj = {};
1366
- for (let i2 = 0; i2 < len2; i2++) {
1367
- obj[foreignKeys[i2]] = selfData[primaryKeys[i2]];
1368
- }
1369
- queries.push(
1370
- _queryUpdate(
1371
- t.where(item.where),
1372
- obj
1373
- )
1374
- );
1375
- }
1376
- }
1377
- connected = await Promise.all(queries);
1378
- } else {
1379
- connected = [];
1380
- }
1381
- let connectedI = 0;
1382
- items.length = 0;
1383
- for (const item of data) {
1384
- if (item[1].connectOrCreate) {
1385
- const length = item[1].connectOrCreate.length;
1386
- connectedI += length;
1387
- for (let i = length; i > 0; i--) {
1388
- if (connected[connectedI - i] === 0) {
1389
- items.push(item);
1390
- break;
1391
- }
1392
- }
1393
- } else if (item[1].create) {
1394
- items.push(item);
1395
- }
1396
- }
1397
- connectedI = 0;
1398
- if (items.length) {
1399
- const records = [];
1400
- for (const [selfData, { create, connectOrCreate }] of items) {
1401
- const obj = {};
1402
- for (let i = 0; i < len; i++) {
1403
- obj[foreignKeys[i]] = selfData[primaryKeys[i]];
1404
- }
1405
- if (create) {
1406
- for (const item of create) {
1407
- records.push({
1408
- ...item,
1409
- ...obj
1410
- });
1411
- }
1412
- }
1413
- if (connectOrCreate) {
1414
- for (const item of connectOrCreate) {
1415
- if (connected[connectedI++] === 0) {
1416
- records.push({
1417
- ...item.create,
1418
- ...obj
1419
- });
1420
- }
1421
- }
1422
- }
1423
- }
1424
- await _queryCreateMany(t, records);
1425
- }
1426
- };
845
+ const len = primaryKeys.length;
846
+ return (async (_, data) => {
847
+ const t = query.clone();
848
+ const items = [];
849
+ for (const item of data) if (item[1].connect) items.push(item);
850
+ if (items.length) {
851
+ for (let i = 0, len = items.length; i < len; i++) {
852
+ const [selfData, { connect }] = items[i];
853
+ const obj = {};
854
+ for (let i = 0; i < len; i++) obj[foreignKeys[i]] = selfData[primaryKeys[i]];
855
+ items[i] = _queryUpdateOrThrow(t.where({ OR: connect }), obj);
856
+ }
857
+ await Promise.all(items);
858
+ }
859
+ items.length = 0;
860
+ for (const item of data) if (item[1].connectOrCreate) items.push(item);
861
+ let connected;
862
+ if (items.length) {
863
+ const queries = [];
864
+ for (let i = 0, len = items.length; i < len; i++) {
865
+ const [selfData, { connectOrCreate }] = items[i];
866
+ for (const item of connectOrCreate) {
867
+ const obj = {};
868
+ for (let i = 0; i < len; i++) obj[foreignKeys[i]] = selfData[primaryKeys[i]];
869
+ queries.push(_queryUpdate(t.where(item.where), obj));
870
+ }
871
+ }
872
+ connected = await Promise.all(queries);
873
+ } else connected = [];
874
+ let connectedI = 0;
875
+ items.length = 0;
876
+ for (const item of data) if (item[1].connectOrCreate) {
877
+ const length = item[1].connectOrCreate.length;
878
+ connectedI += length;
879
+ for (let i = length; i > 0; i--) if (connected[connectedI - i] === 0) {
880
+ items.push(item);
881
+ break;
882
+ }
883
+ } else if (item[1].create) items.push(item);
884
+ connectedI = 0;
885
+ if (items.length) {
886
+ const records = [];
887
+ for (const [selfData, { create, connectOrCreate }] of items) {
888
+ const obj = {};
889
+ for (let i = 0; i < len; i++) obj[foreignKeys[i]] = selfData[primaryKeys[i]];
890
+ if (create) for (const item of create) records.push({
891
+ ...item,
892
+ ...obj
893
+ });
894
+ if (connectOrCreate) {
895
+ for (const item of connectOrCreate) if (connected[connectedI++] === 0) records.push({
896
+ ...item.create,
897
+ ...obj
898
+ });
899
+ }
900
+ }
901
+ await _queryCreateMany(t, records);
902
+ }
903
+ });
1427
904
  };
1428
905
  const nestedUpdate$1 = ({ query, primaryKeys, foreignKeys }) => {
1429
- const len = primaryKeys.length;
1430
- return async (_, data, params) => {
1431
- const t = query.clone();
1432
- if (params.create) {
1433
- const obj = {};
1434
- for (let i = 0; i < len; i++) {
1435
- obj[foreignKeys[i]] = data[0][primaryKeys[i]];
1436
- }
1437
- await t.insertMany(
1438
- params.create.map((create) => ({
1439
- ...create,
1440
- ...obj
1441
- }))
1442
- );
1443
- }
1444
- if (params.add) {
1445
- if (data.length > 1) {
1446
- throw new OrchidOrmInternalError(
1447
- query,
1448
- "`connect` is not available when updating multiple records, it is only applicable for a single record update"
1449
- );
1450
- }
1451
- const obj = {};
1452
- for (let i = 0; i < len; i++) {
1453
- obj[foreignKeys[i]] = data[0][primaryKeys[i]];
1454
- }
1455
- const relatedWheres = toArray(params.add);
1456
- const count = await _queryUpdate(
1457
- t.where({ OR: relatedWheres }),
1458
- obj
1459
- );
1460
- if (count < relatedWheres.length) {
1461
- throw new OrchidOrmInternalError(
1462
- query,
1463
- `Expected to find at least ${relatedWheres.length} record(s) based on \`add\` conditions, but found ${count}`
1464
- );
1465
- }
1466
- }
1467
- if (params.disconnect || params.set) {
1468
- const obj = {};
1469
- for (const foreignKey of foreignKeys) {
1470
- obj[foreignKey] = null;
1471
- }
1472
- const setConditions = params.set && (Array.isArray(params.set) ? params.set.length : objectHasValues(params.set)) && (Array.isArray(params.set) ? {
1473
- OR: params.set
1474
- } : params.set);
1475
- let queryToDisconnect = getWhereForNestedUpdate(
1476
- t,
1477
- data,
1478
- params.disconnect,
1479
- primaryKeys,
1480
- foreignKeys
1481
- );
1482
- if (setConditions) {
1483
- queryToDisconnect = queryToDisconnect.whereNot(setConditions);
1484
- }
1485
- await _queryUpdate(queryToDisconnect, obj);
1486
- if (setConditions) {
1487
- const obj2 = {};
1488
- for (let i = 0; i < len; i++) {
1489
- obj2[foreignKeys[i]] = data[0][primaryKeys[i]];
1490
- }
1491
- await _queryUpdate(
1492
- t.where(setConditions),
1493
- obj2
1494
- );
1495
- }
1496
- }
1497
- if (params.delete || params.update) {
1498
- const q = getWhereForNestedUpdate(
1499
- t,
1500
- data,
1501
- params.delete || params.update?.where,
1502
- primaryKeys,
1503
- foreignKeys
1504
- );
1505
- if (params.delete) {
1506
- await _queryDelete(q);
1507
- } else if (params.update) {
1508
- await _queryUpdate(q, params.update.data);
1509
- }
1510
- }
1511
- };
906
+ const len = primaryKeys.length;
907
+ return (async (_, data, params) => {
908
+ const t = query.clone();
909
+ if (params.create) {
910
+ const obj = {};
911
+ for (let i = 0; i < len; i++) obj[foreignKeys[i]] = data[0][primaryKeys[i]];
912
+ await t.insertMany(params.create.map((create) => ({
913
+ ...create,
914
+ ...obj
915
+ })));
916
+ }
917
+ if (params.add) {
918
+ if (data.length > 1) throw new OrchidOrmInternalError(query, "`connect` is not available when updating multiple records, it is only applicable for a single record update");
919
+ const obj = {};
920
+ for (let i = 0; i < len; i++) obj[foreignKeys[i]] = data[0][primaryKeys[i]];
921
+ const relatedWheres = toArray(params.add);
922
+ const count = await _queryUpdate(t.where({ OR: relatedWheres }), obj);
923
+ if (count < relatedWheres.length) throw new OrchidOrmInternalError(query, `Expected to find at least ${relatedWheres.length} record(s) based on \`add\` conditions, but found ${count}`);
924
+ }
925
+ if (params.disconnect || params.set) {
926
+ const obj = {};
927
+ for (const foreignKey of foreignKeys) obj[foreignKey] = null;
928
+ const setConditions = params.set && (Array.isArray(params.set) ? params.set.length : objectHasValues(params.set)) && (Array.isArray(params.set) ? { OR: params.set } : params.set);
929
+ let queryToDisconnect = getWhereForNestedUpdate(t, data, params.disconnect, primaryKeys, foreignKeys);
930
+ if (setConditions) queryToDisconnect = queryToDisconnect.whereNot(setConditions);
931
+ await _queryUpdate(queryToDisconnect, obj);
932
+ if (setConditions) {
933
+ const obj = {};
934
+ for (let i = 0; i < len; i++) obj[foreignKeys[i]] = data[0][primaryKeys[i]];
935
+ await _queryUpdate(t.where(setConditions), obj);
936
+ }
937
+ }
938
+ if (params.delete || params.update) {
939
+ const q = getWhereForNestedUpdate(t, data, params.delete || params.update?.where, primaryKeys, foreignKeys);
940
+ if (params.delete) await _queryDelete(q);
941
+ else if (params.update) await _queryUpdate(q, params.update.data);
942
+ }
943
+ });
944
+ };
945
+ var HasAndBelongsToManyVirtualColumn = class extends VirtualColumn {
946
+ constructor(joinTable, schema, key, state) {
947
+ super(schema);
948
+ this.joinTable = joinTable;
949
+ this.key = key;
950
+ this.state = state;
951
+ this.nestedInsert = nestedInsert(state);
952
+ this.nestedUpdate = nestedUpdate(state);
953
+ }
954
+ create(q, ctx, items, rowIndexes) {
955
+ hasRelationHandleCreate(q, ctx, items, rowIndexes, this.key, this.state.primaryKeys, this.nestedInsert);
956
+ }
957
+ update(q, set) {
958
+ hasRelationHandleUpdate(q, set, this.key, this.state.primaryKeys, this.nestedUpdate);
959
+ }
1512
960
  };
1513
-
1514
- class HasAndBelongsToManyVirtualColumn extends VirtualColumn {
1515
- constructor(joinTable, schema, key, state) {
1516
- super(schema);
1517
- this.joinTable = joinTable;
1518
- this.key = key;
1519
- this.state = state;
1520
- this.nestedInsert = nestedInsert(state);
1521
- this.nestedUpdate = nestedUpdate(state);
1522
- }
1523
- create(q, ctx, items, rowIndexes) {
1524
- hasRelationHandleCreate(
1525
- q,
1526
- ctx,
1527
- items,
1528
- rowIndexes,
1529
- this.key,
1530
- this.state.primaryKeys,
1531
- this.nestedInsert
1532
- );
1533
- }
1534
- update(q, set) {
1535
- hasRelationHandleUpdate(
1536
- q,
1537
- set,
1538
- this.key,
1539
- this.state.primaryKeys,
1540
- this.nestedUpdate
1541
- );
1542
- }
1543
- }
1544
961
  const removeColumnName = (column) => {
1545
- if (!column.data.name) return column;
1546
- const cloned = Object.create(column);
1547
- cloned.data = { ...column.data, name: void 0 };
1548
- return cloned;
962
+ if (!column.data.name) return column;
963
+ const cloned = Object.create(column);
964
+ cloned.data = {
965
+ ...column.data,
966
+ name: void 0
967
+ };
968
+ return cloned;
1549
969
  };
1550
970
  const makeHasAndBelongsToManyMethod = (tableConfig, table, qb, relation, relationName, query, schema) => {
1551
- const { options } = relation;
1552
- const { snakeCase } = table.internal;
1553
- const primaryKeys = options.columns;
1554
- const foreignKeys = options.references;
1555
- const originalForeignKeys = snakeCase ? [...foreignKeys] : foreignKeys;
1556
- const joinTable = options.through.table;
1557
- const throughForeignKeys = options.through.columns;
1558
- const originalThroughForeignKeys = snakeCase ? [...throughForeignKeys] : throughForeignKeys;
1559
- const throughPrimaryKeys = options.through.references;
1560
- const { on } = options;
1561
- if (on) {
1562
- _queryWhere(query, [on]);
1563
- _queryDefaults(query, on);
1564
- }
1565
- const foreignKeysFull = foreignKeys.map((key, i) => {
1566
- if (snakeCase) key = foreignKeys[i] = toSnakeCase(key);
1567
- return `${joinTable}.${key}`;
1568
- });
1569
- const throughForeignKeysFull = throughForeignKeys.map((key, i) => {
1570
- if (snakeCase) key = throughForeignKeys[i] = toSnakeCase(key);
1571
- return `${joinTable}.${key}`;
1572
- });
1573
- const foreignTable = getQueryAs(query);
1574
- const throughPrimaryKeysFull = throughPrimaryKeys.map(
1575
- (key) => `${foreignTable}.${key}`
1576
- );
1577
- const len = primaryKeys.length;
1578
- const throughLen = throughPrimaryKeys.length;
1579
- const baseQuery = Object.create(qb.baseQuery);
1580
- baseQuery.baseQuery = baseQuery;
1581
- baseQuery.table = joinTable;
1582
- const shape = {};
1583
- const primaryKeysShape = {};
1584
- for (let i = 0; i < len; i++) {
1585
- const pk = primaryKeys[i];
1586
- shape[foreignKeys[i]] = removeColumnName(
1587
- table.shape[pk]
1588
- );
1589
- primaryKeysShape[pk] = table.shape[pk];
1590
- }
1591
- for (let i = 0; i < throughLen; i++) {
1592
- shape[throughForeignKeys[i]] = removeColumnName(
1593
- query.shape[throughPrimaryKeys[i]]
1594
- );
1595
- }
1596
- baseQuery.shape = shape;
1597
- baseQuery.q = {
1598
- ...baseQuery.q,
1599
- schema: options.through.schema || schema,
1600
- shape: baseQuery.shape
1601
- };
1602
- const subQuery = Object.create(baseQuery);
1603
- addAutoForeignKey(
1604
- tableConfig,
1605
- subQuery,
1606
- table,
1607
- primaryKeys,
1608
- foreignKeys,
1609
- relation.options,
1610
- originalForeignKeys
1611
- );
1612
- addAutoForeignKey(
1613
- tableConfig,
1614
- subQuery,
1615
- query,
1616
- throughPrimaryKeys,
1617
- throughForeignKeys,
1618
- relation.options.through,
1619
- originalThroughForeignKeys
1620
- );
1621
- const state = {
1622
- relatedTableQuery: query,
1623
- joinTableQuery: subQuery,
1624
- primaryKeys,
1625
- foreignKeys,
1626
- throughForeignKeys,
1627
- throughPrimaryKeys,
1628
- foreignKeysFull,
1629
- throughForeignKeysFull,
1630
- throughPrimaryKeysFull,
1631
- primaryKeysShape,
1632
- on
1633
- };
1634
- const joinQuery = (joiningQuery, tableAs, foreignAs, joinedShapes) => {
1635
- const cloned = joiningQuery.clone();
1636
- cloned.q.joinedShapes = joinedShapes;
1637
- return _queryWhereExists(cloned, subQuery, [
1638
- (q) => {
1639
- for (let i = 0; i < throughLen; i++) {
1640
- _queryJoinOn(q, [
1641
- throughForeignKeysFull[i],
1642
- `${foreignAs}.${throughPrimaryKeys[i]}`
1643
- ]);
1644
- }
1645
- for (let i = 0; i < len; i++) {
1646
- _queryJoinOn(q, [foreignKeysFull[i], `${tableAs}.${primaryKeys[i]}`]);
1647
- }
1648
- return q;
1649
- }
1650
- ]);
1651
- };
1652
- const obj = {};
1653
- for (let i = 0; i < len; i++) {
1654
- obj[foreignKeys[i]] = primaryKeys[i];
1655
- }
1656
- const selectPrimaryKeysAsForeignKeys = [{ selectAs: obj }];
1657
- const reverseJoin = (baseQuery2, joiningQuery) => {
1658
- const foreignAs = getQueryAs(joiningQuery);
1659
- return joinQuery(
1660
- baseQuery2,
1661
- getQueryAs(baseQuery2),
1662
- foreignAs,
1663
- {
1664
- ...baseQuery2.q.joinedShapes,
1665
- [foreignAs]: joiningQuery.q.shape
1666
- }
1667
- );
1668
- };
1669
- return {
1670
- returns: "many",
1671
- queryRelated(params) {
1672
- const q = query.whereExists(subQuery, (q2) => {
1673
- q2 = q2.clone();
1674
- const where = {};
1675
- for (let i = 0; i < len; i++) {
1676
- where[foreignKeysFull[i]] = params[primaryKeys[i]];
1677
- }
1678
- for (let i = 0; i < throughLen; i++) {
1679
- _queryJoinOn(q2, [
1680
- throughForeignKeysFull[i],
1681
- throughPrimaryKeysFull[i]
1682
- ]);
1683
- }
1684
- return _queryWhere(q2, [where]);
1685
- });
1686
- return on ? _queryDefaults(q, on) : q;
1687
- },
1688
- virtualColumn: new HasAndBelongsToManyVirtualColumn(
1689
- subQuery,
1690
- defaultSchemaConfig,
1691
- relationName,
1692
- state
1693
- ),
1694
- joinQuery: joinQueryChainHOF(
1695
- getPrimaryKeys(query),
1696
- reverseJoin,
1697
- (joiningQuery, baseQuery2) => joinQuery(
1698
- joiningQuery,
1699
- getQueryAs(baseQuery2),
1700
- getQueryAs(joiningQuery),
1701
- {
1702
- ...joiningQuery.q.joinedShapes,
1703
- [baseQuery2.q.as || baseQuery2.table]: baseQuery2.q.shape
1704
- }
1705
- )
1706
- ),
1707
- reverseJoin,
1708
- modifyRelatedQuery(relationQuery) {
1709
- const ref = {};
1710
- _queryHookAfterCreate(
1711
- relationQuery,
1712
- [],
1713
- async (result) => {
1714
- const baseQuery2 = ref.q.clone();
1715
- baseQuery2.q.select = selectPrimaryKeysAsForeignKeys;
1716
- const data = result.map((resultRow) => {
1717
- const dataRow = {};
1718
- for (let i = 0; i < throughLen; i++) {
1719
- dataRow[throughForeignKeys[i]] = resultRow[throughPrimaryKeys[i]];
1720
- }
1721
- return dataRow;
1722
- });
1723
- const createdCount = await _queryCreateManyFrom(
1724
- subQuery.count(),
1725
- baseQuery2,
1726
- data
1727
- );
1728
- if (createdCount === 0) {
1729
- throw new NotFoundError(baseQuery2);
1730
- }
1731
- }
1732
- );
1733
- return (q) => {
1734
- ref.q = q;
1735
- };
1736
- }
1737
- };
971
+ const { options } = relation;
972
+ const { snakeCase } = table.internal;
973
+ const primaryKeys = options.columns;
974
+ const foreignKeys = options.references;
975
+ const originalForeignKeys = snakeCase ? [...foreignKeys] : foreignKeys;
976
+ const joinTable = options.through.table;
977
+ const throughForeignKeys = options.through.columns;
978
+ const originalThroughForeignKeys = snakeCase ? [...throughForeignKeys] : throughForeignKeys;
979
+ const throughPrimaryKeys = options.through.references;
980
+ const { on } = options;
981
+ if (on) {
982
+ _queryWhere(query, [on]);
983
+ _queryDefaults(query, on);
984
+ }
985
+ const foreignKeysFull = foreignKeys.map((key, i) => {
986
+ if (snakeCase) key = foreignKeys[i] = toSnakeCase(key);
987
+ return `${joinTable}.${key}`;
988
+ });
989
+ const throughForeignKeysFull = throughForeignKeys.map((key, i) => {
990
+ if (snakeCase) key = throughForeignKeys[i] = toSnakeCase(key);
991
+ return `${joinTable}.${key}`;
992
+ });
993
+ const foreignTable = getQueryAs(query);
994
+ const throughPrimaryKeysFull = throughPrimaryKeys.map((key) => `${foreignTable}.${key}`);
995
+ const len = primaryKeys.length;
996
+ const throughLen = throughPrimaryKeys.length;
997
+ const baseQuery = Object.create(qb.baseQuery);
998
+ baseQuery.baseQuery = baseQuery;
999
+ baseQuery.table = joinTable;
1000
+ const shape = {};
1001
+ const primaryKeysShape = {};
1002
+ for (let i = 0; i < len; i++) {
1003
+ const pk = primaryKeys[i];
1004
+ shape[foreignKeys[i]] = removeColumnName(table.shape[pk]);
1005
+ primaryKeysShape[pk] = table.shape[pk];
1006
+ }
1007
+ for (let i = 0; i < throughLen; i++) shape[throughForeignKeys[i]] = removeColumnName(query.shape[throughPrimaryKeys[i]]);
1008
+ baseQuery.shape = shape;
1009
+ baseQuery.q = {
1010
+ ...baseQuery.q,
1011
+ schema: options.through.schema || schema,
1012
+ shape: baseQuery.shape
1013
+ };
1014
+ const subQuery = Object.create(baseQuery);
1015
+ addAutoForeignKey(tableConfig, subQuery, table, primaryKeys, foreignKeys, relation.options, originalForeignKeys);
1016
+ addAutoForeignKey(tableConfig, subQuery, query, throughPrimaryKeys, throughForeignKeys, relation.options.through, originalThroughForeignKeys);
1017
+ const state = {
1018
+ relatedTableQuery: query,
1019
+ joinTableQuery: subQuery,
1020
+ primaryKeys,
1021
+ foreignKeys,
1022
+ throughForeignKeys,
1023
+ throughPrimaryKeys,
1024
+ foreignKeysFull,
1025
+ throughForeignKeysFull,
1026
+ throughPrimaryKeysFull,
1027
+ primaryKeysShape,
1028
+ on
1029
+ };
1030
+ const joinQuery = (joiningQuery, tableAs, foreignAs, joinedShapes) => {
1031
+ const cloned = joiningQuery.clone();
1032
+ cloned.q.joinedShapes = joinedShapes;
1033
+ return _queryWhereExists(cloned, subQuery, [(q) => {
1034
+ for (let i = 0; i < throughLen; i++) _queryJoinOn(q, [throughForeignKeysFull[i], `${foreignAs}.${throughPrimaryKeys[i]}`]);
1035
+ for (let i = 0; i < len; i++) _queryJoinOn(q, [foreignKeysFull[i], `${tableAs}.${primaryKeys[i]}`]);
1036
+ return q;
1037
+ }]);
1038
+ };
1039
+ const obj = {};
1040
+ for (let i = 0; i < len; i++) obj[foreignKeys[i]] = primaryKeys[i];
1041
+ const selectPrimaryKeysAsForeignKeys = [{ selectAs: obj }];
1042
+ const reverseJoin = (baseQuery, joiningQuery) => {
1043
+ const foreignAs = getQueryAs(joiningQuery);
1044
+ return joinQuery(baseQuery, getQueryAs(baseQuery), foreignAs, {
1045
+ ...baseQuery.q.joinedShapes,
1046
+ [foreignAs]: joiningQuery.q.shape
1047
+ });
1048
+ };
1049
+ return {
1050
+ returns: "many",
1051
+ queryRelated(params) {
1052
+ const q = query.whereExists(subQuery, (q) => {
1053
+ q = q.clone();
1054
+ const where = {};
1055
+ for (let i = 0; i < len; i++) where[foreignKeysFull[i]] = params[primaryKeys[i]];
1056
+ for (let i = 0; i < throughLen; i++) _queryJoinOn(q, [throughForeignKeysFull[i], throughPrimaryKeysFull[i]]);
1057
+ return _queryWhere(q, [where]);
1058
+ });
1059
+ return on ? _queryDefaults(q, on) : q;
1060
+ },
1061
+ virtualColumn: new HasAndBelongsToManyVirtualColumn(subQuery, defaultSchemaConfig, relationName, state),
1062
+ joinQuery: joinQueryChainHOF(getPrimaryKeys(query), reverseJoin, (joiningQuery, baseQuery) => joinQuery(joiningQuery, getQueryAs(baseQuery), getQueryAs(joiningQuery), {
1063
+ ...joiningQuery.q.joinedShapes,
1064
+ [baseQuery.q.as || baseQuery.table]: baseQuery.q.shape
1065
+ })),
1066
+ reverseJoin,
1067
+ modifyRelatedQuery(relationQuery) {
1068
+ const ref = {};
1069
+ _queryHookAfterCreate(relationQuery, [], async (result) => {
1070
+ const baseQuery = ref.q.clone();
1071
+ baseQuery.q.select = selectPrimaryKeysAsForeignKeys;
1072
+ const data = result.map((resultRow) => {
1073
+ const dataRow = {};
1074
+ for (let i = 0; i < throughLen; i++) dataRow[throughForeignKeys[i]] = resultRow[throughPrimaryKeys[i]];
1075
+ return dataRow;
1076
+ });
1077
+ if (await _queryCreateManyFrom(subQuery.count(), baseQuery, data) === 0) throw new NotFoundError(baseQuery);
1078
+ });
1079
+ return (q) => {
1080
+ ref.q = q;
1081
+ };
1082
+ }
1083
+ };
1738
1084
  };
1739
1085
  const queryJoinTable = (state, data, conditions) => {
1740
- const t = state.joinTableQuery.where({
1741
- IN: {
1742
- columns: state.foreignKeys,
1743
- values: data.map((item) => state.primaryKeys.map((key) => item[key]))
1744
- }
1745
- });
1746
- if (conditions) {
1747
- _queryWhere(t, [
1748
- {
1749
- IN: {
1750
- columns: state.throughForeignKeys,
1751
- values: _querySelect(
1752
- state.relatedTableQuery.where(conditionsToWhereArg(conditions)),
1753
- state.throughPrimaryKeys
1754
- )
1755
- }
1756
- }
1757
- ]);
1758
- }
1759
- if (state.on) {
1760
- _queryWhereExists(t, state.relatedTableQuery, [
1761
- (q) => {
1762
- for (let i = 0; i < state.throughPrimaryKeys.length; i++) {
1763
- _queryJoinOn(q, [
1764
- state.throughPrimaryKeysFull[i],
1765
- state.throughForeignKeysFull[i]
1766
- ]);
1767
- }
1768
- return q;
1769
- }
1770
- ]);
1771
- }
1772
- return t;
1086
+ const t = state.joinTableQuery.where({ IN: {
1087
+ columns: state.foreignKeys,
1088
+ values: data.map((item) => state.primaryKeys.map((key) => item[key]))
1089
+ } });
1090
+ if (conditions) _queryWhere(t, [{ IN: {
1091
+ columns: state.throughForeignKeys,
1092
+ values: _querySelect(state.relatedTableQuery.where(conditionsToWhereArg(conditions)), state.throughPrimaryKeys)
1093
+ } }]);
1094
+ if (state.on) _queryWhereExists(t, state.relatedTableQuery, [(q) => {
1095
+ for (let i = 0; i < state.throughPrimaryKeys.length; i++) _queryJoinOn(q, [state.throughPrimaryKeysFull[i], state.throughForeignKeysFull[i]]);
1096
+ return q;
1097
+ }]);
1098
+ return t;
1773
1099
  };
1774
1100
  const conditionsToWhereArg = (conditions) => Array.isArray(conditions) ? { OR: conditions } : conditions;
1775
1101
  const insertToJoinTable = (state, joinTableTransaction, data, idsRows) => {
1776
- const len = state.primaryKeys.length;
1777
- const throughLen = state.throughPrimaryKeys.length;
1778
- const records = [];
1779
- for (const item of data) {
1780
- const obj = {};
1781
- for (let i = 0; i < len; i++) {
1782
- obj[state.foreignKeys[i]] = item[state.primaryKeys[i]];
1783
- }
1784
- for (const ids of idsRows) {
1785
- const record = { ...obj };
1786
- for (let i = 0; i < throughLen; i++) {
1787
- record[state.throughForeignKeys[i]] = ids[i];
1788
- }
1789
- records.push(record);
1790
- }
1791
- }
1792
- return joinTableTransaction.insertMany(records);
1102
+ const len = state.primaryKeys.length;
1103
+ const throughLen = state.throughPrimaryKeys.length;
1104
+ const records = [];
1105
+ for (const item of data) {
1106
+ const obj = {};
1107
+ for (let i = 0; i < len; i++) obj[state.foreignKeys[i]] = item[state.primaryKeys[i]];
1108
+ for (const ids of idsRows) {
1109
+ const record = { ...obj };
1110
+ for (let i = 0; i < throughLen; i++) record[state.throughForeignKeys[i]] = ids[i];
1111
+ records.push(record);
1112
+ }
1113
+ }
1114
+ return joinTableTransaction.insertMany(records);
1793
1115
  };
1794
- const nestedInsert = ({
1795
- relatedTableQuery,
1796
- joinTableQuery,
1797
- primaryKeys,
1798
- foreignKeys,
1799
- throughPrimaryKeys,
1800
- throughForeignKeys
1801
- }) => {
1802
- const len = primaryKeys.length;
1803
- const throughLen = primaryKeys.length;
1804
- return async (_, data) => {
1805
- const t = relatedTableQuery.clone();
1806
- const items = [];
1807
- for (const item of data) {
1808
- if (item[1].connect) {
1809
- items.push(item);
1810
- }
1811
- }
1812
- let connected;
1813
- if (items.length) {
1814
- const queries = [];
1815
- for (const [, { connect }] of items) {
1816
- for (const item of connect) {
1817
- queries.push(
1818
- _queryFindBy(
1819
- t.select(...throughPrimaryKeys),
1820
- item
1821
- )
1822
- );
1823
- }
1824
- }
1825
- connected = await Promise.all(queries);
1826
- } else {
1827
- connected = [];
1828
- }
1829
- items.length = 0;
1830
- for (const item of data) {
1831
- if (item[1].connectOrCreate) {
1832
- items.push(item);
1833
- }
1834
- }
1835
- let connectOrCreated;
1836
- if (items.length) {
1837
- const queries = [];
1838
- for (const [, { connectOrCreate }] of items) {
1839
- for (const item of connectOrCreate) {
1840
- queries.push(
1841
- _queryFindByOptional(
1842
- t.select(...throughPrimaryKeys),
1843
- item.where
1844
- )
1845
- );
1846
- }
1847
- }
1848
- connectOrCreated = await Promise.all(queries);
1849
- } else {
1850
- connectOrCreated = [];
1851
- }
1852
- let connectOrCreateI = 0;
1853
- items.length = 0;
1854
- for (const item of data) {
1855
- if (item[1].connectOrCreate) {
1856
- const length = item[1].connectOrCreate.length;
1857
- connectOrCreateI += length;
1858
- for (let i = length; i > 0; i--) {
1859
- if (!connectOrCreated[connectOrCreateI - i]) {
1860
- items.push(item);
1861
- break;
1862
- }
1863
- }
1864
- } else if (item[1].create) {
1865
- items.push(item);
1866
- }
1867
- }
1868
- connectOrCreateI = 0;
1869
- let created;
1870
- if (items.length) {
1871
- const records2 = [];
1872
- for (const [, { create, connectOrCreate }] of items) {
1873
- if (create) {
1874
- records2.push(...create);
1875
- }
1876
- if (connectOrCreate) {
1877
- for (const item of connectOrCreate) {
1878
- if (!connectOrCreated[connectOrCreateI++]) {
1879
- records2.push(item.create);
1880
- }
1881
- }
1882
- }
1883
- }
1884
- created = await _queryCreateMany(
1885
- t.select(...throughPrimaryKeys),
1886
- records2
1887
- );
1888
- } else {
1889
- created = [];
1890
- }
1891
- const allKeys = data;
1892
- let createI = 0;
1893
- let connectI = 0;
1894
- connectOrCreateI = 0;
1895
- for (let index = 0, len2 = data.length; index < len2; index++) {
1896
- const item = data[index][1];
1897
- if (item.create || item.connectOrCreate) {
1898
- if (item.create) {
1899
- const len3 = item.create.length;
1900
- allKeys[index][1] = created.slice(createI, createI + len3);
1901
- createI += len3;
1902
- }
1903
- if (item.connectOrCreate) {
1904
- const arr = [];
1905
- allKeys[index][1] = arr;
1906
- const len3 = item.connectOrCreate.length;
1907
- for (let i = 0; i < len3; i++) {
1908
- const item2 = connectOrCreated[connectOrCreateI++];
1909
- if (item2) {
1910
- arr.push(item2);
1911
- } else {
1912
- arr.push(created[createI++]);
1913
- }
1914
- }
1915
- }
1916
- }
1917
- if (item.connect) {
1918
- const len3 = item.connect.length;
1919
- allKeys[index][1] = connected.slice(connectI, connectI + len3);
1920
- connectI += len3;
1921
- }
1922
- }
1923
- const records = [];
1924
- for (const [selfData, relationKeys] of allKeys) {
1925
- const obj = {};
1926
- for (let i = 0; i < len; i++) {
1927
- obj[foreignKeys[i]] = selfData[primaryKeys[i]];
1928
- }
1929
- for (const relationData of relationKeys) {
1930
- const record = { ...obj };
1931
- for (let i = 0; i < throughLen; i++) {
1932
- record[throughForeignKeys[i]] = relationData[throughPrimaryKeys[i]];
1933
- }
1934
- records.push(record);
1935
- }
1936
- }
1937
- await joinTableQuery.insertMany(records);
1938
- };
1116
+ const nestedInsert = ({ relatedTableQuery, joinTableQuery, primaryKeys, foreignKeys, throughPrimaryKeys, throughForeignKeys }) => {
1117
+ const len = primaryKeys.length;
1118
+ const throughLen = primaryKeys.length;
1119
+ return (async (_, data) => {
1120
+ const t = relatedTableQuery.clone();
1121
+ const items = [];
1122
+ for (const item of data) if (item[1].connect) items.push(item);
1123
+ let connected;
1124
+ if (items.length) {
1125
+ const queries = [];
1126
+ for (const [, { connect }] of items) for (const item of connect) queries.push(_queryFindBy(t.select(...throughPrimaryKeys), item));
1127
+ connected = await Promise.all(queries);
1128
+ } else connected = [];
1129
+ items.length = 0;
1130
+ for (const item of data) if (item[1].connectOrCreate) items.push(item);
1131
+ let connectOrCreated;
1132
+ if (items.length) {
1133
+ const queries = [];
1134
+ for (const [, { connectOrCreate }] of items) for (const item of connectOrCreate) queries.push(_queryFindByOptional(t.select(...throughPrimaryKeys), item.where));
1135
+ connectOrCreated = await Promise.all(queries);
1136
+ } else connectOrCreated = [];
1137
+ let connectOrCreateI = 0;
1138
+ items.length = 0;
1139
+ for (const item of data) if (item[1].connectOrCreate) {
1140
+ const length = item[1].connectOrCreate.length;
1141
+ connectOrCreateI += length;
1142
+ for (let i = length; i > 0; i--) if (!connectOrCreated[connectOrCreateI - i]) {
1143
+ items.push(item);
1144
+ break;
1145
+ }
1146
+ } else if (item[1].create) items.push(item);
1147
+ connectOrCreateI = 0;
1148
+ let created;
1149
+ if (items.length) {
1150
+ const records = [];
1151
+ for (const [, { create, connectOrCreate }] of items) {
1152
+ if (create) records.push(...create);
1153
+ if (connectOrCreate) {
1154
+ for (const item of connectOrCreate) if (!connectOrCreated[connectOrCreateI++]) records.push(item.create);
1155
+ }
1156
+ }
1157
+ created = await _queryCreateMany(t.select(...throughPrimaryKeys), records);
1158
+ } else created = [];
1159
+ const allKeys = data;
1160
+ let createI = 0;
1161
+ let connectI = 0;
1162
+ connectOrCreateI = 0;
1163
+ for (let index = 0, len = data.length; index < len; index++) {
1164
+ const item = data[index][1];
1165
+ if (item.create || item.connectOrCreate) {
1166
+ if (item.create) {
1167
+ const len = item.create.length;
1168
+ allKeys[index][1] = created.slice(createI, createI + len);
1169
+ createI += len;
1170
+ }
1171
+ if (item.connectOrCreate) {
1172
+ const arr = [];
1173
+ allKeys[index][1] = arr;
1174
+ const len = item.connectOrCreate.length;
1175
+ for (let i = 0; i < len; i++) {
1176
+ const item = connectOrCreated[connectOrCreateI++];
1177
+ if (item) arr.push(item);
1178
+ else arr.push(created[createI++]);
1179
+ }
1180
+ }
1181
+ }
1182
+ if (item.connect) {
1183
+ const len = item.connect.length;
1184
+ allKeys[index][1] = connected.slice(connectI, connectI + len);
1185
+ connectI += len;
1186
+ }
1187
+ }
1188
+ const records = [];
1189
+ for (const [selfData, relationKeys] of allKeys) {
1190
+ const obj = {};
1191
+ for (let i = 0; i < len; i++) obj[foreignKeys[i]] = selfData[primaryKeys[i]];
1192
+ for (const relationData of relationKeys) {
1193
+ const record = { ...obj };
1194
+ for (let i = 0; i < throughLen; i++) record[throughForeignKeys[i]] = relationData[throughPrimaryKeys[i]];
1195
+ records.push(record);
1196
+ }
1197
+ }
1198
+ await joinTableQuery.insertMany(records);
1199
+ });
1939
1200
  };
1940
1201
  const nestedUpdate = (state) => {
1941
- const len = state.primaryKeys.length;
1942
- const throughLen = state.throughPrimaryKeys.length;
1943
- return async (query, data, params) => {
1944
- if (params.create) {
1945
- const idsRows = await _queryCreateMany(
1946
- _queryRows(state.relatedTableQuery.select(...state.throughPrimaryKeys)),
1947
- params.create
1948
- );
1949
- const records = [];
1950
- for (const item of data) {
1951
- const obj = {};
1952
- for (let i = 0; i < len; i++) {
1953
- obj[state.foreignKeys[i]] = item[state.primaryKeys[i]];
1954
- }
1955
- for (const ids of idsRows) {
1956
- const record = { ...obj };
1957
- for (let i = 0; i < throughLen; i++) {
1958
- record[state.throughForeignKeys[i]] = ids[i];
1959
- }
1960
- records.push(record);
1961
- }
1962
- }
1963
- await state.joinTableQuery.createMany(records);
1964
- }
1965
- if (params.update) {
1966
- await _queryUpdate(
1967
- _queryWhere(
1968
- state.relatedTableQuery.whereExists(state.joinTableQuery, (q) => {
1969
- for (let i = 0; i < throughLen; i++) {
1970
- _queryJoinOn(q, [
1971
- state.throughForeignKeysFull[i],
1972
- state.throughPrimaryKeysFull[i]
1973
- ]);
1974
- }
1975
- return _queryWhere(q, [
1976
- {
1977
- IN: {
1978
- columns: state.foreignKeysFull,
1979
- values: data.map(
1980
- (item) => state.primaryKeys.map((key) => item[key])
1981
- )
1982
- }
1983
- }
1984
- ]);
1985
- }),
1986
- [conditionsToWhereArg(params.update.where)]
1987
- ),
1988
- params.update.data
1989
- );
1990
- }
1991
- if (params.add) {
1992
- const as = query.table;
1993
- const relatedWheres = toArray(params.add);
1994
- const joinTableColumns = [
1995
- ...state.foreignKeys,
1996
- ...state.throughForeignKeys
1997
- ];
1998
- try {
1999
- const count = await state.joinTableQuery.insertForEachFrom(
2000
- _querySelect(
2001
- state.relatedTableQuery.whereOneOf(...relatedWheres),
2002
- [
2003
- Object.fromEntries([
2004
- ...state.primaryKeys.map((key, i) => [
2005
- state.foreignKeys[i],
2006
- as + "." + (state.primaryKeysShape[key].data.name || key)
2007
- ]),
2008
- ...state.throughForeignKeys.map((key, i) => [
2009
- key,
2010
- state.throughPrimaryKeys[i]
2011
- ])
2012
- ])
2013
- ]
2014
- ).joinData(
2015
- as,
2016
- () => Object.fromEntries(
2017
- state.primaryKeys.map((key) => [
2018
- key,
2019
- state.primaryKeysShape[key]
2020
- ])
2021
- ),
2022
- data.map((x) => pick(x, state.primaryKeys))
2023
- )
2024
- ).onConflict(joinTableColumns).merge([state.foreignKeys[0]]);
2025
- if (count < data.length * relatedWheres.length) {
2026
- throw new OrchidOrmInternalError(
2027
- query,
2028
- `Expected to find at least ${relatedWheres.length} record(s) based on \`add\` conditions, but found ${count / data.length}`
2029
- );
2030
- }
2031
- } catch (err) {
2032
- if (err.code === "42P10") {
2033
- throw new OrchidOrmInternalError(
2034
- query,
2035
- `"${state.joinTableQuery.table}" must have a primary key or a unique index on columns (${joinTableColumns.join(
2036
- ", "
2037
- )}) for this kind of query.`
2038
- );
2039
- }
2040
- throw err;
2041
- }
2042
- }
2043
- if (params.disconnect) {
2044
- await _queryDelete(
2045
- queryJoinTable(state, data, params.disconnect)
2046
- );
2047
- }
2048
- if (params.delete) {
2049
- const j = queryJoinTable(state, data, params.delete);
2050
- const idsRows = await _queryDelete(
2051
- _queryRows(_querySelect(j, state.throughForeignKeys))
2052
- );
2053
- await _queryDelete(
2054
- state.relatedTableQuery.where({
2055
- IN: {
2056
- columns: state.throughPrimaryKeys,
2057
- values: idsRows
2058
- }
2059
- })
2060
- );
2061
- }
2062
- if (params.set) {
2063
- const j = queryJoinTable(state, data);
2064
- await _queryDelete(j);
2065
- if (Array.isArray(params.set) ? params.set.length : objectHasValues(params.set)) {
2066
- const idsRows = await _queryRows(
2067
- _querySelect(
2068
- state.relatedTableQuery.where(
2069
- conditionsToWhereArg(params.set)
2070
- ),
2071
- state.throughPrimaryKeys
2072
- )
2073
- );
2074
- await insertToJoinTable(state, j, data, idsRows);
2075
- }
2076
- }
2077
- };
1202
+ const len = state.primaryKeys.length;
1203
+ const throughLen = state.throughPrimaryKeys.length;
1204
+ return (async (query, data, params) => {
1205
+ if (params.create) {
1206
+ const idsRows = await _queryCreateMany(_queryRows(state.relatedTableQuery.select(...state.throughPrimaryKeys)), params.create);
1207
+ const records = [];
1208
+ for (const item of data) {
1209
+ const obj = {};
1210
+ for (let i = 0; i < len; i++) obj[state.foreignKeys[i]] = item[state.primaryKeys[i]];
1211
+ for (const ids of idsRows) {
1212
+ const record = { ...obj };
1213
+ for (let i = 0; i < throughLen; i++) record[state.throughForeignKeys[i]] = ids[i];
1214
+ records.push(record);
1215
+ }
1216
+ }
1217
+ await state.joinTableQuery.createMany(records);
1218
+ }
1219
+ if (params.update) await _queryUpdate(_queryWhere(state.relatedTableQuery.whereExists(state.joinTableQuery, (q) => {
1220
+ for (let i = 0; i < throughLen; i++) _queryJoinOn(q, [state.throughForeignKeysFull[i], state.throughPrimaryKeysFull[i]]);
1221
+ return _queryWhere(q, [{ IN: {
1222
+ columns: state.foreignKeysFull,
1223
+ values: data.map((item) => state.primaryKeys.map((key) => item[key]))
1224
+ } }]);
1225
+ }), [conditionsToWhereArg(params.update.where)]), params.update.data);
1226
+ /**
1227
+ * Performs `insertForEachFrom` on the joining table,
1228
+ * based on a query to the related table with applied filters of `params.connect`,
1229
+ * joins the main table data using `joinData`.
1230
+ */
1231
+ if (params.add) {
1232
+ const as = query.table;
1233
+ const relatedWheres = toArray(params.add);
1234
+ const joinTableColumns = [...state.foreignKeys, ...state.throughForeignKeys];
1235
+ try {
1236
+ const count = await state.joinTableQuery.insertForEachFrom(_querySelect(state.relatedTableQuery.whereOneOf(...relatedWheres), [Object.fromEntries([...state.primaryKeys.map((key, i) => [state.foreignKeys[i], as + "." + (state.primaryKeysShape[key].data.name || key)]), ...state.throughForeignKeys.map((key, i) => [key, state.throughPrimaryKeys[i]])])]).joinData(as, () => Object.fromEntries(state.primaryKeys.map((key) => [key, state.primaryKeysShape[key]])), data.map((x) => pick(x, state.primaryKeys)))).onConflict(joinTableColumns).merge([state.foreignKeys[0]]);
1237
+ if (count < data.length * relatedWheres.length) throw new OrchidOrmInternalError(query, `Expected to find at least ${relatedWheres.length} record(s) based on \`add\` conditions, but found ${count / data.length}`);
1238
+ } catch (err) {
1239
+ if (err.code === "42P10") throw new OrchidOrmInternalError(query, `"${state.joinTableQuery.table}" must have a primary key or a unique index on columns (${joinTableColumns.join(", ")}) for this kind of query.`);
1240
+ throw err;
1241
+ }
1242
+ }
1243
+ if (params.disconnect) await _queryDelete(queryJoinTable(state, data, params.disconnect));
1244
+ if (params.delete) {
1245
+ const idsRows = await _queryDelete(_queryRows(_querySelect(queryJoinTable(state, data, params.delete), state.throughForeignKeys)));
1246
+ await _queryDelete(state.relatedTableQuery.where({ IN: {
1247
+ columns: state.throughPrimaryKeys,
1248
+ values: idsRows
1249
+ } }));
1250
+ }
1251
+ if (params.set) {
1252
+ const j = queryJoinTable(state, data);
1253
+ await _queryDelete(j);
1254
+ if (Array.isArray(params.set) ? params.set.length : objectHasValues(params.set)) await insertToJoinTable(state, j, data, await _queryRows(_querySelect(state.relatedTableQuery.where(conditionsToWhereArg(params.set)), state.throughPrimaryKeys)));
1255
+ }
1256
+ });
2078
1257
  };
2079
-
2080
1258
  const applyRelations = (qb, tables, result, schema) => {
2081
- const tableEntries = Object.entries(tables);
2082
- const delayedRelations = /* @__PURE__ */ new Map();
2083
- for (const name in tables) {
2084
- const table = tables[name];
2085
- if (!("relations" in table) || typeof table.relations !== "object")
2086
- continue;
2087
- const dbTable = result[name];
2088
- for (const relationName in table.relations) {
2089
- const relation = table.relations[relationName];
2090
- const otherTableClass = relation.fn();
2091
- const otherTable = tableEntries.find(
2092
- (pair) => pair[1] instanceof otherTableClass
2093
- );
2094
- if (!otherTable) {
2095
- throw new Error(
2096
- `Cannot find table class for class ${otherTableClass.name}`
2097
- );
2098
- }
2099
- const otherTableName = otherTable[0];
2100
- const otherDbTable = result[otherTableName];
2101
- if (!otherDbTable)
2102
- throw new Error(`Cannot find table class by name ${otherTableName}`);
2103
- const data = {
2104
- relationName,
2105
- relation,
2106
- dbTable,
2107
- otherDbTable
2108
- };
2109
- const options = relation.options;
2110
- if (typeof options.through === "string" && typeof options.source === "string") {
2111
- const throughRelation = getThroughRelation(dbTable, options.through);
2112
- if (!throughRelation) {
2113
- delayRelation(delayedRelations, dbTable, options.through, data);
2114
- continue;
2115
- }
2116
- const sourceRelation = getSourceRelation(
2117
- throughRelation,
2118
- options.source
2119
- );
2120
- if (!sourceRelation) {
2121
- delayRelation(
2122
- delayedRelations,
2123
- throughRelation.table,
2124
- options.source,
2125
- data
2126
- );
2127
- continue;
2128
- }
2129
- }
2130
- applyRelation(table, qb, data, delayedRelations, schema);
2131
- }
2132
- }
2133
- if (delayedRelations.size) {
2134
- const { value } = delayedRelations.values().next();
2135
- for (const key in value) {
2136
- for (const item of value[key]) {
2137
- const { relation } = item;
2138
- if (item.dbTable.relations[item.relationName]) continue;
2139
- const as = item.dbTable.definedAs;
2140
- let message = `Cannot define a \`${item.relationName}\` relation on \`${as}\``;
2141
- const table = result[as];
2142
- const { through, source } = relation.options;
2143
- const throughRel = table.relations[through];
2144
- if (through && !throughRel) {
2145
- message += `: cannot find \`${through}\` relation required by the \`through\` option`;
2146
- } else if (source && throughRel && !throughRel.table.relations[source]) {
2147
- message += `: cannot find \`${source}\` relation in \`${throughRel.table.definedAs}\` required by the \`source\` option`;
2148
- }
2149
- throw new Error(message);
2150
- }
2151
- }
2152
- }
1259
+ const tableEntries = Object.entries(tables);
1260
+ const delayedRelations = /* @__PURE__ */ new Map();
1261
+ for (const name in tables) {
1262
+ const table = tables[name];
1263
+ if (!("relations" in table) || typeof table.relations !== "object") continue;
1264
+ const dbTable = result[name];
1265
+ for (const relationName in table.relations) {
1266
+ const relation = table.relations[relationName];
1267
+ const otherTableClass = relation.fn();
1268
+ const otherTable = tableEntries.find((pair) => pair[1] instanceof otherTableClass);
1269
+ if (!otherTable) throw new Error(`Cannot find table class for class ${otherTableClass.name}`);
1270
+ const otherTableName = otherTable[0];
1271
+ const otherDbTable = result[otherTableName];
1272
+ if (!otherDbTable) throw new Error(`Cannot find table class by name ${otherTableName}`);
1273
+ const data = {
1274
+ relationName,
1275
+ relation,
1276
+ dbTable,
1277
+ otherDbTable
1278
+ };
1279
+ const options = relation.options;
1280
+ if (typeof options.through === "string" && typeof options.source === "string") {
1281
+ const throughRelation = getThroughRelation(dbTable, options.through);
1282
+ if (!throughRelation) {
1283
+ delayRelation(delayedRelations, dbTable, options.through, data);
1284
+ continue;
1285
+ }
1286
+ if (!getSourceRelation(throughRelation, options.source)) {
1287
+ delayRelation(delayedRelations, throughRelation.table, options.source, data);
1288
+ continue;
1289
+ }
1290
+ }
1291
+ applyRelation(table, qb, data, delayedRelations, schema);
1292
+ }
1293
+ }
1294
+ if (delayedRelations.size) {
1295
+ const { value } = delayedRelations.values().next();
1296
+ for (const key in value) for (const item of value[key]) {
1297
+ const { relation } = item;
1298
+ if (item.dbTable.relations[item.relationName]) continue;
1299
+ const as = item.dbTable.definedAs;
1300
+ let message = `Cannot define a \`${item.relationName}\` relation on \`${as}\``;
1301
+ const table = result[as];
1302
+ const { through, source } = relation.options;
1303
+ const throughRel = table.relations[through];
1304
+ if (through && !throughRel) message += `: cannot find \`${through}\` relation required by the \`through\` option`;
1305
+ else if (source && throughRel && !throughRel.table.relations[source]) message += `: cannot find \`${source}\` relation in \`${throughRel.table.definedAs}\` required by the \`source\` option`;
1306
+ throw new Error(message);
1307
+ }
1308
+ }
2153
1309
  };
2154
1310
  const delayRelation = (delayedRelations, table, relationName, data) => {
2155
- let tableRelations = delayedRelations.get(table);
2156
- if (!tableRelations) {
2157
- tableRelations = {};
2158
- delayedRelations.set(table, tableRelations);
2159
- }
2160
- if (tableRelations[relationName]) {
2161
- tableRelations[relationName].push(data);
2162
- } else {
2163
- tableRelations[relationName] = [data];
2164
- }
1311
+ let tableRelations = delayedRelations.get(table);
1312
+ if (!tableRelations) {
1313
+ tableRelations = {};
1314
+ delayedRelations.set(table, tableRelations);
1315
+ }
1316
+ if (tableRelations[relationName]) tableRelations[relationName].push(data);
1317
+ else tableRelations[relationName] = [data];
2165
1318
  };
2166
1319
  const applyRelation = (table, qb, { relationName, relation, dbTable, otherDbTable }, delayedRelations, schema) => {
2167
- const baseQuery = Object.create(otherDbTable);
2168
- baseQuery.baseQuery = baseQuery;
2169
- const query = baseQuery.as(relationName);
2170
- const definedAs = query.definedAs;
2171
- if (!definedAs) {
2172
- throw new Error(
2173
- `Table class for table ${query.table} is not attached to db instance`
2174
- );
2175
- }
2176
- const { type } = relation;
2177
- let data;
2178
- if (type === "belongsTo") {
2179
- data = makeBelongsToMethod(table, dbTable, relation, relationName, query);
2180
- } else if (type === "hasOne") {
2181
- data = makeHasOneMethod(table, dbTable, relation, relationName, query);
2182
- } else if (type === "hasMany") {
2183
- data = makeHasManyMethod(table, dbTable, relation, relationName, query);
2184
- } else if (type === "hasAndBelongsToMany") {
2185
- data = makeHasAndBelongsToManyMethod(
2186
- table,
2187
- dbTable,
2188
- qb,
2189
- relation,
2190
- relationName,
2191
- query,
2192
- schema
2193
- );
2194
- } else {
2195
- throw new Error(`Unknown relation type ${type}`);
2196
- }
2197
- if (data.returns === "one") {
2198
- if (relation.options.required) {
2199
- _queryTake(query);
2200
- } else {
2201
- _queryTakeOptional(query);
2202
- }
2203
- query.q.returnsOne = true;
2204
- }
2205
- if (data.virtualColumn) {
2206
- dbTable.shape[relationName] = dbTable.q.shape[relationName] = data.virtualColumn;
2207
- }
2208
- baseQuery.joinQuery = data.joinQuery;
2209
- const { join: originalJoin } = baseQuery;
2210
- baseQuery.join = function(...args) {
2211
- if (args.length) {
2212
- return originalJoin.apply(this, args);
2213
- } else {
2214
- const q = this.clone();
2215
- q.q.innerJoinLateral = true;
2216
- return q;
2217
- }
2218
- };
2219
- dbTable.relations[relationName] = {
2220
- table: otherDbTable,
2221
- query,
2222
- queryRelated: data.queryRelated,
2223
- joinQuery: data.joinQuery,
2224
- reverseJoin: data.reverseJoin,
2225
- modifyRelatedQuery: data.modifyRelatedQuery
2226
- };
2227
- (dbTable.relationQueries ?? (dbTable.relationQueries = {}))[relationName] = query;
2228
- const tableRelations = delayedRelations.get(dbTable);
2229
- if (!tableRelations) return;
2230
- tableRelations[relationName]?.forEach((data2) => {
2231
- applyRelation(table, qb, data2, delayedRelations, schema);
2232
- });
1320
+ const baseQuery = Object.create(otherDbTable);
1321
+ baseQuery.baseQuery = baseQuery;
1322
+ const query = baseQuery.as(relationName);
1323
+ if (!query.definedAs) throw new Error(`Table class for table ${query.table} is not attached to db instance`);
1324
+ const { type } = relation;
1325
+ let data;
1326
+ if (type === "belongsTo") data = makeBelongsToMethod(table, dbTable, relation, relationName, query);
1327
+ else if (type === "hasOne") data = makeHasOneMethod(table, dbTable, relation, relationName, query);
1328
+ else if (type === "hasMany") data = makeHasManyMethod(table, dbTable, relation, relationName, query);
1329
+ else if (type === "hasAndBelongsToMany") data = makeHasAndBelongsToManyMethod(table, dbTable, qb, relation, relationName, query, schema);
1330
+ else throw new Error(`Unknown relation type ${type}`);
1331
+ if (data.returns === "one") {
1332
+ if (relation.options.required) _queryTake(query);
1333
+ else _queryTakeOptional(query);
1334
+ query.q.returnsOne = true;
1335
+ }
1336
+ if (data.virtualColumn) dbTable.shape[relationName] = dbTable.q.shape[relationName] = data.virtualColumn;
1337
+ baseQuery.joinQuery = data.joinQuery;
1338
+ const { join: originalJoin } = baseQuery;
1339
+ baseQuery.join = function(...args) {
1340
+ if (args.length) return originalJoin.apply(this, args);
1341
+ else {
1342
+ const q = this.clone();
1343
+ q.q.innerJoinLateral = true;
1344
+ return q;
1345
+ }
1346
+ };
1347
+ dbTable.relations[relationName] = {
1348
+ table: otherDbTable,
1349
+ query,
1350
+ queryRelated: data.queryRelated,
1351
+ joinQuery: data.joinQuery,
1352
+ reverseJoin: data.reverseJoin,
1353
+ modifyRelatedQuery: data.modifyRelatedQuery
1354
+ };
1355
+ (dbTable.relationQueries ??= {})[relationName] = query;
1356
+ const tableRelations = delayedRelations.get(dbTable);
1357
+ if (!tableRelations) return;
1358
+ tableRelations[relationName]?.forEach((data) => {
1359
+ applyRelation(table, qb, data, delayedRelations, schema);
1360
+ });
2233
1361
  };
2234
-
2235
1362
  function transaction(fnOrOptions, fn) {
2236
- return this.$qb.transaction(
2237
- fnOrOptions,
2238
- fn
2239
- );
1363
+ return this.$qb.transaction(fnOrOptions, fn);
2240
1364
  }
2241
1365
  function ensureTransaction(cb) {
2242
- return this.$qb.ensureTransaction(cb);
1366
+ return this.$qb.ensureTransaction(cb);
2243
1367
  }
2244
1368
  function isInTransaction() {
2245
- return this.$qb.isInTransaction();
1369
+ return this.$qb.isInTransaction();
2246
1370
  }
2247
1371
  function afterCommit(hook) {
2248
- this.$qb.afterCommit(hook);
1372
+ this.$qb.afterCommit(hook);
2249
1373
  }
2250
-
2251
- const orchidORMWithAdapter = ({
2252
- log,
2253
- logger,
2254
- autoPreparedStatements,
2255
- noPrimaryKey = "error",
2256
- schema,
2257
- ...options
2258
- }, tables) => {
2259
- const commonOptions = {
2260
- log,
2261
- logger,
2262
- autoPreparedStatements,
2263
- noPrimaryKey
2264
- };
2265
- let adapter;
2266
- let asyncStorage;
2267
- let qb;
2268
- if ("db" in options) {
2269
- adapter = options.db.q.adapter;
2270
- asyncStorage = options.db.internal.asyncStorage;
2271
- qb = options.db.qb;
2272
- } else {
2273
- adapter = options.adapter;
2274
- asyncStorage = new AsyncLocalStorage();
2275
- qb = _initQueryBuilder(
2276
- adapter,
2277
- makeColumnTypes(defaultSchemaConfig),
2278
- asyncStorage,
2279
- commonOptions,
2280
- options
2281
- );
2282
- }
2283
- const result = {
2284
- $transaction: transaction,
2285
- $ensureTransaction: ensureTransaction,
2286
- $isInTransaction: isInTransaction,
2287
- $afterCommit: afterCommit,
2288
- $adapterNotInTransaction: adapter,
2289
- $getAdapter,
2290
- $qb: qb,
2291
- get $query() {
2292
- return qb.query;
2293
- },
2294
- $queryArrays: (...args) => qb.queryArrays(...args),
2295
- $with: qb.with.bind(qb),
2296
- $withRecursive: qb.withRecursive.bind(qb),
2297
- $withSql: qb.withSql.bind(qb),
2298
- $from: qb.from.bind(qb),
2299
- $close: adapter.close.bind(adapter),
2300
- $withOptions: qb.withOptions.bind(qb)
2301
- };
2302
- const tableInstances = {};
2303
- for (const key in tables) {
2304
- if (key[0] === "$") {
2305
- throw new Error(`Table class name must not start with $`);
2306
- }
2307
- const tableClass = tables[key];
2308
- const table = tableClass.instance();
2309
- tableInstances[key] = table;
2310
- const options2 = {
2311
- ...commonOptions,
2312
- schema: table.schema || schema,
2313
- language: table.language,
2314
- scopes: table.scopes,
2315
- softDelete: table.softDelete,
2316
- snakeCase: table.snakeCase,
2317
- comment: table.comment,
2318
- noPrimaryKey: table.noPrimaryKey ? "ignore" : void 0,
2319
- computed: table.computed,
2320
- nowSQL: tableClass.nowSQL
2321
- };
2322
- const dbTable = new Db(
2323
- adapter,
2324
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2325
- qb,
2326
- table.table,
2327
- table.columns.shape,
2328
- table.types,
2329
- asyncStorage,
2330
- options2,
2331
- table.constructor.prototype.columns?.data ?? {}
2332
- );
2333
- dbTable.definedAs = key;
2334
- dbTable.db = result;
2335
- dbTable.filePath = table.filePath;
2336
- dbTable.name = table.constructor.name;
2337
- result[key] = dbTable;
2338
- }
2339
- applyRelations(qb, tableInstances, result, schema);
2340
- for (const key in tables) {
2341
- const table = tableInstances[key];
2342
- if (table.init) {
2343
- table.init(result);
2344
- Object.assign(result[key].baseQuery.q, table.q);
2345
- }
2346
- }
2347
- return result;
1374
+ const orchidORMWithAdapter = ({ log, logger, autoPreparedStatements, noPrimaryKey = "error", schema, ...options }, tables) => {
1375
+ const commonOptions = {
1376
+ log,
1377
+ logger,
1378
+ autoPreparedStatements,
1379
+ noPrimaryKey
1380
+ };
1381
+ let adapter;
1382
+ let asyncStorage;
1383
+ let qb;
1384
+ if ("db" in options) {
1385
+ adapter = options.db.q.adapter;
1386
+ asyncStorage = options.db.internal.asyncStorage;
1387
+ qb = options.db.qb;
1388
+ } else {
1389
+ adapter = options.adapter;
1390
+ asyncStorage = new AsyncLocalStorage();
1391
+ qb = _initQueryBuilder(adapter, makeColumnTypes(defaultSchemaConfig), asyncStorage, commonOptions, options);
1392
+ }
1393
+ const result = {
1394
+ $transaction: transaction,
1395
+ $ensureTransaction: ensureTransaction,
1396
+ $isInTransaction: isInTransaction,
1397
+ $afterCommit: afterCommit,
1398
+ $adapterNotInTransaction: adapter,
1399
+ $getAdapter,
1400
+ $qb: qb,
1401
+ get $query() {
1402
+ return qb.query;
1403
+ },
1404
+ $queryArrays: ((...args) => qb.queryArrays(...args)),
1405
+ $with: qb.with.bind(qb),
1406
+ $withRecursive: qb.withRecursive.bind(qb),
1407
+ $withSql: qb.withSql.bind(qb),
1408
+ $from: qb.from.bind(qb),
1409
+ $close: adapter.close.bind(adapter),
1410
+ $withOptions: qb.withOptions.bind(qb)
1411
+ };
1412
+ const tableInstances = {};
1413
+ for (const key in tables) {
1414
+ if (key[0] === "$") throw new Error(`Table class name must not start with $`);
1415
+ const tableClass = tables[key];
1416
+ const table = tableClass.instance();
1417
+ tableInstances[key] = table;
1418
+ const options = {
1419
+ ...commonOptions,
1420
+ schema: table.schema || schema,
1421
+ language: table.language,
1422
+ scopes: table.scopes,
1423
+ softDelete: table.softDelete,
1424
+ snakeCase: table.snakeCase,
1425
+ comment: table.comment,
1426
+ noPrimaryKey: table.noPrimaryKey ? "ignore" : void 0,
1427
+ computed: table.computed,
1428
+ nowSQL: tableClass.nowSQL
1429
+ };
1430
+ const dbTable = new Db(adapter, qb, table.table, table.columns.shape, table.types, asyncStorage, options, table.constructor.prototype.columns?.data ?? {});
1431
+ dbTable.definedAs = key;
1432
+ dbTable.db = result;
1433
+ dbTable.filePath = table.filePath;
1434
+ dbTable.name = table.constructor.name;
1435
+ result[key] = dbTable;
1436
+ }
1437
+ applyRelations(qb, tableInstances, result, schema);
1438
+ for (const key in tables) {
1439
+ const table = tableInstances[key];
1440
+ if (table.init) {
1441
+ table.init(result);
1442
+ Object.assign(result[key].baseQuery.q, table.q);
1443
+ }
1444
+ }
1445
+ return result;
2348
1446
  };
2349
1447
  function $getAdapter() {
2350
- return this.$qb.$getAdapter();
1448
+ return this.$qb.$getAdapter();
2351
1449
  }
2352
-
2353
1450
  const createRepo = (table, methods) => {
2354
- const queryMethods = {
2355
- ...methods.queryMethods,
2356
- ...methods.queryOneMethods,
2357
- ...methods.queryWithWhereMethods,
2358
- ...methods.queryOneWithWhereMethods
2359
- };
2360
- const plainMethods = methods.methods;
2361
- const repo = (q2) => {
2362
- const proto = Object.create(q2.baseQuery);
2363
- proto.baseQuery = proto;
2364
- const result = Object.create(proto);
2365
- result.q = getClonedQueryData(q2.q);
2366
- if (plainMethods) {
2367
- Object.assign(proto.baseQuery, plainMethods);
2368
- }
2369
- for (const key in queryMethods) {
2370
- const method = queryMethods[key];
2371
- proto.baseQuery[key] = function(...args) {
2372
- return method(this, ...args);
2373
- };
2374
- }
2375
- return result;
2376
- };
2377
- const q = repo(table);
2378
- return new Proxy(repo, {
2379
- get(_, key) {
2380
- return q[key];
2381
- }
2382
- });
1451
+ const queryMethods = {
1452
+ ...methods.queryMethods,
1453
+ ...methods.queryOneMethods,
1454
+ ...methods.queryWithWhereMethods,
1455
+ ...methods.queryOneWithWhereMethods
1456
+ };
1457
+ const plainMethods = methods.methods;
1458
+ const repo = (q) => {
1459
+ const proto = Object.create(q.baseQuery);
1460
+ proto.baseQuery = proto;
1461
+ const result = Object.create(proto);
1462
+ result.q = getClonedQueryData(q.q);
1463
+ if (plainMethods) Object.assign(proto.baseQuery, plainMethods);
1464
+ for (const key in queryMethods) {
1465
+ const method = queryMethods[key];
1466
+ proto.baseQuery[key] = function(...args) {
1467
+ return method(this, ...args);
1468
+ };
1469
+ }
1470
+ return result;
1471
+ };
1472
+ const q = repo(table);
1473
+ return new Proxy(repo, { get(_, key) {
1474
+ return q[key];
1475
+ } });
2383
1476
  };
2384
-
2385
1477
  export { createBaseTable, createRepo, orchidORMWithAdapter };
2386
- //# sourceMappingURL=index.mjs.map
1478
+
1479
+ //# sourceMappingURL=index.mjs.map