@rebasepro/server-postgres 0.10.1-canary.ff9ccd6 → 0.10.1-canary.gdaf6ba4
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/auth/schema-version.d.ts +106 -0
- package/dist/collections/validate-relations.d.ts +53 -0
- package/dist/data-transformer.d.ts +3 -3
- package/dist/{ensure-collection-tables-C9gy4STB.js → ensure-collection-tables-DGMYK0fr.js} +5 -5
- package/dist/ensure-collection-tables-DGMYK0fr.js.map +1 -0
- package/dist/index.es.js +905 -383
- package/dist/index.es.js.map +1 -1
- package/dist/services/FetchService.d.ts +21 -8
- package/dist/services/PersistService.d.ts +12 -0
- package/dist/services/RelationService.d.ts +39 -8
- package/dist/services/cdc/junction-tables.d.ts +38 -0
- package/dist/services/nested-path.d.ts +59 -0
- package/dist/services/realtimeService.d.ts +19 -0
- package/dist/services/row-pipeline.d.ts +2 -2
- package/dist/{src-DG6ZsQQ3.js → src-3VmUJ8Xn.js} +211 -243
- package/dist/src-3VmUJ8Xn.js.map +1 -0
- package/dist/{src-CBgtrPhJ.js → src-D5xBTl32.js} +12 -2
- package/dist/src-D5xBTl32.js.map +1 -0
- package/dist/utils/drizzle-conditions.d.ts +71 -18
- package/package.json +6 -6
- package/src/PostgresBootstrapper.ts +15 -2
- package/src/auth/ensure-tables.ts +23 -0
- package/src/auth/schema-version.ts +260 -0
- package/src/cli-errors.ts +1 -1
- package/src/cli-helpers.ts +4 -3
- package/src/collections/PostgresCollectionRegistry.ts +9 -4
- package/src/collections/buildRegistry.ts +7 -0
- package/src/collections/validate-relations.ts +280 -0
- package/src/data-transformer.ts +28 -38
- package/src/schema/doctor.ts +8 -8
- package/src/schema/generate-drizzle-schema-logic.ts +49 -101
- package/src/schema/generate-postgres-ddl-logic.ts +9 -9
- package/src/schema/introspect-db-logic.ts +19 -23
- package/src/services/FetchService.ts +116 -126
- package/src/services/PersistService.ts +126 -88
- package/src/services/RelationService.ts +157 -86
- package/src/services/cdc/junction-tables.ts +91 -0
- package/src/services/nested-path.ts +145 -0
- package/src/services/realtimeService.ts +60 -0
- package/src/services/row-pipeline.ts +5 -6
- package/src/utils/drizzle-conditions.ts +268 -330
- package/dist/ensure-collection-tables-C9gy4STB.js.map +0 -1
- package/dist/src-CBgtrPhJ.js.map +0 -1
- package/dist/src-DG6ZsQQ3.js.map +0 -1
|
@@ -2,7 +2,7 @@ import { createRequire as __createRequire } from "module";
|
|
|
2
2
|
import "process";
|
|
3
3
|
__createRequire(import.meta.url);
|
|
4
4
|
import { r as __require, t as __commonJSMin } from "./chunk-DSJWtz9O.js";
|
|
5
|
-
import {
|
|
5
|
+
import { d as isPostgresCollectionConfig, f as NULL_OPS, h as EntityRelation, l as isManyToMany, m as toCanonicalOp, n as getDataSourceCapabilities, o as ANONYMOUS_USER_ID, p as REST_TO_CANONICAL, s as policy, u as getDeclaredSubcollections } from "./src-D5xBTl32.js";
|
|
6
6
|
//#region ../common/src/util/common.ts
|
|
7
7
|
var DEFAULT_ONE_OF_TYPE = "type";
|
|
8
8
|
var DEFAULT_ONE_OF_VALUE = "value";
|
|
@@ -1405,151 +1405,143 @@ function enumToObjectEntries(enumValues) {
|
|
|
1405
1405
|
});
|
|
1406
1406
|
}
|
|
1407
1407
|
//#endregion
|
|
1408
|
-
//#region ../common/src/util/
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1408
|
+
//#region ../common/src/util/resolve-relation.ts
|
|
1409
|
+
/**
|
|
1410
|
+
* Fill in a relation's defaults.
|
|
1411
|
+
*
|
|
1412
|
+
* This replaces `sanitizeRelation`, which had to work out *which kind of link
|
|
1413
|
+
* you meant* from whichever optional fields happened to be set — 194 lines of
|
|
1414
|
+
* it, including a pass that inspected the target collection's own relations to
|
|
1415
|
+
* decide whether a `many`/`inverse` pair was a one-to-many or the far side of a
|
|
1416
|
+
* many-to-many, wrapped in a `try/catch` that fell through to the wrong answer
|
|
1417
|
+
* when it could not tell. Two consumers running that logic at different moments
|
|
1418
|
+
* could reach different conclusions about the same relation.
|
|
1419
|
+
*
|
|
1420
|
+
* With the kind declared there is nothing to work out. What remains is
|
|
1421
|
+
* defaulting — a table name, a column name — which is deterministic, depends
|
|
1422
|
+
* only on the relation and its two endpoints, and cannot fail. That is why this
|
|
1423
|
+
* function returns rather than throws, and why it needs no cache to be
|
|
1424
|
+
* consistent.
|
|
1425
|
+
*/
|
|
1426
|
+
function resolveRelation(relation, sourceCollection, propertyKey) {
|
|
1427
|
+
const target = relation.target;
|
|
1428
|
+
if (typeof target !== "function") throw new Error(`Relation${relation.relationName ? ` '${relation.relationName}'` : ""} on '${sourceCollection.slug}' has no \`target\`. Give it a thunk: \`target: () => otherCollection\`.`);
|
|
1429
|
+
const targetCollection = target();
|
|
1430
|
+
if (!targetCollection?.slug) throw new Error(`Relation${relation.relationName ? ` '${relation.relationName}'` : ""} on '${sourceCollection.slug}' has a \`target\` that did not resolve to a collection.`);
|
|
1431
|
+
const relationName = relation.relationName ?? propertyKey ?? toSnakeCase(targetCollection.slug);
|
|
1432
|
+
const shared = {
|
|
1433
|
+
relationName,
|
|
1434
|
+
target,
|
|
1435
|
+
targetSlug: targetCollection.slug,
|
|
1436
|
+
onUpdate: relation.onUpdate,
|
|
1437
|
+
onDelete: relation.onDelete,
|
|
1438
|
+
overrides: relation.overrides,
|
|
1439
|
+
validation: relation.validation
|
|
1439
1440
|
};
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
}
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
break;
|
|
1480
|
-
}
|
|
1441
|
+
const sourceName = toSnakeCase(sourceCollection.slug ?? sourceCollection.name);
|
|
1442
|
+
switch (relation.kind) {
|
|
1443
|
+
case "belongsTo": return {
|
|
1444
|
+
...shared,
|
|
1445
|
+
kind: "belongsTo",
|
|
1446
|
+
cardinality: "one",
|
|
1447
|
+
writable: true,
|
|
1448
|
+
shared: false,
|
|
1449
|
+
localKey: relation.localKey ?? generateForeignKeyName(relationName)
|
|
1450
|
+
};
|
|
1451
|
+
case "hasOne": return {
|
|
1452
|
+
...shared,
|
|
1453
|
+
kind: "hasOne",
|
|
1454
|
+
cardinality: "one",
|
|
1455
|
+
writable: true,
|
|
1456
|
+
shared: false,
|
|
1457
|
+
foreignKeyOnTarget: relation.foreignKeyOnTarget ?? generateForeignKeyName(sourceName)
|
|
1458
|
+
};
|
|
1459
|
+
case "hasMany": return {
|
|
1460
|
+
...shared,
|
|
1461
|
+
kind: "hasMany",
|
|
1462
|
+
cardinality: "many",
|
|
1463
|
+
writable: true,
|
|
1464
|
+
shared: false,
|
|
1465
|
+
foreignKeyOnTarget: relation.foreignKeyOnTarget ?? generateForeignKeyName(sourceName)
|
|
1466
|
+
};
|
|
1467
|
+
case "manyToMany": {
|
|
1468
|
+
const sourceTable = getTableName(sourceCollection);
|
|
1469
|
+
const targetTable = getTableName(targetCollection);
|
|
1470
|
+
return {
|
|
1471
|
+
...shared,
|
|
1472
|
+
kind: "manyToMany",
|
|
1473
|
+
cardinality: "many",
|
|
1474
|
+
writable: true,
|
|
1475
|
+
shared: true,
|
|
1476
|
+
through: {
|
|
1477
|
+
table: relation.through?.table ?? [sourceTable, targetTable].sort().join("_"),
|
|
1478
|
+
sourceColumn: relation.through?.sourceColumn ?? generateForeignKeyName(sourceName),
|
|
1479
|
+
targetColumn: relation.through?.targetColumn ?? generateForeignKeyName(relationName)
|
|
1481
1480
|
}
|
|
1482
|
-
} catch (e) {}
|
|
1483
|
-
if (!isManyToManyInverse && !newRelation.foreignKeyOnTarget) newRelation.foreignKeyOnTarget = generateForeignKeyName(sourceName);
|
|
1484
|
-
} else if (newRelation.cardinality === "many" && newRelation.direction === "owning") {
|
|
1485
|
-
const sourceTableName = getTableName(sourceCollection);
|
|
1486
|
-
const targetTableName = getTableName(targetCollection);
|
|
1487
|
-
newRelation.through = {
|
|
1488
|
-
table: newRelation.through?.table ?? [sourceTableName, targetTableName].sort().join("_"),
|
|
1489
|
-
sourceColumn: newRelation.through?.sourceColumn ?? generateForeignKeyName(sourceName),
|
|
1490
|
-
targetColumn: newRelation.through?.targetColumn ?? generateForeignKeyName(newRelation.relationName)
|
|
1491
1481
|
};
|
|
1492
1482
|
}
|
|
1483
|
+
case "via": return {
|
|
1484
|
+
...shared,
|
|
1485
|
+
kind: "via",
|
|
1486
|
+
cardinality: relation.cardinality,
|
|
1487
|
+
writable: false,
|
|
1488
|
+
shared: true,
|
|
1489
|
+
joinPath: relation.joinPath
|
|
1490
|
+
};
|
|
1491
|
+
default: throw new Error(`Unknown relation kind: ${JSON.stringify(relation)}`);
|
|
1493
1492
|
}
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1493
|
+
}
|
|
1494
|
+
//#endregion
|
|
1495
|
+
//#region ../common/src/util/relations.ts
|
|
1496
|
+
/**
|
|
1497
|
+
* Whether the target rows are shared with other parents — a many-to-many, or a
|
|
1498
|
+
* multi-hop `via` chain.
|
|
1499
|
+
*
|
|
1500
|
+
* Decides what a write "through" the relation may touch: a shared target
|
|
1501
|
+
* belongs to every parent that links it, so the parent owns the *link* and not
|
|
1502
|
+
* the row. The backend enforces that (an unlink rather than a delete) and the
|
|
1503
|
+
* admin renders it (remove-from-parent rather than delete).
|
|
1504
|
+
*
|
|
1505
|
+
* Now a field on the resolved relation rather than a re-derivation, so both
|
|
1506
|
+
* sides read the same answer instead of each computing one.
|
|
1507
|
+
*/
|
|
1508
|
+
function isJunctionBackedRelation(relation) {
|
|
1509
|
+
return relation.shared;
|
|
1498
1510
|
}
|
|
1499
1511
|
/** WeakMap cache — same collection instance always yields the same relation map. */
|
|
1500
1512
|
var _resolvedRelationsCache = /* @__PURE__ */ new WeakMap();
|
|
1513
|
+
/**
|
|
1514
|
+
* Every relation a collection declares, keyed by the name it is addressed by.
|
|
1515
|
+
*
|
|
1516
|
+
* A relation reaches the map from either of two places — the collection's
|
|
1517
|
+
* `relations` array, or a `relation` property that declares one inline — and is
|
|
1518
|
+
* keyed by its resolved `relationName`, which is what a nested path segment,
|
|
1519
|
+
* an `include` key and an admin tab all match against.
|
|
1520
|
+
*
|
|
1521
|
+
* Resolution no longer swallows failures. It used to wrap each relation in a
|
|
1522
|
+
* `try/catch` that dropped anything it could not work out, so a
|
|
1523
|
+
* mis-declared relation silently vanished instead of being reported; with the
|
|
1524
|
+
* kind declared, the only remaining failure is a `target` that does not resolve,
|
|
1525
|
+
* which is worth hearing about.
|
|
1526
|
+
*/
|
|
1501
1527
|
function resolveCollectionRelations(collection) {
|
|
1502
1528
|
const cached = _resolvedRelationsCache.get(collection);
|
|
1503
1529
|
if (cached) return cached;
|
|
1504
1530
|
if (!getDataSourceCapabilities(collection.engine).supportsRelations) return {};
|
|
1505
1531
|
const relations = {};
|
|
1506
|
-
const
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
});
|
|
1517
|
-
if (collection.properties) Object.entries(collection.properties).forEach(([propKey, prop]) => {
|
|
1518
|
-
const relation = resolvePropertyRelation({
|
|
1519
|
-
propertyKey: propKey,
|
|
1520
|
-
property: prop,
|
|
1521
|
-
sourceCollection: collection
|
|
1522
|
-
});
|
|
1523
|
-
if (relation) {
|
|
1524
|
-
if (relations[propKey]) return;
|
|
1525
|
-
if (!relation.relationName) relation.relationName = propKey;
|
|
1526
|
-
const normalizedRelation = sanitizeRelation(relation, collection);
|
|
1527
|
-
relations[propKey] = normalizedRelation;
|
|
1528
|
-
registeredRelationNames.add(normalizedRelation.relationName ?? propKey);
|
|
1529
|
-
}
|
|
1530
|
-
});
|
|
1532
|
+
for (const relation of collection.relations ?? []) {
|
|
1533
|
+
const resolved = resolveRelation(relation, collection);
|
|
1534
|
+
relations[resolved.relationName] = resolved;
|
|
1535
|
+
}
|
|
1536
|
+
for (const [propertyKey, property] of Object.entries(collection.properties ?? {})) {
|
|
1537
|
+
if (property?.type !== "relation") continue;
|
|
1538
|
+
const declared = property.relation;
|
|
1539
|
+
if (!declared || relations[propertyKey]) continue;
|
|
1540
|
+
relations[propertyKey] = resolveRelation(declared, collection, propertyKey);
|
|
1541
|
+
}
|
|
1531
1542
|
_resolvedRelationsCache.set(collection, relations);
|
|
1532
1543
|
return relations;
|
|
1533
1544
|
}
|
|
1534
|
-
function resolvePropertyRelation({ propertyKey, property, sourceCollection }) {
|
|
1535
|
-
if (property.type !== "relation") return void 0;
|
|
1536
|
-
const relProp = property;
|
|
1537
|
-
if (relProp.target) return {
|
|
1538
|
-
relationName: relProp.relationName || propertyKey,
|
|
1539
|
-
target: relProp.target,
|
|
1540
|
-
cardinality: relProp.cardinality || "one",
|
|
1541
|
-
direction: relProp.direction || "owning",
|
|
1542
|
-
inverseRelationName: relProp.inverseRelationName,
|
|
1543
|
-
localKey: relProp.localKey,
|
|
1544
|
-
foreignKeyOnTarget: relProp.foreignKeyOnTarget,
|
|
1545
|
-
through: relProp.through,
|
|
1546
|
-
joinPath: relProp.joinPath,
|
|
1547
|
-
onUpdate: relProp.onUpdate,
|
|
1548
|
-
onDelete: relProp.onDelete,
|
|
1549
|
-
overrides: relProp.overrides
|
|
1550
|
-
};
|
|
1551
|
-
console.warn(`Unrecognized or missing relation target for property '${propertyKey}' in collection '${sourceCollection.slug}'`);
|
|
1552
|
-
}
|
|
1553
1545
|
function getTableName(collection) {
|
|
1554
1546
|
if (getDataSourceCapabilities(collection.engine).supportsRelations) return collection.table ?? toSnakeCase(collection.slug) ?? toSnakeCase(collection.name);
|
|
1555
1547
|
return toSnakeCase(collection.slug) ?? toSnakeCase(collection.name);
|
|
@@ -1581,34 +1573,79 @@ function findRelation(resolvedRelations, key) {
|
|
|
1581
1573
|
}
|
|
1582
1574
|
//#endregion
|
|
1583
1575
|
//#region ../common/src/util/resolutions.ts
|
|
1584
|
-
|
|
1585
|
-
|
|
1576
|
+
/**
|
|
1577
|
+
* The lists rendered inside an entity view of `collection` — its tabs.
|
|
1578
|
+
*
|
|
1579
|
+
* The single derivation. There used to be two that disagreed: this one, and a
|
|
1580
|
+
* copy in `CollectionRegistry.normalizeCollection` that stamped each child with
|
|
1581
|
+
* the *target collection's* slug instead of the relation key. Since the
|
|
1582
|
+
* registry ran first and cached its answer onto `childCollections`, its version
|
|
1583
|
+
* was the one that won, and the frontend addressed child listings by a segment
|
|
1584
|
+
* the backend could not resolve.
|
|
1585
|
+
*
|
|
1586
|
+
* Order of precedence:
|
|
1587
|
+
* 1. `childCollections` — the explicit escape hatch for custom drivers.
|
|
1588
|
+
* 2. `subcollections` on an engine that has real containment (Firestore).
|
|
1589
|
+
* 3. many-relations on an engine that has relations (SQL).
|
|
1590
|
+
*/
|
|
1591
|
+
function getEntityChildViews(collection) {
|
|
1592
|
+
const asSubcollections = (collections) => collections.filter(Boolean).map((child) => ({
|
|
1593
|
+
key: child.slug,
|
|
1594
|
+
collection: child,
|
|
1595
|
+
source: { kind: "subcollection" }
|
|
1596
|
+
}));
|
|
1597
|
+
if (collection.childCollections) return asSubcollections(collection.childCollections() ?? []);
|
|
1598
|
+
const capabilities = getDataSourceCapabilities(collection.engine);
|
|
1586
1599
|
const declaredSubcollections = getDeclaredSubcollections(collection);
|
|
1587
|
-
if (
|
|
1588
|
-
if (
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1600
|
+
if (capabilities.supportsSubcollections && declaredSubcollections) return asSubcollections(declaredSubcollections() ?? []);
|
|
1601
|
+
if (!capabilities.supportsRelations) return [];
|
|
1602
|
+
const resolvedRelations = resolveCollectionRelations(collection);
|
|
1603
|
+
const views = [];
|
|
1604
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1605
|
+
for (const [relationKey, relation] of Object.entries(resolvedRelations)) {
|
|
1606
|
+
if (relation.cardinality !== "many") continue;
|
|
1607
|
+
const identity = relation.relationName ?? relationKey;
|
|
1608
|
+
if (seen.has(identity)) continue;
|
|
1609
|
+
let target;
|
|
1610
|
+
try {
|
|
1611
|
+
target = relation.target();
|
|
1612
|
+
} catch {
|
|
1613
|
+
continue;
|
|
1614
|
+
}
|
|
1615
|
+
if (!target) continue;
|
|
1616
|
+
seen.add(identity);
|
|
1617
|
+
const customName = Object.entries(collection.properties ?? {}).find(([propKey, p]) => p.type === "relation" && (p.relation?.relationName ?? propKey) === identity)?.[1]?.name;
|
|
1618
|
+
const base = {
|
|
1619
|
+
...target,
|
|
1620
|
+
slug: relationKey,
|
|
1621
|
+
...customName ? {
|
|
1622
|
+
name: customName,
|
|
1623
|
+
singularName: customName
|
|
1624
|
+
} : {}
|
|
1625
|
+
};
|
|
1626
|
+
views.push({
|
|
1627
|
+
key: relationKey,
|
|
1628
|
+
collection: relation.overrides ? mergeDeep(base, relation.overrides) : base,
|
|
1629
|
+
source: {
|
|
1630
|
+
kind: "relation",
|
|
1631
|
+
relationKey,
|
|
1632
|
+
mode: isJunctionBackedRelation(relation) ? "linked" : "owned",
|
|
1633
|
+
targetSlug: target.slug
|
|
1603
1634
|
}
|
|
1604
|
-
|
|
1605
|
-
...target,
|
|
1606
|
-
...baseOverrides
|
|
1607
|
-
};
|
|
1608
|
-
return r.overrides ? mergeDeep(targetWithOverrides, r.overrides) : targetWithOverrides;
|
|
1609
|
-
}).filter((c) => Boolean(c));
|
|
1635
|
+
});
|
|
1610
1636
|
}
|
|
1611
|
-
return
|
|
1637
|
+
return views;
|
|
1638
|
+
}
|
|
1639
|
+
/**
|
|
1640
|
+
* The child views of `collection` as bare collections.
|
|
1641
|
+
*
|
|
1642
|
+
* The flattened view of {@link getEntityChildViews}, for navigation code that
|
|
1643
|
+
* only needs to match a path segment against a slug. Anything that cares *what
|
|
1644
|
+
* kind* of list it is showing — chiefly the admin, which must not offer a
|
|
1645
|
+
* global delete on a shared row — should read the views instead.
|
|
1646
|
+
*/
|
|
1647
|
+
function getSubcollections(collection) {
|
|
1648
|
+
return getEntityChildViews(collection).map((view) => view.collection);
|
|
1612
1649
|
}
|
|
1613
1650
|
//#endregion
|
|
1614
1651
|
//#region ../common/src/util/policy/sqlToPolicy.ts
|
|
@@ -2160,8 +2197,8 @@ function resolveJunctionSpecs(collections) {
|
|
|
2160
2197
|
for (const collection of collections) {
|
|
2161
2198
|
const resolved = resolveCollectionRelations(collection);
|
|
2162
2199
|
for (const relation of Object.values(resolved)) {
|
|
2163
|
-
if (!relation
|
|
2164
|
-
const targetCollection =
|
|
2200
|
+
if (!isManyToMany(relation)) continue;
|
|
2201
|
+
const targetCollection = relation.target();
|
|
2165
2202
|
if (!targetCollection) continue;
|
|
2166
2203
|
const rawName = relation.through.table;
|
|
2167
2204
|
const table = rawName.includes(".") ? rawName.split(".").pop() : rawName;
|
|
@@ -3203,100 +3240,33 @@ var CollectionRegistry = class {
|
|
|
3203
3240
|
if (!result.dataSource) result.dataSource = resolved.key;
|
|
3204
3241
|
if (!result.engine) result.engine = resolved.engine;
|
|
3205
3242
|
}
|
|
3206
|
-
|
|
3207
|
-
const relResult = result;
|
|
3208
|
-
const manualRelations = getDataSourceCapabilities(result.engine).supportsRelations ? relResult.relations ?? [] : [];
|
|
3209
|
-
const mergedRelationsRaw = [...extractedRelations];
|
|
3210
|
-
for (const manual of manualRelations) {
|
|
3211
|
-
const name = manual.relationName;
|
|
3212
|
-
if (!name) mergedRelationsRaw.push(manual);
|
|
3213
|
-
else {
|
|
3214
|
-
const existingIndex = mergedRelationsRaw.findIndex((r) => r.relationName === name);
|
|
3215
|
-
if (existingIndex === -1) mergedRelationsRaw.push(manual);
|
|
3216
|
-
else mergedRelationsRaw[existingIndex] = {
|
|
3217
|
-
...manual,
|
|
3218
|
-
...mergedRelationsRaw[existingIndex]
|
|
3219
|
-
};
|
|
3220
|
-
}
|
|
3221
|
-
}
|
|
3222
|
-
let mergedRelations = mergedRelationsRaw;
|
|
3223
|
-
if (getDataSourceCapabilities(result.engine).supportsRelations) {
|
|
3224
|
-
mergedRelations = mergedRelationsRaw.map((r) => {
|
|
3225
|
-
try {
|
|
3226
|
-
return sanitizeRelation(r, result, (slug) => this.get(slug));
|
|
3227
|
-
} catch {
|
|
3228
|
-
return r;
|
|
3229
|
-
}
|
|
3230
|
-
});
|
|
3231
|
-
relResult.relations = mergedRelations;
|
|
3232
|
-
}
|
|
3233
|
-
result.properties = this.normalizeProperties(result.properties, mergedRelations);
|
|
3234
|
-
if (!result.childCollections) {
|
|
3235
|
-
const capabilities = getDataSourceCapabilities(result.engine);
|
|
3236
|
-
const declaredSubcollections = getDeclaredSubcollections(result);
|
|
3237
|
-
if (capabilities.supportsSubcollections && declaredSubcollections) result.childCollections = declaredSubcollections;
|
|
3238
|
-
else if (capabilities.supportsRelations && relResult.relations) {
|
|
3239
|
-
const manyRelations = relResult.relations.filter((r) => r.cardinality === "many");
|
|
3240
|
-
if (manyRelations.length > 0) result.childCollections = () => manyRelations.map((r) => {
|
|
3241
|
-
const target = r.target();
|
|
3242
|
-
return r.overrides ? mergeDeep(target, r.overrides) : target;
|
|
3243
|
-
});
|
|
3244
|
-
}
|
|
3245
|
-
}
|
|
3243
|
+
result.properties = this.normalizeProperties(result.properties, result);
|
|
3246
3244
|
return result;
|
|
3247
3245
|
}
|
|
3248
|
-
|
|
3249
|
-
* Extract Relation[] from properties that have inline relation config (i.e. `target` is set).
|
|
3250
|
-
* This allows developers to define relations directly on properties without a separate
|
|
3251
|
-
* `relations[]` entry on the collection.
|
|
3252
|
-
*/
|
|
3253
|
-
extractRelationsFromProperties(properties) {
|
|
3254
|
-
const relations = [];
|
|
3255
|
-
for (const [key, property] of Object.entries(properties)) if (property.type === "relation") {
|
|
3256
|
-
const relProp = property;
|
|
3257
|
-
const target = relProp.target ?? relProp.relation?.target;
|
|
3258
|
-
if (target) {
|
|
3259
|
-
const relationName = relProp.relationName ?? relProp.relation?.relationName ?? key;
|
|
3260
|
-
relations.push({
|
|
3261
|
-
relationName,
|
|
3262
|
-
target,
|
|
3263
|
-
cardinality: relProp.cardinality ?? relProp.relation?.cardinality ?? "one",
|
|
3264
|
-
direction: relProp.direction ?? relProp.relation?.direction ?? "owning",
|
|
3265
|
-
inverseRelationName: relProp.inverseRelationName ?? relProp.relation?.inverseRelationName,
|
|
3266
|
-
localKey: relProp.localKey ?? relProp.relation?.localKey,
|
|
3267
|
-
foreignKeyOnTarget: relProp.foreignKeyOnTarget ?? relProp.relation?.foreignKeyOnTarget,
|
|
3268
|
-
through: relProp.through ?? relProp.relation?.through,
|
|
3269
|
-
joinPath: relProp.joinPath ?? relProp.relation?.joinPath,
|
|
3270
|
-
onUpdate: relProp.onUpdate ?? relProp.relation?.onUpdate,
|
|
3271
|
-
onDelete: relProp.onDelete ?? relProp.relation?.onDelete,
|
|
3272
|
-
overrides: relProp.overrides ?? relProp.relation?.overrides
|
|
3273
|
-
});
|
|
3274
|
-
}
|
|
3275
|
-
} else if (property.type === "map" && property.properties) relations.push(...this.extractRelationsFromProperties(property.properties));
|
|
3276
|
-
return relations;
|
|
3277
|
-
}
|
|
3278
|
-
normalizeProperties(properties, relations) {
|
|
3246
|
+
normalizeProperties(properties, collection) {
|
|
3279
3247
|
const newProperties = {};
|
|
3280
|
-
for (const key in properties) newProperties[key] = this.normalizeProperty(key, properties[key],
|
|
3248
|
+
for (const key in properties) newProperties[key] = this.normalizeProperty(key, properties[key], collection);
|
|
3281
3249
|
return newProperties;
|
|
3282
3250
|
}
|
|
3283
|
-
normalizeProperty(key, property,
|
|
3251
|
+
normalizeProperty(key, property, collection) {
|
|
3284
3252
|
const newProperty = { ...property };
|
|
3285
|
-
if (newProperty.type === "map" && newProperty.properties) newProperty.properties = this.normalizeProperties(newProperty.properties,
|
|
3253
|
+
if (newProperty.type === "map" && newProperty.properties) newProperty.properties = this.normalizeProperties(newProperty.properties, collection);
|
|
3286
3254
|
else if (newProperty.type === "array") {
|
|
3287
3255
|
const arrayProp = newProperty;
|
|
3288
|
-
if (arrayProp.of) if (Array.isArray(arrayProp.of)) arrayProp.of = arrayProp.of.map((p, i) => this.normalizeProperty(`${key}[${i}]`, p,
|
|
3289
|
-
else arrayProp.of = this.normalizeProperty(`${key}.of`, arrayProp.of,
|
|
3290
|
-
else if (arrayProp.oneOf && arrayProp.oneOf.properties) arrayProp.oneOf.properties = this.normalizeProperties(arrayProp.oneOf.properties,
|
|
3256
|
+
if (arrayProp.of) if (Array.isArray(arrayProp.of)) arrayProp.of = arrayProp.of.map((p, i) => this.normalizeProperty(`${key}[${i}]`, p, collection));
|
|
3257
|
+
else arrayProp.of = this.normalizeProperty(`${key}.of`, arrayProp.of, collection);
|
|
3258
|
+
else if (arrayProp.oneOf && arrayProp.oneOf.properties) arrayProp.oneOf.properties = this.normalizeProperties(arrayProp.oneOf.properties, collection);
|
|
3291
3259
|
} else if ((newProperty.type === "string" || newProperty.type === "number") && newProperty.enum) {
|
|
3292
3260
|
const stringOrNumberProperty = newProperty;
|
|
3293
3261
|
if (typeof stringOrNumberProperty.enum === "object" && !Array.isArray(stringOrNumberProperty.enum)) stringOrNumberProperty.enum = enumToObjectEntries(stringOrNumberProperty.enum)?.filter((value) => value && (value.id || value.id === 0) && value.label) ?? [];
|
|
3294
3262
|
} else if (newProperty.type === "relation") {
|
|
3295
3263
|
const relationProperty = newProperty;
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3264
|
+
if (relationProperty.relation) relationProperty.resolvedRelation = resolveRelation(relationProperty.relation, collection, key);
|
|
3265
|
+
else {
|
|
3266
|
+
const declared = resolveCollectionRelations(collection)[key];
|
|
3267
|
+
if (declared) relationProperty.resolvedRelation = declared;
|
|
3268
|
+
else console.warn(`Relation property '${key}' on '${collection.slug}' declares no \`relation\`, and the collection has no relation of that name.`);
|
|
3269
|
+
}
|
|
3300
3270
|
}
|
|
3301
3271
|
return newProperty;
|
|
3302
3272
|
}
|
|
@@ -3341,9 +3311,7 @@ var CollectionRegistry = class {
|
|
|
3341
3311
|
const relation = findRelation(resolveCollectionRelations(currentCollection), relationKey);
|
|
3342
3312
|
if (!relation) throw new Error(`Relation '${relationKey}' not found in collection '${currentCollection.slug}'`);
|
|
3343
3313
|
const target = relation.target();
|
|
3344
|
-
|
|
3345
|
-
const targetSlug = relation.overrides?.slug ?? targetRelationKey;
|
|
3346
|
-
currentCollection = this.get(targetSlug) || this.normalizeCollection(target);
|
|
3314
|
+
currentCollection = this.collectionsByTableName.get(getTableName(target)) ?? this.normalizeCollection(target);
|
|
3347
3315
|
if (i + 1 < pathSegments.length) {}
|
|
3348
3316
|
}
|
|
3349
3317
|
return currentCollection;
|
|
@@ -3378,7 +3346,7 @@ var CollectionRegistry = class {
|
|
|
3378
3346
|
if (!subcollections || subcollections.length === 0) throw new Error(`No subcollections found for ${currentCollection.slug} in path: ${path}`);
|
|
3379
3347
|
const subcollection = subcollections.find((c) => c.slug === subcollectionSlug);
|
|
3380
3348
|
if (!subcollection) throw new Error(`Subcollection '${subcollectionSlug}' not found in ${currentCollection.slug}`);
|
|
3381
|
-
currentCollection = this.
|
|
3349
|
+
currentCollection = this.normalizeCollection(subcollection);
|
|
3382
3350
|
collections.push(currentCollection);
|
|
3383
3351
|
}
|
|
3384
3352
|
}
|
|
@@ -4023,4 +3991,4 @@ async function detectJunctionTables(executeSql) {
|
|
|
4023
3991
|
//#endregion
|
|
4024
3992
|
export { DEFAULT_ONE_OF_TYPE as A, createRelationRefWithData as C, mergeDeep as D, getPolicyNamesForRule as E, camelCase as O, createRelationRef as S, updateDateAutoValues as T, getTableVarName as _, getJunctionCollectionConfig as a, getDeclaredPrimaryKeys as b, getEffectiveSecurityRules as c, securityRuleToConditions as d, findAnonymousGrants as f, getTableName as g, getEnumVarName as h, CollectionRegistry as i, DEFAULT_ONE_OF_VALUE as j, toSnakeCase as k, buildPropertyCallbacks as l, getColumnName as m, detectJunctionTables as n, getJunctionSecurityRules as o, findRelation as p, buildSdkData as r, resolveJunctionSpecs as s, classifyTable as t, policyToPostgres as u, resolveCollectionRelations as v, normalizeToEntityRelation as w, parseIdValues as x, buildCompositeId as y };
|
|
4025
3993
|
|
|
4026
|
-
//# sourceMappingURL=src-
|
|
3994
|
+
//# sourceMappingURL=src-3VmUJ8Xn.js.map
|