palgres 0.3.0 → 0.3.2

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.
@@ -14,25 +14,22 @@ export declare function qualifiedTableKey(schemaName: string, tableName: string)
14
14
  */
15
15
  export type ColumnMap = Record<string, ColumnBuilder>;
16
16
  /**
17
- * The author-facing value written under each table key:
18
- * `{ columns, rls?, policies? }`.
17
+ * One index of a table, as `defineTable` stores it: what `index(name)` builds,
18
+ * or a plain object you can write under a table's `indexes` yourself.
19
19
  *
20
- * - `columns`: the column map (required).
21
- * - `rls`: enable + FORCE row-level security on this table. **Defaults to
22
- * `true`**, and is forced on when `policies` is non-empty. A table with RLS
23
- * and no policies is deny-all, which is the starting state: nothing reads it
24
- * until a policy says who may. Set `rls: false` only for a genuinely public
25
- * table — it is an explicit opt-out that a reviewer can grep for, not
26
- * something you get by forgetting.
27
- * - `policies`: the RLS policies for this table, authored with `policy(name)`.
28
- * Each entry may be a {@link PolicyBuilder} (the normal `policy(...)` chain)
29
- * or a raw {@link PolicyDef} object.
30
- *
31
- * The `C` type parameter preserves the precise per-column phantom types so the
32
- * typed `Database.public.*` surface keeps inferring insert/row shapes.
20
+ * `columns` and `expression` are alternatives: either a list of columns, or an
21
+ * SQL expression such as `lower(email)`. `where` makes it a partial index; its
22
+ * condition is written in the same expression language as RLS policies, so
23
+ * there is no separate filter syntax to learn.
33
24
  */
34
25
  export interface IndexDef {
35
26
  name: string;
27
+ /**
28
+ * Makes this a `CREATE UNIQUE INDEX`. Unlike the table-level `unique`
29
+ * option, which creates a UNIQUE constraint and so cannot have a `WHERE`, a
30
+ * unique index can also be partial: set `where` as well for a partial unique
31
+ * index.
32
+ */
36
33
  unique?: boolean;
37
34
  columns?: string[];
38
35
  expression?: string;
@@ -41,18 +38,75 @@ export interface IndexDef {
41
38
  nulls?: "first" | "last";
42
39
  include?: string[];
43
40
  }
41
+ /**
42
+ * Builds one index for a table's `indexes`. Start it with `index(name)`.
43
+ *
44
+ * ```ts
45
+ * indexes: (c) => [
46
+ * index("orders_open")
47
+ * .on(c.col("status")) // typed column
48
+ * .where(c.col("deleted_at").isNull()) // partial
49
+ * .include(["total"]), // covering
50
+ * ]
51
+ * ```
52
+ *
53
+ * The `where` condition uses the same expression language as `policy()`, so
54
+ * policies and indexes share one way of writing a filter.
55
+ *
56
+ * Columns come from the `indexes` callback (`c.col(...)`) rather than from the
57
+ * table value (`orders.status`), because the index is declared inside the
58
+ * table's own definition, where the table value does not exist yet. `policies`
59
+ * works the same way for the same reason.
60
+ */
44
61
  export declare class IndexBuilder {
45
62
  readonly _def: IndexDef;
46
63
  constructor(name: string);
64
+ /**
65
+ * Makes the index `UNIQUE` (`CREATE UNIQUE INDEX`). Together with `.where()`
66
+ * it gives a partial unique index, the only declarative way to say "NULLs
67
+ * are free, non-NULLs are unique".
68
+ */
47
69
  unique(): this;
70
+ /**
71
+ * The indexed columns, as `c.col(...)` references. Their order is kept and
72
+ * matters: a multi-column index is defined by its column order. For an
73
+ * expression, use `onExpression()` instead.
74
+ */
48
75
  on(...cols: PolicyExprRef[]): this;
76
+ /**
77
+ * Indexes an SQL expression, such as `lower(email)`, instead of columns.
78
+ *
79
+ * The text is used verbatim, as with `policy().using("…")`: it is trusted SQL
80
+ * from your schema file, never user input. It covers what the typed builder
81
+ * cannot express, so you do not have to write a migration by hand.
82
+ */
49
83
  onExpression(expr: string): this;
84
+ /** The partial-index condition, written in the same expression language as RLS policies. */
50
85
  where(expr: PolicyExprRef): this;
86
+ /** Sorts the index in descending order. The direction rarely matters for an
87
+ * index read one way; it does when the index has to match a query's `ORDER BY`. */
51
88
  desc(): this;
89
+ /** Sorts the index in ascending order, which is the Postgres default. */
52
90
  asc(): this;
91
+ /** Where NULLs sort in the index (`NULLS FIRST` or `NULLS LAST`), so it can match an `ORDER BY … NULLS LAST` query. */
53
92
  nulls(where: "first" | "last"): this;
93
+ /** Makes a covering index (`INCLUDE`): these columns are stored in the index
94
+ * so a query can be answered by an index-only scan, but they are not searched by. */
54
95
  include(cols: string[]): this;
55
96
  }
97
+ /**
98
+ * Starts an index named `name`, for a table's `indexes` callback.
99
+ *
100
+ * Indexes are matched by name across deploys. Change the definition of a
101
+ * live index under the same name and the deploy builds the new one
102
+ * `CONCURRENTLY` next to it, under a name of its own, while the old one keeps
103
+ * serving; at complete the old one goes and the new one takes its name. Give
104
+ * it a new name instead and the old one simply goes at complete. An index
105
+ * renamed with the same definition is only renamed.
106
+ *
107
+ * @param name The index name. It must not be empty.
108
+ * @returns An {@link IndexBuilder}: chain `.on()` or `.onExpression()`, and optionally `.where()`, `.unique()`, `.include()`, `.asc()`, `.desc()`, `.nulls()`.
109
+ */
56
110
  export declare function index(name: string): IndexBuilder;
57
111
  /**
58
112
  * A table's rows found by meaning and by word — `Database.public.<table>.search("…")`.
@@ -83,10 +137,63 @@ export interface SearchInput<Col extends string = string> {
83
137
  */
84
138
  staleness?: 'null' | 'keep';
85
139
  }
140
+ /**
141
+ * What you pass to `defineTable(name, { columns, rls?, policies?, … })`.
142
+ *
143
+ * - `columns`: the column map (required).
144
+ * - `rls`: enable + FORCE row-level security on this table. **Defaults to
145
+ * `true`**, and is forced on when `policies` is non-empty. A table with RLS
146
+ * and no policies is deny-all, which is the starting state: nothing reads it
147
+ * until a policy says who may. Set `rls: false` only for a genuinely public
148
+ * table — it is an explicit opt-out that a reviewer can grep for, not
149
+ * something you get by forgetting.
150
+ * - `policies`: the RLS policies for this table, authored with `policy(name)`.
151
+ * Each entry may be a {@link PolicyBuilder} (the normal `policy(...)` chain)
152
+ * or a raw {@link PolicyDef} object.
153
+ *
154
+ * The `C` type parameter preserves the precise per-column phantom types so the
155
+ * typed `Database.public.*` surface keeps inferring insert/row shapes.
156
+ */
86
157
  export interface TableInput<C extends ColumnMap = ColumnMap> {
87
158
  columns: C;
88
159
  rls?: boolean;
160
+ /**
161
+ * The table's RLS policies, written as a function of the table's own columns.
162
+ *
163
+ * It is a callback so that TypeScript knows which table the policies belong
164
+ * to: the column names inferred from `columns` are passed in, and a typo such
165
+ * as `p.col("ownerr")` is a compile error. In a plain array, `policy("x")`
166
+ * could not know its table, and a wrong column name would only come back from
167
+ * Postgres when `CREATE POLICY` runs during the deploy. A wrong column in an
168
+ * RLS policy is an access-control bug, so it is caught at compile time.
169
+ *
170
+ * ```ts
171
+ * policies: (p) => [
172
+ * policy("owner_read").for("select").using(p.col("owner").eq(p.auth.uid())),
173
+ * ]
174
+ * ```
175
+ */
89
176
  policies?: (p: PolicyExprCtx<Extract<keyof C, string>>) => (PolicyBuilder | PolicyDef)[];
177
+ /**
178
+ * Marks the table as no longer used by this release: the first step of
179
+ * dropping it.
180
+ *
181
+ * This is the table version of a column's `.ignored()`, and it exists for the
182
+ * same reason: while a deploy runs, the release still serving reads the
183
+ * table, so a table that holds rows is not dropped while that release may
184
+ * still use it.
185
+ *
186
+ * A table removed from the schema is dropped at complete when it is empty. A
187
+ * table with rows is refused unless the release already serving marked it
188
+ * ignored: mark it, deploy, then remove it from the schema in a later deploy.
189
+ *
190
+ * Marking produces no DDL, so the deploy that ships it changes nothing in the
191
+ * database.
192
+ *
193
+ * ```ts
194
+ * const cloud_images = defineTable("cloud_images", { ignored: true, columns: { … } });
195
+ * ```
196
+ */
90
197
  ignored?: boolean;
91
198
  /** Composite/named primary key (ordered column names). Omit for single-column inline .primaryKey(). */
92
199
  primaryKey?: string[];
@@ -97,18 +204,43 @@ export interface TableInput<C extends ColumnMap = ColumnMap> {
97
204
  }[];
98
205
  /** Named raw-SQL DDL objects (EXCLUDE, triggers, views) that the typed DSL cannot express. */
99
206
  raw?: RawConstraintDef[];
207
+ /**
208
+ * Named first-class CHECK constraints. Matched by NAME; a changed `expr`
209
+ * (compared as written, ignoring leading and trailing spaces) replaces the
210
+ * constraint: the new one is added `NOT VALID`, so new writes are held to it
211
+ * at once, and validated while writes go on. `name` must be a valid
212
+ * identifier.
213
+ *
214
+ * Two forms, stored the same way:
215
+ *
216
+ * - An array: each `expr` is trusted SQL used verbatim, like a policy's
217
+ * `using`.
218
+ * - A callback: `(c) => [check(name, c.col("amount").gt(0))]`. The expression
219
+ * is written with the same expression builder as policies, and column names
220
+ * are checked at compile time. It has to be a callback for that: with a
221
+ * plain array, TypeScript could not tie the expression to this table's
222
+ * `columns`.
223
+ *
224
+ * In the string form, a misspelled column name only comes back from Postgres
225
+ * at `ALTER TABLE … ADD CONSTRAINT`, in the middle of a deploy. The typed form
226
+ * reports the same mistake while you write it.
227
+ *
228
+ * The typed form allows less than a policy does: `existsIn` and `auth.uid()`
229
+ * are subqueries, which Postgres does not allow in a CHECK, so `check()`
230
+ * rejects them.
231
+ */
100
232
  checks?: CheckDef[] | ((c: PolicyExprCtx<Extract<keyof C, string>>) => CheckDef[]);
101
233
  /**
102
234
  * Plain (non-unique) btree indexes over an ordered column list, emitted as
103
235
  * standalone `CREATE INDEX [IF NOT EXISTS] name ON table (col1, col2)`
104
236
  * statements (NOT a table clause — a separate migration statement category).
105
- * Structural compare by NAME (no expression normalization). `name` and each
106
- * column are identifier-validated by the Go differ.
237
+ * Matched by NAME. `name` and each column must be valid identifiers; a
238
+ * deploy refuses one that is not.
107
239
  *
108
- * NAME is the WHOLE diff key. Editing `.where()`, `.onExpression()`,
109
- * `.include()` or the sort under a name that is already live does NOTHING —
110
- * the deploy matches the name, sees the index, and skips. Give a changed
111
- * definition a new name.
240
+ * Editing `.where()`, `.onExpression()`, `.include()`, the sort or
241
+ * `.unique()` under a name that is already live rebuilds the index: the new
242
+ * one is built `CONCURRENTLY` next to the old one, which keeps serving until
243
+ * complete, and then takes its name.
112
244
  *
113
245
  * Scope, via `index(name)`: `.on(...cols)` · `.onExpression(sql)` (expression
114
246
  * index) · `.where(pred)` (partial index, typed predicate) · `.unique()`
@@ -127,6 +259,16 @@ export interface TableInput<C extends ColumnMap = ColumnMap> {
127
259
  * opclass, or CONCURRENTLY.
128
260
  */
129
261
  indexes?: (p: PolicyExprCtx<Extract<keyof C, string>>) => (IndexBuilder | IndexDef)[];
262
+ /**
263
+ * Table-level foreign keys, including multi-column ones, built with
264
+ * `foreignKey(name)`.
265
+ *
266
+ * A column's `.references()` covers one column and one target. It cannot
267
+ * express what multi-tenant integrity needs, such as
268
+ * `FOREIGN KEY (tenant_id, child_id) REFERENCES parent (tenant_id, id)`.
269
+ * The two can be used together and neither drops the other: a key declared
270
+ * here is tracked by its own name, a column's by `<table>_<column>_fkey`.
271
+ */
130
272
  foreignKeys?: (p: PolicyExprCtx<Extract<keyof C, string>>) => (ForeignKeyBuilder | ForeignKeyDef)[];
131
273
  }
132
274
  /**
@@ -144,6 +286,7 @@ export interface TableDef<C extends ColumnMap = ColumnMap> {
144
286
  name: string;
145
287
  columns: C;
146
288
  rls: boolean;
289
+ /** Set when the table is marked as no longer used by this release; see `TableInput.ignored`. */
147
290
  ignored?: boolean;
148
291
  policies: PolicyDef[];
149
292
  primaryKey?: string[];
@@ -153,8 +296,13 @@ export interface TableDef<C extends ColumnMap = ColumnMap> {
153
296
  }[];
154
297
  /** Named raw-SQL DDL objects emitted verbatim on deploy. Tracked by name. */
155
298
  raw?: RawConstraintDef[];
299
+ /** Named first-class CHECK constraints, matched by name and compared by the
300
+ * expression as written. Both forms of `TableInput.checks` (array and
301
+ * callback) end up here. */
156
302
  checks?: CheckDef[];
303
+ /** The table's indexes, with their partial, expression, sort and covering options. */
157
304
  indexes?: IndexDef[];
305
+ /** The table's table-level foreign keys, including multi-column ones. */
158
306
  foreignKeys?: ForeignKeyDef[];
159
307
  /** The table's search, its defaults said — see SearchInput. */
160
308
  search?: Search;
@@ -169,7 +317,7 @@ export interface TableDef<C extends ColumnMap = ColumnMap> {
169
317
  export interface SchemaDef<T extends Record<string, TableDef> = Record<string, TableDef>> {
170
318
  /** The schema's own name — `public`, `billing`, … Declared, never derived. */
171
319
  name: string;
172
- /** Kept for the schema files v2 wrote; v3 has no REST surface over tables, so it changes nothing. */
320
+ /** Accepted so older schema files still read; there is no REST surface over tables, so it changes nothing. */
173
321
  exposed: boolean;
174
322
  tables: T;
175
323
  /** Postgres extensions the deploy creates (CREATE EXTENSION IF NOT EXISTS). */
@@ -179,9 +327,11 @@ export interface SchemaDef<T extends Record<string, TableDef> = Record<string, T
179
327
  * hand-built `SchemaDef` from before the field still compiles. */
180
328
  raw?: RawUnitDef[];
181
329
  }
182
- /** The author-facing input to `defineSchema` — a `tables` map whose keys are
183
- * the table names and whose values are `{ columns, rls?, policies? }`, plus an
184
- * optional `extensions` allowlist. */
330
+ /**
331
+ * The retired dictionary form of `defineSchema`'s input (a `tables` map keyed
332
+ * by table name). `defineSchema` refuses it: pass the schema's name and an
333
+ * array of `defineTable(…)` tables instead.
334
+ */
185
335
  export interface SchemaInput<T extends Record<string, TableInput> = Record<string, TableInput>> {
186
336
  tables: T;
187
337
  /**
@@ -197,8 +347,44 @@ type TablesByName<T extends readonly TableHandle[]> = {
197
347
  [K in T[number] as K[typeof TABLE_META]["name"]]: K[typeof TABLE_META];
198
348
  };
199
349
  /**
200
- * How a schema file reads. One file per schema — `db/public.ts`, `db/billing.ts`
201
- * — and the schema says its own name:
350
+ * Where a table's metadata lives.
351
+ *
352
+ * The table VALUE is its columns, so `lists.id` is the column — which means a
353
+ * column called `name` would overwrite the table's own name if metadata sat in
354
+ * a plain field. `columns`, `rls`, `unique` and `indexes` are all plausible
355
+ * column names too. A column cannot collide with a symbol.
356
+ */
357
+ export declare const TABLE_META: unique symbol;
358
+ /**
359
+ * A value produced by `defineTable`: the columns, plus metadata behind the
360
+ * symbol. `S` is the table's search as declared: with one, the table's type
361
+ * says so, and `search()` is typed for it.
362
+ */
363
+ export type TableHandle<C extends ColumnMap = ColumnMap, N extends string = string, S = undefined> = C & {
364
+ readonly [TABLE_META]: TableDef<C> & {
365
+ name: N;
366
+ } & ([S] extends [undefined] ? unknown : {
367
+ search: Search;
368
+ });
369
+ };
370
+ /**
371
+ * Declare one table as a standalone value that KNOWS ITS OWN NAME.
372
+ *
373
+ * The name lives here, not in a dictionary key. A table whose name comes from a
374
+ * key cannot resolve `references(() => other.id)` when it is built — it does not
375
+ * know what to call itself — which forces a two-phase resolution with an
376
+ * empty-name intermediate state. One name source, no empty identity.
377
+ *
378
+ * The returned object spreads its own columns, so a sibling can point at it:
379
+ * `references(() => lists.id)`.
380
+ */
381
+ export declare function defineTable<const N extends string, C extends ColumnMap, const S extends SearchInput<Extract<keyof C, string>> | undefined = undefined>(name: N, input: TableInput<C> & {
382
+ search?: S;
383
+ }): TableHandle<C, N, S>;
384
+ /**
385
+ * Collects declared tables into one schema: the default export of a schema
386
+ * file. One file per schema — `db/public.ts`, `db/billing.ts` — and the schema
387
+ * says its own name:
202
388
  *
203
389
  * const todos = defineTable("todos", {
204
390
  * columns: {
@@ -234,49 +420,9 @@ type TablesByName<T extends readonly TableHandle[]> = {
234
420
  * statement of intent instead of an omission. When `policies` is non-empty,
235
421
  * `rls` is forced on (ENABLE + FORCE) regardless of the declared flag — a table
236
422
  * with policies must have RLS enabled or the policies would be inert.
237
- */
238
- /**
239
- * Where a table's metadata lives.
240
- *
241
- * The table VALUE is its columns, so `lists.id` is the column — which means a
242
- * column called `name` would overwrite the table's own name if metadata sat in
243
- * a plain field. Measured, not imagined: the existing `users` / `rooms` tests
244
- * (both declare a `name` column) produced an `[object Object]` table key.
245
- * `columns`, `rls`, `unique` and `indexes` are all plausible column
246
- * names too. A column cannot collide with a symbol.
247
- */
248
- export declare const TABLE_META: unique symbol;
249
- /**
250
- * A value produced by `defineTable`: the columns, plus metadata behind the
251
- * symbol. `S` is the table's search as declared: with one, the table's type
252
- * says so, and `search()` is typed for it.
253
- */
254
- export type TableHandle<C extends ColumnMap = ColumnMap, N extends string = string, S = undefined> = C & {
255
- readonly [TABLE_META]: TableDef<C> & {
256
- name: N;
257
- } & ([S] extends [undefined] ? unknown : {
258
- search: Search;
259
- });
260
- };
261
- /**
262
- * Declare one table as a standalone value that KNOWS ITS OWN NAME.
263
- *
264
- * The name lives here, not in a dictionary key. A table whose name comes from a
265
- * key cannot resolve `references(() => other.id)` when it is built — it does not
266
- * know what to call itself — which forces a two-phase resolution with an
267
- * empty-name intermediate state. One name source, no empty identity.
268
- *
269
- * The returned object spreads its own columns, so a sibling can point at it:
270
- * `references(() => lists.id)`.
271
- */
272
- export declare function defineTable<const N extends string, C extends ColumnMap, const S extends SearchInput<Extract<keyof C, string>> | undefined = undefined>(name: N, input: TableInput<C> & {
273
- search?: S;
274
- }): TableHandle<C, N, S>;
275
- /**
276
- * Collect declared tables into one schema.
277
423
  *
278
- * Takes an ARRAY, not a dictionary: the tables already carry their names, and a
279
- * second name source is a second thing that can disagree.
424
+ * Takes an ARRAY of tables, not a dictionary: the tables already carry their
425
+ * names, and a second name source is a second thing that can disagree.
280
426
  */
281
427
  export declare function defineSchema<const T extends readonly TableHandle[]>(name: string, input: {
282
428
  tables: T;
@@ -1,2 +0,0 @@
1
- /*! palgres 0.3.0 — Palbase SDK License (see LICENSE) */
2
- import{d as b,e as p,y as c}from"./N5PWAFHA.js";var g={uuid:"uuid",text:"text",integer:"integer",bigint:"bigint",numeric:"numeric",boolean:"boolean",timestamp:"timestamp with time zone",date:"date",jsonb:"jsonb"};function v(e){let n=Array.isArray(e)?e:[e],t={tables:[],enums:[],extensions:[],raw:[]},i=new Map;for(let l of n){for(let o of Object.values(l.tables))t.tables.push(E(l.name,o,i));t.extensions.push(...l.extensions);for(let o of l.raw??[])t.raw.push({name:o.name,schema:l.name,sql:o.up,...o.drop!==void 0?{drop:o.drop}:{},...o.before===!0?{before:!0}:{}})}t.enums=[...i.values()];for(let l of n)for(let o of Object.values(l.tables))for(let f of o.raw??[])t.raw.push({name:f.name,table:`${l.name}.${o.name}`,sql:f.up});return t}function x(e){return e._def}function E(e,n,t){let i=[],l=(n.unique??[]).map(r=>({name:r.name,columns:[...r.columns]})),o=[],f=[],s=new Set;for(let[r,y]of Object.entries(n.columns)){let u=x(y),m={name:r,type:D(e,r,n.name,u,t),nullable:u.nullable},h=K(u);if(h!==void 0&&(m.default=h),u.renamedFrom!==void 0&&(m.renamedFrom=u.renamedFrom),u.ignored&&(m.ignored=!0),u.fill!==void 0&&(m.fill=u.fill),u.identity!==void 0&&(m.identity=u.identity==="always"?"always":"by default"),u.generated!==void 0&&(m.generated={...u.generated}),u.user!==void 0&&(m.user={...u.user}),u.primaryKey&&f.push(r),u.unique&&l.push({name:`${n.name}_${r}_key`,columns:[r]}),u.references!==void 0){let[T,C]=w(u.references.table);o.push({name:`${q(e,n.name)}_${r}_fkey`,columns:[r],refSchema:T,refTable:C,refColumns:[u.references.column],onDelete:u.onDeleteAction??"no action",onUpdate:u.onUpdateAction??"no action"}),u.index===!1&&s.add(r)}i.push(m)}for(let r of n.foreignKeys??[]){r.index===!1&&r.columns.length===1&&s.add(r.columns[0]);let[y,u]=w(r.refTable);o.push({name:r.name,columns:[...r.columns],refSchema:y,refTable:u,refColumns:[...r.refColumns],onDelete:r.onDelete??"no action",onUpdate:r.onUpdate??"no action",...r.match==="full"?{match:"full"}:{}})}let a={schema:e,name:n.name,columns:i,primaryKey:n.primaryKey!==void 0?[...n.primaryKey]:f,uniques:l,indexes:(n.indexes??[]).map(N),checks:(n.checks??[]).map(r=>({name:r.name,expr:r.expr})),foreignKeys:o,rls:n.rls,policies:n.policies.map(P)};return n.ignored&&(a.ignored=!0),n.search!==void 0&&(a.search={...n.search,from:[...n.search.from]}),a.uniques=B(a.uniques),S(a,s,new Set((n.raw??[]).map(r=>r.name)),new Set(n.policies.filter(r=>r.indexes===!1).map(r=>r.name))),a}function D(e,n,t,i,l){let o=i.type;if(o==="enum"||o==="enum[]"){let f=i.enumName,s=`${e}.${f}`,a=i.enumValues??[],r=l.get(s);if(r&&r.values.join()!==a.join())throw new Error(`enum ${s} is declared with different values by ${t}.${n}: (${r.values.join(", ")}) and (${a.join(", ")}) \u2014 one type has one list`);return l.set(s,{schema:e,name:f,values:[...a]}),o==="enum[]"?`${p(e,f)}[]`:p(e,f)}return o==="sql"?b(i.sqlType):o==="numeric"&&i.precision!==void 0?`numeric(${i.precision},${i.scale??0})`:o.endsWith("[]")?`${g[o.slice(0,-2)]??o.slice(0,-2)}[]`:g[o]??o}function K(e){if(e.defaultSql!==void 0)return e.defaultSql;if(e.defaultRandom)return"gen_random_uuid()";if(e.defaultNow)return e.type==="date"?"CURRENT_DATE":"now()";let n=e.defaultValue;if(n!==void 0){if(Array.isArray(n)&&n.length===0&&e.type.endsWith("[]"))return"'{}'";if(typeof n=="string")return`'${n.replace(/'/g,"''")}'`;if(typeof n=="boolean")return n?"true":"false";if(typeof n=="number"){if(!Number.isFinite(n))throw new Error(`default ${n} is not a number Postgres can store`);return String(n)}return n===null?"NULL":`'${JSON.stringify(n).replace(/'/g,"''")}'::jsonb`}}function N(e){let n=e.expression!==void 0?[{expr:e.expression}]:(e.columns??[]).map(l=>({column:l}));for(let l of n)e.sort==="desc"&&(l.desc=!0),e.nulls!==void 0&&(l.nulls=e.nulls);let t={name:e.name,keys:n,unique:e.unique===!0},i=e.where===void 0?void 0:c(e.where);return i!==void 0&&(t.where=i),e.include?.length&&(t.include=[...e.include]),t}function P(e){let n={name:e.name,for:e.command,to:e.roles.length===0?["public"]:[...e.roles]},t=c(e.using),i=c(e.withCheck);return t!==void 0&&(n.using=t),i!==void 0&&(n.withCheck=i),e.permissive||(n.restrictive=!0),n}function S(e,n,t,i){let l=new Set,o=s=>s[0]!==void 0&&l.add(s[0]);o(e.primaryKey);for(let s of e.uniques)o(s.columns);for(let s of e.indexes){let a=s.keys[0];a&&"column"in a&&s.where===void 0&&l.add(a.column)}let f=s=>{if(l.has(s)||e.columns.find(r=>r.name===s)?.ignored)return;let a=`${e.name}_${s}_idx`;Buffer.byteLength(a)>63||e.indexes.some(r=>r.name===a)||t.has(a)||(e.indexes.push({name:a,keys:[{column:s}],unique:!1}),l.add(s))};for(let s of e.foreignKeys)s.columns.length===1&&!n.has(s.columns[0])&&f(s.columns[0]);for(let s of e.policies)if(!i.has(s.name))for(let a of A(e,s))f(a)}function A(e,n){let t=[];for(let i of[n.using,n.withCheck])if(i!==void 0)for(let l of i.matchAll(/(?<![.\w"])"((?:[^"]|"")+)"(?!\s*\.)/g)){let o=l[1].replace(/""/g,'"');e.columns.some(f=>f.name===o)&&!t.includes(o)&&t.push(o)}return t}function w(e){let n=e.indexOf(".");return n<0?["public",e]:[e.slice(0,n),e.slice(n+1)]}function q(e,n){return e==="public"?n:`${e}_${n}`}function B(e){let n=new Map;return e.filter(t=>{let i=n.get(t.name);if(i===void 0)return n.set(t.name,t),!0;if(i.columns.join()!==t.columns.join())throw new Error(`palgres: unique ${t.name} is declared over (${i.columns.join(", ")}) and over (${t.columns.join(", ")}): give one of them another name`);return!1})}var _=new Set(["uuid","text","integer","bigint","numeric","boolean","timestamp","date","enum"]),R={number:{fromDb:e=>Number(e),toDb:e=>{if(typeof e=="number"&&!Number.isSafeInteger(e))throw new Error(`asNumber() cannot write ${e}: it is outside the safe integer range and would be stored as a different number. Declare .asDecimal() and hand this column a string.`);return String(e)},tsType:"number"},decimal:{fromDb:e=>e==null?e:String(e),toDb:e=>e==null?e:String(e),tsType:"string"}},d=class e{_def;constructor(n,t){this._def=t??{type:n,nullable:!1,primaryKey:!1}}primaryKey(){return this._def.primaryKey=!0,new e(this._def.type,this._def)}notNull(){return this._def.nullable=!1,new e(this._def.type,this._def)}nullable(){if(this._def.identity!==void 0)throw new Error(".nullable() on an identity column: an identity is always NOT NULL");return this._def.nullable=!0,new e(this._def.type,this._def)}default(n){return this._def.defaultValue=n,new e(this._def.type,this._def)}defaultRandom(){return this._def.defaultRandom=!0,new e(this._def.type,this._def)}defaultNow(){return this._def.defaultNow=!0,new e(this._def.type,this._def)}defaultSql(n){if(typeof n!="string"||n.trim()==="")throw new Error("defaultSql() takes the SQL of the default");return this._def.defaultSql=n,new e(this._def.type,this._def)}dbAssigned(){return this._def.dbAssigned=!0,new e(this._def.type,this._def)}array(){let n=this._def.type;if(!_.has(n))throw new Error(`${n} column: .array() is available on uuid(), text(), integer(), bigint(), numeric(), boolean(), timestamp(), date() and enumType()`);if(this._def.defaultValue!==void 0||this._def.defaultNow||this._def.defaultRandom||this._def.defaultSql!==void 0)throw new Error(`.array() comes before the default \u2014 write ${n}().array().default([])`);if(this._def.codec!==void 0||this._def.transform!==void 0)throw new Error(".array() cannot follow a codec or a transform \u2014 they convert one value, not a list of them");let t=`${n}[]`;return new e(t,{...this._def,type:t})}identity(n){if(this._def.type!=="integer"&&this._def.type!=="bigint"&&!(this._def.type==="sql"&&this._def.sqlType==="smallint"))throw new Error(`${this._def.type} column: .identity() is for integer(), bigint() and sqlType('smallint') columns`);if(this._def.defaultValue!==void 0||this._def.defaultNow||this._def.defaultRandom||this._def.defaultSql!==void 0||this._def.fill!==void 0)throw new Error(".identity() is the column's value \u2014 it cannot also have a default or a fill");let t=n?.always===!1?"byDefault":"always";return new e(this._def.type,{...this._def,nullable:!1,identity:t})}generated(n,t={}){if(typeof n!="string"||n.trim()==="")throw new Error(".generated() takes the SQL expression the column is");if(this._def.defaultValue!==void 0||this._def.defaultNow||this._def.defaultRandom||this._def.defaultSql!==void 0||this._def.fill!==void 0||this._def.identity!==void 0)throw new Error(".generated() is the column's value \u2014 it cannot also have a default, a fill or an identity");return new e(this._def.type,{...this._def,generated:{expr:n,stored:t.stored===!0}})}fillWith(n){return new e(this._def.type,{...this._def,fill:n})}renamedFrom(n){return this._def.renamedFrom=n,this}ignored(){return new e(this._def.type,{...this._def,ignored:!0})}references(n,t){if(typeof n!="function")throw new Error('references(...) takes a callback: write references(() => otherTable.column). The two-string form references("table", "column") is gone \u2014 a string cannot be type-checked and cannot point at a table that does not exist yet.');return this._def.referencesThunk=n,t?.as!==void 0&&(this._def.refAs=t.as),t?.reverseAs!==void 0&&(this._def.reverseAs=t.reverseAs),t?.onDelete!==void 0&&(this._def.onDeleteAction=t.onDelete),t?.onUpdate!==void 0&&(this._def.onUpdateAction=t.onUpdate),t?.index===!1&&(this._def.index=!1),new e(this._def.type,this._def)}selfReferences(n,t){return this._def.selfRefColumn=n,t?.as!==void 0&&(this._def.refAs=t.as),t?.onDelete!==void 0&&(this._def.onDeleteAction=t.onDelete),new e(this._def.type,this._def)}onDelete(n){return this._def.onDeleteAction=n,new e(this._def.type,this._def)}unique(){return this._def.unique=!0,new e(this._def.type,this._def)}asNumber(){return this.withCodec("number","asNumber")}asDecimal(){return this.withCodec("decimal","asDecimal")}withCodec(n,t){if(this._def.type!=="bigint"&&this._def.type!=="numeric")throw new Error(`${this._def.type} column: .${t}() is only available on bigint()/numeric() \u2014 those are the exact-precision types that surface as string.`);if(this._def.transform!==void 0)throw new Error(`.${t}() and .transform() are two ways to say the same thing on one column \u2014 keep .${t}().`);if(this._def.codec!==void 0)throw new Error(`column already declares .as${this._def.codec==="number"?"Number":"Decimal"}(); a column has ONE codec.`);return new e(this._def.type,{...this._def,codec:n})}transform(n){if(this._def.codec!==void 0)throw new Error("column already declares a named codec; .transform() and .as*() are two ways to say the same thing \u2014 keep the codec.");return new e(this._def.type,{...this._def,transform:n})}};function U(){return new d("uuid")}function V(){return new d("text")}function j(){return new d("integer")}function L(){return new d("bigint")}function F(e){if(e===void 0)return new d("numeric");let{precision:n,scale:t=0}=e;if(!Number.isInteger(n)||n<1||n>1e3)throw new Error(`numeric({ precision: ${n} }): precision is a whole number from 1 to 1000`);if(!Number.isInteger(t)||t<0||t>n)throw new Error(`numeric({ precision: ${n}, scale: ${t} }): scale is a whole number from 0 to the precision`);return new d("numeric",{type:"numeric",nullable:!1,primaryKey:!1,precision:n,scale:t})}function I(){return new d("date")}var W={uuid:"uuid()",text:"text()",integer:"integer()",int:"integer()",int4:"integer()",bigint:"bigint()",int8:"bigint()",numeric:"numeric()",decimal:"numeric()",boolean:"boolean()",bool:"boolean()",timestamptz:"timestamp()","timestamp with time zone":"timestamp()",date:"date()",jsonb:"jsonb()"};function M(e){let n=typeof e=="string"?e.trim():"";if(n==="")throw new Error('sqlType() takes the Postgres type, e.g. sqlType("inet")');let t=n.toLowerCase().replace(/\[\]$/,""),i=W[t];if(i!==void 0&&!(n.endsWith("[]")&&!_.has(i.slice(0,-2))))throw new Error(`sqlType(${JSON.stringify(n)}): the DSL has this type \u2014 declare it as ${i}${n.endsWith("[]")?".array()":""}`);return new d("sql",{type:"sql",nullable:!1,primaryKey:!1,sqlType:n})}var Q=new Set(["smallint","real","double precision"]),Y=new Set(["json"]);function H(){return new d("boolean")}function z(){return new d("timestamp")}function J(){return new d("jsonb")}function G(e,n){let t=new d("enum");return t._def.enumName=e,t._def.enumValues=[...n],t}function X(){let e=new d("text");return e._def.nullable=!1,e._def.user={onDelete:"cascade",owns:!0},e}function Z(e){let n=new d("text");return n._def.user={onDelete:e.onDelete,owns:!1},e.as!==void 0&&(n._def.refAs=e.as),n}export{v as a,A as b,R as c,d,U as e,V as f,j as g,L as h,F as i,I as j,M as k,Q as l,Y as m,H as n,z as o,J as p,G as q,X as r,Z as s};