@rebasepro/server-postgres 0.17.3 → 0.18.1

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 (204) hide show
  1. package/LICENSE +0 -1
  2. package/README.md +31 -0
  3. package/dist/BranchService-ByLfM_Tt.js +360 -0
  4. package/dist/BranchService-ByLfM_Tt.js.map +1 -0
  5. package/dist/__vite-browser-external-BnuHet1e.js +46 -0
  6. package/dist/__vite-browser-external-BnuHet1e.js.map +1 -0
  7. package/dist/arg-Dni7MzLB.js +87 -0
  8. package/dist/arg-Dni7MzLB.js.map +1 -0
  9. package/dist/auth-users-columns-D2LBFrMH.js +116 -0
  10. package/dist/auth-users-columns-D2LBFrMH.js.map +1 -0
  11. package/dist/backup-argv.d.ts +19 -0
  12. package/dist/backup-cli-oM9WQVlV.js +408 -0
  13. package/dist/backup-cli-oM9WQVlV.js.map +1 -0
  14. package/dist/backup-service-Br3tqwsy.js +715 -0
  15. package/dist/backup-service-Br3tqwsy.js.map +1 -0
  16. package/dist/branch-argv.d.ts +28 -0
  17. package/dist/branch-prune.d.ts +77 -0
  18. package/dist/cli-collections-path.d.ts +31 -0
  19. package/dist/cli-errors-DxN4yzdH.js +657 -0
  20. package/dist/cli-errors-DxN4yzdH.js.map +1 -0
  21. package/dist/cli-errors.d.ts +123 -0
  22. package/dist/cli-flags.d.ts +101 -0
  23. package/dist/cli-helpers.d.ts +94 -10
  24. package/dist/cli-output-CNdMql-L.js +47 -0
  25. package/dist/cli-output-CNdMql-L.js.map +1 -0
  26. package/dist/cli.js +2020 -0
  27. package/dist/cli.js.map +1 -0
  28. package/dist/collection-index-BHgT_TKd.js +276 -0
  29. package/dist/collection-index-BHgT_TKd.js.map +1 -0
  30. package/dist/{collections-schema-version-BMeu3cgv.js → collections-schema-version-T6cGvrDi.js} +1 -2
  31. package/dist/{collections-schema-version-BMeu3cgv.js.map → collections-schema-version-T6cGvrDi.js.map} +1 -1
  32. package/dist/{connection-GOKU3Hu5.js → databasePoolManager-Bj5FbeAs.js} +112 -40
  33. package/dist/databasePoolManager-Bj5FbeAs.js.map +1 -0
  34. package/dist/databasePoolManager.d.ts +27 -0
  35. package/dist/doctor-D7HWmGzs.js +974 -0
  36. package/dist/doctor-D7HWmGzs.js.map +1 -0
  37. package/dist/{ensure-collection-policies-UCqgv_8c.js → ensure-collection-policies-2c2NV8zX.js} +7 -27
  38. package/dist/ensure-collection-policies-2c2NV8zX.js.map +1 -0
  39. package/dist/ensure-collection-tables-D4wJzM4y.js +820 -0
  40. package/dist/ensure-collection-tables-D4wJzM4y.js.map +1 -0
  41. package/dist/ensure-tables-CIojK-Rx.js +650 -0
  42. package/dist/ensure-tables-CIojK-Rx.js.map +1 -0
  43. package/dist/generate-drizzle-schema-CwEgVyjO.js +123 -0
  44. package/dist/generate-drizzle-schema-CwEgVyjO.js.map +1 -0
  45. package/dist/generate-drizzle-schema-logic-so2Z_lyC.js +528 -0
  46. package/dist/generate-drizzle-schema-logic-so2Z_lyC.js.map +1 -0
  47. package/dist/{ensure-collection-tables-DgVixhX3.js → generate-postgres-ddl-logic-CtnpIBVv.js} +126 -984
  48. package/dist/generate-postgres-ddl-logic-CtnpIBVv.js.map +1 -0
  49. package/dist/generated-schema-staleness-DQdfJl2A.js +157 -0
  50. package/dist/generated-schema-staleness-DQdfJl2A.js.map +1 -0
  51. package/dist/index.d.ts +12 -0
  52. package/dist/index.es.js +7423 -1133
  53. package/dist/index.es.js.map +1 -1
  54. package/dist/introspect-db-logic-C6LQdTxj.js +1378 -0
  55. package/dist/introspect-db-logic-C6LQdTxj.js.map +1 -0
  56. package/dist/policy-drift-kNJ6X2Uj.js +313 -0
  57. package/dist/policy-drift-kNJ6X2Uj.js.map +1 -0
  58. package/dist/{backup-service-DCk7KhhL.js → rls-bootstrap-sql-DLDnUjtx.js} +737 -2689
  59. package/dist/rls-bootstrap-sql-DLDnUjtx.js.map +1 -0
  60. package/dist/{rls-enforcement-DvAbL9YJ.js → rls-enforcement-DeYEjYLt.js} +65 -190
  61. package/dist/rls-enforcement-DeYEjYLt.js.map +1 -0
  62. package/dist/schema/bin/generate-drizzle-schema.d.ts +1 -0
  63. package/dist/schema/bin/generate-postgres-ddl.d.ts +1 -0
  64. package/dist/schema/column-type-drift.d.ts +79 -0
  65. package/dist/schema/doctor-cli.js +129 -0
  66. package/dist/schema/doctor-cli.js.map +1 -0
  67. package/dist/schema/doctor.d.ts +42 -0
  68. package/dist/schema/ensure-collection-tables.d.ts +90 -0
  69. package/dist/schema/generate-drizzle-schema.d.ts +1 -1
  70. package/dist/schema/generate-drizzle-schema.js +24 -0
  71. package/dist/schema/generate-drizzle-schema.js.map +1 -0
  72. package/dist/schema/generate-next-step.d.ts +30 -0
  73. package/dist/schema/generate-postgres-ddl-logic.d.ts +28 -0
  74. package/dist/schema/generate-postgres-ddl.d.ts +1 -1
  75. package/dist/schema/generate-postgres-ddl.js +138 -0
  76. package/dist/schema/generate-postgres-ddl.js.map +1 -0
  77. package/dist/schema/generated-schema-staleness.d.ts +37 -0
  78. package/dist/schema/introspect-db-queries.d.ts +34 -0
  79. package/dist/schema/introspect-db.js +866 -0
  80. package/dist/schema/introspect-db.js.map +1 -0
  81. package/dist/security/rls-enforcement.d.ts +63 -2
  82. package/dist/services/BranchService.d.ts +86 -1
  83. package/dist/services/collection-helpers.d.ts +1 -1
  84. package/dist/services/realtimeService.d.ts +30 -2
  85. package/dist/services/row-pipeline.d.ts +12 -1
  86. package/dist/source-Br7L7GOI.js +410 -0
  87. package/dist/source-Br7L7GOI.js.map +1 -0
  88. package/dist/utils/pg-error-utils.d.ts +3 -1
  89. package/dist/utils/pg-numeric-number-patch.d.ts +31 -0
  90. package/dist/vector-index-DkWxm2de.js +309 -0
  91. package/dist/vector-index-DkWxm2de.js.map +1 -0
  92. package/package.json +32 -27
  93. package/dist/backup-service-DCk7KhhL.js.map +0 -1
  94. package/dist/collection-index-BRUg10H5.js +0 -5690
  95. package/dist/collection-index-BRUg10H5.js.map +0 -1
  96. package/dist/connection-GOKU3Hu5.js.map +0 -1
  97. package/dist/ensure-collection-policies-UCqgv_8c.js.map +0 -1
  98. package/dist/ensure-collection-tables-DgVixhX3.js.map +0 -1
  99. package/dist/rls-bootstrap-sql-B5C9LoJ6.js +0 -244
  100. package/dist/rls-bootstrap-sql-B5C9LoJ6.js.map +0 -1
  101. package/dist/rls-enforcement-DvAbL9YJ.js.map +0 -1
  102. package/dist/src-DiB5RP2Z.js +0 -541
  103. package/dist/src-DiB5RP2Z.js.map +0 -1
  104. package/dist/websocket-BZ4H5wUz.js +0 -8198
  105. package/dist/websocket-BZ4H5wUz.js.map +0 -1
  106. package/src/PostgresAdapter.ts +0 -91
  107. package/src/PostgresBackendDriver.ts +0 -1857
  108. package/src/PostgresBootstrapper.ts +0 -1157
  109. package/src/auth/ensure-tables.ts +0 -896
  110. package/src/auth/schema-version.ts +0 -260
  111. package/src/auth/services.ts +0 -1610
  112. package/src/backup/backup-cli.ts +0 -520
  113. package/src/backup/backup-cron.ts +0 -212
  114. package/src/backup/backup-logic.ts +0 -93
  115. package/src/backup/backup-service.ts +0 -485
  116. package/src/backup/index.ts +0 -12
  117. package/src/backup/pg-tools.ts +0 -403
  118. package/src/backup/retention.ts +0 -86
  119. package/src/cli-errors.ts +0 -265
  120. package/src/cli-helpers.ts +0 -569
  121. package/src/cli-output.ts +0 -43
  122. package/src/cli.ts +0 -1339
  123. package/src/collections/PostgresCollectionRegistry.ts +0 -108
  124. package/src/collections/buildRegistry.ts +0 -68
  125. package/src/collections/validate-relations.ts +0 -402
  126. package/src/connection.ts +0 -333
  127. package/src/data-transformer.ts +0 -845
  128. package/src/databasePoolManager.ts +0 -95
  129. package/src/history/HistoryService.ts +0 -254
  130. package/src/history/ensure-history-table.ts +0 -53
  131. package/src/index.ts +0 -19
  132. package/src/interfaces.ts +0 -60
  133. package/src/module-dir.ts +0 -7
  134. package/src/schema/atlas-argv.ts +0 -94
  135. package/src/schema/auth-schema.ts +0 -298
  136. package/src/schema/auth-users-columns.ts +0 -131
  137. package/src/schema/carved-out-migration.ts +0 -404
  138. package/src/schema/classify-change.ts +0 -436
  139. package/src/schema/collection-index.ts +0 -427
  140. package/src/schema/collections-schema-version.ts +0 -103
  141. package/src/schema/destructive-sql.ts +0 -94
  142. package/src/schema/doctor-cli.ts +0 -66
  143. package/src/schema/doctor-policy-checks.ts +0 -105
  144. package/src/schema/doctor.ts +0 -837
  145. package/src/schema/drizzle-ddl.ts +0 -33
  146. package/src/schema/dynamic-tables.test.ts +0 -302
  147. package/src/schema/dynamic-tables.ts +0 -293
  148. package/src/schema/ensure-collection-policies.ts +0 -198
  149. package/src/schema/ensure-collection-tables.test.ts +0 -518
  150. package/src/schema/ensure-collection-tables.ts +0 -1267
  151. package/src/schema/generate-drizzle-schema-logic.ts +0 -957
  152. package/src/schema/generate-drizzle-schema.ts +0 -143
  153. package/src/schema/generate-postgres-ddl-logic.ts +0 -1339
  154. package/src/schema/generate-postgres-ddl.ts +0 -180
  155. package/src/schema/generate-schema-commit.ts +0 -267
  156. package/src/schema/generated-schema-staleness.ts +0 -284
  157. package/src/schema/introspect-db-constraints.ts +0 -385
  158. package/src/schema/introspect-db-inference.ts +0 -255
  159. package/src/schema/introspect-db-logic.ts +0 -1387
  160. package/src/schema/introspect-db-naming.ts +0 -15
  161. package/src/schema/introspect-db-project.ts +0 -78
  162. package/src/schema/introspect-db-queries.ts +0 -326
  163. package/src/schema/introspect-db-structure.ts +0 -670
  164. package/src/schema/introspect-db-types.ts +0 -56
  165. package/src/schema/introspect-db.ts +0 -257
  166. package/src/schema/introspect-runtime.test.ts +0 -260
  167. package/src/schema/introspect-runtime.ts +0 -327
  168. package/src/schema/non-sql-collections.test.ts +0 -131
  169. package/src/schema/rls-bootstrap-sql.ts +0 -288
  170. package/src/schema/search-column.ts +0 -643
  171. package/src/schema/test-schema.ts +0 -11
  172. package/src/schema/vector-index.ts +0 -491
  173. package/src/security/anonymous-grants.test.ts +0 -73
  174. package/src/security/policy-drift.test.ts +0 -435
  175. package/src/security/policy-drift.ts +0 -473
  176. package/src/security/rls-enforcement.ts +0 -505
  177. package/src/services/BranchService.ts +0 -326
  178. package/src/services/FetchService.ts +0 -2115
  179. package/src/services/PersistService.ts +0 -557
  180. package/src/services/RelationService.ts +0 -978
  181. package/src/services/RelationWriteService.ts +0 -653
  182. package/src/services/cdc/CdcListener.ts +0 -103
  183. package/src/services/cdc/junction-tables.ts +0 -91
  184. package/src/services/cdc/trigger-cdc.ts +0 -173
  185. package/src/services/channel-bus/ChannelBus.ts +0 -44
  186. package/src/services/channel-bus/PostgresChannelBus.ts +0 -299
  187. package/src/services/channel-bus/index.ts +0 -114
  188. package/src/services/channel-history.ts +0 -424
  189. package/src/services/channel-presence.ts +0 -185
  190. package/src/services/collection-helpers.ts +0 -420
  191. package/src/services/dataService.ts +0 -256
  192. package/src/services/index.ts +0 -14
  193. package/src/services/junction-writes.ts +0 -295
  194. package/src/services/nested-path.ts +0 -145
  195. package/src/services/pg-notify-listener.ts +0 -151
  196. package/src/services/realtimeService.ts +0 -2545
  197. package/src/services/row-pipeline.ts +0 -240
  198. package/src/services/write-denial.ts +0 -55
  199. package/src/types.ts +0 -4
  200. package/src/utils/connection-string.ts +0 -58
  201. package/src/utils/drizzle-conditions.ts +0 -2743
  202. package/src/utils/pg-array-null-patch.ts +0 -42
  203. package/src/utils/pg-error-utils.ts +0 -391
  204. package/src/websocket.ts +0 -855
@@ -0,0 +1,528 @@
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