@rebasepro/server-postgres 0.19.1 → 0.19.2-canary.g09316f6

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.
Files changed (96) hide show
  1. package/dist/{BranchService-ByLfM_Tt.js → BranchService-W3DMfcZZ.js} +2 -2
  2. package/dist/{BranchService-ByLfM_Tt.js.map → BranchService-W3DMfcZZ.js.map} +1 -1
  3. package/dist/PostgresBackendDriver.d.ts +81 -7
  4. package/dist/PostgresBootstrapper.d.ts +10 -0
  5. package/dist/{backup-cli-oM9WQVlV.js → backup-cli-DSpQyqcG.js} +2 -2
  6. package/dist/{backup-cli-oM9WQVlV.js.map → backup-cli-DSpQyqcG.js.map} +1 -1
  7. package/dist/{backup-service-Br3tqwsy.js → backup-service-DA7a6SUV.js} +2 -2
  8. package/dist/{backup-service-Br3tqwsy.js.map → backup-service-DA7a6SUV.js.map} +1 -1
  9. package/dist/{cli-errors-DxN4yzdH.js → cli-errors-C3g_kHBw.js} +137 -18
  10. package/dist/cli-errors-C3g_kHBw.js.map +1 -0
  11. package/dist/cli-errors.d.ts +19 -0
  12. package/dist/cli-helpers.d.ts +47 -0
  13. package/dist/cli.js +233 -19
  14. package/dist/cli.js.map +1 -1
  15. package/dist/{collection-index-BHgT_TKd.js → collection-index-DdnsxiJ_.js} +14 -4
  16. package/dist/{collection-index-BHgT_TKd.js.map → collection-index-DdnsxiJ_.js.map} +1 -1
  17. package/dist/collections/validate-relations.d.ts +7 -0
  18. package/dist/column-plan-helpers-CpILzHJS.js +145 -0
  19. package/dist/column-plan-helpers-CpILzHJS.js.map +1 -0
  20. package/dist/{doctor-D7HWmGzs.js → doctor-D5SrGJ5P.js} +175 -61
  21. package/dist/doctor-D5SrGJ5P.js.map +1 -0
  22. package/dist/{ensure-collection-policies-2c2NV8zX.js → ensure-collection-policies-CHO0moXQ.js} +5 -5
  23. package/dist/{ensure-collection-policies-2c2NV8zX.js.map → ensure-collection-policies-CHO0moXQ.js.map} +1 -1
  24. package/dist/{ensure-collection-tables-D4wJzM4y.js → ensure-collection-tables-Bkvehxdm.js} +318 -312
  25. package/dist/ensure-collection-tables-Bkvehxdm.js.map +1 -0
  26. package/dist/{ensure-tables-CIojK-Rx.js → ensure-tables-CYMtuuOd.js} +2 -2
  27. package/dist/{ensure-tables-CIojK-Rx.js.map → ensure-tables-CYMtuuOd.js.map} +1 -1
  28. package/dist/generate-drizzle-schema-logic-Dfyf_MRu.js +228 -0
  29. package/dist/generate-drizzle-schema-logic-Dfyf_MRu.js.map +1 -0
  30. package/dist/{generate-drizzle-schema-CwEgVyjO.js → generate-drizzle-schema-vSK-VdYT.js} +3 -3
  31. package/dist/generate-drizzle-schema-vSK-VdYT.js.map +1 -0
  32. package/dist/generate-postgres-ddl-logic-CR2xcS7e.js +475 -0
  33. package/dist/generate-postgres-ddl-logic-CR2xcS7e.js.map +1 -0
  34. package/dist/{generated-schema-staleness-DQdfJl2A.js → generated-schema-staleness-DRQe2BpC.js} +81 -3
  35. package/dist/{generated-schema-staleness-DQdfJl2A.js.map → generated-schema-staleness-DRQe2BpC.js.map} +1 -1
  36. package/dist/history/HistoryService.d.ts +23 -4
  37. package/dist/index.es.js +1991 -580
  38. package/dist/index.es.js.map +1 -1
  39. package/dist/introspect-db-logic-C6LQdTxj.js.map +1 -1
  40. package/dist/plan-schema-Hgl62S-w.js +1531 -0
  41. package/dist/plan-schema-Hgl62S-w.js.map +1 -0
  42. package/dist/{policy-drift-kNJ6X2Uj.js → policy-drift-B0GDRh7_.js} +2 -2
  43. package/dist/{policy-drift-kNJ6X2Uj.js.map → policy-drift-B0GDRh7_.js.map} +1 -1
  44. package/dist/{rls-bootstrap-sql-DLDnUjtx.js → rls-bootstrap-sql-BlzsOUtz.js} +111 -8
  45. package/dist/{rls-bootstrap-sql-DLDnUjtx.js.map → rls-bootstrap-sql-BlzsOUtz.js.map} +1 -1
  46. package/dist/{rls-enforcement-DeYEjYLt.js → rls-enforcement-BV12vBwQ.js} +2 -1
  47. package/dist/rls-enforcement-BV12vBwQ.js.map +1 -0
  48. package/dist/schema/catalogue-schema.d.ts +97 -0
  49. package/dist/schema/collection-index.d.ts +9 -0
  50. package/dist/schema/column-plan-helpers.d.ts +125 -0
  51. package/dist/schema/config-relations.d.ts +32 -0
  52. package/dist/schema/doctor-cli.js +4 -4
  53. package/dist/schema/doctor.d.ts +9 -0
  54. package/dist/schema/dynamic-tables.d.ts +27 -6
  55. package/dist/schema/ensure-collection-tables.d.ts +31 -268
  56. package/dist/schema/generate-drizzle-schema-logic.d.ts +26 -8
  57. package/dist/schema/generate-drizzle-schema.js +1 -1
  58. package/dist/schema/generate-postgres-ddl-logic.d.ts +84 -168
  59. package/dist/schema/generate-postgres-ddl.js +8 -2
  60. package/dist/schema/generate-postgres-ddl.js.map +1 -1
  61. package/dist/schema/generated-column-conflicts.d.ts +84 -0
  62. package/dist/schema/generated-schema-diff.d.ts +56 -0
  63. package/dist/schema/generated-schema-staleness.d.ts +33 -0
  64. package/dist/schema/introspect-db-logic.d.ts +2 -0
  65. package/dist/schema/plan/diff-plan.d.ts +220 -0
  66. package/dist/schema/plan/plan-schema.d.ts +84 -0
  67. package/dist/schema/plan/render-ddl.d.ts +62 -0
  68. package/dist/schema/plan/render-drizzle.d.ts +31 -0
  69. package/dist/schema/plan/types.d.ts +410 -0
  70. package/dist/schema/plan/updated-at-trigger.d.ts +22 -0
  71. package/dist/schema/relation-names.d.ts +28 -0
  72. package/dist/schema/search-column.d.ts +9 -0
  73. package/dist/security/rls-enforcement.d.ts +17 -0
  74. package/dist/services/FetchService.d.ts +176 -36
  75. package/dist/services/PersistService.d.ts +17 -4
  76. package/dist/services/RelationService.d.ts +11 -3
  77. package/dist/services/collection-helpers.d.ts +16 -2
  78. package/dist/services/dataService.d.ts +29 -2
  79. package/dist/services/field-op-sql.d.ts +16 -0
  80. package/dist/services/field-viewer.d.ts +19 -0
  81. package/dist/services/realtimeService.d.ts +35 -1
  82. package/dist/services/row-pipeline.d.ts +29 -5
  83. package/dist/services/soft-delete.d.ts +73 -0
  84. package/dist/utils/pg-error-utils.d.ts +41 -1
  85. package/dist/{vector-index-DkWxm2de.js → vector-index-CMJKb3C9.js} +3 -14
  86. package/dist/{vector-index-DkWxm2de.js.map → vector-index-CMJKb3C9.js.map} +1 -1
  87. package/package.json +18 -10
  88. package/dist/cli-errors-DxN4yzdH.js.map +0 -1
  89. package/dist/doctor-D7HWmGzs.js.map +0 -1
  90. package/dist/ensure-collection-tables-D4wJzM4y.js.map +0 -1
  91. package/dist/generate-drizzle-schema-CwEgVyjO.js.map +0 -1
  92. package/dist/generate-drizzle-schema-logic-so2Z_lyC.js +0 -528
  93. package/dist/generate-drizzle-schema-logic-so2Z_lyC.js.map +0 -1
  94. package/dist/generate-postgres-ddl-logic-CtnpIBVv.js +0 -1312
  95. package/dist/generate-postgres-ddl-logic-CtnpIBVv.js.map +0 -1
  96. package/dist/rls-enforcement-DeYEjYLt.js.map +0 -1
@@ -1,528 +0,0 @@
1
- import { createRequire as __createRequire } from "module";
2
- __createRequire(import.meta.url);
3
- import { t as defaultBelongsToOnDelete, v as buildSearchColumnSpec } from "./generate-postgres-ddl-logic-CtnpIBVv.js";
4
- import { logger } from "@rebasepro/server";
5
- import { hasForeignKeyOnTarget, isManyToMany, isPostgresCollectionConfig } from "@rebasepro/types";
6
- import { fieldKeyForColumn, findRelation, getEffectiveSecurityRules, getEnumVarName, getJunctionCollectionConfig, getJunctionSecurityRules, getTableName, getTableVarName, policyToPostgres, relationalCollections, resolveCollectionRelations, resolveJunctionSpecs, resolveStringColumnLength, securityRuleToConditions, sortCollectionsBySlug } from "@rebasepro/common";
7
- import { getPolicyNamesForRule, toSnakeCase } from "@rebasepro/utils";
8
- //#region src/schema/generate-drizzle-schema-logic.ts
9
- /**
10
- * Resolve the SQL column name for a property.
11
- * Uses the explicit `columnName` when set (e.g. from introspection),
12
- * falling back to `toSnakeCase(propName)` for manually-authored collections.
13
- */
14
- var JS_IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
15
- /**
16
- * A string literal for the generated schema file.
17
- *
18
- * Column names, table names and enum values are all written into this file as
19
- * literals, and none of them is constrained to be quote-free: a Postgres
20
- * identifier only has to be quoted, and `O'Brien` is an ordinary enum value.
21
- * Interpolating them raw ended the literal early — for enum values, inside
22
- * single quotes, where an apostrophe is not an edge case.
23
- */
24
- var quote = (value) => JSON.stringify(value);
25
- /** An object key: verbatim when it is an identifier, quoted otherwise. */
26
- var propKey = (name) => JS_IDENTIFIER.test(name) ? name : quote(name);
27
- /**
28
- * A property access on a generated table variable.
29
- *
30
- * `users.full name` is not an expression; `users["full name"]` is, and Drizzle
31
- * treats the two identically.
32
- */
33
- var member = (object, key) => JS_IDENTIFIER.test(key) ? `${object}.${key}` : `${object}[${quote(key)}]`;
34
- var resolveColumnName = (propName, prop) => {
35
- if (prop && "columnName" in prop && typeof prop.columnName === "string") return prop.columnName;
36
- return toSnakeCase(propName);
37
- };
38
- var getPrimaryKeyProp = (collection) => {
39
- if (collection.properties) {
40
- const idPropEntry = Object.entries(collection.properties).find(([_, prop]) => "isId" in prop && Boolean(prop.isId));
41
- if (idPropEntry) {
42
- const prop = idPropEntry[1];
43
- const isUuid = prop.type === "string" && "isId" in prop && prop.isId === "uuid";
44
- return {
45
- name: idPropEntry[0],
46
- type: prop.type === "number" ? "number" : "string",
47
- isUuid
48
- };
49
- }
50
- }
51
- const idProp = collection.properties?.["id"];
52
- if (idProp?.type === "number") return {
53
- name: "id",
54
- type: "number",
55
- isUuid: false
56
- };
57
- return {
58
- name: "id",
59
- type: "string",
60
- isUuid: idProp?.type === "string" && "isId" in idProp && idProp.isId === "uuid"
61
- };
62
- };
63
- /**
64
- * Given a raw DB column name (e.g. "client_id"), the Drizzle property key that
65
- * maps to it.
66
- *
67
- * One line, because the rule is shared: the Drizzle object key is the wire
68
- * name, and {@link fieldKeyForColumn} is the one definition of what a column is
69
- * named on the wire. This used to be a private copy that fell back to the
70
- * column verbatim, which is how a derived foreign key ended up served as
71
- * `author_id` beside a hand-authored `displayName`.
72
- */
73
- var resolvePropertyKeyForColumn = (collection, column) => fieldKeyForColumn(collection, column);
74
- var isNumericId = (collection) => {
75
- return getPrimaryKeyProp(collection).type === "number";
76
- };
77
- var getPrimaryKeyName = (collection) => {
78
- return getPrimaryKeyProp(collection).name;
79
- };
80
- var isIdProperty = (propName, prop, collection) => {
81
- if ("isId" in prop && Boolean(prop.isId)) return true;
82
- return !Object.values(collection.properties ?? {}).some((p) => "isId" in p && Boolean(p.isId)) && propName === "id";
83
- };
84
- /**
85
- * The Drizzle column declaration a property compiles to, or `null` when the
86
- * property puts no column on *this* table (an inverse relation, whose column
87
- * lives on the target). Exported so it can be checked against its DDL twin
88
- * `getSqlColumnType` directly — the two disagreeing is what left `geopoint`
89
- * with a database column and no Drizzle key.
90
- */
91
- var getDrizzleColumn = (propName, prop, collection, collections) => {
92
- const colName = resolveColumnName(propName, prop);
93
- let columnDefinition;
94
- switch (prop.type) {
95
- case "string": {
96
- const stringProp = prop;
97
- if (stringProp.enum) columnDefinition = `${getEnumVarName(getTableName(collection), propName)}(${quote(colName)})`;
98
- else if ("isId" in stringProp && stringProp.isId === "uuid") columnDefinition = `uuid(${quote(colName)})`;
99
- else if (stringProp.columnType === "uuid") columnDefinition = `uuid(${quote(colName)})`;
100
- else if (stringProp.columnType === "char") columnDefinition = `char(${quote(colName)}, { length: ${resolveStringColumnLength(stringProp)} })`;
101
- else if (stringProp.columnType === "varchar") columnDefinition = `varchar(${quote(colName)}, { length: ${resolveStringColumnLength(stringProp)} })`;
102
- else columnDefinition = `text(${quote(colName)})`;
103
- if (isIdProperty(propName, prop, collection)) columnDefinition += ".primaryKey()";
104
- if ("isId" in stringProp && stringProp.isId !== "manual" && stringProp.isId !== true) {
105
- if (stringProp.isId === "uuid") columnDefinition += ".defaultRandom()";
106
- else if (stringProp.isId === "cuid") columnDefinition += ".default(sql`cuid()`)";
107
- else if (typeof stringProp.isId === "string") {
108
- const sqlContent = stringProp.isId.startsWith("sql`") && stringProp.isId.endsWith("`") ? stringProp.isId.substring(4, stringProp.isId.length - 1) : stringProp.isId;
109
- columnDefinition += `.default(sql\`${sqlContent}\`)`;
110
- }
111
- }
112
- if (stringProp.validation?.unique) columnDefinition += ".unique()";
113
- break;
114
- }
115
- case "number": {
116
- const numProp = prop;
117
- const isId = isIdProperty(propName, prop, collection);
118
- let baseType = numProp.validation?.integer || isId ? `integer(${quote(colName)})` : `numeric(${quote(colName)})`;
119
- if (numProp.columnType) if (numProp.columnType === "double precision") baseType = `doublePrecision(${quote(colName)})`;
120
- else if (numProp.columnType === "bigint" || numProp.columnType === "bigserial") baseType = `${numProp.columnType}(${quote(colName)}, { mode: "number" })`;
121
- else baseType = `${numProp.columnType}(${quote(colName)})`;
122
- if ("isId" in numProp && numProp.isId === "increment") columnDefinition = `${baseType}.generatedByDefaultAsIdentity()`;
123
- else if ("isId" in numProp && typeof numProp.isId === "string" && numProp.isId !== "manual") {
124
- columnDefinition = baseType;
125
- const sqlContent = numProp.isId.startsWith("sql`") && numProp.isId.endsWith("`") ? numProp.isId.substring(4, numProp.isId.length - 1) : numProp.isId;
126
- columnDefinition += `.default(sql\`${sqlContent}\`)`;
127
- } else columnDefinition = baseType;
128
- if (isId) columnDefinition += ".primaryKey()";
129
- if (numProp.validation?.unique) columnDefinition += ".unique()";
130
- break;
131
- }
132
- case "boolean":
133
- columnDefinition = `boolean(${quote(colName)})`;
134
- break;
135
- case "date": {
136
- const dateProp = prop;
137
- if (dateProp.columnType === "date") columnDefinition = `date(${quote(colName)}, { mode: 'string' })`;
138
- else if (dateProp.columnType === "time") columnDefinition = `time(${quote(colName)})`;
139
- else columnDefinition = `timestamp(${quote(colName)}, { withTimezone: true, mode: 'string' })`;
140
- if (dateProp.autoValue === "on_create" || dateProp.autoValue === "on_update") columnDefinition += ".default(sql`now()`)";
141
- break;
142
- }
143
- case "map":
144
- if (prop.columnType === "json") columnDefinition = `json(${quote(colName)})`;
145
- else columnDefinition = `jsonb(${quote(colName)})`;
146
- break;
147
- case "geopoint":
148
- columnDefinition = `jsonb(${quote(colName)})`;
149
- break;
150
- case "array": {
151
- const arrayProp = prop;
152
- let colType = arrayProp.columnType;
153
- if (!colType && arrayProp.of && !Array.isArray(arrayProp.of)) {
154
- const ofProp = arrayProp.of;
155
- if (ofProp.type === "string") colType = "text[]";
156
- else if (ofProp.type === "number") colType = ofProp.validation?.integer ? "integer[]" : "numeric[]";
157
- else if (ofProp.type === "boolean") colType = "boolean[]";
158
- }
159
- if (colType === "json") columnDefinition = `json(${quote(colName)})`;
160
- else if (colType === "text[]") columnDefinition = `text(${quote(colName)}).array()`;
161
- else if (colType === "integer[]") columnDefinition = `integer(${quote(colName)}).array()`;
162
- else if (colType === "boolean[]") columnDefinition = `boolean(${quote(colName)}).array()`;
163
- else if (colType === "numeric[]") columnDefinition = `numeric(${quote(colName)}).array()`;
164
- else columnDefinition = `jsonb(${quote(colName)})`;
165
- break;
166
- }
167
- case "vector": {
168
- const vp = prop;
169
- columnDefinition = `vector(${quote(colName)}, { dimensions: ${vp.dimensions} })`;
170
- break;
171
- }
172
- case "binary":
173
- columnDefinition = `customType({ dataType() { return 'bytea'; } })(${quote(colName)})`;
174
- break;
175
- case "relation": {
176
- const refProp = prop;
177
- const relation = findRelation(resolveCollectionRelations(collection), refProp.relation?.relationName ?? propName);
178
- if (!relation || relation.kind !== "belongsTo") return null;
179
- const fkFieldKey = fieldKeyForColumn(collection, relation.localKey);
180
- if (collection.properties[fkFieldKey] && propName !== fkFieldKey) return null;
181
- let targetCollection;
182
- try {
183
- targetCollection = relation.target();
184
- } catch {
185
- return null;
186
- }
187
- const fkColumnName = relation.localKey;
188
- const targetTableVar = getTableVarName(getTableName(targetCollection));
189
- const pkProp = getPrimaryKeyProp(targetCollection);
190
- const targetIdField = pkProp.name;
191
- const baseColumn = pkProp.type === "number" ? `integer(${quote(fkColumnName)})` : pkProp.isUuid ? `uuid(${quote(fkColumnName)})` : `text(${quote(fkColumnName)})`;
192
- const onUpdate = relation.onUpdate ? `onUpdate: "${relation.onUpdate}"` : "";
193
- const required = prop.validation?.required;
194
- const refOptionsParts = [onUpdate, `onDelete: \"${relation.onDelete ?? defaultBelongsToOnDelete(required).toLowerCase()}\"`].filter(Boolean);
195
- const refOptions = refOptionsParts.length > 0 ? `{ ${refOptionsParts.join(", ")} }` : "";
196
- let columnDef = `${baseColumn}.references(() => ${member(targetTableVar, targetIdField)}${refOptions ? `, ${refOptions}` : ""})`;
197
- if (required) columnDef += ".notNull()";
198
- return ` ${propKey(fkFieldKey)}: ${columnDef}`;
199
- }
200
- case "reference": {
201
- const refProp = prop;
202
- const targetCollection = collections.find((c) => c.slug === refProp.path || getTableName(c) === refProp.path);
203
- if (!targetCollection) {
204
- columnDefinition = `text(${quote(colName)})`;
205
- break;
206
- }
207
- const pkProp = getPrimaryKeyProp(targetCollection);
208
- const targetTableVar = getTableVarName(getTableName(targetCollection));
209
- const targetIdField = pkProp.name;
210
- const baseColumn = pkProp.type === "number" ? `integer(${quote(colName)})` : pkProp.isUuid ? `uuid(${quote(colName)})` : `text(${quote(colName)})`;
211
- const required = prop.validation?.required;
212
- const refOptions = `{ onDelete: "${required ? "cascade" : "set null"}" }`;
213
- columnDefinition = `${baseColumn}.references(() => ${member(targetTableVar, targetIdField)}, ${refOptions})`;
214
- if (required) columnDefinition += ".notNull()";
215
- return ` ${propKey(propName)}: ${columnDefinition}`;
216
- }
217
- default: throw new Error(`No Postgres column mapping for property '${propName}' of type '${prop.type}' in collection '${collection.slug}'. Add a case to \`getDrizzleColumn\` (and to \`getSqlColumnType\`, which must agree).`);
218
- }
219
- if (prop.validation?.required) columnDefinition += ".notNull()";
220
- return ` ${propKey(propName)}: ${columnDefinition}`;
221
- };
222
- /**
223
- * Wraps a compiled SQL clause in a Drizzle `sql\`...\`` template literal.
224
- *
225
- * The clause is SQL being written into a TypeScript file, so it has to survive
226
- * being read back as a template literal. Three characters do not:
227
- *
228
- * - `` ` `` closes the template early, and the rest of the clause becomes code.
229
- * - `${` opens an interpolation — the file stops compiling, or worse, compiles
230
- * against whatever identifier happens to be in scope.
231
- * - `\` is an escape, and Drizzle's `sql` tag reads the *cooked* strings, not
232
- * `.raw`. So a policy written as `email ~ '^admin\.user@corp\.com$'` reaches
233
- * the database as `^admin.user@corp.com$`, where every `\.` now matches any
234
- * character. A `USING` clause is a security boundary and that one silently
235
- * widened it — the SQL file emitted by the DDL generator kept the backslashes
236
- * while this path dropped them, so the two disagreed about who could read the
237
- * table.
238
- *
239
- * Escaping here rather than in the compiler: the clause is correct SQL, and it
240
- * is only this destination that has an opinion about backslashes.
241
- */
242
- var wrapSql = (clause) => `sql\`${clause.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${")}\``;
243
- var generatePolicyCode = (collection, rule, index, resolveCollection) => {
244
- const tableName = getTableName(collection);
245
- const ops = rule.operations && rule.operations.length > 0 ? rule.operations : [rule.operation ?? "all"];
246
- const policyNames = getPolicyNamesForRule(rule, tableName);
247
- return ops.map((op, opIdx) => {
248
- return generateSinglePolicyCode(collection, rule, op, policyNames[opIdx], resolveCollection);
249
- }).join("");
250
- };
251
- /**
252
- * Generates a single pgPolicy() call for one specific operation.
253
- */
254
- var generateSinglePolicyCode = (collection, rule, operation, policyName, resolveCollection) => {
255
- const mode = rule.mode ?? "permissive";
256
- const needsUsing = operation !== "insert";
257
- const needsWithCheck = operation !== "select" && operation !== "delete";
258
- const { usingExpr, withCheckExpr } = securityRuleToConditions(rule);
259
- let usingClause = needsUsing && usingExpr ? wrapSql(policyToPostgres(usingExpr, collection, { resolveCollection })) : null;
260
- let withCheckClause = needsWithCheck && withCheckExpr ? wrapSql(policyToPostgres(withCheckExpr, collection, { resolveCollection })) : null;
261
- if (!usingClause && needsUsing) usingClause = "sql`false`";
262
- if (!withCheckClause && needsWithCheck) withCheckClause = "sql`false`";
263
- const parts = [];
264
- parts.push(`as: "${mode}"`);
265
- parts.push(`for: "${operation}"`);
266
- const toRoles = rule.pgRoles ? [...rule.pgRoles].sort() : ["public"];
267
- parts.push(`to: [${toRoles.map((r) => `"${r}"`).join(", ")}]`);
268
- if (usingClause) parts.push(`using: ${usingClause}`);
269
- if (withCheckClause) parts.push(`withCheck: ${withCheckClause}`);
270
- return ` pgPolicy(${quote(policyName)}, { ${parts.join(", ")} }),\n`;
271
- };
272
- /**
273
- * Computes a deterministic shared relation name for Drizzle.
274
- *
275
- * Drizzle requires both sides of a relation (owning + inverse) to use the
276
- * exact same `relationName` string so it can pair them. Each collection
277
- * definition may use a different local `relationName`, so we need a canonical
278
- * form that both sides can independently compute.
279
- *
280
- * Strategy: `{owningTable}_{foreignKey}`
281
- * - owning side → `{thisTable}_{localKey}` e.g. "jobs_company_id"
282
- * - inverse side → `{targetTable}_{foreignKeyOnTarget}` e.g. "jobs_company_id"
283
- *
284
- * For M2M with junction tables the owning relation name is already shared via
285
- * the junction table wiring, so we keep it as-is.
286
- *
287
- * Falls back to the local relation name when the counterpart can't be resolved.
288
- */
289
- var computeSharedRelationName = (rel, sourceCollection, _collections) => {
290
- const fallback = rel.relationName ?? toSnakeCase(rel.target().slug);
291
- if (rel.kind === "belongsTo") {
292
- const normalisedKey = resolvePropertyKeyForColumn(sourceCollection, rel.localKey);
293
- return `${getTableName(sourceCollection)}_${normalisedKey}`;
294
- }
295
- if (rel.kind === "hasMany" || rel.kind === "hasOne") try {
296
- const targetCollection = rel.target();
297
- const normalisedFK = resolvePropertyKeyForColumn(targetCollection, rel.foreignKeyOnTarget);
298
- return `${getTableName(targetCollection)}_${normalisedFK}`;
299
- } catch {
300
- return fallback;
301
- }
302
- return fallback;
303
- };
304
- var generateSchema = async (allCollections, stripPolicies = false) => {
305
- const collections = sortCollectionsBySlug(relationalCollections(allCollections));
306
- let schemaContent = "// This file is auto-generated by the Rebase Drizzle generator. Do not edit manually.\n\n";
307
- const hasUuid = collections.some((c) => c.properties && Object.values(c.properties).some((p) => p.type === "string" && (p.autoValue === "uuid" || p.isId === "uuid")));
308
- const hasVector = collections.some((c) => c.properties && Object.values(c.properties).some((p) => p.type === "vector"));
309
- const hasBinary = collections.some((c) => c.properties && Object.values(c.properties).some((p) => p.type === "binary"));
310
- const hasSearch = collections.some((c) => buildSearchColumnSpec(c) !== void 0);
311
- const pgCoreImports = [
312
- "primaryKey",
313
- "pgTable",
314
- "integer",
315
- "varchar",
316
- "text",
317
- "char",
318
- "boolean",
319
- "timestamp",
320
- "date",
321
- "time",
322
- "jsonb",
323
- "json",
324
- "pgEnum",
325
- "numeric",
326
- "real",
327
- "doublePrecision",
328
- "bigint",
329
- "serial",
330
- "bigserial",
331
- "pgPolicy"
332
- ];
333
- if (hasUuid) pgCoreImports.push("uuid");
334
- if (hasVector) pgCoreImports.push("vector");
335
- if (hasBinary || hasSearch) pgCoreImports.push("customType");
336
- const uniqueSchemas = Array.from(new Set(collections.map((c) => isPostgresCollectionConfig(c) ? c.schema : void 0).filter(Boolean)));
337
- if (uniqueSchemas.length > 0) pgCoreImports.push("pgSchema");
338
- schemaContent += `import { ${pgCoreImports.join(", ")} } from 'drizzle-orm/pg-core';\n`;
339
- schemaContent += "import { relations as drizzleRelations, sql } from 'drizzle-orm';\n\n";
340
- uniqueSchemas.forEach((schema) => {
341
- schemaContent += `export const ${schema}Schema = pgSchema("${schema}");\n`;
342
- });
343
- if (uniqueSchemas.length > 0) schemaContent += "\n";
344
- const exportedTableVars = [];
345
- const exportedEnumVars = [];
346
- const exportedRelationVars = [];
347
- const allTablesToGenerate = /* @__PURE__ */ new Map();
348
- collections.forEach((collection) => {
349
- const collectionPath = getTableName(collection);
350
- Object.entries(collection.properties ?? {}).forEach(([propName, prop]) => {
351
- if ("enum" in prop && (prop.type === "string" || prop.type === "number") && prop.enum) {
352
- const enumVarName = getEnumVarName(collectionPath, propName);
353
- const enumDbName = `${collectionPath}_${resolveColumnName(propName, prop)}`;
354
- const values = Array.isArray(prop.enum) ? prop.enum.map((v) => String(typeof v === "object" && v !== null && "id" in v ? v.id : v)) : Object.keys(prop.enum);
355
- if (values.length > 0) {
356
- schemaContent += `export const ${enumVarName} = pgEnum(${quote(enumDbName)}, [${values.map((v) => quote(v)).join(", ")}]);\n`;
357
- if (!exportedEnumVars.includes(enumVarName)) exportedEnumVars.push(enumVarName);
358
- }
359
- }
360
- });
361
- });
362
- schemaContent += "\n";
363
- const junctionSpecs = resolveJunctionSpecs(collections);
364
- for (const collection of collections) {
365
- const tableName = getTableName(collection);
366
- if (tableName) allTablesToGenerate.set(tableName, { collection });
367
- const resolvedRelations = resolveCollectionRelations(collection);
368
- for (const relation of Object.values(resolvedRelations)) if (isManyToMany(relation)) {
369
- const junctionTableName = relation.through.table;
370
- if (!allTablesToGenerate.has(junctionTableName)) allTablesToGenerate.set(junctionTableName, {
371
- collection: {
372
- table: junctionTableName,
373
- properties: {}
374
- },
375
- isJunction: true,
376
- relation,
377
- sourceCollection: collection
378
- });
379
- }
380
- }
381
- for (const [tableName, { collection, isJunction, relation, sourceCollection }] of allTablesToGenerate.entries()) {
382
- const tableVarName = getTableVarName(tableName);
383
- if (isJunction && relation && sourceCollection && isManyToMany(relation)) {
384
- const targetCollection = relation.target();
385
- const tableCreator = "pgTable";
386
- const baseTableName = tableName.includes(".") ? tableName.split(".").pop() : tableName;
387
- const { sourceColumn, targetColumn } = relation.through;
388
- const refOptions = `{ onDelete: \"${relation.onDelete ?? "cascade"}\" }`;
389
- const sourceColType = isNumericId(sourceCollection) ? "integer" : getPrimaryKeyProp(sourceCollection).isUuid ? "uuid" : "text";
390
- const targetColType = isNumericId(targetCollection) ? "integer" : getPrimaryKeyProp(targetCollection).isUuid ? "uuid" : "text";
391
- const sourceId = getPrimaryKeyName(sourceCollection);
392
- const targetId = getPrimaryKeyName(targetCollection);
393
- schemaContent += `export const ${tableVarName} = ${tableCreator}(\"${baseTableName}\", {\n`;
394
- schemaContent += ` ${propKey(sourceColumn)}: ${sourceColType}(${quote(sourceColumn)}).notNull().references(() => ${member(getTableVarName(getTableName(sourceCollection)), sourceId)}, ${refOptions}),\n`;
395
- schemaContent += ` ${propKey(targetColumn)}: ${targetColType}(${quote(targetColumn)}).notNull().references(() => ${member(getTableVarName(getTableName(targetCollection)), targetId)}, ${refOptions}),\n`;
396
- schemaContent += "}, (table) => ([\n";
397
- schemaContent += ` primaryKey({ columns: [${member("table", sourceColumn)}, ${member("table", targetColumn)}] }),\n`;
398
- const junctionSpec = junctionSpecs.get(baseTableName);
399
- if (!stripPolicies && junctionSpec) {
400
- const junctionCollection = getJunctionCollectionConfig(junctionSpec);
401
- const resolveCollection = (slug) => collections.find((c) => c.slug === slug || getTableName(c) === slug);
402
- getJunctionSecurityRules(junctionSpec).forEach((rule, idx) => {
403
- schemaContent += generatePolicyCode(junctionCollection, rule, idx, resolveCollection);
404
- });
405
- }
406
- schemaContent += "])).enableRLS();\n\n";
407
- } else if (!isJunction) {
408
- const schema = isPostgresCollectionConfig(collection) ? collection.schema : void 0;
409
- const tableCreator = schema ? `${schema}Schema.table` : "pgTable";
410
- const baseTableName = tableName.includes(".") ? tableName.split(".").pop() : tableName;
411
- schemaContent += `export const ${tableVarName} = ${tableCreator}(\"${baseTableName}\", {\n`;
412
- const columns = /* @__PURE__ */ new Set();
413
- Object.entries(collection.properties ?? {}).forEach(([propName, prop]) => {
414
- const columnString = getDrizzleColumn(propName, prop, collection, collections);
415
- if (columnString) columns.add(columnString);
416
- });
417
- const searchSpec = buildSearchColumnSpec(collection);
418
- if (searchSpec) {
419
- columns.add(` ${propKey(searchSpec.column)}: customType({ dataType() { return 'tsvector'; } })(${quote(searchSpec.column)}).generatedAlwaysAs(sql\`${searchSpec.expression}\`)`);
420
- if (searchSpec.fuzzy) columns.add(` ${propKey(searchSpec.fuzzy.column)}: text(${quote(searchSpec.fuzzy.column)}).generatedAlwaysAs(sql\`${searchSpec.fuzzy.expression}\`)`);
421
- }
422
- if (!Array.from(columns).some((col) => col.includes(".primaryKey()"))) columns.add(" id: text(\"id\").primaryKey()");
423
- schemaContent += `${Array.from(columns).join(",\n")}`;
424
- const securityRules = getEffectiveSecurityRules(collection);
425
- if (!stripPolicies && securityRules.length > 0) {
426
- schemaContent += "\n}, (table) => ([\n";
427
- const resolveCollection = (slug) => collections.find((c) => c.slug === slug || getTableName(c) === slug);
428
- securityRules.forEach((rule, idx) => {
429
- schemaContent += generatePolicyCode(collection, rule, idx, resolveCollection);
430
- });
431
- schemaContent += "])).enableRLS();\n\n";
432
- } else schemaContent += "\n}).enableRLS();\n\n";
433
- }
434
- if (!exportedTableVars.includes(tableVarName)) exportedTableVars.push(tableVarName);
435
- }
436
- for (const [tableName, { collection, isJunction }] of allTablesToGenerate.entries()) {
437
- const tableVarName = getTableVarName(tableName);
438
- const tableRelations = [];
439
- if (isJunction) {
440
- const relationInfo = Array.from(allTablesToGenerate.values()).find((v) => v.isJunction && getTableName(v.collection) === tableName);
441
- if (relationInfo && relationInfo.relation && relationInfo.sourceCollection && isManyToMany(relationInfo.relation)) {
442
- const { relation, sourceCollection } = relationInfo;
443
- const targetCollection = relation.target();
444
- const sourceTableVar = getTableVarName(getTableName(sourceCollection));
445
- const targetTableVar = getTableVarName(getTableName(targetCollection));
446
- const sourceId = getPrimaryKeyName(sourceCollection);
447
- const targetId = getPrimaryKeyName(targetCollection);
448
- if (!relation?.through) throw new Error("Internal, the relation should have a through property. Relations passed to this script should sanitized first with sanitizeRelation().");
449
- const owningRelationName = relation.relationName ?? toSnakeCase(getTableName(targetCollection));
450
- let inverseRelationName = null;
451
- try {
452
- const targetRelations = resolveCollectionRelations(targetCollection);
453
- for (const [, targetRel] of Object.entries(targetRelations)) if (targetRel.kind !== "belongsTo" && targetRel.cardinality === "many" && targetRel.relationName === owningRelationName) {
454
- inverseRelationName = targetRel.relationName ?? null;
455
- break;
456
- }
457
- } catch {}
458
- tableRelations.push(` ${quote(relation.through.sourceColumn)}: one(${sourceTableVar}, {\n fields: [${member(tableVarName, relation.through.sourceColumn)}],\n references: [${member(sourceTableVar, sourceId)}],\n relationName: ${quote(owningRelationName)}\n })`);
459
- const targetRelationName = inverseRelationName ? inverseRelationName : `${tableName}_${relation.through.targetColumn}`;
460
- tableRelations.push(` ${quote(relation.through.targetColumn)}: one(${targetTableVar}, {\n fields: [${member(tableVarName, relation.through.targetColumn)}],\n references: [${member(targetTableVar, targetId)}],\n relationName: ${quote(targetRelationName)}\n })`);
461
- }
462
- } else {
463
- const resolvedRelations = resolveCollectionRelations(collection);
464
- const emittedRelationNames = /* @__PURE__ */ new Set();
465
- for (const [relationKey, rel] of Object.entries(resolvedRelations)) try {
466
- const target = rel.target();
467
- const targetTableVar = getTableVarName(getTableName(target));
468
- const drizzleRelationName = computeSharedRelationName(rel, collection, collections);
469
- const deduplicationKey = `${drizzleRelationName}::${rel.kind}`;
470
- if (emittedRelationNames.has(deduplicationKey)) continue;
471
- emittedRelationNames.add(deduplicationKey);
472
- switch (rel.kind) {
473
- case "belongsTo": {
474
- const localFieldKey = resolvePropertyKeyForColumn(collection, rel.localKey);
475
- tableRelations.push(` ${quote(relationKey)}: one(${targetTableVar}, {\n fields: [${member(tableVarName, localFieldKey)}],\n references: [${member(targetTableVar, getPrimaryKeyName(target))}],\n relationName: ${quote(drizzleRelationName)}\n })`);
476
- break;
477
- }
478
- case "hasOne":
479
- tableRelations.push(` ${quote(relationKey)}: one(${targetTableVar}, {\n relationName: ${quote(drizzleRelationName)}\n })`);
480
- break;
481
- case "hasMany":
482
- tableRelations.push(` ${quote(relationKey)}: many(${targetTableVar}, { relationName: ${quote(drizzleRelationName)} })`);
483
- break;
484
- case "manyToMany": {
485
- const junctionTableVar = getTableVarName(rel.through.table);
486
- tableRelations.push(` ${quote(relationKey)}: many(${junctionTableVar}, { relationName: ${quote(drizzleRelationName)} })`);
487
- break;
488
- }
489
- case "via": break;
490
- }
491
- } catch (e) {
492
- logger.warn(`Could not generate relation ${relationKey} for ${collection.name}`, { error: e });
493
- }
494
- for (const otherCollection of collections) {
495
- if (otherCollection.slug === collection.slug) continue;
496
- const otherRelations = resolveCollectionRelations(otherCollection);
497
- for (const [otherKey, otherRel] of Object.entries(otherRelations)) if (hasForeignKeyOnTarget(otherRel)) try {
498
- if (otherRel.target().slug === collection.slug) {
499
- const drizzleRelationName = computeSharedRelationName(otherRel, otherCollection, collections);
500
- const deduplicationKey = `${drizzleRelationName}::belongsTo`;
501
- if (!emittedRelationNames.has(deduplicationKey)) {
502
- const otherTableVar = getTableVarName(getTableName(otherCollection));
503
- const drizzleFieldKey = resolvePropertyKeyForColumn(collection, otherRel.foreignKeyOnTarget);
504
- const referencedKey = otherRel.sourceKey ? resolvePropertyKeyForColumn(otherCollection, otherRel.sourceKey) : getPrimaryKeyName(otherCollection);
505
- const synthKey = `_synth_${otherTableVar}_${drizzleFieldKey}`;
506
- tableRelations.push(` ${quote(synthKey)}: one(${otherTableVar}, {\n fields: [${member(tableVarName, drizzleFieldKey)}],\n references: [${member(otherTableVar, referencedKey)}],\n relationName: ${quote(drizzleRelationName)}\n })`);
507
- emittedRelationNames.add(deduplicationKey);
508
- }
509
- }
510
- } catch (e) {}
511
- }
512
- }
513
- if (tableRelations.length > 0) {
514
- const relVarName = `${tableVarName}Relations`;
515
- schemaContent += `export const ${relVarName} = drizzleRelations(${tableVarName}, ({ one, many }) => ({\n${tableRelations.join(",\n")}\n}));\n\n`;
516
- if (!exportedRelationVars.includes(relVarName)) exportedRelationVars.push(relVarName);
517
- }
518
- }
519
- const tablesExport = `export const tables = { ${exportedTableVars.join(", ")} };\n`;
520
- const enumsExport = `export const enums = { ${exportedEnumVars.join(", ")} };\n`;
521
- const relationsExport = `export const relations = { ${exportedRelationVars.join(", ")} };\n\n`;
522
- schemaContent += tablesExport + enumsExport + relationsExport;
523
- return schemaContent;
524
- };
525
- //#endregion
526
- export { getDrizzleColumn as n, generateSchema as t };
527
-
528
- //# sourceMappingURL=generate-drizzle-schema-logic-so2Z_lyC.js.map