@rebasepro/server-postgres 0.22.0 → 0.23.0
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/{BranchService-CucnFcSE.js → BranchService-DGPL6G_C.js} +2 -2
- package/dist/{BranchService-CucnFcSE.js.map → BranchService-DGPL6G_C.js.map} +1 -1
- package/dist/PostgresBackendDriver.d.ts +41 -1
- package/dist/auth/services.d.ts +27 -8
- package/dist/backup/backup-cli.d.ts +22 -0
- package/dist/{backup-cli-DqBakiMO.js → backup-cli-24v4OlSp.js} +17 -14
- package/dist/backup-cli-24v4OlSp.js.map +1 -0
- package/dist/{backup-service-CaMOS76G.js → backup-service-HQ9GC4tN.js} +2 -2
- package/dist/{backup-service-CaMOS76G.js.map → backup-service-HQ9GC4tN.js.map} +1 -1
- package/dist/{cli-errors-Dka89exj.js → cli-errors-B8qHg02P.js} +6 -1
- package/dist/cli-errors-B8qHg02P.js.map +1 -0
- package/dist/cli-flags-BglvpjHv.js +138 -0
- package/dist/cli-flags-BglvpjHv.js.map +1 -0
- package/dist/cli-flags.d.ts +28 -0
- package/dist/cli-helpers.d.ts +6 -0
- package/dist/cli-scratch-database.d.ts +34 -0
- package/dist/cli.js +97 -261
- package/dist/cli.js.map +1 -1
- package/dist/{column-plan-helpers-CpILzHJS.js → column-plan-helpers-DF-8dTVa.js} +16 -20
- package/dist/column-plan-helpers-DF-8dTVa.js.map +1 -0
- package/dist/{doctor-CU9IogdL.js → doctor-Cb2thZ8s.js} +8 -7
- package/dist/doctor-Cb2thZ8s.js.map +1 -0
- package/dist/{ensure-collection-policies-Dzd-2S81.js → ensure-collection-policies-RHUcEp4v.js} +5 -5
- package/dist/{ensure-collection-policies-Dzd-2S81.js.map → ensure-collection-policies-RHUcEp4v.js.map} +1 -1
- package/dist/{ensure-collection-tables-CpAgy51F.js → ensure-collection-tables-BEEjn5cn.js} +53 -22
- package/dist/ensure-collection-tables-BEEjn5cn.js.map +1 -0
- package/dist/{ensure-tables-Cr5B4UmH.js → ensure-tables-Dhn9KM3B.js} +2 -2
- package/dist/{ensure-tables-Cr5B4UmH.js.map → ensure-tables-Dhn9KM3B.js.map} +1 -1
- package/dist/{generate-drizzle-schema-logic-BcMl7VSy.js → generate-drizzle-schema-logic-BfzK7UQd.js} +2 -2
- package/dist/{generate-drizzle-schema-logic-BcMl7VSy.js.map → generate-drizzle-schema-logic-BfzK7UQd.js.map} +1 -1
- package/dist/{generate-drizzle-schema-B537GIvz.js → generate-drizzle-schema-yzY_BLhr.js} +2 -2
- package/dist/{generate-drizzle-schema-B537GIvz.js.map → generate-drizzle-schema-yzY_BLhr.js.map} +1 -1
- package/dist/{generate-postgres-ddl-logic-D7imhYV8.js → generate-postgres-ddl-logic-Bt2d2mRH.js} +2 -2
- package/dist/{generate-postgres-ddl-logic-D7imhYV8.js.map → generate-postgres-ddl-logic-Bt2d2mRH.js.map} +1 -1
- package/dist/index.es.js +1508 -355
- package/dist/index.es.js.map +1 -1
- package/dist/{introspect-db-logic-C6LQdTxj.js → introspect-db-logic-WMuAfxvw.js} +323 -4
- package/dist/introspect-db-logic-WMuAfxvw.js.map +1 -0
- package/dist/{plan-schema-CboAIwLN.js → plan-schema-C0fxM8dY.js} +158 -31
- package/dist/plan-schema-C0fxM8dY.js.map +1 -0
- package/dist/{policy-drift-xJfy9xG7.js → policy-drift-DljYdrpW.js} +2 -2
- package/dist/{policy-drift-xJfy9xG7.js.map → policy-drift-DljYdrpW.js.map} +1 -1
- package/dist/{rls-bootstrap-sql-H3rCFi3F.js → rls-bootstrap-sql-B8EclDyM.js} +320 -17
- package/dist/rls-bootstrap-sql-B8EclDyM.js.map +1 -0
- package/dist/schema/atlas-argv.d.ts +15 -0
- package/dist/schema/column-plan-helpers.d.ts +23 -4
- package/dist/schema/destructive-sql.d.ts +52 -1
- package/dist/schema/doctor-cli.js +3 -3
- package/dist/schema/generate-drizzle-schema.js +1 -1
- package/dist/schema/generate-postgres-ddl.js +1 -1
- package/dist/schema/introspect-db.js +1 -312
- package/dist/schema/introspect-db.js.map +1 -1
- package/dist/schema/plan/diff-plan.d.ts +3 -2
- package/dist/schema/plan/plan-schema.d.ts +10 -3
- package/dist/schema/plan/types.d.ts +6 -1
- package/dist/services/FetchService.d.ts +97 -28
- package/dist/services/PersistService.d.ts +41 -5
- package/dist/services/RelationService.d.ts +11 -0
- package/dist/services/RelationWriteService.d.ts +6 -0
- package/dist/services/cdc/CdcListener.d.ts +6 -1
- package/dist/services/collection-helpers.d.ts +11 -0
- package/dist/services/dataService.d.ts +3 -20
- package/dist/services/field-op-sql.d.ts +71 -0
- package/dist/services/junction-writes.d.ts +19 -3
- package/dist/services/pg-notify-listener.d.ts +7 -0
- package/dist/services/read-field-access.d.ts +19 -0
- package/dist/services/realtimeService.d.ts +77 -3
- package/dist/services/row-pipeline.d.ts +5 -0
- package/dist/services/soft-delete.d.ts +0 -2
- package/dist/services/write-transaction-scope.d.ts +39 -0
- package/dist/utils/drizzle-conditions.d.ts +7 -2
- package/dist/websocket.d.ts +10 -3
- package/package.json +9 -9
- package/dist/backup-cli-DqBakiMO.js.map +0 -1
- package/dist/cli-errors-Dka89exj.js.map +0 -1
- package/dist/column-plan-helpers-CpILzHJS.js.map +0 -1
- package/dist/doctor-CU9IogdL.js.map +0 -1
- package/dist/ensure-collection-tables-CpAgy51F.js.map +0 -1
- package/dist/introspect-db-logic-C6LQdTxj.js.map +0 -1
- package/dist/plan-schema-CboAIwLN.js.map +0 -1
- package/dist/rls-bootstrap-sql-H3rCFi3F.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from "module";
|
|
2
2
|
__createRequire(import.meta.url);
|
|
3
|
-
import { a as
|
|
3
|
+
import { a as getPrimaryKeyColumn, c as idColumnDefault, i as enumLabelsOf, l as isIdProperty, o as getPrimaryKeyName, r as declaresEnumType, s as getPrimaryKeyProp, t as assertSinglePrimaryKey, u as resolveColumnName } from "./column-plan-helpers-DF-8dTVa.js";
|
|
4
4
|
import { i as isAuthCollection, n as authUsersColumnDefinition, r as authUsersColumnSql, t as AUTH_USERS_COLUMNS } from "./auth-users-columns-D2LBFrMH.js";
|
|
5
5
|
import { c as vectorExtensionStatement, n as buildVectorColumnSpecs, o as vectorExtensionDeclared, r as buildVectorIndexPlan } from "./vector-index-CMJKb3C9.js";
|
|
6
6
|
import { a as deriveIndexName, t as buildCollectionIndexSpecs } from "./collection-index-DdnsxiJ_.js";
|
|
@@ -622,14 +622,30 @@ var foreignKeyPlan = (args) => {
|
|
|
622
622
|
* The type a column pointing at this collection's primary key must have — a
|
|
623
623
|
* junction endpoint, a `belongsTo` foreign key, a `reference`.
|
|
624
624
|
*
|
|
625
|
-
*
|
|
626
|
-
*
|
|
627
|
-
*
|
|
625
|
+
* The key's own column type, from the same functions that typed the key: a
|
|
626
|
+
* foreign key only holds between compatible types, so any second reading of
|
|
627
|
+
* the key is a constraint waiting to fail. This used to look at the id
|
|
628
|
+
* strategy alone, so `id: { isId: true, columnType: "uuid" }` was referenced by
|
|
629
|
+
* TEXT columns (42804 — the constraint was never created) and a `bigint` key by
|
|
630
|
+
* INTEGER ones, which overflow at 2^31.
|
|
631
|
+
*
|
|
632
|
+
* One exception: a `serial` key owns a sequence, and a column pointing at it is
|
|
633
|
+
* the plain integer of the same width — `SERIAL` there would give every
|
|
634
|
+
* referencing column a sequence of its own.
|
|
628
635
|
*/
|
|
629
636
|
var primaryKeyPgType = (collection) => {
|
|
630
|
-
const
|
|
631
|
-
if (
|
|
632
|
-
|
|
637
|
+
const { name, prop } = getPrimaryKeyProp(collection);
|
|
638
|
+
if (prop?.type === "number") return withoutSequence(numberType(name, prop, collection, true));
|
|
639
|
+
if (prop?.type === "string") return stringType(name, prop, collection);
|
|
640
|
+
return { kind: "text" };
|
|
641
|
+
};
|
|
642
|
+
var withoutSequence = (type) => {
|
|
643
|
+
switch (type.kind) {
|
|
644
|
+
case "smallserial": return { kind: "smallint" };
|
|
645
|
+
case "serial": return { kind: "integer" };
|
|
646
|
+
case "bigserial": return { kind: "bigint" };
|
|
647
|
+
default: return type;
|
|
648
|
+
}
|
|
633
649
|
};
|
|
634
650
|
/** The `columnType`s a `number` property may name, and what each one is. */
|
|
635
651
|
var NUMBER_COLUMN_TYPES = {
|
|
@@ -766,6 +782,33 @@ var linkTarget = (propName, prop, collection, resolveCollection) => {
|
|
|
766
782
|
return;
|
|
767
783
|
}
|
|
768
784
|
};
|
|
785
|
+
/** A value already written as a day, or as a time of day. */
|
|
786
|
+
var BARE_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
787
|
+
var BARE_TIME = /^\d{2}:\d{2}(:\d{2}(\.\d+)?)?$/;
|
|
788
|
+
/**
|
|
789
|
+
* A date default in the shape its column's type accepts: a day for `date`, a
|
|
790
|
+
* time of day for `time`, an instant for a timestamp.
|
|
791
|
+
*
|
|
792
|
+
* Rendered as a full ISO timestamp whatever the column, a `time` column's
|
|
793
|
+
* DEFAULT was `'2024-03-01T15:30:00.000Z'`, which Postgres refuses — "invalid
|
|
794
|
+
* input syntax for type time" — so the schema would not apply. A value already
|
|
795
|
+
* written in the column's shape (`"2024-12-25"`, `"09:00"`) is kept as written;
|
|
796
|
+
* anything else is read as an instant and its UTC day or time of day taken, the
|
|
797
|
+
* same zone the timestamp rendering has always used. A string that is no date
|
|
798
|
+
* at all is no DEFAULT, rather than a schema that cannot be applied.
|
|
799
|
+
*/
|
|
800
|
+
var dateDefaultLiteral = (value, type) => {
|
|
801
|
+
if (typeof value === "string") {
|
|
802
|
+
if (type.kind === "date" && BARE_DATE.test(value)) return value;
|
|
803
|
+
if (type.kind === "time" && BARE_TIME.test(value)) return value;
|
|
804
|
+
}
|
|
805
|
+
const instant = value instanceof Date ? value : typeof value === "string" ? new Date(value) : void 0;
|
|
806
|
+
if (!instant || Number.isNaN(instant.getTime())) return void 0;
|
|
807
|
+
const iso = instant.toISOString();
|
|
808
|
+
if (type.kind === "date") return iso.slice(0, 10);
|
|
809
|
+
if (type.kind === "time") return iso.slice(11, 23);
|
|
810
|
+
return typeof value === "string" ? value : iso;
|
|
811
|
+
};
|
|
769
812
|
/**
|
|
770
813
|
* A `defaultValue` as a database DEFAULT.
|
|
771
814
|
*
|
|
@@ -800,11 +843,11 @@ var literalDefault = (prop, type) => {
|
|
|
800
843
|
sql: value ? "TRUE" : "FALSE"
|
|
801
844
|
} : void 0;
|
|
802
845
|
case "date": {
|
|
803
|
-
const
|
|
804
|
-
return
|
|
846
|
+
const literal = dateDefaultLiteral(value, type);
|
|
847
|
+
return literal === void 0 ? void 0 : {
|
|
805
848
|
kind: "literal",
|
|
806
|
-
value:
|
|
807
|
-
sql: quoteSqlLiteral(
|
|
849
|
+
value: literal,
|
|
850
|
+
sql: quoteSqlLiteral(literal)
|
|
808
851
|
};
|
|
809
852
|
}
|
|
810
853
|
case "map":
|
|
@@ -893,7 +936,7 @@ function planSchema(allCollections, options = {}) {
|
|
|
893
936
|
const declaredSchemas = Array.from(new Set(collections.map((c) => isPostgresCollectionConfig(c) ? c.schema : void 0).filter(Boolean)));
|
|
894
937
|
const schemas = Array.from(/* @__PURE__ */ new Set([REBASE_SCHEMA, ...declaredSchemas]));
|
|
895
938
|
const enums = [];
|
|
896
|
-
const
|
|
939
|
+
const enumOwners = /* @__PURE__ */ new Map();
|
|
897
940
|
/**
|
|
898
941
|
* Every enum type one table's properties declare, appended once.
|
|
899
942
|
*
|
|
@@ -911,10 +954,21 @@ function planSchema(allCollections, options = {}) {
|
|
|
911
954
|
const labels = enumLabelsOf(propName, prop, collection);
|
|
912
955
|
if (!declaresEnumType(prop)) continue;
|
|
913
956
|
const schema = schemaOf(collection);
|
|
914
|
-
const
|
|
915
|
-
const
|
|
916
|
-
|
|
917
|
-
|
|
957
|
+
const table = getTableName(collection);
|
|
958
|
+
const column = resolveColumnName(propName, prop);
|
|
959
|
+
const name = `${table}_${column}`;
|
|
960
|
+
const qualified = `${schema}.${toPostgresIdentifier(name)}`;
|
|
961
|
+
const owner = `property "${propName}" of collection "${describe(collection)}"`;
|
|
962
|
+
const claimed = enumOwners.get(qualified);
|
|
963
|
+
if (claimed) {
|
|
964
|
+
if (claimed.table === table && claimed.column === column) continue;
|
|
965
|
+
throw new Error(`The enum ${owner} and the enum ${claimed.owner} both derive the Postgres type "${schema}"."${toPostgresIdentifier(name)}" (an enum type is named <table>_<column>, and Postgres keeps the first 63 bytes). One type cannot hold both columns' values, and a type's name cannot change once a database holds it. Give one of the two columns another name with \`columnName\`, or its collection another \`table\` or \`schema\`.`);
|
|
966
|
+
}
|
|
967
|
+
enumOwners.set(qualified, {
|
|
968
|
+
table,
|
|
969
|
+
column,
|
|
970
|
+
owner
|
|
971
|
+
});
|
|
918
972
|
enums.push({
|
|
919
973
|
schema,
|
|
920
974
|
name,
|
|
@@ -927,12 +981,14 @@ function planSchema(allCollections, options = {}) {
|
|
|
927
981
|
};
|
|
928
982
|
for (const collection of collections) collectEnumTypes(collection, collection.properties ?? {}, isPostgresCollectionConfig(collection) ? collection.schema : void 0);
|
|
929
983
|
const tableEntries = /* @__PURE__ */ new Map();
|
|
984
|
+
const junctionShapes = /* @__PURE__ */ new Map();
|
|
930
985
|
for (const collection of collections) {
|
|
931
986
|
const tableName = getTableName(collection);
|
|
932
987
|
if (tableName) tableEntries.set(tableName, { collection });
|
|
933
|
-
for (const relation of Object.
|
|
988
|
+
for (const [relationKey, relation] of Object.entries(resolveCollectionRelations(collection))) {
|
|
934
989
|
if (!isManyToMany(relation)) continue;
|
|
935
990
|
const junctionTable = relation.through.table;
|
|
991
|
+
assertOneJunctionShape(junctionShapes, junctionTable, collection, relation.relationName ?? relationKey, relation);
|
|
936
992
|
if (tableEntries.has(junctionTable)) continue;
|
|
937
993
|
tableEntries.set(junctionTable, {
|
|
938
994
|
collection: {
|
|
@@ -984,6 +1040,38 @@ function planSchema(allCollections, options = {}) {
|
|
|
984
1040
|
options
|
|
985
1041
|
};
|
|
986
1042
|
}
|
|
1043
|
+
/**
|
|
1044
|
+
* Refuse two many-to-many relations that resolve to one junction table with
|
|
1045
|
+
* different key columns.
|
|
1046
|
+
*
|
|
1047
|
+
* A default `through` is named after the two tables, so `posts.tags` and
|
|
1048
|
+
* `posts.featuredTags` both resolve to `posts_tags` — one keyed by `tag_id`,
|
|
1049
|
+
* the other by `featured_tag_id`. One table is created, from whichever came
|
|
1050
|
+
* first, so the other relation read and wrote a column that was never there.
|
|
1051
|
+
* The two sides of one link (`posts.tags` and `tags.posts`) share a junction
|
|
1052
|
+
* legitimately, and they name the same two columns — so the comparison is of
|
|
1053
|
+
* the (column, endpoint) pairs, in either order.
|
|
1054
|
+
*/
|
|
1055
|
+
function assertOneJunctionShape(seen, junctionTable, collection, relationName, relation) {
|
|
1056
|
+
if (!isManyToMany(relation)) return;
|
|
1057
|
+
const target = relation.target();
|
|
1058
|
+
if (!target) return;
|
|
1059
|
+
const sourceTable = getTableName(collection);
|
|
1060
|
+
const targetTable = getTableName(target);
|
|
1061
|
+
const { sourceColumn, targetColumn } = relation.through;
|
|
1062
|
+
const keys = JSON.stringify([[sourceColumn, sourceTable], [targetColumn, targetTable]].sort());
|
|
1063
|
+
const claim = `the relation "${relationName}" of collection "${describe(collection)}" ("${sourceColumn}" → ${sourceTable}, "${targetColumn}" → ${targetTable})`;
|
|
1064
|
+
const first = seen.get(junctionTable);
|
|
1065
|
+
if (!first) {
|
|
1066
|
+
seen.set(junctionTable, {
|
|
1067
|
+
keys,
|
|
1068
|
+
claim
|
|
1069
|
+
});
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1072
|
+
if (first.keys === keys) return;
|
|
1073
|
+
throw new Error(`Two many-to-many relations resolve to the junction table "${junctionTable}" with different key columns: ${first.claim} and ${claim}. Only one table is created, so one of them would read and write columns that do not exist. Give the second its own junction — \`through: { table: "${sourceTable}_${toSnakeCase(relationName)}" }\` — or, if both are meant to be one link, declare it once.`);
|
|
1074
|
+
}
|
|
987
1075
|
function planCollectionTable(collection, resolveCollection, triggerFunctionNeeded) {
|
|
988
1076
|
const schema = schemaOf(collection);
|
|
989
1077
|
const table = bareTableName(getTableName(collection));
|
|
@@ -1083,6 +1171,7 @@ function planCollectionTable(collection, resolveCollection, triggerFunctionNeede
|
|
|
1083
1171
|
const injected = new Set(getInjectedSecurityRules(collection).map((rule) => rule.name));
|
|
1084
1172
|
const policies = getEffectiveSecurityRules(collection).flatMap((rule, index) => compileSecurityRule(collection, rule, resolveCollection, Boolean(rule.name && injected.has(rule.name)), rule.name ?? `#${index}`));
|
|
1085
1173
|
const tenantIndexes = applyTenantColumnEffects(collection, columns, schema, table);
|
|
1174
|
+
settleDefaultOnDelete(collection, columns, relations);
|
|
1086
1175
|
return {
|
|
1087
1176
|
schema,
|
|
1088
1177
|
table,
|
|
@@ -1222,19 +1311,58 @@ function applyTenantColumnEffects(collection, columns, schema, table) {
|
|
|
1222
1311
|
* column — for the shape the documentation recommends.
|
|
1223
1312
|
*/
|
|
1224
1313
|
function findTenantColumn(collection, columns, field) {
|
|
1225
|
-
const
|
|
1314
|
+
const created = columns.filter((c) => !c.columnOwnedByProperty);
|
|
1315
|
+
const direct = created.find((c) => c.key === field);
|
|
1226
1316
|
if (direct) return direct;
|
|
1227
1317
|
const prop = collection.properties?.[field];
|
|
1228
1318
|
if (prop?.type === "relation") {
|
|
1229
1319
|
const relation = findRelation(resolveCollectionRelations(collection), prop.relation?.relationName ?? field);
|
|
1230
|
-
if (relation?.kind === "belongsTo" && relation.localKey) return
|
|
1320
|
+
if (relation?.kind === "belongsTo" && relation.localKey) return created.find((c) => c.column === relation.localKey);
|
|
1231
1321
|
return;
|
|
1232
1322
|
}
|
|
1233
1323
|
if (!prop) return void 0;
|
|
1234
1324
|
const columnName = resolveColumnName(field, prop);
|
|
1235
|
-
return
|
|
1325
|
+
return created.find((c) => c.column === columnName);
|
|
1236
1326
|
}
|
|
1237
1327
|
/**
|
|
1328
|
+
* The `ON DELETE` a link gets when the author did not say, decided from the
|
|
1329
|
+
* column as it will be created.
|
|
1330
|
+
*
|
|
1331
|
+
* {@link planRelationColumn} and {@link planReferenceColumn} see only their own
|
|
1332
|
+
* property's `required`, and two later facts change the premise: `tenant` makes
|
|
1333
|
+
* its column NOT NULL, and a declared property that owns a relation's column
|
|
1334
|
+
* decides that column's nullability itself. Defaulting before either produced
|
|
1335
|
+
* `NOT NULL … ON DELETE SET NULL` — a parent's delete that can only fail, and
|
|
1336
|
+
* fails with 23502 naming the child's column rather than as the foreign-key
|
|
1337
|
+
* refusal it is. An `onDelete` the author wrote is theirs and is kept.
|
|
1338
|
+
*/
|
|
1339
|
+
function settleDefaultOnDelete(collection, columns, relations) {
|
|
1340
|
+
for (const column of columns) {
|
|
1341
|
+
const fk = column.foreignKey;
|
|
1342
|
+
if (!fk || declaresOnDelete(collection, relations, column)) continue;
|
|
1343
|
+
const onDelete = defaultBelongsToOnDelete(!(columns.find((c) => c.column === column.column && !c.columnOwnedByProperty) ?? column).nullable);
|
|
1344
|
+
if (onDelete === fk.onDelete) continue;
|
|
1345
|
+
column.foreignKey = foreignKeyPlan({
|
|
1346
|
+
schema: fk.schema,
|
|
1347
|
+
table: fk.table,
|
|
1348
|
+
column: fk.column,
|
|
1349
|
+
targetSchema: fk.targetSchema,
|
|
1350
|
+
targetTable: fk.targetTable,
|
|
1351
|
+
targetColumn: fk.targetColumn,
|
|
1352
|
+
onDelete,
|
|
1353
|
+
onUpdate: fk.onUpdate
|
|
1354
|
+
});
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
/** Whether the author wrote this link's `onDelete`. A `reference` has none to write. */
|
|
1358
|
+
var declaresOnDelete = (collection, relations, column) => {
|
|
1359
|
+
const propName = column.source.propName;
|
|
1360
|
+
if (column.source.kind !== "relation" || !propName) return false;
|
|
1361
|
+
const prop = collection.properties?.[propName];
|
|
1362
|
+
const relation = findRelation(relations, prop?.relation?.relationName ?? propName);
|
|
1363
|
+
return relation?.kind === "belongsTo" && relation.onDelete !== void 0;
|
|
1364
|
+
};
|
|
1365
|
+
/**
|
|
1238
1366
|
* The column a `belongsTo` relation owns, or `undefined` when the relation puts
|
|
1239
1367
|
* no column on this table.
|
|
1240
1368
|
*
|
|
@@ -1271,7 +1399,7 @@ function planRelationColumn(propName, prop, collection, relations, schema, table
|
|
|
1271
1399
|
column: relation.localKey,
|
|
1272
1400
|
targetSchema: schemaOf(target),
|
|
1273
1401
|
targetTable: bareTableName(getTableName(target)),
|
|
1274
|
-
targetColumn:
|
|
1402
|
+
targetColumn: getPrimaryKeyColumn(target),
|
|
1275
1403
|
onDelete: relation.onDelete ?? defaultBelongsToOnDelete(required),
|
|
1276
1404
|
onUpdate: relation.onUpdate
|
|
1277
1405
|
}),
|
|
@@ -1300,7 +1428,7 @@ function planReferenceColumn(propName, prop, collection, resolveCollection, sche
|
|
|
1300
1428
|
column,
|
|
1301
1429
|
targetSchema: schemaOf(target),
|
|
1302
1430
|
targetTable: bareTableName(getTableName(target)),
|
|
1303
|
-
targetColumn:
|
|
1431
|
+
targetColumn: getPrimaryKeyColumn(target),
|
|
1304
1432
|
onDelete: defaultBelongsToOnDelete(required)
|
|
1305
1433
|
}) : void 0,
|
|
1306
1434
|
source: {
|
|
@@ -1361,7 +1489,7 @@ function planJunctionTable(tableName, relation, source, junctionSpecs, resolveCo
|
|
|
1361
1489
|
column,
|
|
1362
1490
|
targetSchema: schemaOf(collection),
|
|
1363
1491
|
targetTable: bareTableName(getTableName(collection)),
|
|
1364
|
-
targetColumn:
|
|
1492
|
+
targetColumn: getPrimaryKeyColumn(collection),
|
|
1365
1493
|
onDelete
|
|
1366
1494
|
}),
|
|
1367
1495
|
source: { kind: "junction-key" }
|
|
@@ -1416,14 +1544,12 @@ function planRelations(collections, tableEntries) {
|
|
|
1416
1544
|
const { relation, source } = entry.junction;
|
|
1417
1545
|
if (!isManyToMany(relation)) continue;
|
|
1418
1546
|
const target = relation.target();
|
|
1419
|
-
const owningRelationName = relation
|
|
1420
|
-
let
|
|
1547
|
+
const owningRelationName = sharedRelationName(relation, source);
|
|
1548
|
+
let inverse;
|
|
1421
1549
|
try {
|
|
1422
|
-
|
|
1423
|
-
inverseRelationName = targetRel.relationName;
|
|
1424
|
-
break;
|
|
1425
|
-
}
|
|
1550
|
+
inverse = Object.values(resolveCollectionRelations(target)).find((r) => r.kind === "manyToMany" && bareTableName(r.through.table) === bareTableName(tableName));
|
|
1426
1551
|
} catch {}
|
|
1552
|
+
const inverseRelationName = inverse ? sharedRelationName(inverse, target) : `${tableName}_${relation.through.targetColumn}`;
|
|
1427
1553
|
plans.push({
|
|
1428
1554
|
tableVar,
|
|
1429
1555
|
key: relation.through.sourceColumn,
|
|
@@ -1433,12 +1559,13 @@ function planRelations(collections, tableEntries) {
|
|
|
1433
1559
|
fields: [relation.through.sourceColumn],
|
|
1434
1560
|
references: [getPrimaryKeyName(source)]
|
|
1435
1561
|
});
|
|
1562
|
+
if (inverseRelationName === owningRelationName) continue;
|
|
1436
1563
|
plans.push({
|
|
1437
1564
|
tableVar,
|
|
1438
1565
|
key: relation.through.targetColumn,
|
|
1439
1566
|
kind: "one",
|
|
1440
1567
|
targetVar: getTableVarName(getTableName(target)),
|
|
1441
|
-
relationName: inverseRelationName
|
|
1568
|
+
relationName: inverseRelationName,
|
|
1442
1569
|
fields: [relation.through.targetColumn],
|
|
1443
1570
|
references: [getPrimaryKeyName(target)]
|
|
1444
1571
|
});
|
|
@@ -1533,4 +1660,4 @@ function planRelations(collections, tableEntries) {
|
|
|
1533
1660
|
//#endregion
|
|
1534
1661
|
export { searchHelperFunctions as _, triggerStatements as a, searchStampGuards as b, SEARCH_TEXT_FN as c, fuzzyColumnDefinition as d, hiddenColumnsOption as f, searchExtensionStatements as g, searchColumnStamps as h, SET_UPDATED_AT_FN as i, SEARCH_UNACCENT_FN as l, searchColumnNames as m, planSchema as n, sharedRelationName as o, searchColumnDefinition as p, quoteSqlLiteral as r, SEARCH_STAMP_PREFIX as s, columnPgType as t, buildSearchColumnSpec as u, searchIndexNames as v, visibleColumnProjection as x, searchIndexStatements as y };
|
|
1535
1662
|
|
|
1536
|
-
//# sourceMappingURL=plan-schema-
|
|
1663
|
+
//# sourceMappingURL=plan-schema-C0fxM8dY.js.map
|