@rebasepro/server-postgres 0.10.1-canary.d8d45b2 → 0.10.1-canary.ed78a2c
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-CNlIONzj.js → ensure-collection-tables-DGMYK0fr.js} +12 -12
- package/dist/ensure-collection-tables-DGMYK0fr.js.map +1 -0
- package/dist/index.es.js +913 -391
- 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-DmsRg8MR.js → src-3VmUJ8Xn.js} +214 -276
- package/dist/src-3VmUJ8Xn.js.map +1 -0
- package/dist/{src-B0v4IKaI.js → src-D5xBTl32.js} +19 -2
- package/dist/src-D5xBTl32.js.map +1 -0
- package/dist/utils/drizzle-conditions.d.ts +71 -18
- package/package.json +8 -9
- 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 +14 -14
- package/src/schema/generate-drizzle-schema-logic.ts +62 -110
- package/src/schema/generate-postgres-ddl-logic.ts +28 -21
- package/src/schema/introspect-db-inference.ts +13 -13
- package/src/schema/introspect-db-logic.ts +25 -29
- 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-CNlIONzj.js.map +0 -1
- package/dist/src-B0v4IKaI.js.map +0 -1
- package/dist/src-DmsRg8MR.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;
|
|
@@ -2621,39 +2658,9 @@ function getJunctionSecurityRules(spec) {
|
|
|
2621
2658
|
return jsonLogic;
|
|
2622
2659
|
});
|
|
2623
2660
|
})))();
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
* Default operators offered per property type, before engine capabilities and
|
|
2628
|
-
* per-property narrowing are applied. These mirror what the built-in filter
|
|
2629
|
-
* fields can render.
|
|
2630
|
-
*/
|
|
2631
|
-
var COMPARISON_OPS = [
|
|
2632
|
-
"==",
|
|
2633
|
-
"!=",
|
|
2634
|
-
">",
|
|
2635
|
-
">=",
|
|
2636
|
-
"<",
|
|
2637
|
-
"<="
|
|
2638
|
-
];
|
|
2639
|
-
var NULL_CHECK_OPS = ["is-null", "is-not-null"];
|
|
2640
|
-
var MEMBERSHIP_OPS = ["in", "not-in"];
|
|
2641
|
-
var PATTERN_OPS = [
|
|
2642
|
-
"like",
|
|
2643
|
-
"ilike",
|
|
2644
|
-
"not-like",
|
|
2645
|
-
"not-ilike"
|
|
2646
|
-
];
|
|
2647
|
-
[
|
|
2648
|
-
...COMPARISON_OPS,
|
|
2649
|
-
...MEMBERSHIP_OPS,
|
|
2650
|
-
...PATTERN_OPS,
|
|
2651
|
-
...NULL_CHECK_OPS
|
|
2652
|
-
], [
|
|
2653
|
-
...COMPARISON_OPS,
|
|
2654
|
-
...MEMBERSHIP_OPS,
|
|
2655
|
-
...NULL_CHECK_OPS
|
|
2656
|
-
], [...COMPARISON_OPS, ...NULL_CHECK_OPS], [...NULL_CHECK_OPS], [...MEMBERSHIP_OPS, ...NULL_CHECK_OPS], [...MEMBERSHIP_OPS, ...NULL_CHECK_OPS];
|
|
2661
|
+
/**
|
|
2662
|
+
* Apply PropertyConditions to a resolved property, evaluating all JSON Logic rules.
|
|
2663
|
+
*/
|
|
2657
2664
|
//#endregion
|
|
2658
2665
|
//#region ../../node_modules/.pnpm/fast-equals@6.0.0/node_modules/fast-equals/dist/es/index.mjs
|
|
2659
2666
|
var { getOwnPropertyNames, getOwnPropertySymbols } = Object;
|
|
@@ -3233,100 +3240,33 @@ var CollectionRegistry = class {
|
|
|
3233
3240
|
if (!result.dataSource) result.dataSource = resolved.key;
|
|
3234
3241
|
if (!result.engine) result.engine = resolved.engine;
|
|
3235
3242
|
}
|
|
3236
|
-
|
|
3237
|
-
const relResult = result;
|
|
3238
|
-
const manualRelations = getDataSourceCapabilities(result.engine).supportsRelations ? relResult.relations ?? [] : [];
|
|
3239
|
-
const mergedRelationsRaw = [...extractedRelations];
|
|
3240
|
-
for (const manual of manualRelations) {
|
|
3241
|
-
const name = manual.relationName;
|
|
3242
|
-
if (!name) mergedRelationsRaw.push(manual);
|
|
3243
|
-
else {
|
|
3244
|
-
const existingIndex = mergedRelationsRaw.findIndex((r) => r.relationName === name);
|
|
3245
|
-
if (existingIndex === -1) mergedRelationsRaw.push(manual);
|
|
3246
|
-
else mergedRelationsRaw[existingIndex] = {
|
|
3247
|
-
...manual,
|
|
3248
|
-
...mergedRelationsRaw[existingIndex]
|
|
3249
|
-
};
|
|
3250
|
-
}
|
|
3251
|
-
}
|
|
3252
|
-
let mergedRelations = mergedRelationsRaw;
|
|
3253
|
-
if (getDataSourceCapabilities(result.engine).supportsRelations) {
|
|
3254
|
-
mergedRelations = mergedRelationsRaw.map((r) => {
|
|
3255
|
-
try {
|
|
3256
|
-
return sanitizeRelation(r, result, (slug) => this.get(slug));
|
|
3257
|
-
} catch {
|
|
3258
|
-
return r;
|
|
3259
|
-
}
|
|
3260
|
-
});
|
|
3261
|
-
relResult.relations = mergedRelations;
|
|
3262
|
-
}
|
|
3263
|
-
result.properties = this.normalizeProperties(result.properties, mergedRelations);
|
|
3264
|
-
if (!result.childCollections) {
|
|
3265
|
-
const capabilities = getDataSourceCapabilities(result.engine);
|
|
3266
|
-
const declaredSubcollections = getDeclaredSubcollections(result);
|
|
3267
|
-
if (capabilities.supportsSubcollections && declaredSubcollections) result.childCollections = declaredSubcollections;
|
|
3268
|
-
else if (capabilities.supportsRelations && relResult.relations) {
|
|
3269
|
-
const manyRelations = relResult.relations.filter((r) => r.cardinality === "many");
|
|
3270
|
-
if (manyRelations.length > 0) result.childCollections = () => manyRelations.map((r) => {
|
|
3271
|
-
const target = r.target();
|
|
3272
|
-
return r.overrides ? mergeDeep(target, r.overrides) : target;
|
|
3273
|
-
});
|
|
3274
|
-
}
|
|
3275
|
-
}
|
|
3243
|
+
result.properties = this.normalizeProperties(result.properties, result);
|
|
3276
3244
|
return result;
|
|
3277
3245
|
}
|
|
3278
|
-
|
|
3279
|
-
* Extract Relation[] from properties that have inline relation config (i.e. `target` is set).
|
|
3280
|
-
* This allows developers to define relations directly on properties without a separate
|
|
3281
|
-
* `relations[]` entry on the collection.
|
|
3282
|
-
*/
|
|
3283
|
-
extractRelationsFromProperties(properties) {
|
|
3284
|
-
const relations = [];
|
|
3285
|
-
for (const [key, property] of Object.entries(properties)) if (property.type === "relation") {
|
|
3286
|
-
const relProp = property;
|
|
3287
|
-
const target = relProp.target ?? relProp.relation?.target;
|
|
3288
|
-
if (target) {
|
|
3289
|
-
const relationName = relProp.relationName ?? relProp.relation?.relationName ?? key;
|
|
3290
|
-
relations.push({
|
|
3291
|
-
relationName,
|
|
3292
|
-
target,
|
|
3293
|
-
cardinality: relProp.cardinality ?? relProp.relation?.cardinality ?? "one",
|
|
3294
|
-
direction: relProp.direction ?? relProp.relation?.direction ?? "owning",
|
|
3295
|
-
inverseRelationName: relProp.inverseRelationName ?? relProp.relation?.inverseRelationName,
|
|
3296
|
-
localKey: relProp.localKey ?? relProp.relation?.localKey,
|
|
3297
|
-
foreignKeyOnTarget: relProp.foreignKeyOnTarget ?? relProp.relation?.foreignKeyOnTarget,
|
|
3298
|
-
through: relProp.through ?? relProp.relation?.through,
|
|
3299
|
-
joinPath: relProp.joinPath ?? relProp.relation?.joinPath,
|
|
3300
|
-
onUpdate: relProp.onUpdate ?? relProp.relation?.onUpdate,
|
|
3301
|
-
onDelete: relProp.onDelete ?? relProp.relation?.onDelete,
|
|
3302
|
-
overrides: relProp.overrides ?? relProp.relation?.overrides
|
|
3303
|
-
});
|
|
3304
|
-
}
|
|
3305
|
-
} else if (property.type === "map" && property.properties) relations.push(...this.extractRelationsFromProperties(property.properties));
|
|
3306
|
-
return relations;
|
|
3307
|
-
}
|
|
3308
|
-
normalizeProperties(properties, relations) {
|
|
3246
|
+
normalizeProperties(properties, collection) {
|
|
3309
3247
|
const newProperties = {};
|
|
3310
|
-
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);
|
|
3311
3249
|
return newProperties;
|
|
3312
3250
|
}
|
|
3313
|
-
normalizeProperty(key, property,
|
|
3251
|
+
normalizeProperty(key, property, collection) {
|
|
3314
3252
|
const newProperty = { ...property };
|
|
3315
|
-
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);
|
|
3316
3254
|
else if (newProperty.type === "array") {
|
|
3317
3255
|
const arrayProp = newProperty;
|
|
3318
|
-
if (arrayProp.of) if (Array.isArray(arrayProp.of)) arrayProp.of = arrayProp.of.map((p, i) => this.normalizeProperty(`${key}[${i}]`, p,
|
|
3319
|
-
else arrayProp.of = this.normalizeProperty(`${key}.of`, arrayProp.of,
|
|
3320
|
-
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);
|
|
3321
3259
|
} else if ((newProperty.type === "string" || newProperty.type === "number") && newProperty.enum) {
|
|
3322
3260
|
const stringOrNumberProperty = newProperty;
|
|
3323
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) ?? [];
|
|
3324
3262
|
} else if (newProperty.type === "relation") {
|
|
3325
3263
|
const relationProperty = newProperty;
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
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
|
+
}
|
|
3330
3270
|
}
|
|
3331
3271
|
return newProperty;
|
|
3332
3272
|
}
|
|
@@ -3371,9 +3311,7 @@ var CollectionRegistry = class {
|
|
|
3371
3311
|
const relation = findRelation(resolveCollectionRelations(currentCollection), relationKey);
|
|
3372
3312
|
if (!relation) throw new Error(`Relation '${relationKey}' not found in collection '${currentCollection.slug}'`);
|
|
3373
3313
|
const target = relation.target();
|
|
3374
|
-
|
|
3375
|
-
const targetSlug = relation.overrides?.slug ?? targetRelationKey;
|
|
3376
|
-
currentCollection = this.get(targetSlug) || this.normalizeCollection(target);
|
|
3314
|
+
currentCollection = this.collectionsByTableName.get(getTableName(target)) ?? this.normalizeCollection(target);
|
|
3377
3315
|
if (i + 1 < pathSegments.length) {}
|
|
3378
3316
|
}
|
|
3379
3317
|
return currentCollection;
|
|
@@ -3408,7 +3346,7 @@ var CollectionRegistry = class {
|
|
|
3408
3346
|
if (!subcollections || subcollections.length === 0) throw new Error(`No subcollections found for ${currentCollection.slug} in path: ${path}`);
|
|
3409
3347
|
const subcollection = subcollections.find((c) => c.slug === subcollectionSlug);
|
|
3410
3348
|
if (!subcollection) throw new Error(`Subcollection '${subcollectionSlug}' not found in ${currentCollection.slug}`);
|
|
3411
|
-
currentCollection = this.
|
|
3349
|
+
currentCollection = this.normalizeCollection(subcollection);
|
|
3412
3350
|
collections.push(currentCollection);
|
|
3413
3351
|
}
|
|
3414
3352
|
}
|
|
@@ -4053,4 +3991,4 @@ async function detectJunctionTables(executeSql) {
|
|
|
4053
3991
|
//#endregion
|
|
4054
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 };
|
|
4055
3993
|
|
|
4056
|
-
//# sourceMappingURL=src-
|
|
3994
|
+
//# sourceMappingURL=src-3VmUJ8Xn.js.map
|