@atscript/db 0.1.146 → 0.1.147
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/agg.cjs +1 -1
- package/dist/agg.d.cts +1 -1
- package/dist/agg.d.mts +1 -1
- package/dist/agg.mjs +1 -1
- package/dist/{aggregate-fns-CfsveE1w.mjs → aggregate-fns-C0BymEqa.mjs} +3 -1
- package/dist/{aggregate-fns-CGBv3E8S.cjs → aggregate-fns-CtsRbZn9.cjs} +8 -0
- package/dist/{buckets-DYFu0eZ8.d.cts → buckets-CjdPipCC.d.cts} +522 -17
- package/dist/{buckets-DRycmhOW.d.mts → buckets-DYopfd2Y.d.mts} +522 -17
- package/dist/{column-diff-e2oHc71_.mjs → column-diff-CO06iQvI.mjs} +862 -115
- package/dist/{column-diff-D_Kyuh0S.cjs → column-diff-Dt7EDJsA.cjs} +872 -113
- package/dist/{column-diff-Q9UmWn5x.d.mts → fk-diff-BtOmL4OW.d.mts} +48 -2
- package/dist/{column-diff-w-Mym_3w.d.cts → fk-diff-DLqwVkKG.d.cts} +48 -2
- package/dist/index.cjs +28 -33
- package/dist/index.d.cts +40 -15
- package/dist/index.d.mts +40 -15
- package/dist/index.mjs +5 -33
- package/dist/{nested-writer-CnOOAehr.mjs → nested-writer-D35UsDBT.mjs} +542 -2
- package/dist/{nested-writer-xfQwxplL.cjs → nested-writer-SqtYJHF0.cjs} +666 -0
- package/dist/plugin.cjs +266 -5
- package/dist/plugin.mjs +267 -6
- package/dist/rel.cjs +2 -2
- package/dist/rel.d.cts +2 -2
- package/dist/rel.d.mts +2 -2
- package/dist/rel.mjs +2 -2
- package/dist/{relation-helpers-B-0NRKat.d.mts → relation-helpers-C2bLtE-t.d.mts} +1 -1
- package/dist/{relation-helpers-BOMm_HUI.d.cts → relation-helpers-DH3LvwLV.d.cts} +1 -1
- package/dist/relation-loader-BFhVuJ-B.cjs +369 -0
- package/dist/relation-loader-C0qE8xgR.mjs +370 -0
- package/dist/shared.cjs +1 -1
- package/dist/shared.d.cts +4 -3
- package/dist/shared.d.mts +4 -3
- package/dist/shared.mjs +1 -1
- package/dist/sync.cjs +10 -6
- package/dist/sync.d.cts +2 -25
- package/dist/sync.d.mts +2 -25
- package/dist/sync.mjs +10 -6
- package/dist/{validation-utils-DOsB4e6G.cjs → validation-utils-Da2GjobR.cjs} +35 -24
- package/dist/{validation-utils-CMR4fe2M.mjs → validation-utils-Dq0uZ7ef.mjs} +35 -24
- package/dist/{validator-Bw6ks9Hy.d.mts → validator-CMnTI6r7.d.cts} +9 -6
- package/dist/{validator-Bw6ks9Hy.d.cts → validator-CMnTI6r7.d.mts} +9 -6
- package/dist/validator.d.cts +1 -1
- package/dist/validator.d.mts +1 -1
- package/package.json +8 -8
- package/dist/relation-loader-CBPY6kM7.cjs +0 -461
- package/dist/relation-loader-D9XuXaMv.mjs +0 -462
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import { I as findFKForRelation, L as findRemoteFK, M as relationStaticFilter, P as compositeKey, R as resolveRelationTargetTable, w as andFilters, z as slicePerGroup } from "./nested-writer-D35UsDBT.mjs";
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __exportAll = (all, no_symbols) => {
|
|
5
|
+
let target = {};
|
|
6
|
+
for (var name in all) __defProp(target, name, {
|
|
7
|
+
get: all[name],
|
|
8
|
+
enumerable: true
|
|
9
|
+
});
|
|
10
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
11
|
+
return target;
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/rel/relation-loader.ts
|
|
15
|
+
var relation_loader_exports = /* @__PURE__ */ __exportAll({
|
|
16
|
+
ensureSelectIncludesFields: () => ensureSelectIncludesFields,
|
|
17
|
+
loadRelationsImpl: () => loadRelationsImpl
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* Loads related data for `$with` relations and attaches them to result rows.
|
|
21
|
+
*/
|
|
22
|
+
async function loadRelationsImpl(rows, withRelations, host) {
|
|
23
|
+
if (rows.length === 0 || withRelations.length === 0) return;
|
|
24
|
+
if (host.adapter.supportsNativeRelations()) return host.adapter.loadRelations(rows, withRelations, host._meta.relations, host._meta.foreignKeys, host._tableResolver);
|
|
25
|
+
if (!host._tableResolver) return;
|
|
26
|
+
const tasks = [];
|
|
27
|
+
for (const withRel of withRelations) {
|
|
28
|
+
const relName = withRel.name;
|
|
29
|
+
if (relName.includes(".")) continue;
|
|
30
|
+
const relation = host._meta.relations.get(relName);
|
|
31
|
+
if (!relation) throw new Error(`Unknown relation "${relName}" in $with. Available relations: ${[...host._meta.relations.keys()].join(", ") || "(none)"}`);
|
|
32
|
+
const targetType = relation.targetType();
|
|
33
|
+
if (!targetType) continue;
|
|
34
|
+
const targetTable = host._tableResolver(targetType);
|
|
35
|
+
if (!targetTable) {
|
|
36
|
+
host.logger.warn(`Could not resolve table for relation "${relName}" — skipping`);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const statics = relationStaticFilter(relation, relName);
|
|
40
|
+
const merged = andFilters(statics.target, withRel.filter);
|
|
41
|
+
const filter = Object.keys(merged).length > 0 ? merged : void 0;
|
|
42
|
+
const flatRel = withRel;
|
|
43
|
+
const controls = { ...withRel.controls || {} };
|
|
44
|
+
if (flatRel.$sort && !controls.$sort) controls.$sort = flatRel.$sort;
|
|
45
|
+
if (flatRel.$limit !== null && flatRel.$limit !== void 0 && (controls.$limit === null || controls.$limit === void 0)) controls.$limit = flatRel.$limit;
|
|
46
|
+
if (flatRel.$skip !== null && flatRel.$skip !== void 0 && (controls.$skip === null || controls.$skip === void 0)) controls.$skip = flatRel.$skip;
|
|
47
|
+
if (flatRel.$select && !controls.$select) controls.$select = flatRel.$select;
|
|
48
|
+
if (flatRel.$with && !controls.$with) controls.$with = flatRel.$with;
|
|
49
|
+
const { $skip, $limit, ...pageless } = controls;
|
|
50
|
+
const skip = asCount($skip) || void 0;
|
|
51
|
+
const limit = asCount($limit);
|
|
52
|
+
const relQuery = {
|
|
53
|
+
filter,
|
|
54
|
+
controls: pageless,
|
|
55
|
+
page: skip === void 0 && limit === void 0 ? void 0 : {
|
|
56
|
+
skip,
|
|
57
|
+
limit
|
|
58
|
+
},
|
|
59
|
+
junctionFilter: statics.junction
|
|
60
|
+
};
|
|
61
|
+
if (relation.direction === "to") tasks.push(loadToRelation(rows, {
|
|
62
|
+
relName,
|
|
63
|
+
relation,
|
|
64
|
+
targetTable,
|
|
65
|
+
relQuery
|
|
66
|
+
}, host));
|
|
67
|
+
else if (relation.direction === "via") tasks.push(loadViaRelation(rows, {
|
|
68
|
+
relName,
|
|
69
|
+
relation,
|
|
70
|
+
targetTable,
|
|
71
|
+
relQuery
|
|
72
|
+
}, host));
|
|
73
|
+
else tasks.push(loadFromRelation(rows, {
|
|
74
|
+
relName,
|
|
75
|
+
relation,
|
|
76
|
+
targetTable,
|
|
77
|
+
relQuery
|
|
78
|
+
}, host));
|
|
79
|
+
}
|
|
80
|
+
await Promise.all(tasks);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Loads a `@db.rel.to` relation (FK is on this table). Single-valued: the
|
|
84
|
+
* relation's `$skip` / `$limit` page each row's (at most one) target row.
|
|
85
|
+
*/
|
|
86
|
+
async function loadToRelation(rows, opts, host) {
|
|
87
|
+
const { relName, relation, targetTable, relQuery } = opts;
|
|
88
|
+
const fkEntry = findFKForRelation(relation, host._meta.foreignKeys);
|
|
89
|
+
if (!fkEntry) return;
|
|
90
|
+
const { localFields, targetFields } = fkEntry;
|
|
91
|
+
const index = indexFirst(await readRelatedByKeys(rows, {
|
|
92
|
+
localFields,
|
|
93
|
+
targetFields,
|
|
94
|
+
targetTable,
|
|
95
|
+
relQuery
|
|
96
|
+
}), targetFields);
|
|
97
|
+
for (const row of rows) row[relName] = index.get(compositeKey(localFields, row)) ?? null;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Loads a `@db.rel.from` relation (FK is on the target table). `$sort`,
|
|
101
|
+
* `$skip` and `$limit` apply to the related rows of each row.
|
|
102
|
+
*/
|
|
103
|
+
async function loadFromRelation(rows, opts, host) {
|
|
104
|
+
const { relName, relation, targetTable, relQuery } = opts;
|
|
105
|
+
const remoteFK = findRemoteFK(targetTable, host.tableName, relation.alias);
|
|
106
|
+
if (!remoteFK) {
|
|
107
|
+
host.logger.warn(`Could not find FK on target table for relation "${relName}"`);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const localFields = remoteFK.targetFields;
|
|
111
|
+
const remoteFields = remoteFK.fields;
|
|
112
|
+
const related = await readRelatedByKeys(rows, {
|
|
113
|
+
localFields,
|
|
114
|
+
targetFields: remoteFields,
|
|
115
|
+
targetTable,
|
|
116
|
+
relQuery
|
|
117
|
+
});
|
|
118
|
+
if (relation.isArray) {
|
|
119
|
+
const groups = groupBy(related, (item) => compositeKey(remoteFields, item));
|
|
120
|
+
for (const row of rows) row[relName] = groups.get(compositeKey(localFields, row)) ?? [];
|
|
121
|
+
} else {
|
|
122
|
+
const index = indexFirst(related, remoteFields);
|
|
123
|
+
for (const row of rows) row[relName] = index.get(compositeKey(localFields, row)) ?? null;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Loads a `@db.rel.via` relation (M:N through a junction table). The target
|
|
128
|
+
* rows are read once for all rows; `$sort` orders, and `$skip` / `$limit`
|
|
129
|
+
* page, the target rows of each row.
|
|
130
|
+
*/
|
|
131
|
+
async function loadViaRelation(rows, opts, host) {
|
|
132
|
+
const { relName, relation, targetTable, relQuery } = opts;
|
|
133
|
+
if (!relation.viaType || !host._tableResolver) return;
|
|
134
|
+
const junctionType = relation.viaType();
|
|
135
|
+
if (!junctionType) return;
|
|
136
|
+
const junctionTable = host._tableResolver(junctionType);
|
|
137
|
+
if (!junctionTable) {
|
|
138
|
+
host.logger.warn(`Could not resolve junction table for via relation "${relName}"`);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const fkToThis = findRemoteFK(junctionTable, host.tableName);
|
|
142
|
+
if (!fkToThis) {
|
|
143
|
+
host.logger.warn(`Could not find FK on junction table pointing to "${host.tableName}" for via relation "${relName}"`);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const targetTableName = resolveRelationTargetTable(relation);
|
|
147
|
+
const fkToTarget = findRemoteFK(junctionTable, targetTableName);
|
|
148
|
+
if (!fkToTarget) {
|
|
149
|
+
host.logger.warn(`Could not find FK on junction table pointing to target "${targetTableName}" for via relation "${relName}"`);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const localPKFields = fkToThis.targetFields;
|
|
153
|
+
const fields = {
|
|
154
|
+
junctionLocalFields: fkToThis.fields,
|
|
155
|
+
junctionTargetFields: fkToTarget.fields,
|
|
156
|
+
targetPKFields: fkToTarget.targetFields
|
|
157
|
+
};
|
|
158
|
+
const parentFilter = matchAnyFilter(rows, localPKFields, fields.junctionLocalFields);
|
|
159
|
+
const junctionRows = parentFilter ? await junctionTable.findMany({
|
|
160
|
+
filter: andFilters(parentFilter, relQuery.junctionFilter),
|
|
161
|
+
controls: { $select: [...fields.junctionLocalFields, ...fields.junctionTargetFields] }
|
|
162
|
+
}) : [];
|
|
163
|
+
const targetFilter = matchAnyFilter(junctionRows, fields.junctionTargetFields, fields.targetPKFields);
|
|
164
|
+
if (!targetFilter) {
|
|
165
|
+
for (const row of rows) row[relName] = relation.isArray ? [] : null;
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const sorted = hasSort(relQuery.controls);
|
|
169
|
+
let groups = /* @__PURE__ */ new Map();
|
|
170
|
+
const pick = (targets) => {
|
|
171
|
+
groups = groupViaTargets(targets, junctionRows, fields, sorted);
|
|
172
|
+
const page = relQuery.page;
|
|
173
|
+
if (!page) return targets;
|
|
174
|
+
const start = page.skip ?? 0;
|
|
175
|
+
const end = page.limit === void 0 ? void 0 : start + page.limit;
|
|
176
|
+
const kept = /* @__PURE__ */ new Set();
|
|
177
|
+
for (const [key, group] of groups) {
|
|
178
|
+
const slice = group.slice(start, end);
|
|
179
|
+
groups.set(key, slice);
|
|
180
|
+
for (const target of slice) kept.add(target);
|
|
181
|
+
}
|
|
182
|
+
return targets.filter((target) => kept.has(target));
|
|
183
|
+
};
|
|
184
|
+
await readRelated(targetTable, {
|
|
185
|
+
filter: relQuery.filter ? { $and: [targetFilter, relQuery.filter] } : targetFilter,
|
|
186
|
+
controls: ensureSelectIncludesFields(relQuery.controls, fields.targetPKFields)
|
|
187
|
+
}, { pick });
|
|
188
|
+
for (const row of rows) {
|
|
189
|
+
const group = groups.get(compositeKey(localPKFields, row));
|
|
190
|
+
row[relName] = relation.isArray ? group ?? [] : group?.[0] ?? null;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Each row's targets (keyed by the junction's local key), once per junction
|
|
195
|
+
* row. The junction rows only map rows to targets: with a `$sort` the targets
|
|
196
|
+
* keep the order the target read returned them in, else junction order.
|
|
197
|
+
*/
|
|
198
|
+
function groupViaTargets(targets, junctionRows, fields, sorted) {
|
|
199
|
+
const groups = /* @__PURE__ */ new Map();
|
|
200
|
+
if (sorted) {
|
|
201
|
+
const linksByTarget = groupBy(junctionRows, (jRow) => compositeKey(fields.junctionTargetFields, jRow));
|
|
202
|
+
for (const target of targets) for (const jRow of linksByTarget.get(compositeKey(fields.targetPKFields, target)) ?? []) appendTo(groups, compositeKey(fields.junctionLocalFields, jRow), target);
|
|
203
|
+
} else {
|
|
204
|
+
const index = indexFirst(targets, fields.targetPKFields);
|
|
205
|
+
for (const jRow of junctionRows) {
|
|
206
|
+
const target = index.get(compositeKey(fields.junctionTargetFields, jRow));
|
|
207
|
+
if (target) appendTo(groups, compositeKey(fields.junctionLocalFields, jRow), target);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return groups;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Reads the target rows whose `targetFields` match `localFields` of any of
|
|
214
|
+
* `rows`, the relation's `$skip` / `$limit` applied per such row.
|
|
215
|
+
*/
|
|
216
|
+
async function readRelatedByKeys(rows, opts) {
|
|
217
|
+
const { localFields, targetFields, targetTable, relQuery } = opts;
|
|
218
|
+
const keyFilter = matchAnyFilter(rows, localFields, targetFields);
|
|
219
|
+
if (!keyFilter) return [];
|
|
220
|
+
return readRelated(targetTable, {
|
|
221
|
+
filter: relQuery.filter ? { $and: [keyFilter, relQuery.filter] } : keyFilter,
|
|
222
|
+
controls: ensureSelectIncludesFields(relQuery.controls, targetFields)
|
|
223
|
+
}, {
|
|
224
|
+
partitionBy: targetFields,
|
|
225
|
+
page: relQuery.page
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Reads related rows. With `partitionBy` and a `page`, the page applies per
|
|
230
|
+
* group of rows sharing the `partitionBy` values; `pick` keeps a subset of
|
|
231
|
+
* the rows before their own (nested) `$with` relations load.
|
|
232
|
+
*/
|
|
233
|
+
async function readRelated(table, query, opts) {
|
|
234
|
+
const { partitionBy, page, pick } = opts;
|
|
235
|
+
const partitioned = partitionBy && page;
|
|
236
|
+
if (table._findManyForRelation) {
|
|
237
|
+
const controls = partitioned ? {
|
|
238
|
+
...query.controls,
|
|
239
|
+
...pageControls(page)
|
|
240
|
+
} : query.controls;
|
|
241
|
+
return table._findManyForRelation({
|
|
242
|
+
filter: query.filter,
|
|
243
|
+
controls
|
|
244
|
+
}, {
|
|
245
|
+
partitionBy: partitioned ? partitionBy : void 0,
|
|
246
|
+
pick
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
let rows = await table.findMany(query);
|
|
250
|
+
if (partitioned) rows = slicePerGroup(rows, (row) => compositeKey(partitionBy, row), page);
|
|
251
|
+
return pick ? pick(rows) : rows;
|
|
252
|
+
}
|
|
253
|
+
/** A `$skip` / `$limit` value as a number (`undefined` when unset or not a number). */
|
|
254
|
+
function asCount(value) {
|
|
255
|
+
if (value === null || value === void 0 || value === "") return;
|
|
256
|
+
const n = Number(value);
|
|
257
|
+
return Number.isFinite(n) ? n : void 0;
|
|
258
|
+
}
|
|
259
|
+
/** `$skip` / `$limit` controls of a page (only the ones set). */
|
|
260
|
+
function pageControls(page) {
|
|
261
|
+
const controls = {};
|
|
262
|
+
if (page.skip !== void 0) controls.$skip = page.skip;
|
|
263
|
+
if (page.limit !== void 0) controls.$limit = page.limit;
|
|
264
|
+
return controls;
|
|
265
|
+
}
|
|
266
|
+
/** Whether `controls` carry a non-empty `$sort`. */
|
|
267
|
+
function hasSort(controls) {
|
|
268
|
+
const sort = controls.$sort;
|
|
269
|
+
return !!sort && typeof sort === "object" && Object.keys(sort).length > 0;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* A filter matching the rows whose `toFields` equal `fromFields` of any of
|
|
273
|
+
* `rows` — `$in` for a single field, `$or` of conditions for a composite key.
|
|
274
|
+
* `undefined` when no row has every `fromFields` value.
|
|
275
|
+
*/
|
|
276
|
+
function matchAnyFilter(rows, fromFields, toFields) {
|
|
277
|
+
if (fromFields.length === 1) {
|
|
278
|
+
const values = /* @__PURE__ */ new Set();
|
|
279
|
+
for (const row of rows) {
|
|
280
|
+
const v = row[fromFields[0]];
|
|
281
|
+
if (v !== null && v !== void 0) values.add(v);
|
|
282
|
+
}
|
|
283
|
+
return values.size > 0 ? { [toFields[0]]: { $in: [...values] } } : void 0;
|
|
284
|
+
}
|
|
285
|
+
const seen = /* @__PURE__ */ new Set();
|
|
286
|
+
const conditions = [];
|
|
287
|
+
for (const row of rows) {
|
|
288
|
+
const key = compositeKey(fromFields, row);
|
|
289
|
+
if (seen.has(key)) continue;
|
|
290
|
+
seen.add(key);
|
|
291
|
+
const condition = {};
|
|
292
|
+
let valid = true;
|
|
293
|
+
for (let i = 0; i < fromFields.length; i++) {
|
|
294
|
+
const v = row[fromFields[i]];
|
|
295
|
+
if (v === null || v === void 0) {
|
|
296
|
+
valid = false;
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
condition[toFields[i]] = v;
|
|
300
|
+
}
|
|
301
|
+
if (valid) conditions.push(condition);
|
|
302
|
+
}
|
|
303
|
+
if (conditions.length === 0) return;
|
|
304
|
+
return conditions.length === 1 ? conditions[0] : { $or: conditions };
|
|
305
|
+
}
|
|
306
|
+
/** The first of `items` per `fields` key. */
|
|
307
|
+
function indexFirst(items, fields) {
|
|
308
|
+
const index = /* @__PURE__ */ new Map();
|
|
309
|
+
for (const item of items) {
|
|
310
|
+
const key = compositeKey(fields, item);
|
|
311
|
+
if (!index.has(key)) index.set(key, item);
|
|
312
|
+
}
|
|
313
|
+
return index;
|
|
314
|
+
}
|
|
315
|
+
/** `items` grouped by `keyOf`, each group in the order of `items`. */
|
|
316
|
+
function groupBy(items, keyOf) {
|
|
317
|
+
const groups = /* @__PURE__ */ new Map();
|
|
318
|
+
for (const item of items) appendTo(groups, keyOf(item), item);
|
|
319
|
+
return groups;
|
|
320
|
+
}
|
|
321
|
+
function appendTo(groups, key, item) {
|
|
322
|
+
const group = groups.get(key);
|
|
323
|
+
if (group) group.push(item);
|
|
324
|
+
else groups.set(key, [item]);
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Ensure the given join fields survive the user's $select on a $with relation
|
|
328
|
+
* read. Without this, the JS-side join would key off undefined and silently
|
|
329
|
+
* return empty relations.
|
|
330
|
+
*
|
|
331
|
+
* - Array $select: append missing FK fields.
|
|
332
|
+
* - Include-mode object $select (any value is 1/true, or empty object): set
|
|
333
|
+
* missing FK fields to 1.
|
|
334
|
+
* - Exclude-mode object $select: leave alone — FK survives by default. If the
|
|
335
|
+
* FK is explicitly excluded, throw rather than silently override user intent.
|
|
336
|
+
*/
|
|
337
|
+
function ensureSelectIncludesFields(controls, fields) {
|
|
338
|
+
if (!controls) return controls;
|
|
339
|
+
const sel = controls.$select;
|
|
340
|
+
if (sel === void 0 || sel === null) return controls;
|
|
341
|
+
if (Array.isArray(sel)) {
|
|
342
|
+
const augmented = [...sel];
|
|
343
|
+
for (const f of fields) if (!augmented.includes(f)) augmented.push(f);
|
|
344
|
+
return {
|
|
345
|
+
...controls,
|
|
346
|
+
$select: augmented
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
if (typeof sel === "object") {
|
|
350
|
+
const selObj = sel;
|
|
351
|
+
const isInclude = Object.keys(selObj).length === 0 || Object.values(selObj).some((v) => v === 1 || v === true);
|
|
352
|
+
const augmented = { ...selObj };
|
|
353
|
+
let mutated = false;
|
|
354
|
+
for (const f of fields) {
|
|
355
|
+
const v = augmented[f];
|
|
356
|
+
if (v === 0 || v === false) throw new Error(`Cannot exclude join column "${f}" from $select on $with relation`);
|
|
357
|
+
if (v === void 0 && isInclude) {
|
|
358
|
+
augmented[f] = 1;
|
|
359
|
+
mutated = true;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return mutated ? {
|
|
363
|
+
...controls,
|
|
364
|
+
$select: augmented
|
|
365
|
+
} : controls;
|
|
366
|
+
}
|
|
367
|
+
return controls;
|
|
368
|
+
}
|
|
369
|
+
//#endregion
|
|
370
|
+
export { relation_loader_exports as n, loadRelationsImpl as t };
|
package/dist/shared.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_validation_utils = require("./validation-utils-
|
|
2
|
+
const require_validation_utils = require("./validation-utils-Da2GjobR.cjs");
|
|
3
3
|
exports.earlierJoinTargets = require_validation_utils.earlierJoinTargets;
|
|
4
4
|
exports.findFKFieldsPointingTo = require_validation_utils.findFKFieldsPointingTo;
|
|
5
5
|
exports.findViewCycle = require_validation_utils.findViewCycle;
|
package/dist/shared.d.cts
CHANGED
|
@@ -108,13 +108,14 @@ declare function viewScopeTypes(owner: SemanticNode): string[];
|
|
|
108
108
|
*/
|
|
109
109
|
declare function hasAnyViewAnnotation(node: SemanticNode): boolean;
|
|
110
110
|
/**
|
|
111
|
-
* Validate that all field refs in a
|
|
112
|
-
* the same {@link TQueryScope} the editor
|
|
111
|
+
* Validate that all field refs in a backtick argument (a query, an `expr` or
|
|
112
|
+
* an `order`) are within `scope` — the same {@link TQueryScope} the editor
|
|
113
|
+
* completes (`lsp-scopes`):
|
|
113
114
|
* qualified refs must name one of `scope.allowedTypes`; an unqualified ref
|
|
114
115
|
* (a dotted path included) must be a field of `scope.unqualifiedTarget`, or
|
|
115
116
|
* is rejected outright when that is `null`.
|
|
116
117
|
*
|
|
117
|
-
* @param queryToken - The
|
|
118
|
+
* @param queryToken - The backtick arg token (with `.queryNode`, `.exprNode` or `.orderNode`)
|
|
118
119
|
* @param scope - The scope of the argument
|
|
119
120
|
* @param doc - The document for type lookups
|
|
120
121
|
* @param scopeHint - Replaces the default "expected 'A' or 'B'" tail of the out-of-scope message
|
package/dist/shared.d.mts
CHANGED
|
@@ -108,13 +108,14 @@ declare function viewScopeTypes(owner: SemanticNode): string[];
|
|
|
108
108
|
*/
|
|
109
109
|
declare function hasAnyViewAnnotation(node: SemanticNode): boolean;
|
|
110
110
|
/**
|
|
111
|
-
* Validate that all field refs in a
|
|
112
|
-
* the same {@link TQueryScope} the editor
|
|
111
|
+
* Validate that all field refs in a backtick argument (a query, an `expr` or
|
|
112
|
+
* an `order`) are within `scope` — the same {@link TQueryScope} the editor
|
|
113
|
+
* completes (`lsp-scopes`):
|
|
113
114
|
* qualified refs must name one of `scope.allowedTypes`; an unqualified ref
|
|
114
115
|
* (a dotted path included) must be a field of `scope.unqualifiedTarget`, or
|
|
115
116
|
* is rejected outright when that is `null`.
|
|
116
117
|
*
|
|
117
|
-
* @param queryToken - The
|
|
118
|
+
* @param queryToken - The backtick arg token (with `.queryNode`, `.exprNode` or `.orderNode`)
|
|
118
119
|
* @param scope - The scope of the argument
|
|
119
120
|
* @param doc - The document for type lookups
|
|
120
121
|
* @param scopeHint - Replaces the default "expected 'A' or 'B'" tail of the out-of-scope message
|
package/dist/shared.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { S as validateSiblingStringField, _ as getParentTypeName, a as hasAnyViewAnnotation, b as validateExclusiveWith, c as joinTargets, d as viewJoins, f as viewScopeTypes, g as getParentStruct, h as getNavTargetTypeName, i as forEachFieldRef, l as validateQueryScope, m as getDbTableOwner, n as findFKFieldsPointingTo, o as isAliasDecl, p as getAnnotationAlias, r as findViewCycle, s as isDbSourceDecl, t as earlierJoinTargets, u as validateRefArgument, v as primitiveBaseType, x as validateFieldBaseType, y as refActionAnnotation } from "./validation-utils-
|
|
1
|
+
import { S as validateSiblingStringField, _ as getParentTypeName, a as hasAnyViewAnnotation, b as validateExclusiveWith, c as joinTargets, d as viewJoins, f as viewScopeTypes, g as getParentStruct, h as getNavTargetTypeName, i as forEachFieldRef, l as validateQueryScope, m as getDbTableOwner, n as findFKFieldsPointingTo, o as isAliasDecl, p as getAnnotationAlias, r as findViewCycle, s as isDbSourceDecl, t as earlierJoinTargets, u as validateRefArgument, v as primitiveBaseType, x as validateFieldBaseType, y as refActionAnnotation } from "./validation-utils-Dq0uZ7ef.mjs";
|
|
2
2
|
export { earlierJoinTargets, findFKFieldsPointingTo, findViewCycle, forEachFieldRef, getAnnotationAlias, getDbTableOwner, getNavTargetTypeName, getParentStruct, getParentTypeName, hasAnyViewAnnotation, isAliasDecl, isDbSourceDecl, joinTargets, primitiveBaseType, refActionAnnotation, validateExclusiveWith, validateFieldBaseType, validateQueryScope, validateRefArgument, validateSiblingStringField, viewJoins, viewScopeTypes };
|
package/dist/sync.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_db_error = require("./db-error-DTkkeu5b.cjs");
|
|
3
|
-
const require_column_diff = require("./column-diff-
|
|
3
|
+
const require_column_diff = require("./column-diff-Dt7EDJsA.cjs");
|
|
4
4
|
//#region src/schema/table-option-diff.ts
|
|
5
5
|
/**
|
|
6
6
|
* Computes the difference between desired and existing table options.
|
|
@@ -745,7 +745,7 @@ async function executeSyncTable(facts, safe, deps, exec) {
|
|
|
745
745
|
};
|
|
746
746
|
} else {
|
|
747
747
|
if (hasFkChanges && fkDiff && adapter.dropForeignKeys) {
|
|
748
|
-
const keysToDrop = [...fkDiff.removed.map((fk) => require_column_diff.fkKey(fk.fields)), ...fkDiff.changed.map((fk) => require_column_diff.fkKey(fk.desired.fields))];
|
|
748
|
+
const keysToDrop = [...fkDiff.removed.map((fk) => require_column_diff.fkKey(fk.fields)), ...fkDiff.changed.map((fk) => require_column_diff.fkKey(require_column_diff.fkColumns(fk.desired).fields))];
|
|
749
749
|
if (keysToDrop.length > 0) {
|
|
750
750
|
await adapter.dropForeignKeys(keysToDrop);
|
|
751
751
|
droppedFks.push(...keysToDrop);
|
|
@@ -1611,7 +1611,7 @@ var SchemaSync = class {
|
|
|
1611
1611
|
const fkDiff = facts.fkDiff;
|
|
1612
1612
|
init.status = "alter";
|
|
1613
1613
|
init.fkAdded = fkDiff.added.map((fk) => ({
|
|
1614
|
-
fields: fk.fields,
|
|
1614
|
+
fields: require_column_diff.fkColumns(fk).fields,
|
|
1615
1615
|
targetTable: fk.targetTable
|
|
1616
1616
|
}));
|
|
1617
1617
|
init.fkRemoved = fkDiff.removed.map((fk) => ({
|
|
@@ -1619,9 +1619,12 @@ var SchemaSync = class {
|
|
|
1619
1619
|
targetTable: fk.targetTable
|
|
1620
1620
|
}));
|
|
1621
1621
|
init.fkChanged = fkDiff.changed.map((fk) => ({
|
|
1622
|
-
fields: fk.desired.fields,
|
|
1622
|
+
fields: require_column_diff.fkColumns(fk.desired).fields,
|
|
1623
1623
|
targetTable: fk.desired.targetTable,
|
|
1624
|
-
details: buildFkChangeDetails(
|
|
1624
|
+
details: buildFkChangeDetails({
|
|
1625
|
+
...fk.desired,
|
|
1626
|
+
targetFields: require_column_diff.fkColumns(fk.desired).targetFields
|
|
1627
|
+
}, fk.existing)
|
|
1625
1628
|
}));
|
|
1626
1629
|
}
|
|
1627
1630
|
if (facts.diff?.primaryKeyChanged) facts.populated = await adapter.hasRows(pendingRename ? dbName : void 0) ?? "unknown";
|
|
@@ -1659,7 +1662,7 @@ var SchemaSync = class {
|
|
|
1659
1662
|
addRefusal(refusals, t.name, `Primary key of "${t.name}" changed ${label} but the referencing table "${child.name}" is renamed in the same run (from "${child.pendingRename}") — rename it in a separate run first, then retarget the foreign key and re-run.`);
|
|
1660
1663
|
continue;
|
|
1661
1664
|
}
|
|
1662
|
-
if (!(child !== void 0 && [...child.readable.foreignKeys.values()].some((desired) => desired.targetTable === t.name && require_column_diff.fkKey(desired.fields) === require_column_diff.fkKey(fk.fields) && require_column_diff.fkKey(desired.targetFields) === require_column_diff.fkKey(pk.to)))) addRefusal(refusals, t.name, `Primary key of "${t.name}" changed ${label} but "${fk.table}.${fk.fields.join(",")}" still references the old key — retarget the foreign key (or migrate manually) and re-run.`);
|
|
1665
|
+
if (!(child !== void 0 && [...child.readable.foreignKeys.values()].some((desired) => desired.targetTable === t.name && require_column_diff.fkKey(require_column_diff.fkColumns(desired).fields) === require_column_diff.fkKey(fk.fields) && require_column_diff.fkKey(require_column_diff.fkColumns(desired).targetFields) === require_column_diff.fkKey(pk.to)))) addRefusal(refusals, t.name, `Primary key of "${t.name}" changed ${label} but "${fk.table}.${fk.fields.join(",")}" still references the old key — retarget the foreign key (or migrate manually) and re-run.`);
|
|
1663
1666
|
}
|
|
1664
1667
|
for (const f of t.readable.fieldDescriptors) if (!f.ignored && !f.isPrimaryKey && f.defaultValue?.kind === "fn" && f.defaultValue.fn === "increment") addRefusal(refusals, t.name, `"${t.name}.${f.physicalName}" is auto-increment but no longer part of the primary key; auto-increment columns must be primary-key columns.`);
|
|
1665
1668
|
}
|
|
@@ -1674,6 +1677,7 @@ var SchemaSync = class {
|
|
|
1674
1677
|
if (d.viewObjectKinds.get(view.tableName) === "table") addRefusal(refusals, view.tableName, `A physical table "${view.tableName}" exists where managed view "${view.tableName}" is declared — drop or rename it`);
|
|
1675
1678
|
const fns = view.dbAdapter.aggregateFns();
|
|
1676
1679
|
for (const col of view.getViewColumnMappings()) if (col.aggFn && !fns.has(col.aggFn)) addRefusal(refusals, view.tableName, `View "${view.tableName}" field "${col.viewPath}": aggregate "${col.aggFn}" is not supported by this adapter (aggregateFns())`);
|
|
1680
|
+
for (const problem of view.viewCapabilityProblems()) addRefusal(refusals, view.tableName, problem);
|
|
1677
1681
|
for (const source of d.viewSources.get(view.tableName)) if (d.externalTargets.get(source) === false) addRefusal(refusals, view.tableName, `View "${view.tableName}" reads "${source}" which is neither in the sync inventory nor present in the database`);
|
|
1678
1682
|
}
|
|
1679
1683
|
if (!safe) for (const r of d.removed) {
|
package/dist/sync.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as
|
|
1
|
+
import { Dt as TTableOptionDiff, Fn as TGenericLogger, Gt as DbSpace, J as TDbObjectKind, St as TReferencingForeignKey, V as TDbFieldMeta, dt as TExistingForeignKey, ft as TExistingTableOption, lt as TEnsureTableOptions, st as TDerivedChangeReason, xt as TPrimaryKeyChange } from "./buckets-CjdPipCC.cjs";
|
|
2
|
+
import { _ as computeTableSnapshot, a as hasForeignKeyChanges, b as snapshotToExistingTableOptions, c as TFieldSnapshot, d as TViewColumnSnapshot, f as TViewJoinSnapshot, g as computeTableHash, h as computeSchemaHash, i as fkKey, l as TForeignKeySnapshot, m as canonicalizeQueryNode, n as computeForeignKeyDiff, o as computeColumnDiff, p as TViewSnapshot, t as TForeignKeyDiff, u as TTableSnapshot, v as computeViewSnapshot, y as snapshotToExistingColumns } from "./fk-diff-DLqwVkKG.cjs";
|
|
3
3
|
import { TAtscriptAnnotatedType } from "@atscript/typescript/utils";
|
|
4
4
|
|
|
5
5
|
//#region src/schema/sync-entry.d.ts
|
|
@@ -472,29 +472,6 @@ declare class SchemaSync {
|
|
|
472
472
|
*/
|
|
473
473
|
declare function computeTableOptionDiff(desired: readonly TExistingTableOption[], existing: readonly TExistingTableOption[], destructiveKeys?: ReadonlySet<string>): TTableOptionDiff;
|
|
474
474
|
//#endregion
|
|
475
|
-
//#region src/schema/fk-diff.d.ts
|
|
476
|
-
interface TForeignKeyDiff {
|
|
477
|
-
/** FKs present in desired but not in stored snapshot (new). */
|
|
478
|
-
added: TDbForeignKey[];
|
|
479
|
-
/** FKs present in stored snapshot but not in desired (removed). */
|
|
480
|
-
removed: TForeignKeySnapshot[];
|
|
481
|
-
/** FKs where fields match but target, onDelete, or onUpdate differ. */
|
|
482
|
-
changed: Array<{
|
|
483
|
-
desired: TDbForeignKey;
|
|
484
|
-
existing: TForeignKeySnapshot;
|
|
485
|
-
}>;
|
|
486
|
-
}
|
|
487
|
-
/** Canonical key for an FK: sorted local field names, comma-joined. */
|
|
488
|
-
declare function fkKey(fields: readonly string[]): string;
|
|
489
|
-
/**
|
|
490
|
-
* Compares desired FK constraints against stored snapshot to detect
|
|
491
|
-
* additions, removals, and property changes (target table, target fields,
|
|
492
|
-
* onDelete, onUpdate).
|
|
493
|
-
*/
|
|
494
|
-
declare function computeForeignKeyDiff(desired: ReadonlyMap<string, TDbForeignKey>, existingSnapshot: readonly TForeignKeySnapshot[]): TForeignKeyDiff;
|
|
495
|
-
/** Whether the FK diff contains any changes. */
|
|
496
|
-
declare function hasForeignKeyChanges(diff: TForeignKeyDiff): boolean;
|
|
497
|
-
//#endregion
|
|
498
475
|
//#region src/schema/dependency-order.d.ts
|
|
499
476
|
/** A directed edge `from → to`: `from` depends on `to` (child → parent). */
|
|
500
477
|
type TDependencyEdge = readonly [from: string, to: string];
|
package/dist/sync.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as
|
|
1
|
+
import { Dt as TTableOptionDiff, Fn as TGenericLogger, Gt as DbSpace, J as TDbObjectKind, St as TReferencingForeignKey, V as TDbFieldMeta, dt as TExistingForeignKey, ft as TExistingTableOption, lt as TEnsureTableOptions, st as TDerivedChangeReason, xt as TPrimaryKeyChange } from "./buckets-DYopfd2Y.mjs";
|
|
2
|
+
import { _ as computeTableSnapshot, a as hasForeignKeyChanges, b as snapshotToExistingTableOptions, c as TFieldSnapshot, d as TViewColumnSnapshot, f as TViewJoinSnapshot, g as computeTableHash, h as computeSchemaHash, i as fkKey, l as TForeignKeySnapshot, m as canonicalizeQueryNode, n as computeForeignKeyDiff, o as computeColumnDiff, p as TViewSnapshot, t as TForeignKeyDiff, u as TTableSnapshot, v as computeViewSnapshot, y as snapshotToExistingColumns } from "./fk-diff-BtOmL4OW.mjs";
|
|
3
3
|
import { TAtscriptAnnotatedType } from "@atscript/typescript/utils";
|
|
4
4
|
|
|
5
5
|
//#region src/schema/sync-entry.d.ts
|
|
@@ -472,29 +472,6 @@ declare class SchemaSync {
|
|
|
472
472
|
*/
|
|
473
473
|
declare function computeTableOptionDiff(desired: readonly TExistingTableOption[], existing: readonly TExistingTableOption[], destructiveKeys?: ReadonlySet<string>): TTableOptionDiff;
|
|
474
474
|
//#endregion
|
|
475
|
-
//#region src/schema/fk-diff.d.ts
|
|
476
|
-
interface TForeignKeyDiff {
|
|
477
|
-
/** FKs present in desired but not in stored snapshot (new). */
|
|
478
|
-
added: TDbForeignKey[];
|
|
479
|
-
/** FKs present in stored snapshot but not in desired (removed). */
|
|
480
|
-
removed: TForeignKeySnapshot[];
|
|
481
|
-
/** FKs where fields match but target, onDelete, or onUpdate differ. */
|
|
482
|
-
changed: Array<{
|
|
483
|
-
desired: TDbForeignKey;
|
|
484
|
-
existing: TForeignKeySnapshot;
|
|
485
|
-
}>;
|
|
486
|
-
}
|
|
487
|
-
/** Canonical key for an FK: sorted local field names, comma-joined. */
|
|
488
|
-
declare function fkKey(fields: readonly string[]): string;
|
|
489
|
-
/**
|
|
490
|
-
* Compares desired FK constraints against stored snapshot to detect
|
|
491
|
-
* additions, removals, and property changes (target table, target fields,
|
|
492
|
-
* onDelete, onUpdate).
|
|
493
|
-
*/
|
|
494
|
-
declare function computeForeignKeyDiff(desired: ReadonlyMap<string, TDbForeignKey>, existingSnapshot: readonly TForeignKeySnapshot[]): TForeignKeyDiff;
|
|
495
|
-
/** Whether the FK diff contains any changes. */
|
|
496
|
-
declare function hasForeignKeyChanges(diff: TForeignKeyDiff): boolean;
|
|
497
|
-
//#endregion
|
|
498
475
|
//#region src/schema/dependency-order.d.ts
|
|
499
476
|
/** A directed edge `from → to`: `from` depends on `to` (child → parent). */
|
|
500
477
|
type TDependencyEdge = readonly [from: string, to: string];
|
package/dist/sync.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as DbError } from "./db-error-D5uilS_A.mjs";
|
|
2
|
-
import { a as
|
|
2
|
+
import { a as computeTableHash, c as snapshotToExistingColumns, d as computeForeignKeyDiff, f as fkColumns, i as computeSchemaHash, l as snapshotToExistingTableOptions, lt as NoopLogger, m as hasForeignKeyChanges, o as computeTableSnapshot, p as fkKey, r as canonicalizeQueryNode, rt as aliasTargetOf, s as computeViewSnapshot, t as computeColumnDiff, u as viewSnapshotSources } from "./column-diff-CO06iQvI.mjs";
|
|
3
3
|
//#region src/schema/table-option-diff.ts
|
|
4
4
|
/**
|
|
5
5
|
* Computes the difference between desired and existing table options.
|
|
@@ -744,7 +744,7 @@ async function executeSyncTable(facts, safe, deps, exec) {
|
|
|
744
744
|
};
|
|
745
745
|
} else {
|
|
746
746
|
if (hasFkChanges && fkDiff && adapter.dropForeignKeys) {
|
|
747
|
-
const keysToDrop = [...fkDiff.removed.map((fk) => fkKey(fk.fields)), ...fkDiff.changed.map((fk) => fkKey(fk.desired.fields))];
|
|
747
|
+
const keysToDrop = [...fkDiff.removed.map((fk) => fkKey(fk.fields)), ...fkDiff.changed.map((fk) => fkKey(fkColumns(fk.desired).fields))];
|
|
748
748
|
if (keysToDrop.length > 0) {
|
|
749
749
|
await adapter.dropForeignKeys(keysToDrop);
|
|
750
750
|
droppedFks.push(...keysToDrop);
|
|
@@ -1610,7 +1610,7 @@ var SchemaSync = class {
|
|
|
1610
1610
|
const fkDiff = facts.fkDiff;
|
|
1611
1611
|
init.status = "alter";
|
|
1612
1612
|
init.fkAdded = fkDiff.added.map((fk) => ({
|
|
1613
|
-
fields: fk.fields,
|
|
1613
|
+
fields: fkColumns(fk).fields,
|
|
1614
1614
|
targetTable: fk.targetTable
|
|
1615
1615
|
}));
|
|
1616
1616
|
init.fkRemoved = fkDiff.removed.map((fk) => ({
|
|
@@ -1618,9 +1618,12 @@ var SchemaSync = class {
|
|
|
1618
1618
|
targetTable: fk.targetTable
|
|
1619
1619
|
}));
|
|
1620
1620
|
init.fkChanged = fkDiff.changed.map((fk) => ({
|
|
1621
|
-
fields: fk.desired.fields,
|
|
1621
|
+
fields: fkColumns(fk.desired).fields,
|
|
1622
1622
|
targetTable: fk.desired.targetTable,
|
|
1623
|
-
details: buildFkChangeDetails(
|
|
1623
|
+
details: buildFkChangeDetails({
|
|
1624
|
+
...fk.desired,
|
|
1625
|
+
targetFields: fkColumns(fk.desired).targetFields
|
|
1626
|
+
}, fk.existing)
|
|
1624
1627
|
}));
|
|
1625
1628
|
}
|
|
1626
1629
|
if (facts.diff?.primaryKeyChanged) facts.populated = await adapter.hasRows(pendingRename ? dbName : void 0) ?? "unknown";
|
|
@@ -1658,7 +1661,7 @@ var SchemaSync = class {
|
|
|
1658
1661
|
addRefusal(refusals, t.name, `Primary key of "${t.name}" changed ${label} but the referencing table "${child.name}" is renamed in the same run (from "${child.pendingRename}") — rename it in a separate run first, then retarget the foreign key and re-run.`);
|
|
1659
1662
|
continue;
|
|
1660
1663
|
}
|
|
1661
|
-
if (!(child !== void 0 && [...child.readable.foreignKeys.values()].some((desired) => desired.targetTable === t.name && fkKey(desired.fields) === fkKey(fk.fields) && fkKey(desired.targetFields) === fkKey(pk.to)))) addRefusal(refusals, t.name, `Primary key of "${t.name}" changed ${label} but "${fk.table}.${fk.fields.join(",")}" still references the old key — retarget the foreign key (or migrate manually) and re-run.`);
|
|
1664
|
+
if (!(child !== void 0 && [...child.readable.foreignKeys.values()].some((desired) => desired.targetTable === t.name && fkKey(fkColumns(desired).fields) === fkKey(fk.fields) && fkKey(fkColumns(desired).targetFields) === fkKey(pk.to)))) addRefusal(refusals, t.name, `Primary key of "${t.name}" changed ${label} but "${fk.table}.${fk.fields.join(",")}" still references the old key — retarget the foreign key (or migrate manually) and re-run.`);
|
|
1662
1665
|
}
|
|
1663
1666
|
for (const f of t.readable.fieldDescriptors) if (!f.ignored && !f.isPrimaryKey && f.defaultValue?.kind === "fn" && f.defaultValue.fn === "increment") addRefusal(refusals, t.name, `"${t.name}.${f.physicalName}" is auto-increment but no longer part of the primary key; auto-increment columns must be primary-key columns.`);
|
|
1664
1667
|
}
|
|
@@ -1673,6 +1676,7 @@ var SchemaSync = class {
|
|
|
1673
1676
|
if (d.viewObjectKinds.get(view.tableName) === "table") addRefusal(refusals, view.tableName, `A physical table "${view.tableName}" exists where managed view "${view.tableName}" is declared — drop or rename it`);
|
|
1674
1677
|
const fns = view.dbAdapter.aggregateFns();
|
|
1675
1678
|
for (const col of view.getViewColumnMappings()) if (col.aggFn && !fns.has(col.aggFn)) addRefusal(refusals, view.tableName, `View "${view.tableName}" field "${col.viewPath}": aggregate "${col.aggFn}" is not supported by this adapter (aggregateFns())`);
|
|
1679
|
+
for (const problem of view.viewCapabilityProblems()) addRefusal(refusals, view.tableName, problem);
|
|
1676
1680
|
for (const source of d.viewSources.get(view.tableName)) if (d.externalTargets.get(source) === false) addRefusal(refusals, view.tableName, `View "${view.tableName}" reads "${source}" which is neither in the sync inventory nor present in the database`);
|
|
1677
1681
|
}
|
|
1678
1682
|
if (!safe) for (const r of d.removed) {
|