@rebasepro/server-postgres 0.10.1-canary.d8d45b2 → 0.10.1-canary.ed8caed
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/{ensure-collection-tables-CNlIONzj.js → ensure-collection-tables-BVvtkkRm.js} +10 -10
- package/dist/ensure-collection-tables-BVvtkkRm.js.map +1 -0
- package/dist/index.es.js +344 -119
- 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 +30 -0
- package/dist/services/nested-path.d.ts +59 -0
- package/dist/{src-B0v4IKaI.js → src-CBgtrPhJ.js} +8 -1
- package/dist/{src-B0v4IKaI.js.map → src-CBgtrPhJ.js.map} +1 -1
- package/dist/{src-DmsRg8MR.js → src-lcfUP4xg.js} +126 -76
- package/dist/src-lcfUP4xg.js.map +1 -0
- package/dist/utils/drizzle-conditions.d.ts +41 -0
- package/package.json +8 -9
- package/src/schema/doctor.ts +6 -6
- package/src/schema/generate-drizzle-schema-logic.ts +13 -9
- package/src/schema/generate-postgres-ddl-logic.ts +19 -12
- package/src/schema/introspect-db-inference.ts +13 -13
- package/src/schema/introspect-db-logic.ts +6 -6
- package/src/services/FetchService.ts +104 -114
- package/src/services/PersistService.ts +127 -85
- package/src/services/RelationService.ts +95 -6
- package/src/services/nested-path.ts +130 -0
- package/src/utils/drizzle-conditions.ts +143 -0
- package/dist/ensure-collection-tables-CNlIONzj.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 { c as getDeclaredSubcollections, d as REST_TO_CANONICAL, f as toCanonicalOp, l as isPostgresCollectionConfig, n as getDataSourceCapabilities, o as ANONYMOUS_USER_ID, p as EntityRelation, s as policy, u as NULL_OPS } from "./src-
|
|
5
|
+
import { c as getDeclaredSubcollections, d as REST_TO_CANONICAL, f as toCanonicalOp, l as isPostgresCollectionConfig, n as getDataSourceCapabilities, o as ANONYMOUS_USER_ID, p as EntityRelation, s as policy, u as NULL_OPS } from "./src-CBgtrPhJ.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";
|
|
@@ -1496,6 +1496,19 @@ function sanitizeRelation(relation, sourceCollection, resolveCollection) {
|
|
|
1496
1496
|
if (newRelation.cardinality === "many" && newRelation.direction === "inverse" && !newRelation.foreignKeyOnTarget && !newRelation.joinPath && !newRelation.inverseRelationName) throw new Error(`Configuration Error in relation from '${sourceCollection.name}': An 'inverse' one-to-many relation requires a 'foreignKeyOnTarget'. Check the relation config for '${newRelation.relationName}'`);
|
|
1497
1497
|
return newRelation;
|
|
1498
1498
|
}
|
|
1499
|
+
/**
|
|
1500
|
+
* Whether the target rows of this relation are reached through a junction — a
|
|
1501
|
+
* many-to-many, or a multi-hop `joinPath`.
|
|
1502
|
+
*
|
|
1503
|
+
* The distinction decides what a write "through" the relation may touch: a
|
|
1504
|
+
* junction-backed target is shared with other parents, so the parent owns the
|
|
1505
|
+
* *link* and not the row. The backend enforces that (an unlink rather than a
|
|
1506
|
+
* delete) and the admin renders it (remove-from-parent rather than delete), so
|
|
1507
|
+
* the predicate lives here rather than once per side.
|
|
1508
|
+
*/
|
|
1509
|
+
function isJunctionBackedRelation(relation) {
|
|
1510
|
+
return Boolean(relation.through) || Boolean(relation.joinPath && relation.joinPath.length > 1);
|
|
1511
|
+
}
|
|
1499
1512
|
/** WeakMap cache — same collection instance always yields the same relation map. */
|
|
1500
1513
|
var _resolvedRelationsCache = /* @__PURE__ */ new WeakMap();
|
|
1501
1514
|
function resolveCollectionRelations(collection) {
|
|
@@ -1581,34 +1594,115 @@ function findRelation(resolvedRelations, key) {
|
|
|
1581
1594
|
}
|
|
1582
1595
|
//#endregion
|
|
1583
1596
|
//#region ../common/src/util/resolutions.ts
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1597
|
+
/**
|
|
1598
|
+
* Relation identities that only ever appear *below* the top level of
|
|
1599
|
+
* `properties` — inside a `map`, an `array`, or a `oneOf` branch.
|
|
1600
|
+
*
|
|
1601
|
+
* A relation declared at the top level is a list hanging off the record and
|
|
1602
|
+
* earns a tab. One declared inside a map is a field of that map. Both end up in
|
|
1603
|
+
* the collection's flat `relations` array after normalization, so the shape of
|
|
1604
|
+
* `properties` is the only remaining evidence of which is which.
|
|
1605
|
+
*
|
|
1606
|
+
* An identity declared in both places is *not* nested-only, and keeps its tab.
|
|
1607
|
+
*/
|
|
1608
|
+
function getNestedRelationIdentities(properties) {
|
|
1609
|
+
const topLevel = /* @__PURE__ */ new Set();
|
|
1610
|
+
const nested = /* @__PURE__ */ new Set();
|
|
1611
|
+
const walk = (props, depth) => {
|
|
1612
|
+
if (!props) return;
|
|
1613
|
+
for (const [key, property] of Object.entries(props)) {
|
|
1614
|
+
if (!property) continue;
|
|
1615
|
+
if (property.type === "relation") {
|
|
1616
|
+
const relProp = property;
|
|
1617
|
+
(depth === 0 ? topLevel : nested).add(relProp.relationName ?? key);
|
|
1618
|
+
} else if (property.type === "map") walk(property.properties, depth + 1);
|
|
1619
|
+
else if (property.type === "array") {
|
|
1620
|
+
const arrayProp = property;
|
|
1621
|
+
if (Array.isArray(arrayProp.of)) arrayProp.of.forEach((p) => walk({ entry: p }, depth + 1));
|
|
1622
|
+
else if (arrayProp.of) walk({ entry: arrayProp.of }, depth + 1);
|
|
1623
|
+
if (arrayProp.oneOf?.properties) walk(arrayProp.oneOf.properties, depth + 1);
|
|
1598
1624
|
}
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1625
|
+
}
|
|
1626
|
+
};
|
|
1627
|
+
walk(properties, 0);
|
|
1628
|
+
for (const identity of topLevel) nested.delete(identity);
|
|
1629
|
+
return nested;
|
|
1630
|
+
}
|
|
1631
|
+
/**
|
|
1632
|
+
* The lists rendered inside an entity view of `collection` — its tabs.
|
|
1633
|
+
*
|
|
1634
|
+
* The single derivation. There used to be two that disagreed: this one, and a
|
|
1635
|
+
* copy in `CollectionRegistry.normalizeCollection` that stamped each child with
|
|
1636
|
+
* the *target collection's* slug instead of the relation key. Since the
|
|
1637
|
+
* registry ran first and cached its answer onto `childCollections`, its version
|
|
1638
|
+
* was the one that won, and the frontend addressed child listings by a segment
|
|
1639
|
+
* the backend could not resolve.
|
|
1640
|
+
*
|
|
1641
|
+
* Order of precedence:
|
|
1642
|
+
* 1. `childCollections` — the explicit escape hatch for custom drivers.
|
|
1643
|
+
* 2. `subcollections` on an engine that has real containment (Firestore).
|
|
1644
|
+
* 3. many-relations on an engine that has relations (SQL).
|
|
1645
|
+
*/
|
|
1646
|
+
function getEntityChildViews(collection) {
|
|
1647
|
+
const asSubcollections = (collections) => collections.filter(Boolean).map((child) => ({
|
|
1648
|
+
key: child.slug,
|
|
1649
|
+
collection: child,
|
|
1650
|
+
source: { kind: "subcollection" }
|
|
1651
|
+
}));
|
|
1652
|
+
if (collection.childCollections) return asSubcollections(collection.childCollections() ?? []);
|
|
1653
|
+
const capabilities = getDataSourceCapabilities(collection.engine);
|
|
1654
|
+
const declaredSubcollections = getDeclaredSubcollections(collection);
|
|
1655
|
+
if (capabilities.supportsSubcollections && declaredSubcollections) return asSubcollections(declaredSubcollections() ?? []);
|
|
1656
|
+
if (!capabilities.supportsRelations) return [];
|
|
1657
|
+
const resolvedRelations = resolveCollectionRelations(collection);
|
|
1658
|
+
const nestedOnly = getNestedRelationIdentities(collection.properties);
|
|
1659
|
+
const views = [];
|
|
1660
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1661
|
+
for (const [relationKey, relation] of Object.entries(resolvedRelations)) {
|
|
1662
|
+
if (relation.cardinality !== "many") continue;
|
|
1663
|
+
const identity = relation.relationName ?? relationKey;
|
|
1664
|
+
if (seen.has(identity)) continue;
|
|
1665
|
+
if (nestedOnly.has(identity)) continue;
|
|
1666
|
+
let target;
|
|
1667
|
+
try {
|
|
1668
|
+
target = relation.target();
|
|
1669
|
+
} catch {
|
|
1670
|
+
continue;
|
|
1671
|
+
}
|
|
1672
|
+
if (!target) continue;
|
|
1673
|
+
seen.add(identity);
|
|
1674
|
+
const customName = Object.entries(collection.properties ?? {}).find(([propKey, p]) => p.type === "relation" && (p.relationName ?? propKey) === identity)?.[1]?.name;
|
|
1675
|
+
const base = {
|
|
1676
|
+
...target,
|
|
1677
|
+
slug: relationKey,
|
|
1678
|
+
...customName ? {
|
|
1679
|
+
name: customName,
|
|
1680
|
+
singularName: customName
|
|
1681
|
+
} : {}
|
|
1682
|
+
};
|
|
1683
|
+
views.push({
|
|
1684
|
+
key: relationKey,
|
|
1685
|
+
collection: relation.overrides ? mergeDeep(base, relation.overrides) : base,
|
|
1686
|
+
source: {
|
|
1687
|
+
kind: "relation",
|
|
1688
|
+
relationKey,
|
|
1689
|
+
mode: isJunctionBackedRelation(relation) ? "linked" : "owned",
|
|
1690
|
+
targetSlug: target.slug
|
|
1603
1691
|
}
|
|
1604
|
-
|
|
1605
|
-
...target,
|
|
1606
|
-
...baseOverrides
|
|
1607
|
-
};
|
|
1608
|
-
return r.overrides ? mergeDeep(targetWithOverrides, r.overrides) : targetWithOverrides;
|
|
1609
|
-
}).filter((c) => Boolean(c));
|
|
1692
|
+
});
|
|
1610
1693
|
}
|
|
1611
|
-
return
|
|
1694
|
+
return views;
|
|
1695
|
+
}
|
|
1696
|
+
/**
|
|
1697
|
+
* The child views of `collection` as bare collections.
|
|
1698
|
+
*
|
|
1699
|
+
* The flattened view of {@link getEntityChildViews}, for navigation code that
|
|
1700
|
+
* only needs to match a path segment against a slug. Anything that cares *what
|
|
1701
|
+
* kind* of list it is showing — chiefly the admin, which must not offer a
|
|
1702
|
+
* global delete on a shared row — should read the views instead.
|
|
1703
|
+
*/
|
|
1704
|
+
function getSubcollections(collection) {
|
|
1705
|
+
return getEntityChildViews(collection).map((view) => view.collection);
|
|
1612
1706
|
}
|
|
1613
1707
|
//#endregion
|
|
1614
1708
|
//#region ../common/src/util/policy/sqlToPolicy.ts
|
|
@@ -2621,39 +2715,9 @@ function getJunctionSecurityRules(spec) {
|
|
|
2621
2715
|
return jsonLogic;
|
|
2622
2716
|
});
|
|
2623
2717
|
})))();
|
|
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];
|
|
2718
|
+
/**
|
|
2719
|
+
* Apply PropertyConditions to a resolved property, evaluating all JSON Logic rules.
|
|
2720
|
+
*/
|
|
2657
2721
|
//#endregion
|
|
2658
2722
|
//#region ../../node_modules/.pnpm/fast-equals@6.0.0/node_modules/fast-equals/dist/es/index.mjs
|
|
2659
2723
|
var { getOwnPropertyNames, getOwnPropertySymbols } = Object;
|
|
@@ -3261,18 +3325,6 @@ var CollectionRegistry = class {
|
|
|
3261
3325
|
relResult.relations = mergedRelations;
|
|
3262
3326
|
}
|
|
3263
3327
|
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
|
-
}
|
|
3276
3328
|
return result;
|
|
3277
3329
|
}
|
|
3278
3330
|
/**
|
|
@@ -3371,9 +3423,7 @@ var CollectionRegistry = class {
|
|
|
3371
3423
|
const relation = findRelation(resolveCollectionRelations(currentCollection), relationKey);
|
|
3372
3424
|
if (!relation) throw new Error(`Relation '${relationKey}' not found in collection '${currentCollection.slug}'`);
|
|
3373
3425
|
const target = relation.target();
|
|
3374
|
-
|
|
3375
|
-
const targetSlug = relation.overrides?.slug ?? targetRelationKey;
|
|
3376
|
-
currentCollection = this.get(targetSlug) || this.normalizeCollection(target);
|
|
3426
|
+
currentCollection = this.collectionsByTableName.get(getTableName(target)) ?? this.normalizeCollection(target);
|
|
3377
3427
|
if (i + 1 < pathSegments.length) {}
|
|
3378
3428
|
}
|
|
3379
3429
|
return currentCollection;
|
|
@@ -3408,7 +3458,7 @@ var CollectionRegistry = class {
|
|
|
3408
3458
|
if (!subcollections || subcollections.length === 0) throw new Error(`No subcollections found for ${currentCollection.slug} in path: ${path}`);
|
|
3409
3459
|
const subcollection = subcollections.find((c) => c.slug === subcollectionSlug);
|
|
3410
3460
|
if (!subcollection) throw new Error(`Subcollection '${subcollectionSlug}' not found in ${currentCollection.slug}`);
|
|
3411
|
-
currentCollection = this.
|
|
3461
|
+
currentCollection = this.normalizeCollection(subcollection);
|
|
3412
3462
|
collections.push(currentCollection);
|
|
3413
3463
|
}
|
|
3414
3464
|
}
|
|
@@ -4053,4 +4103,4 @@ async function detectJunctionTables(executeSql) {
|
|
|
4053
4103
|
//#endregion
|
|
4054
4104
|
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
4105
|
|
|
4056
|
-
//# sourceMappingURL=src-
|
|
4106
|
+
//# sourceMappingURL=src-lcfUP4xg.js.map
|