@palbase/backend 8.2.0 → 8.3.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.
@@ -20,6 +20,7 @@ interface ColumnDef {
20
20
  onDeleteAction?: OnDeleteAction;
21
21
  enumName?: string;
22
22
  enumValues?: string[];
23
+ unique?: boolean;
23
24
  }
24
25
  declare const __colKind: unique symbol;
25
26
  declare const __colNullable: unique symbol;
@@ -62,6 +63,8 @@ declare class ColumnBuilder<K extends ColumnType = ColumnType, N extends boolean
62
63
  references(table: string, column: string): ColumnBuilder<K, N, D, E>;
63
64
  /** Set the ON DELETE action for a foreign key reference. */
64
65
  onDelete(action: OnDeleteAction): ColumnBuilder<K, N, D, E>;
66
+ /** Add a single-column UNIQUE constraint. */
67
+ unique(): ColumnBuilder<K, N, D, E>;
65
68
  }
66
69
  /**
67
70
  * Extracts the TypeScript value type for a column, respecting nullability.
@@ -212,6 +215,22 @@ declare const EXTENSION_DEPENDENCIES: Partial<Record<PalbaseExtension, PalbaseEx
212
215
  /** Runtime guard: is `name` a supported Palbase extension? */
213
216
  declare function isPalbaseExtension(name: string): name is PalbaseExtension;
214
217
 
218
+ /**
219
+ * A named raw-SQL DDL object declared in db/schema.ts for anything the typed DSL
220
+ * cannot express (EXCLUDE, CHECK, partial/expression indexes, triggers, views).
221
+ * The deploy emits `up` verbatim on the privileged DDL connection — same trust
222
+ * posture as policy().using(). Tracked by NAME (not by diffing the body), so a
223
+ * changed body needs a new name or an explicit drop+add.
224
+ */
225
+ interface RawConstraintDef {
226
+ name: string;
227
+ up: string;
228
+ down?: string;
229
+ }
230
+ declare function raw(name: string, up: string, opts?: {
231
+ down?: string;
232
+ }): RawConstraintDef;
233
+
215
234
  /**
216
235
  * A map of column builders keyed by column name — the value you write under
217
236
  * the `columns` key of `defineSchema({ tables: { <name>: { columns } } })`.
@@ -239,6 +258,41 @@ interface TableInput<C extends ColumnMap = ColumnMap> {
239
258
  columns: C;
240
259
  rls?: boolean;
241
260
  policies?: (PolicyBuilder | PolicyDef)[];
261
+ /** Composite/named primary key (ordered column names). Omit for single-column inline .primaryKey(). */
262
+ primaryKey?: string[];
263
+ /** Named multi-column UNIQUE constraints. */
264
+ unique?: {
265
+ name: string;
266
+ columns: string[];
267
+ }[];
268
+ /** Named raw-SQL DDL objects (EXCLUDE, triggers, views) that the typed DSL cannot express. */
269
+ raw?: RawConstraintDef[];
270
+ /**
271
+ * Named first-class CHECK constraints. Diffed by NAME with a BODY compare:
272
+ * a changed `expr` (after pg normalization) recreates the constraint
273
+ * (DROP + ADD). `expr` is trusted SQL emitted verbatim (like policy USING),
274
+ * `name` is identifier-validated.
275
+ */
276
+ checks?: {
277
+ name: string;
278
+ expr: string;
279
+ }[];
280
+ /**
281
+ * Plain (non-unique) btree indexes over an ordered column list, emitted as
282
+ * standalone `CREATE INDEX [IF NOT EXISTS] name ON table (col1, col2)`
283
+ * statements (NOT a table clause — a separate migration statement category).
284
+ * Structural compare by NAME (no expression normalization). `name` and each
285
+ * column are identifier-validated by the Go differ.
286
+ *
287
+ * Scope: columns-only plain btree. Partial (`where`) and expression indexes
288
+ * are a deliberate follow-up — modelling them needs the same raw-SQL
289
+ * normalization round-trip CHECK uses (Task 10), so they are NOT in this
290
+ * type yet to avoid a half-working partial-index path.
291
+ */
292
+ indexes?: {
293
+ name: string;
294
+ columns: string[];
295
+ }[];
242
296
  }
243
297
  /**
244
298
  * A table definition — the runtime value the Go runtime's `schema_extract.js`
@@ -257,6 +311,23 @@ interface TableDef<C extends ColumnMap = ColumnMap> {
257
311
  columns: C;
258
312
  rls: boolean;
259
313
  policies: PolicyDef[];
314
+ primaryKey?: string[];
315
+ unique?: {
316
+ name: string;
317
+ columns: string[];
318
+ }[];
319
+ /** Named raw-SQL DDL objects emitted verbatim on deploy. Tracked by name. */
320
+ raw?: RawConstraintDef[];
321
+ /** Named first-class CHECK constraints. Diffed by name + (normalized) body. */
322
+ checks?: {
323
+ name: string;
324
+ expr: string;
325
+ }[];
326
+ /** Plain btree indexes (columns-only), emitted as standalone CREATE INDEX. Diffed by name. */
327
+ indexes?: {
328
+ name: string;
329
+ columns: string[];
330
+ }[];
260
331
  }
261
332
  /**
262
333
  * A schema definition containing multiple tables, keyed by table name.
@@ -466,4 +537,4 @@ interface EnvTypedDatabase extends Omit<DBClient, "transaction" | "asService"> {
466
537
  asService(): EnvServiceDatabase;
467
538
  }
468
539
 
469
- export { text as A, timestamp as B, ColumnBuilder as C, uuid as D, type EnvTypedDatabase as E, type InsertShape as I, type OnDeleteAction as O, PALBASE_EXTENSIONS as P, type RowShape as R, type SchemaDef as S, type TableDef as T, type ColumnDef as a, type ColumnMap as b, type ColumnType as c, EXTENSION_DEPENDENCIES as d, type EnvServiceDatabase as e, type EnvTables as f, type EnvTypedTable as g, type EnvTypedTx as h, type PalbaseExtension as i, PolicyBuilder as j, type PolicyCommand as k, type PolicyDef as l, type PolicyMode as m, type SchemaInput as n, type TableInput as o, type TypedDB as p, type TypedTable as q, type TypedTx as r, boolean as s, defineSchema as t, enumType as u, integer as v, isPalbaseExtension as w, jsonb as x, makeTypedDB as y, policy as z };
540
+ export { policy as A, raw as B, ColumnBuilder as C, text as D, type EnvTypedDatabase as E, timestamp as F, uuid as G, type InsertShape as I, type OnDeleteAction as O, PALBASE_EXTENSIONS as P, type RawConstraintDef as R, type SchemaDef as S, type TableDef as T, type ColumnDef as a, type ColumnMap as b, type ColumnType as c, EXTENSION_DEPENDENCIES as d, type EnvServiceDatabase as e, type EnvTables as f, type EnvTypedTable as g, type EnvTypedTx as h, type PalbaseExtension as i, PolicyBuilder as j, type PolicyCommand as k, type PolicyDef as l, type PolicyMode as m, type RowShape as n, type SchemaInput as o, type TableInput as p, type TypedDB as q, type TypedTable as r, type TypedTx as s, boolean as t, defineSchema as u, enumType as v, integer as w, isPalbaseExtension as x, jsonb as y, makeTypedDB as z };
package/dist/index.cjs CHANGED
@@ -95,6 +95,7 @@ __export(src_exports, {
95
95
  makeTypedDB: () => makeTypedDB,
96
96
  parseFileSizeLimit: () => parseFileSizeLimit,
97
97
  policy: () => policy,
98
+ raw: () => raw,
98
99
  recordThrows: () => recordThrows,
99
100
  reservedSecretKey: () => reservedSecretKey,
100
101
  storage: () => storage,
@@ -156,19 +157,19 @@ function makeTablesAccessor(ops) {
156
157
  return tablesProxy;
157
158
  }
158
159
  var rawDatabase = makeServiceProxy("Database");
159
- function makeTypedSurface(raw) {
160
+ function makeTypedSurface(raw2) {
160
161
  const ops = {
161
- query: (sql, params) => raw.query(sql, params),
162
- insert: (table, data) => raw.insert(table, data),
163
- update: (table, id, data) => raw.update(table, id, data),
164
- delete: (table, id) => raw.delete(table, id),
165
- findById: (table, id) => raw.findById(table, id),
166
- findMany: (table, query) => raw.findMany(table, query)
162
+ query: (sql, params) => raw2.query(sql, params),
163
+ insert: (table, data) => raw2.insert(table, data),
164
+ update: (table, id, data) => raw2.update(table, id, data),
165
+ delete: (table, id) => raw2.delete(table, id),
166
+ findById: (table, id) => raw2.findById(table, id),
167
+ findMany: (table, query) => raw2.findMany(table, query)
167
168
  };
168
169
  return Object.assign(ops, {
169
- tables: makeTablesAccessor(() => raw),
170
+ tables: makeTablesAccessor(() => raw2),
170
171
  transaction(fn) {
171
- return raw.transaction((rawTx) => fn({ tables: makeTablesAccessor(() => rawTx) }));
172
+ return raw2.transaction((rawTx) => fn({ tables: makeTablesAccessor(() => rawTx) }));
172
173
  }
173
174
  });
174
175
  }
@@ -283,12 +284,18 @@ function defineSchema(input) {
283
284
  if (table === void 0) continue;
284
285
  const policies = (table.policies ?? []).map(toPolicyDef);
285
286
  const rls = table.rls === true || policies.length > 0;
286
- tables[name] = {
287
+ const tableDef = {
287
288
  name,
288
289
  columns: table.columns,
289
290
  rls,
290
291
  policies
291
292
  };
293
+ if (table.primaryKey !== void 0) tableDef.primaryKey = table.primaryKey;
294
+ if (table.unique !== void 0) tableDef.unique = table.unique;
295
+ if (table.raw !== void 0 && table.raw.length > 0) tableDef.raw = table.raw.slice();
296
+ if (table.checks !== void 0 && table.checks.length > 0) tableDef.checks = table.checks.slice();
297
+ if (table.indexes !== void 0 && table.indexes.length > 0) tableDef.indexes = table.indexes.slice();
298
+ tables[name] = tableDef;
292
299
  }
293
300
  const extensions = [...new Set(input.extensions ?? [])];
294
301
  return { tables, extensions };
@@ -384,6 +391,11 @@ var ColumnBuilder = class _ColumnBuilder {
384
391
  this._def.onDeleteAction = action;
385
392
  return new _ColumnBuilder(this._def.type, this._def);
386
393
  }
394
+ /** Add a single-column UNIQUE constraint. */
395
+ unique() {
396
+ this._def.unique = true;
397
+ return new _ColumnBuilder(this._def.type, this._def);
398
+ }
387
399
  };
388
400
  function uuid() {
389
401
  return new ColumnBuilder("uuid");
@@ -410,17 +422,22 @@ function enumType(name, values) {
410
422
  return builder;
411
423
  }
412
424
 
425
+ // src/db/raw.ts
426
+ function raw(name, up, opts) {
427
+ return { name, up, ...opts?.down != null ? { down: opts.down } : {} };
428
+ }
429
+
413
430
  // src/db/typed-db.ts
414
- function makeTypedTable(name, raw) {
431
+ function makeTypedTable(name, raw2) {
415
432
  return {
416
- insert: (data) => raw.insert(name, data),
417
- update: (id, data) => raw.update(name, id, data),
418
- delete: (id) => raw.delete(name, id),
419
- findById: (id) => raw.findById(name, id),
420
- findMany: (query) => raw.findMany(name, query)
433
+ insert: (data) => raw2.insert(name, data),
434
+ update: (id, data) => raw2.update(name, id, data),
435
+ delete: (id) => raw2.delete(name, id),
436
+ findById: (id) => raw2.findById(name, id),
437
+ findMany: (query) => raw2.findMany(name, query)
421
438
  };
422
439
  }
423
- function makeTypedDB(schema, raw) {
440
+ function makeTypedDB(schema, raw2) {
424
441
  function buildTables(client) {
425
442
  const tables = {};
426
443
  for (const key of Object.keys(schema.tables)) {
@@ -432,8 +449,8 @@ function makeTypedDB(schema, raw) {
432
449
  return tables;
433
450
  }
434
451
  const result = {
435
- tables: buildTables(raw),
436
- transaction: (fn) => raw.transaction((rawTx) => fn({ tables: buildTables(rawTx) }))
452
+ tables: buildTables(raw2),
453
+ transaction: (fn) => raw2.transaction((rawTx) => fn({ tables: buildTables(rawTx) }))
437
454
  };
438
455
  return result;
439
456
  }
@@ -1536,6 +1553,7 @@ var import_zod2 = require("zod");
1536
1553
  makeTypedDB,
1537
1554
  parseFileSizeLimit,
1538
1555
  policy,
1556
+ raw,
1539
1557
  recordThrows,
1540
1558
  reservedSecretKey,
1541
1559
  storage,