@rebasepro/server-postgres 0.12.1-canary.g4e7bcbf → 0.12.1-canary.g52d71ee
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/services.d.ts +6 -1
- package/dist/backup/backup-service.d.ts +10 -1
- package/dist/backup/pg-tools.d.ts +47 -0
- package/dist/{backup-service-DLb2drIH.js → backup-service-CD8o_1Sl.js} +136 -10
- package/dist/backup-service-CD8o_1Sl.js.map +1 -0
- package/dist/{ensure-collection-policies-Dv21KDMJ.js → ensure-collection-policies-ViG8XiPn.js} +2 -2
- package/dist/{ensure-collection-policies-Dv21KDMJ.js.map → ensure-collection-policies-ViG8XiPn.js.map} +1 -1
- package/dist/{ensure-collection-tables-CT6xHB1d.js → ensure-collection-tables-CBQdOETu.js} +2 -2
- package/dist/{ensure-collection-tables-CT6xHB1d.js.map → ensure-collection-tables-CBQdOETu.js.map} +1 -1
- package/dist/index.es.js +768 -537
- package/dist/index.es.js.map +1 -1
- package/dist/schema/introspect-db-constraints.d.ts +57 -0
- package/dist/schema/introspect-db-logic.d.ts +94 -5
- package/dist/schema/introspect-db-queries.d.ts +119 -0
- package/dist/schema/introspect-db-structure.d.ts +263 -0
- package/dist/schema/introspect-db-types.d.ts +11 -0
- package/dist/services/RelationService.d.ts +24 -1
- package/dist/services/channel-bus/index.d.ts +1 -7
- package/dist/services/collection-helpers.d.ts +36 -2
- package/dist/{src-BkdpiQdw.js → src-DlPBctw_.js} +72 -6
- package/dist/src-DlPBctw_.js.map +1 -0
- package/dist/utils/connection-string.d.ts +29 -0
- package/dist/utils/drizzle-conditions.d.ts +5 -4
- package/dist/utils/pg-error-utils.d.ts +16 -0
- package/package.json +6 -6
- package/src/auth/services.ts +6 -3
- package/src/backup/backup-cli.ts +41 -2
- package/src/backup/backup-service.ts +38 -5
- package/src/backup/pg-tools.ts +96 -3
- package/src/cli.ts +11 -4
- package/src/collections/validate-relations.ts +15 -0
- package/src/data-transformer.ts +9 -3
- package/src/schema/generate-drizzle-schema-logic.ts +26 -1
- package/src/schema/introspect-db-constraints.ts +385 -0
- package/src/schema/introspect-db-inference.ts +18 -8
- package/src/schema/introspect-db-logic.ts +364 -68
- package/src/schema/introspect-db-queries.ts +326 -0
- package/src/schema/introspect-db-structure.ts +670 -0
- package/src/schema/introspect-db-types.ts +56 -0
- package/src/schema/introspect-db.ts +37 -80
- package/src/services/BranchService.ts +66 -28
- package/src/services/FetchService.ts +14 -0
- package/src/services/PersistService.ts +20 -6
- package/src/services/RelationService.ts +211 -45
- package/src/services/channel-bus/index.ts +0 -9
- package/src/services/collection-helpers.ts +69 -3
- package/src/utils/connection-string.ts +58 -0
- package/src/utils/drizzle-conditions.ts +31 -6
- package/src/utils/pg-error-utils.ts +19 -0
- package/dist/backup-service-DLb2drIH.js.map +0 -1
- package/dist/src-BkdpiQdw.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PgTable, AnyPgColumn } from "drizzle-orm/pg-core";
|
|
2
|
-
import { CollectionConfig } from "@rebasepro/types";
|
|
2
|
+
import { CollectionConfig, ResolvedHasMany, ResolvedHasOne } from "@rebasepro/types";
|
|
3
3
|
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
4
|
-
export { buildCompositeId, parseIdValues, COMPOSITE_ID_SEPARATOR } from "@rebasepro/common";
|
|
4
|
+
export { buildCompositeId, parseIdValues, isAddressableId, COMPOSITE_ID_SEPARATOR } from "@rebasepro/common";
|
|
5
5
|
export type { PrimaryKeyInfo } from "@rebasepro/common";
|
|
6
6
|
import type { PrimaryKeyInfo } from "@rebasepro/common";
|
|
7
7
|
/**
|
|
@@ -22,6 +22,17 @@ export interface DrizzleColumnMeta {
|
|
|
22
22
|
}
|
|
23
23
|
/** Safely extract Drizzle column metadata from a column object. */
|
|
24
24
|
export declare function getColumnMeta(col: AnyPgColumn): DrizzleColumnMeta;
|
|
25
|
+
/**
|
|
26
|
+
* Whether an address could name a row in this table, judged by the columns.
|
|
27
|
+
*
|
|
28
|
+
* {@link getPrimaryKeys} lets a config's `isId: "uuid"` win over the schema, so
|
|
29
|
+
* its `isUUID` is a claim rather than a fact — right for deriving addresses,
|
|
30
|
+
* wrong for refusing a query. Here the Drizzle column type decides, because it
|
|
31
|
+
* is what Postgres will enforce: a `uuid` column meets `/c/products/new` with
|
|
32
|
+
* `22P02`, which aborts the surrounding transaction and turns every later
|
|
33
|
+
* statement into an unrelated-looking `25P02`.
|
|
34
|
+
*/
|
|
35
|
+
export declare function idCanAddressTable(id: string | number, table: PgTable, idInfoArray: PrimaryKeyInfo[]): boolean;
|
|
25
36
|
export declare function getCollectionByPath(collectionPath: string, registry: PostgresCollectionRegistry): CollectionConfig;
|
|
26
37
|
export declare function getTableForCollection(collection: CollectionConfig, registry: PostgresCollectionRegistry): PgTable<any>;
|
|
27
38
|
/**
|
|
@@ -55,6 +66,29 @@ export declare function getPrimaryKeys(collection: CollectionConfig, registry: P
|
|
|
55
66
|
* wrong and which collection it is wrong about.
|
|
56
67
|
*/
|
|
57
68
|
export declare function requirePrimaryKeys(collection: CollectionConfig, registry: PostgresCollectionRegistry): PrimaryKeyInfo[];
|
|
69
|
+
/**
|
|
70
|
+
* The column on the *source* table that a `hasOne`/`hasMany` link points at.
|
|
71
|
+
*
|
|
72
|
+
* `sourceKey` is authored when the two sides join on a natural key — an
|
|
73
|
+
* external identity id, a SKU — and left off when they join on the row id,
|
|
74
|
+
* which is the overwhelming majority. That makes `undefined` the only optional
|
|
75
|
+
* field on a resolved relation, so it gets exactly one reader: this function.
|
|
76
|
+
* Every consumer that needs the column asks here, and none of them re-derives
|
|
77
|
+
* "or else the primary key" for itself. That is the whole point — the fallback
|
|
78
|
+
* chains this codebase removed from relation resolution were dangerous because
|
|
79
|
+
* they were *duplicated* and could disagree, not because they existed.
|
|
80
|
+
*/
|
|
81
|
+
export declare function sourceKeyField(relation: ResolvedHasOne | ResolvedHasMany, sourceCollection: CollectionConfig, registry: PostgresCollectionRegistry): string;
|
|
82
|
+
/**
|
|
83
|
+
* Whether this link joins on something other than the source's primary key.
|
|
84
|
+
*
|
|
85
|
+
* Callers that hold a parent *id* — which is most of them, since an id is what
|
|
86
|
+
* a URL carries — must translate it to the source key's value before it can be
|
|
87
|
+
* compared with the target's foreign key. Those that hold the parent *row*, or
|
|
88
|
+
* that build a correlated subquery over the source table, can read the column
|
|
89
|
+
* directly and skip the lookup.
|
|
90
|
+
*/
|
|
91
|
+
export declare function joinsOnNaturalKey(relation: ResolvedHasOne | ResolvedHasMany, sourceCollection: CollectionConfig, registry: PostgresCollectionRegistry): boolean;
|
|
58
92
|
/**
|
|
59
93
|
* Collections whose key the *browser* cannot resolve, and what it will do
|
|
60
94
|
* instead.
|
|
@@ -1458,6 +1458,34 @@ function createRelationRefWithData(id, path, data) {
|
|
|
1458
1458
|
data
|
|
1459
1459
|
};
|
|
1460
1460
|
}
|
|
1461
|
+
/** The eight-four-four-four-twelve shape of a UUID, any version. */
|
|
1462
|
+
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1463
|
+
/** Whether one address part can be a value of the column it addresses. */
|
|
1464
|
+
function partIsAddressable(part, pk) {
|
|
1465
|
+
if (pk.isUUID) return UUID_PATTERN.test(String(part));
|
|
1466
|
+
if (pk.type === "number") return typeof part === "number" ? Number.isFinite(part) : !isNaN(parseInt(String(part), 10));
|
|
1467
|
+
return true;
|
|
1468
|
+
}
|
|
1469
|
+
/**
|
|
1470
|
+
* Whether an address could name a row at all, before asking the database.
|
|
1471
|
+
*
|
|
1472
|
+
* A `uuid` column cannot hold `"new"`, and an `integer` column cannot hold
|
|
1473
|
+
* `"abc"` — so the answer to "which row is this" is "none", and that is a 404,
|
|
1474
|
+
* not a failure. Postgres cannot say so politely: the comparison never runs, it
|
|
1475
|
+
* raises `22P02` and aborts the enclosing transaction, after which every
|
|
1476
|
+
* further statement returns the far less helpful `25P02`.
|
|
1477
|
+
*
|
|
1478
|
+
* `isUUID` must come from the column, not from `isId: "uuid"` in a config: the
|
|
1479
|
+
* config is a claim about a key, and a `text` column that holds ids of some
|
|
1480
|
+
* other shape is a working app this must not start rejecting.
|
|
1481
|
+
*/
|
|
1482
|
+
function isAddressableId(idValue, primaryKeys) {
|
|
1483
|
+
if (primaryKeys.length === 0) return false;
|
|
1484
|
+
if (primaryKeys.length === 1) return partIsAddressable(idValue, primaryKeys[0]);
|
|
1485
|
+
const parts = String(idValue).split(":::");
|
|
1486
|
+
if (parts.length !== primaryKeys.length) return false;
|
|
1487
|
+
return parts.every((part, i) => partIsAddressable(part, primaryKeys[i]));
|
|
1488
|
+
}
|
|
1461
1489
|
/**
|
|
1462
1490
|
* Derive a row's address from its key columns.
|
|
1463
1491
|
*
|
|
@@ -1598,8 +1626,7 @@ function enumToObjectEntries(enumValues) {
|
|
|
1598
1626
|
function resolveRelation(relation, sourceCollection, propertyKey) {
|
|
1599
1627
|
const target = relation.target;
|
|
1600
1628
|
if (typeof target !== "function") throw new Error(`Relation${relation.relationName ? ` '${relation.relationName}'` : ""} on '${sourceCollection.slug}' has no \`target\`. Give it a thunk: \`target: () => otherCollection\`.`);
|
|
1601
|
-
const targetCollection = target
|
|
1602
|
-
if (!targetCollection?.slug) throw new Error(`Relation${relation.relationName ? ` '${relation.relationName}'` : ""} on '${sourceCollection.slug}' has a \`target\` that did not resolve to a collection.`);
|
|
1629
|
+
const targetCollection = callTarget(relation, sourceCollection, propertyKey, target);
|
|
1603
1630
|
const relationName = relation.relationName ?? propertyKey ?? toSnakeCase(targetCollection.slug);
|
|
1604
1631
|
const shared = {
|
|
1605
1632
|
relationName,
|
|
@@ -1626,7 +1653,8 @@ function resolveRelation(relation, sourceCollection, propertyKey) {
|
|
|
1626
1653
|
cardinality: "one",
|
|
1627
1654
|
writable: true,
|
|
1628
1655
|
shared: false,
|
|
1629
|
-
foreignKeyOnTarget: relation.foreignKeyOnTarget ?? generateForeignKeyName(sourceName)
|
|
1656
|
+
foreignKeyOnTarget: relation.foreignKeyOnTarget ?? generateForeignKeyName(sourceName),
|
|
1657
|
+
sourceKey: relation.sourceKey
|
|
1630
1658
|
};
|
|
1631
1659
|
case "hasMany": return {
|
|
1632
1660
|
...shared,
|
|
@@ -1634,7 +1662,8 @@ function resolveRelation(relation, sourceCollection, propertyKey) {
|
|
|
1634
1662
|
cardinality: "many",
|
|
1635
1663
|
writable: true,
|
|
1636
1664
|
shared: false,
|
|
1637
|
-
foreignKeyOnTarget: relation.foreignKeyOnTarget ?? generateForeignKeyName(sourceName)
|
|
1665
|
+
foreignKeyOnTarget: relation.foreignKeyOnTarget ?? generateForeignKeyName(sourceName),
|
|
1666
|
+
sourceKey: relation.sourceKey
|
|
1638
1667
|
};
|
|
1639
1668
|
case "manyToMany": {
|
|
1640
1669
|
const sourceTable = getTableName(sourceCollection);
|
|
@@ -1663,6 +1692,43 @@ function resolveRelation(relation, sourceCollection, propertyKey) {
|
|
|
1663
1692
|
default: throw new Error(`Unknown relation kind: ${JSON.stringify(relation)}`);
|
|
1664
1693
|
}
|
|
1665
1694
|
}
|
|
1695
|
+
/** How this relation is addressed in an error message, before it has a resolved name. */
|
|
1696
|
+
function describe(relation, sourceCollection, propertyKey) {
|
|
1697
|
+
const name = relation.relationName ?? propertyKey;
|
|
1698
|
+
return `Relation${name ? ` '${name}'` : ""} on '${sourceCollection.slug}'`;
|
|
1699
|
+
}
|
|
1700
|
+
/**
|
|
1701
|
+
* Call the `target` thunk, and translate the two ways an import cycle breaks it
|
|
1702
|
+
* into an error that names the cause.
|
|
1703
|
+
*
|
|
1704
|
+
* The thunk exists to defer the reference until every module has finished
|
|
1705
|
+
* evaluating, and for a cycle that closes at import time it does. What it cannot
|
|
1706
|
+
* defer is a cycle that leaves the binding permanently unusable, and there are
|
|
1707
|
+
* two shapes of that:
|
|
1708
|
+
*
|
|
1709
|
+
* - **ESM/TDZ.** `const` and `class` bindings in a not-yet-evaluated module are
|
|
1710
|
+
* in the temporal dead zone, so reading one throws `ReferenceError: x is not
|
|
1711
|
+
* defined`. The stack points at the thunk — a one-line arrow function that is
|
|
1712
|
+
* obviously fine — and says nothing about the cycle that made it throw.
|
|
1713
|
+
* - **CJS interop.** The half-initialised module object has no `default` yet,
|
|
1714
|
+
* the import resolves to `undefined`, and the thunk returns it without
|
|
1715
|
+
* complaint. That one used to surface here as "did not resolve to a
|
|
1716
|
+
* collection", which is true and unhelpful.
|
|
1717
|
+
*
|
|
1718
|
+
* Both mean the same thing, and the fix for both is the same: break the cycle,
|
|
1719
|
+
* or move the relation into the collection that does not close it.
|
|
1720
|
+
*/
|
|
1721
|
+
function callTarget(relation, sourceCollection, propertyKey, target) {
|
|
1722
|
+
let targetCollection;
|
|
1723
|
+
try {
|
|
1724
|
+
targetCollection = target();
|
|
1725
|
+
} catch (error) {
|
|
1726
|
+
if (error instanceof ReferenceError) throw new Error(`${describe(relation, sourceCollection, propertyKey)} targets a collection that is not initialized yet — almost always an import cycle between the two collection files. Break the cycle (move the shared piece into a third module, or import the target lazily) so the target's module finishes evaluating before the registry is built.`, { cause: error });
|
|
1727
|
+
throw error;
|
|
1728
|
+
}
|
|
1729
|
+
if (!targetCollection?.slug) throw new Error(`${describe(relation, sourceCollection, propertyKey)} has a \`target\` that resolved to ${targetCollection === void 0 ? "`undefined`" : "something that is not a collection"}. ` + (targetCollection === void 0 ? "Under CommonJS interop an import cycle resolves the default import to `undefined`, so check whether this collection and its target import each other. Otherwise the thunk is returning the wrong value — it must return the collection itself, not a promise or a module." : "The thunk must return a collection config with a `slug`."));
|
|
1730
|
+
return targetCollection;
|
|
1731
|
+
}
|
|
1666
1732
|
//#endregion
|
|
1667
1733
|
//#region ../common/src/util/relations.ts
|
|
1668
1734
|
/**
|
|
@@ -4228,6 +4294,6 @@ function buildSdkData(driver) {
|
|
|
4228
4294
|
return wrapAsSdkData(buildRebaseData(driver));
|
|
4229
4295
|
}
|
|
4230
4296
|
//#endregion
|
|
4231
|
-
export {
|
|
4297
|
+
export { toSnakeCase as A, normalizeToEntityRelation as C, getPolicyNamesForRule as D, legacyForeignKeyName as E, Vector as F, DEFAULT_ONE_OF_VALUE as M, hasForeignKeyOnTarget as N, mergeDeep as O, isManyToMany as P, createRelationRefWithData as S, generateForeignKeyName as T, buildCompositeId as _, getJunctionSecurityRules as a, parseIdValues as b, policyToPostgres as c, findRelation as d, getColumnName as f, resolveCollectionRelations as g, getTableVarName as h, getJunctionCollectionConfig as i, DEFAULT_ONE_OF_TYPE as j, camelCase as k, securityRuleToConditions as l, getTableName as m, CollectionRegistry as n, resolveJunctionSpecs as o, getEnumVarName as p, resolveStringColumnLength as r, getEffectiveSecurityRules as s, buildSdkData as t, findAnonymousGrants as u, getDeclaredPrimaryKeys as v, updateDateAutoValues as w, createRelationRef as x, isAddressableId as y };
|
|
4232
4298
|
|
|
4233
|
-
//# sourceMappingURL=src-
|
|
4299
|
+
//# sourceMappingURL=src-DlPBctw_.js.map
|