@atscript/db-postgres 0.1.38 → 0.1.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,55 +1,46 @@
1
- "use strict";
2
- //#region rolldown:runtime
3
- var __create = Object.create;
4
- var __defProp = Object.defineProperty;
5
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getProtoOf = Object.getPrototypeOf;
8
- var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __copyProps = (to, from, except, desc) => {
10
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
- key = keys[i];
12
- if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
- get: ((k) => from[k]).bind(null, key),
14
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
- });
16
- }
17
- return to;
18
- };
19
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
- value: mod,
21
- enumerable: true
22
- }) : target, mod));
23
-
24
- //#endregion
25
- const __atscript_db = __toESM(require("@atscript/db"));
26
- const __atscript_db_sql_tools = __toESM(require("@atscript/db-sql-tools"));
27
- const __atscript_core = __toESM(require("@atscript/core"));
28
-
29
- //#region packages/db-postgres/src/sql-builder.ts
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_plugin = require("./plugin-Cx6tCzk4.cjs");
3
+ let _atscript_db = require("@atscript/db");
4
+ let _atscript_db_sql_tools = require("@atscript/db-sql-tools");
5
+ //#region src/sql-builder.ts
6
+ /**
7
+ * PostgreSQL-aware default value for a given design type.
8
+ * PG uses native BOOLEAN (not TINYINT), so defaults must be `false`/`true` not `0`/`1`.
9
+ */
30
10
  function defaultValueForType(designType) {
31
11
  if (designType === "boolean") return "false";
32
12
  if (designType === "json" || designType === "object") return "'{}'";
33
13
  if (designType === "array") return "'[]'";
34
- return (0, __atscript_db_sql_tools.defaultValueForType)(designType);
14
+ return (0, _atscript_db_sql_tools.defaultValueForType)(designType);
35
15
  }
16
+ /**
17
+ * PostgreSQL-aware default value literal.
18
+ * Converts boolean defaults to `true`/`false` instead of `1`/`0`.
19
+ */
36
20
  function defaultValueToSqlLiteral(designType, value) {
37
21
  if (designType === "boolean") return value === "true" || value === "1" ? "true" : "false";
38
- return (0, __atscript_db_sql_tools.defaultValueToSqlLiteral)(designType, value);
22
+ return (0, _atscript_db_sql_tools.defaultValueToSqlLiteral)(designType, value);
39
23
  }
24
+ /** Escapes a PostgreSQL identifier by doubling double-quotes. */
40
25
  function esc(name) {
41
26
  return name.replace(/"/g, "\"\"");
42
27
  }
28
+ /** Double-quote-quotes a single identifier. */
43
29
  function qi(name) {
44
30
  return `"${esc(name)}"`;
45
31
  }
32
+ /**
33
+ * Double-quote-quotes a table name, handling `schema.table` format.
34
+ * Input is a raw name like `public.users` or just `users`.
35
+ */
46
36
  function quoteTableName(name) {
47
37
  const dot = name.indexOf(".");
48
38
  if (dot >= 0) return `${qi(name.slice(0, dot))}.${qi(name.slice(dot + 1))}`;
49
39
  return qi(name);
50
40
  }
51
- /** Converts JS values to SQL-bindable params, keeping booleans native. */ function toPgValue(value) {
52
- if (value === undefined) return null;
41
+ /** Converts JS values to SQL-bindable params, keeping booleans native. */
42
+ function toPgValue(value) {
43
+ if (value === void 0) return null;
53
44
  if (value === null) return null;
54
45
  if (value instanceof Date) return value.toISOString();
55
46
  if (typeof value === "object") return JSON.stringify(value);
@@ -65,7 +56,7 @@ const pgDialect = {
65
56
  unlimitedLimit: "ALL",
66
57
  toValue: toPgValue,
67
58
  toParam(value) {
68
- if (value === undefined) return null;
59
+ if (value === void 0) return null;
69
60
  return value;
70
61
  },
71
62
  regex(quotedCol, value) {
@@ -81,26 +72,33 @@ const pgDialect = {
81
72
  }
82
73
  };
83
74
  function buildInsert(table, data) {
84
- return (0, __atscript_db_sql_tools.buildInsert)(pgDialect, table, data);
75
+ return (0, _atscript_db_sql_tools.buildInsert)(pgDialect, table, data);
85
76
  }
86
77
  function buildSelect(table, where, controls) {
87
- return (0, __atscript_db_sql_tools.buildSelect)(pgDialect, table, where, controls);
78
+ return (0, _atscript_db_sql_tools.buildSelect)(pgDialect, table, where, controls);
88
79
  }
89
- function buildUpdate(table, data, where, limit) {
90
- return (0, __atscript_db_sql_tools.buildUpdate)(pgDialect, table, data, where, limit);
80
+ function buildUpdate(table, data, where, limit, ops) {
81
+ return (0, _atscript_db_sql_tools.buildUpdate)(pgDialect, table, data, where, limit, ops);
91
82
  }
92
83
  function buildDelete(table, where, limit) {
93
- return (0, __atscript_db_sql_tools.buildDelete)(pgDialect, table, where, limit);
84
+ return (0, _atscript_db_sql_tools.buildDelete)(pgDialect, table, where, limit);
94
85
  }
95
86
  function buildCreateView(viewName, plan, columns, resolveFieldRef) {
96
- return (0, __atscript_db_sql_tools.buildCreateView)(pgDialect, viewName, plan, columns, resolveFieldRef);
87
+ return (0, _atscript_db_sql_tools.buildCreateView)(pgDialect, viewName, plan, columns, resolveFieldRef);
97
88
  }
98
89
  function buildAggregateSelect(table, where, controls) {
99
- return (0, __atscript_db_sql_tools.buildAggregateSelect)(pgDialect, table, where, controls);
90
+ return (0, _atscript_db_sql_tools.buildAggregateSelect)(pgDialect, table, where, controls);
100
91
  }
101
92
  function buildAggregateCount(table, where, controls) {
102
- return (0, __atscript_db_sql_tools.buildAggregateCount)(pgDialect, table, where, controls);
93
+ return (0, _atscript_db_sql_tools.buildAggregateCount)(pgDialect, table, where, controls);
103
94
  }
95
+ /**
96
+ * Maps portable collation values to PostgreSQL collation names.
97
+ *
98
+ * Returns `null` for `'nocase'` — case-insensitive columns use CITEXT type instead
99
+ * (provisioned via `CREATE EXTENSION IF NOT EXISTS citext` in `ensureTable`).
100
+ * Users can also opt into ICU collation explicitly via `@db.pg.collate "und-u-ks-level2"`.
101
+ */
104
102
  function collationToPg(collation) {
105
103
  switch (collation) {
106
104
  case "binary": return "\"C\"";
@@ -114,7 +112,8 @@ function collationToPg(collation) {
114
112
  * PostgreSQL only has signed integer types:
115
113
  * uint16 (0-65535) → INTEGER (not SMALLINT which caps at 32767)
116
114
  * uint32 (0-4.3B) → BIGINT (not INTEGER which caps at ~2.1B)
117
- */ function intTypeFromTags(tags) {
115
+ */
116
+ function intTypeFromTags(tags) {
118
117
  if (tags?.has("int8") || tags?.has("byte")) return "SMALLINT";
119
118
  if (tags?.has("uint8")) return "SMALLINT";
120
119
  if (tags?.has("int16") || tags?.has("port")) return "SMALLINT";
@@ -124,6 +123,12 @@ function collationToPg(collation) {
124
123
  if (tags?.has("int64") || tags?.has("uint64")) return "BIGINT";
125
124
  return "INTEGER";
126
125
  }
126
+ /**
127
+ * Maps an Atscript field descriptor to a PostgreSQL column type.
128
+ *
129
+ * For FK fields, delegates to the target PK's type via `field.fkTargetField`
130
+ * so the FK column type always matches the referenced column.
131
+ */
127
132
  function pgTypeFromField(field) {
128
133
  if (field.fkTargetField) return pgTypeFromField(field.fkTargetField);
129
134
  const tags = field.type?.type?.tags;
@@ -132,36 +137,36 @@ function pgTypeFromField(field) {
132
137
  if (pgTypeOverride) return pgTypeOverride;
133
138
  const precision = metadata?.get("db.column.precision");
134
139
  switch (field.designType) {
135
- case "number": {
140
+ case "number":
136
141
  if (precision) return `NUMERIC(${precision.precision},${precision.scale})`;
137
142
  if (field.defaultValue?.kind === "fn" && field.defaultValue.fn === "increment") return "BIGINT";
138
143
  if (field.defaultValue?.kind === "fn" && field.defaultValue.fn === "now") return "BIGINT";
139
144
  if (tags?.has("int")) return intTypeFromTags(tags);
140
145
  return "DOUBLE PRECISION";
141
- }
142
146
  case "integer": return intTypeFromTags(tags);
143
- case "decimal": {
147
+ case "decimal":
144
148
  if (precision) return `NUMERIC(${precision.precision},${precision.scale})`;
145
149
  return "NUMERIC(10,2)";
146
- }
147
150
  case "boolean": return "BOOLEAN";
148
151
  case "string": {
149
152
  if (field.collate === "nocase" && !metadata?.get("db.pg.collate")) return "CITEXT";
150
153
  if (tags?.has("char")) return "CHAR(1)";
151
- const maxLen = metadata?.get("expect.maxLength")?.length;
152
- if (maxLen !== undefined) return `VARCHAR(${maxLen})`;
154
+ const maxLen = (metadata?.get("expect.maxLength"))?.length;
155
+ if (maxLen !== void 0) return `VARCHAR(${maxLen})`;
153
156
  if (field.isPrimaryKey || field.defaultValue) return "VARCHAR(255)";
154
157
  return "TEXT";
155
158
  }
156
159
  case "json":
157
160
  case "object":
158
161
  case "array": return "JSONB";
159
- default: {
162
+ default:
160
163
  if (field.isPrimaryKey || field.defaultValue) return "VARCHAR(255)";
161
164
  return "TEXT";
162
- }
163
165
  }
164
166
  }
167
+ /**
168
+ * Builds a CREATE TABLE IF NOT EXISTS statement with PostgreSQL syntax.
169
+ */
165
170
  function buildCreateTable(table, fields, foreignKeys, options) {
166
171
  const colDefs = [];
167
172
  const primaryKeys = fields.filter((f) => f.isPrimaryKey);
@@ -171,17 +176,17 @@ function buildCreateTable(table, fields, foreignKeys, options) {
171
176
  let def = `${qi(field.physicalName)} ${sqlType}`;
172
177
  if (options?.incrementFields?.has(field.physicalName)) {
173
178
  const start = options.autoIncrementStart;
174
- def += start !== undefined ? ` GENERATED BY DEFAULT AS IDENTITY (START WITH ${start})` : " GENERATED BY DEFAULT AS IDENTITY";
179
+ def += start !== void 0 ? ` GENERATED BY DEFAULT AS IDENTITY (START WITH ${start})` : " GENERATED BY DEFAULT AS IDENTITY";
175
180
  }
176
181
  if (!field.optional && !field.isPrimaryKey && !options?.incrementFields?.has(field.physicalName)) def += " NOT NULL";
177
182
  if (field.defaultValue?.kind === "value") def += ` DEFAULT ${defaultValueToSqlLiteral(field.designType, field.defaultValue.value)}`;
178
- else if (field.defaultValue?.kind === "fn") {
183
+ else if (field.defaultValue?.kind === "fn") {
179
184
  if (field.defaultValue.fn === "uuid") def += " DEFAULT gen_random_uuid()";
180
- else if (field.defaultValue.fn === "now") def += " DEFAULT (extract(epoch from now()) * 1000)::bigint";
185
+ else if (field.defaultValue.fn === "now") def += " DEFAULT (extract(epoch from now()) * 1000)::bigint";
181
186
  }
182
187
  const nativeCollate = field.type?.metadata?.get("db.pg.collate");
183
188
  if (nativeCollate) def += ` COLLATE "${nativeCollate}"`;
184
- else if (field.collate) {
189
+ else if (field.collate) {
185
190
  const pgCollate = collationToPg(field.collate);
186
191
  if (pgCollate) def += ` COLLATE ${pgCollate}`;
187
192
  }
@@ -201,47 +206,88 @@ else if (field.collate) {
201
206
  const localCols = fk.fields.map((f) => qi(f)).join(", ");
202
207
  const targetCols = fk.targetFields.map((f) => qi(f)).join(", ");
203
208
  let constraint = `FOREIGN KEY (${localCols}) REFERENCES ${qi(fk.targetTable)} (${targetCols})`;
204
- if (fk.onDelete) constraint += ` ON DELETE ${(0, __atscript_db_sql_tools.refActionToSql)(fk.onDelete)}`;
205
- if (fk.onUpdate) constraint += ` ON UPDATE ${(0, __atscript_db_sql_tools.refActionToSql)(fk.onUpdate)}`;
209
+ if (fk.onDelete) constraint += ` ON DELETE ${(0, _atscript_db_sql_tools.refActionToSql)(fk.onDelete)}`;
210
+ if (fk.onUpdate) constraint += ` ON UPDATE ${(0, _atscript_db_sql_tools.refActionToSql)(fk.onUpdate)}`;
206
211
  colDefs.push(constraint);
207
212
  }
208
213
  return `CREATE TABLE IF NOT EXISTS ${quoteTableName(table)} (${colDefs.join(", ")})`;
209
214
  }
215
+ /**
216
+ * Offsets numbered placeholders ($1, $2, ...) in a SQL fragment by a given amount.
217
+ * Used when WHERE params follow SET params in UPDATE statements.
218
+ */
210
219
  function offsetPlaceholders(fragment, offset) {
211
220
  if (offset === 0) return fragment;
212
- const sql = fragment.sql.replace(/\$(\d+)/g, (_, n) => `$${Number(n) + offset}`);
213
221
  return {
214
- sql,
222
+ sql: fragment.sql.replace(/\$(\d+)/g, (_, n) => `$${Number(n) + offset}`),
215
223
  params: fragment.params
216
224
  };
217
225
  }
218
-
219
226
  //#endregion
220
- //#region packages/db-postgres/src/filter-builder.ts
227
+ //#region src/filter-builder.ts
228
+ /**
229
+ * Translates a filter expression into a parameterized PostgreSQL WHERE clause.
230
+ *
231
+ * Note: The returned fragment uses `?` placeholders (not `$N`).
232
+ * Finalization to `$N` happens when the fragment is consumed by a DML builder
233
+ * (buildSelect, buildUpdate, etc.) via the dialect's `paramPlaceholder`.
234
+ *
235
+ * Case-insensitive columns (`@db.collate 'nocase'`) are handled by CITEXT
236
+ * column type at the storage level — no query-side wrapping needed.
237
+ */
221
238
  function buildWhere(filter) {
222
- return (0, __atscript_db_sql_tools.buildWhere)(pgDialect, filter);
239
+ return (0, _atscript_db_sql_tools.buildWhere)(pgDialect, filter);
223
240
  }
224
-
225
241
  //#endregion
226
- //#region packages/db-postgres/src/postgres-adapter.ts
227
- function _define_property$1(obj, key, value) {
228
- if (key in obj) Object.defineProperty(obj, key, {
229
- value,
230
- enumerable: true,
231
- configurable: true,
232
- writable: true
233
- });
234
- else obj[key] = value;
235
- return obj;
236
- }
237
- /** PostgreSQL COUNT() may return string (bigint) — parse to number. */ function parseCount(value) {
242
+ //#region src/postgres-adapter.ts
243
+ /** PostgreSQL COUNT() may return string (bigint) — parse to number. */
244
+ function parseCount(value) {
238
245
  if (typeof value === "string") return Number.parseInt(value, 10);
239
246
  return value ?? 0;
240
247
  }
241
- var PostgresAdapter = class PostgresAdapter extends __atscript_db.BaseDbAdapter {
242
- /** Schema name for queries (null falls through to 'public'). */ get _schema() {
248
+ /**
249
+ * PostgreSQL adapter for {@link AtscriptDbTable}.
250
+ *
251
+ * Accepts any {@link TPgDriver} implementation — the actual PostgreSQL driver
252
+ * is fully swappable (pg Pool, custom implementations, etc.).
253
+ *
254
+ * Usage:
255
+ * ```typescript
256
+ * import { PgDriver, PostgresAdapter } from '@atscript/db-postgres'
257
+ * import { DbSpace } from '@atscript/db'
258
+ *
259
+ * const driver = new PgDriver('postgresql://user@localhost:5432/mydb')
260
+ * const space = new DbSpace(() => new PostgresAdapter(driver))
261
+ * const users = space.getTable(UsersType)
262
+ * ```
263
+ */
264
+ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
265
+ supportsColumnModify = true;
266
+ static NATIVE_DEFAULT_FNS = new Set([
267
+ "now",
268
+ "uuid",
269
+ "increment"
270
+ ]);
271
+ _incrementFields = /* @__PURE__ */ new Set();
272
+ _autoIncrementStart;
273
+ /** Physical column names with @db.collate 'nocase'. Used to trigger CITEXT extension. */
274
+ _nocaseColumns = /* @__PURE__ */ new Set();
275
+ /** Whether citext extension has been provisioned (avoids redundant round-trips). */
276
+ _citextProvisioned = false;
277
+ /** Whether the connected PostgreSQL instance has the pgvector extension. */
278
+ _supportsVector;
279
+ /** Vector fields: physical field name → { dimensions, similarity, indexName }. */
280
+ _vectorFields = /* @__PURE__ */ new Map();
281
+ /** Default similarity thresholds per vector field (from @db.search.vector.threshold). */
282
+ _vectorThresholds = /* @__PURE__ */ new Map();
283
+ /** Schema name for queries (null falls through to 'public'). */
284
+ get _schema() {
243
285
  return this._table.schema ?? null;
244
286
  }
287
+ constructor(driver) {
288
+ super();
289
+ this.driver = driver;
290
+ }
245
291
  async _beginTransaction() {
246
292
  const conn = await this.driver.getConnection();
247
293
  try {
@@ -274,11 +320,12 @@ var PostgresAdapter = class PostgresAdapter extends __atscript_db.BaseDbAdapter
274
320
  /**
275
321
  * Returns the active executor: dedicated connection if inside a transaction,
276
322
  * otherwise the pool-based driver.
277
- */ _exec() {
278
- const txState = this._getTransactionState();
279
- return txState ?? this.driver;
323
+ */
324
+ _exec() {
325
+ return this._getTransactionState() ?? this.driver;
280
326
  }
281
- /** PostgreSQL enforces FK constraints natively. */ supportsNativeForeignKeys() {
327
+ /** PostgreSQL enforces FK constraints natively. */
328
+ supportsNativeForeignKeys() {
282
329
  return true;
283
330
  }
284
331
  prepareId(id, _fieldType) {
@@ -309,7 +356,7 @@ var PostgresAdapter = class PostgresAdapter extends __atscript_db.BaseDbAdapter
309
356
  indexName
310
357
  });
311
358
  const threshold = metadata.get("db.search.vector.threshold");
312
- if (threshold !== undefined) this._vectorThresholds.set(indexName, threshold);
359
+ if (threshold !== void 0) this._vectorThresholds.set(indexName, threshold);
313
360
  }
314
361
  }
315
362
  getDesiredTableOptions() {
@@ -322,8 +369,9 @@ var PostgresAdapter = class PostgresAdapter extends __atscript_db.BaseDbAdapter
322
369
  * Converts vector fields between JavaScript `number[]` and pgvector text format `[1,2,3]`.
323
370
  * The pg driver serializes JS arrays as PostgreSQL array literals `{1,2,3}` which is
324
371
  * invalid for the pgvector `vector` type — it expects bracket-delimited `[1,2,3]`.
325
- */ formatValue(field) {
326
- if (!this._vectorFields.has(field.path)) return undefined;
372
+ */
373
+ formatValue(field) {
374
+ if (!this._vectorFields.has(field.path)) return;
327
375
  return {
328
376
  toStorage: (value) => Array.isArray(value) ? `[${value.join(",")}]` : value,
329
377
  fromStorage: (value) => typeof value === "string" ? JSON.parse(value) : value
@@ -336,29 +384,24 @@ var PostgresAdapter = class PostgresAdapter extends __atscript_db.BaseDbAdapter
336
384
  * PostgreSQL uses SQLSTATE codes:
337
385
  * - 23505 = unique_violation
338
386
  * - 23503 = foreign_key_violation
339
- */ async _wrapConstraintError(fn) {
387
+ */
388
+ async _wrapConstraintError(fn) {
340
389
  try {
341
390
  return await fn();
342
391
  } catch (error) {
343
392
  if (error && typeof error === "object" && "code" in error) {
344
393
  const err = error;
345
- if (err.code === "23505") {
346
- const field = this._extractFieldFromConstraint(err.constraint) ?? "";
347
- throw new __atscript_db.DbError("CONFLICT", [{
348
- path: field,
349
- message: err.detail ?? err.message
350
- }]);
351
- }
352
- if (err.code === "23503") {
353
- const errors = this._mapFkError(err.detail ?? err.message, err.constraint);
354
- throw new __atscript_db.DbError("FK_VIOLATION", errors);
355
- }
394
+ if (err.code === "23505") throw new _atscript_db.DbError("CONFLICT", [{
395
+ path: this._extractFieldFromConstraint(err.constraint) ?? "",
396
+ message: err.detail ?? err.message
397
+ }]);
398
+ if (err.code === "23503") throw new _atscript_db.DbError("FK_VIOLATION", this._mapFkError(err.detail ?? err.message, err.constraint));
356
399
  }
357
400
  throw error;
358
401
  }
359
402
  }
360
403
  _extractFieldFromConstraint(constraint) {
361
- if (!constraint) return undefined;
404
+ if (!constraint) return;
362
405
  const tableName = this._table.tableName;
363
406
  if (constraint.startsWith(`${tableName}_`) && constraint.endsWith("_key")) {
364
407
  const fieldPart = constraint.slice(tableName.length + 1, -4);
@@ -371,9 +414,8 @@ var PostgresAdapter = class PostgresAdapter extends __atscript_db.BaseDbAdapter
371
414
  const fkMatch = detail.match(/Key \(([^)]+)\)/);
372
415
  if (fkMatch) {
373
416
  const physicalCol = fkMatch[1].split(",")[0].trim();
374
- const field = this._table.fieldDescriptors.find((f) => f.physicalName === physicalCol);
375
417
  return [{
376
- path: field?.path ?? physicalCol,
418
+ path: this._table.fieldDescriptors.find((f) => f.physicalName === physicalCol)?.path ?? physicalCol,
377
419
  message: detail
378
420
  }];
379
421
  }
@@ -387,9 +429,8 @@ var PostgresAdapter = class PostgresAdapter extends __atscript_db.BaseDbAdapter
387
429
  const pkCols = this._table.primaryKeys.map((pk) => qi(pk));
388
430
  if (pkCols.length > 0) sql += ` RETURNING ${pkCols.join(", ")}`;
389
431
  this._log(sql, params);
390
- const result = await this._wrapConstraintError(() => this._exec().run(sql, params));
391
- const returned = result.rows?.[0];
392
- return { insertedId: this._resolveInsertedId(data, returned ? Object.values(returned)[0] : undefined) };
432
+ const returned = (await this._wrapConstraintError(() => this._exec().run(sql, params))).rows?.[0];
433
+ return { insertedId: this._resolveInsertedId(data, returned ? Object.values(returned)[0] : void 0) };
393
434
  }
394
435
  async insertMany(data) {
395
436
  if (data.length === 0) return {
@@ -424,7 +465,7 @@ var PostgresAdapter = class PostgresAdapter extends __atscript_db.BaseDbAdapter
424
465
  const result = await this._wrapConstraintError(() => this._exec().run(sql, params));
425
466
  for (let i = 0; i < batchSize; i++) {
426
467
  const returned = result.rows?.[i];
427
- allIds.push(this._resolveInsertedId(data[offset + i], returned ? Object.values(returned)[0] : undefined));
468
+ allIds.push(this._resolveInsertedId(data[offset + i], returned ? Object.values(returned)[0] : void 0));
428
469
  }
429
470
  }
430
471
  return {
@@ -451,40 +492,32 @@ var PostgresAdapter = class PostgresAdapter extends __atscript_db.BaseDbAdapter
451
492
  }
452
493
  async count(query) {
453
494
  const where = buildWhere(query.filter);
454
- const tableName = this.resolveTableName();
455
- const raw = {
456
- sql: `SELECT COUNT(*) as cnt FROM ${quoteTableName(tableName)} WHERE ${where.sql}`,
495
+ const { sql, params } = (0, _atscript_db_sql_tools.finalizeParams)(pgDialect, {
496
+ sql: `SELECT COUNT(*) as cnt FROM ${quoteTableName(this.resolveTableName())} WHERE ${where.sql}`,
457
497
  params: where.params
458
- };
459
- const { sql, params } = (0, __atscript_db_sql_tools.finalizeParams)(pgDialect, raw);
498
+ });
460
499
  this._log(sql, params);
461
- const row = await this._exec().get(sql, params);
462
- return parseCount(row?.cnt);
500
+ return parseCount((await this._exec().get(sql, params))?.cnt);
463
501
  }
464
502
  async aggregate(query) {
465
503
  const where = buildWhere(query.filter);
466
504
  const tableName = this.resolveTableName();
467
505
  if (query.controls.$count) {
468
- const { sql: sql$1, params: params$1 } = buildAggregateCount(tableName, where, query.controls);
469
- this._log(sql$1, params$1);
470
- const row = await this._exec().get(sql$1, params$1);
471
- const count = parseCount(row?.count);
472
- return [{ count }];
506
+ const { sql, params } = buildAggregateCount(tableName, where, query.controls);
507
+ this._log(sql, params);
508
+ return [{ count: parseCount((await this._exec().get(sql, params))?.count) }];
473
509
  }
474
510
  const { sql, params } = buildAggregateSelect(tableName, where, query.controls);
475
511
  this._log(sql, params);
476
512
  return this._exec().all(sql, params);
477
513
  }
478
- async updateOne(filter, data) {
514
+ async updateOne(filter, data, ops) {
479
515
  const where = buildWhere(filter);
480
516
  const tableName = this.resolveTableName();
481
- const keys = Object.keys(data);
482
- const setClauses = keys.map((k, i) => `${qi(k)} = $${i + 1}`);
483
- const setParams = keys.map((k) => pgDialect.toValue(data[k]));
484
- const finalizedWhere = (0, __atscript_db_sql_tools.finalizeParams)(pgDialect, where);
485
- const offsetWhere = offsetPlaceholders(finalizedWhere, keys.length);
486
- const sql = `UPDATE ${quoteTableName(tableName)} SET ${setClauses.join(", ")} WHERE ctid = (SELECT ctid FROM ${quoteTableName(tableName)} WHERE ${offsetWhere.sql} LIMIT 1)`;
487
- const params = [...setParams, ...where.params];
517
+ const { sql, params } = buildUpdate(tableName, data, {
518
+ sql: `ctid = (SELECT ctid FROM ${quoteTableName(tableName)} WHERE ${where.sql} LIMIT 1)`,
519
+ params: where.params
520
+ }, void 0, ops);
488
521
  this._log(sql, params);
489
522
  const result = await this._wrapConstraintError(() => this._exec().run(sql, params));
490
523
  return {
@@ -492,9 +525,9 @@ var PostgresAdapter = class PostgresAdapter extends __atscript_db.BaseDbAdapter
492
525
  modifiedCount: result.affectedRows
493
526
  };
494
527
  }
495
- async updateMany(filter, data) {
528
+ async updateMany(filter, data, ops) {
496
529
  const where = buildWhere(filter);
497
- const { sql, params } = buildUpdate(this.resolveTableName(), data, where);
530
+ const { sql, params } = buildUpdate(this.resolveTableName(), data, where, void 0, ops);
498
531
  this._log(sql, params);
499
532
  const result = await this._wrapConstraintError(() => this._exec().run(sql, params));
500
533
  return {
@@ -511,21 +544,18 @@ var PostgresAdapter = class PostgresAdapter extends __atscript_db.BaseDbAdapter
511
544
  async deleteOne(filter) {
512
545
  const where = buildWhere(filter);
513
546
  const tableName = this.resolveTableName();
514
- const raw = {
547
+ const { sql, params } = (0, _atscript_db_sql_tools.finalizeParams)(pgDialect, {
515
548
  sql: `DELETE FROM ${quoteTableName(tableName)} WHERE ctid = (SELECT ctid FROM ${quoteTableName(tableName)} WHERE ${where.sql} LIMIT 1)`,
516
549
  params: where.params
517
- };
518
- const { sql, params } = (0, __atscript_db_sql_tools.finalizeParams)(pgDialect, raw);
550
+ });
519
551
  this._log(sql, params);
520
- const result = await this._wrapConstraintError(() => this._exec().run(sql, params));
521
- return { deletedCount: result.affectedRows };
552
+ return { deletedCount: (await this._wrapConstraintError(() => this._exec().run(sql, params))).affectedRows };
522
553
  }
523
554
  async deleteMany(filter) {
524
555
  const where = buildWhere(filter);
525
556
  const { sql, params } = buildDelete(this.resolveTableName(), where);
526
557
  this._log(sql, params);
527
- const result = await this._wrapConstraintError(() => this._exec().run(sql, params));
528
- return { deletedCount: result.affectedRows };
558
+ return { deletedCount: (await this._wrapConstraintError(() => this._exec().run(sql, params))).affectedRows };
529
559
  }
530
560
  async ensureTable() {
531
561
  if (this._nocaseColumns.size > 0 && !this._citextProvisioned) try {
@@ -533,10 +563,10 @@ var PostgresAdapter = class PostgresAdapter extends __atscript_db.BaseDbAdapter
533
563
  this._citextProvisioned = true;
534
564
  } catch (err) {
535
565
  const msg = err instanceof Error ? err.message : String(err);
536
- throw new Error(`Failed to create citext extension for @db.collate 'nocase' columns: ${msg}. ` + `Either run 'CREATE EXTENSION citext' as a superuser, or use @db.pg.type "CITEXT" after provisioning the extension manually.`);
566
+ throw new Error(`Failed to create citext extension for @db.collate 'nocase' columns: ${msg}. Either run 'CREATE EXTENSION citext' as a superuser, or use @db.pg.type "CITEXT" after provisioning the extension manually.`, { cause: err });
537
567
  }
538
- if (this._supportsVector === undefined && this._vectorFields.size > 0) await this._detectVectorSupport();
539
- if (this._table instanceof __atscript_db.AtscriptDbView) return this._ensureView();
568
+ if (this._supportsVector === void 0 && this._vectorFields.size > 0) await this._detectVectorSupport();
569
+ if (this._table instanceof _atscript_db.AtscriptDbView) return this._ensureView();
540
570
  const sql = buildCreateTable(this.resolveTableName(), this._table.fieldDescriptors, this._table.foreignKeys, {
541
571
  incrementFields: this._incrementFields,
542
572
  autoIncrementStart: this._autoIncrementStart,
@@ -593,18 +623,18 @@ var PostgresAdapter = class PostgresAdapter extends __atscript_db.BaseDbAdapter
593
623
  const sqlType = this.typeMapper(field);
594
624
  let ddl = `ALTER TABLE ${quoteTableName(tableName)} ADD COLUMN ${qi(field.physicalName)} ${sqlType}`;
595
625
  if (field.defaultValue?.kind === "fn" && field.defaultValue.fn === "increment") ddl += " GENERATED BY DEFAULT AS IDENTITY";
596
- else {
626
+ else {
597
627
  if (!field.optional && !field.isPrimaryKey) ddl += " NOT NULL";
598
628
  if (field.defaultValue?.kind === "value") ddl += ` DEFAULT ${defaultValueToSqlLiteral(field.designType, field.defaultValue.value)}`;
599
- else if (field.defaultValue?.kind === "fn") {
629
+ else if (field.defaultValue?.kind === "fn") {
600
630
  if (field.defaultValue.fn === "uuid") ddl += " DEFAULT gen_random_uuid()";
601
- else if (field.defaultValue.fn === "now") ddl += " DEFAULT (extract(epoch from now()) * 1000)::bigint";
631
+ else if (field.defaultValue.fn === "now") ddl += " DEFAULT (extract(epoch from now()) * 1000)::bigint";
602
632
  } else if (!field.optional && !field.isPrimaryKey) ddl += ` DEFAULT ${defaultValueForType(field.designType)}`;
603
633
  }
604
634
  if (field.collate) {
605
635
  const nativeCollate = field.type?.metadata?.get("db.pg.collate");
606
636
  if (nativeCollate) ddl += ` COLLATE "${nativeCollate}"`;
607
- else {
637
+ else {
608
638
  const pgCollate = collationToPg(field.collate);
609
639
  if (pgCollate) ddl += ` COLLATE ${pgCollate}`;
610
640
  }
@@ -635,7 +665,7 @@ else {
635
665
  for (const { field } of diff.defaultChanged ?? []) {
636
666
  let ddl;
637
667
  if (field.defaultValue?.kind === "value") ddl = `ALTER TABLE ${quoteTableName(tableName)} ALTER COLUMN ${qi(field.physicalName)} SET DEFAULT ${defaultValueToSqlLiteral(field.designType, field.defaultValue.value)}`;
638
- else if (field.defaultValue?.kind === "fn") {
668
+ else if (field.defaultValue?.kind === "fn") {
639
669
  const fnExpr = field.defaultValue.fn === "now" ? "(extract(epoch from now()) * 1000)::bigint" : field.defaultValue.fn === "uuid" ? "gen_random_uuid()" : `${field.defaultValue.fn}()`;
640
670
  ddl = `ALTER TABLE ${quoteTableName(tableName)} ALTER COLUMN ${qi(field.physicalName)} SET DEFAULT ${fnExpr}`;
641
671
  } else ddl = `ALTER TABLE ${quoteTableName(tableName)} ALTER COLUMN ${qi(field.physicalName)} DROP DEFAULT`;
@@ -671,7 +701,7 @@ else if (field.defaultValue?.kind === "fn") {
671
701
  SELECT constraint_name FROM information_schema.table_constraints
672
702
  WHERE table_name = $2 AND table_schema = COALESCE($1, 'public') AND constraint_type = 'PRIMARY KEY'
673
703
  )`, [schema, this._table.tableName]);
674
- const fkByName = new Map();
704
+ const fkByName = /* @__PURE__ */ new Map();
675
705
  for (const fk of fkRefs) {
676
706
  let entry = fkByName.get(fk.constraint_name);
677
707
  if (!entry) {
@@ -750,7 +780,8 @@ else if (field.defaultValue?.kind === "fn") {
750
780
  * value doesn't conflict with existing data. PostgreSQL's GENERATED BY DEFAULT
751
781
  * AS IDENTITY does not advance the sequence when rows are inserted with explicit
752
782
  * values, so this is needed after data seeding, bulk imports, or recreateTable().
753
- */ async _resetIdentitySequences() {
783
+ */
784
+ async _resetIdentitySequences() {
754
785
  if (this._incrementFields.size === 0) return;
755
786
  const tableName = this.resolveTableName();
756
787
  const emptyFallback = this._autoIncrementStart ?? 1;
@@ -762,8 +793,7 @@ else if (field.defaultValue?.kind === "fn") {
762
793
  }
763
794
  }
764
795
  async tableExists() {
765
- const row = await this._exec().get(`SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = $1 AND table_schema = COALESCE($2, 'public')) AS "exists"`, [this._table.tableName, this._schema]);
766
- return row?.exists ?? false;
796
+ return (await this._exec().get(`SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = $1 AND table_schema = COALESCE($2, 'public')) AS "exists"`, [this._table.tableName, this._schema]))?.exists ?? false;
767
797
  }
768
798
  async dropTable() {
769
799
  const ddl = `DROP TABLE IF EXISTS ${quoteTableName(this.resolveTableName())} CASCADE`;
@@ -809,9 +839,9 @@ else if (field.defaultValue?.kind === "fn") {
809
839
  createIndex: async (index) => {
810
840
  if (index.type === "fulltext") {
811
841
  const tsvectorExpr = this._buildTsvectorExpr(index.fields);
812
- const sql$1 = `CREATE INDEX IF NOT EXISTS ${qi(index.key)} ON ${quoteTableName(this.resolveTableName())} USING gin(to_tsvector('english', ${tsvectorExpr}))`;
813
- this._log(sql$1);
814
- await this._exec().exec(sql$1);
842
+ const sql = `CREATE INDEX IF NOT EXISTS ${qi(index.key)} ON ${quoteTableName(this.resolveTableName())} USING gin(to_tsvector('english', ${tsvectorExpr}))`;
843
+ this._log(sql);
844
+ await this._exec().exec(sql);
815
845
  return;
816
846
  }
817
847
  const unique = index.type === "unique" ? "UNIQUE " : "";
@@ -821,8 +851,7 @@ else if (field.defaultValue?.kind === "fn") {
821
851
  await this._exec().exec(sql);
822
852
  },
823
853
  dropIndex: async (name) => {
824
- const schemaPrefix = schema ? `${qi(schema)}.` : "";
825
- const sql = `DROP INDEX IF EXISTS ${schemaPrefix}${qi(name)}`;
854
+ const sql = `DROP INDEX IF EXISTS ${schema ? `${qi(schema)}.` : ""}${qi(name)}`;
826
855
  this._log(sql);
827
856
  await this._exec().exec(sql);
828
857
  }
@@ -837,25 +866,25 @@ else if (field.defaultValue?.kind === "fn") {
837
866
  }
838
867
  async syncForeignKeys() {
839
868
  const existingByName = await this._getExistingFkConstraints();
840
- const desiredFkKeys = new Set();
841
- for (const fk of this._table.foreignKeys.values()) desiredFkKeys.add([...fk.fields].sort().join(","));
869
+ const desiredFkKeys = /* @__PURE__ */ new Set();
870
+ for (const fk of this._table.foreignKeys.values()) desiredFkKeys.add([...fk.fields].toSorted().join(","));
842
871
  for (const [constraintName, columns] of existingByName) {
843
- const key = [...columns].sort().join(",");
872
+ const key = [...columns].toSorted().join(",");
844
873
  if (!desiredFkKeys.has(key)) {
845
874
  const ddl = `ALTER TABLE ${quoteTableName(this.resolveTableName())} DROP CONSTRAINT ${qi(constraintName)}`;
846
875
  this._log(ddl);
847
876
  await this._exec().exec(ddl);
848
877
  }
849
878
  }
850
- const existingKeys = new Set([...existingByName.values()].map((cols) => cols.sort().join(",")));
879
+ const existingKeys = new Set([...existingByName.values()].map((cols) => cols.toSorted().join(",")));
851
880
  for (const fk of this._table.foreignKeys.values()) {
852
- const key = [...fk.fields].sort().join(",");
881
+ const key = [...fk.fields].toSorted().join(",");
853
882
  if (!existingKeys.has(key)) {
854
883
  const localCols = fk.fields.map((f) => qi(f)).join(", ");
855
884
  const targetCols = fk.targetFields.map((f) => qi(f)).join(", ");
856
885
  let ddl = `ALTER TABLE ${quoteTableName(this.resolveTableName())} ADD FOREIGN KEY (${localCols}) REFERENCES ${qi(fk.targetTable)} (${targetCols})`;
857
- if (fk.onDelete) ddl += ` ON DELETE ${(0, __atscript_db_sql_tools.refActionToSql)(fk.onDelete)}`;
858
- if (fk.onUpdate) ddl += ` ON UPDATE ${(0, __atscript_db_sql_tools.refActionToSql)(fk.onUpdate)}`;
886
+ if (fk.onDelete) ddl += ` ON DELETE ${(0, _atscript_db_sql_tools.refActionToSql)(fk.onDelete)}`;
887
+ if (fk.onUpdate) ddl += ` ON UPDATE ${(0, _atscript_db_sql_tools.refActionToSql)(fk.onUpdate)}`;
859
888
  this._log(ddl);
860
889
  await this._exec().exec(ddl);
861
890
  }
@@ -866,7 +895,7 @@ else if (field.defaultValue?.kind === "fn") {
866
895
  const keySet = new Set(fkFieldKeys);
867
896
  const existingByName = await this._getExistingFkConstraints();
868
897
  for (const [constraintName, cols] of existingByName) {
869
- const key = cols.sort().join(",");
898
+ const key = cols.toSorted().join(",");
870
899
  if (keySet.has(key)) {
871
900
  const ddl = `ALTER TABLE ${quoteTableName(this.resolveTableName())} DROP CONSTRAINT ${qi(constraintName)}`;
872
901
  this._log(ddl);
@@ -874,14 +903,15 @@ else if (field.defaultValue?.kind === "fn") {
874
903
  }
875
904
  }
876
905
  }
877
- /** Queries information_schema for existing FK constraints. */ async _getExistingFkConstraints() {
906
+ /** Queries information_schema for existing FK constraints. */
907
+ async _getExistingFkConstraints() {
878
908
  const rows = await this._exec().all(`SELECT kcu.constraint_name, kcu.column_name
879
909
  FROM information_schema.table_constraints tc
880
910
  JOIN information_schema.key_column_usage kcu
881
911
  ON tc.constraint_name = kcu.constraint_name AND tc.table_schema = kcu.table_schema
882
912
  WHERE tc.table_name = $1 AND tc.table_schema = COALESCE($2, 'public')
883
913
  AND tc.constraint_type = 'FOREIGN KEY'`, [this._table.tableName, this._schema]);
884
- const byName = new Map();
914
+ const byName = /* @__PURE__ */ new Map();
885
915
  for (const row of rows) {
886
916
  let cols = byName.get(row.constraint_name);
887
917
  if (!cols) {
@@ -926,14 +956,12 @@ else if (field.defaultValue?.kind === "fn") {
926
956
  return this._exec().all(sql, params);
927
957
  })();
928
958
  const countPromise = (async () => {
929
- const raw = {
959
+ const { sql, params } = (0, _atscript_db_sql_tools.finalizeParams)(pgDialect, {
930
960
  sql: `SELECT COUNT(*) as cnt FROM ${quoteTableName(tableName)} WHERE ${combinedWhere.sql}`,
931
961
  params: combinedWhere.params
932
- };
933
- const { sql, params } = (0, __atscript_db_sql_tools.finalizeParams)(pgDialect, raw);
962
+ });
934
963
  this._log(sql, params);
935
- const row = await this._exec().get(sql, params);
936
- return parseCount(row?.cnt);
964
+ return parseCount((await this._exec().get(sql, params))?.cnt);
937
965
  })();
938
966
  const [data, count] = await Promise.all([selectPromise, countPromise]);
939
967
  return {
@@ -952,20 +980,21 @@ else if (field.defaultValue?.kind === "fn") {
952
980
  params: [...where.params, text]
953
981
  };
954
982
  }
955
- /** Builds the tsvector SQL expression for a fulltext index's fields. Must match between index DDL and queries. */ _buildTsvectorExpr(fields) {
983
+ /** Builds the tsvector SQL expression for a fulltext index's fields. Must match between index DDL and queries. */
984
+ _buildTsvectorExpr(fields) {
956
985
  return fields.map((f) => `coalesce(${qi(f.name)}, '')`).join(" || ' ' || ");
957
986
  }
958
987
  _getFulltextIndex(indexName) {
959
988
  for (const index of this._table.indexes.values()) if (index.type === "fulltext") {
960
989
  if (!indexName || index.key === indexName) return index;
961
990
  }
962
- return undefined;
963
991
  }
964
992
  /**
965
993
  * Detects pgvector support by attempting to enable the extension.
966
994
  * Idempotent — safe to call multiple times.
967
- */ async _detectVectorSupport() {
968
- if (this._supportsVector !== undefined) return this._supportsVector;
995
+ */
996
+ async _detectVectorSupport() {
997
+ if (this._supportsVector !== void 0) return this._supportsVector;
969
998
  try {
970
999
  await this._exec().exec("CREATE EXTENSION IF NOT EXISTS vector");
971
1000
  this._supportsVector = true;
@@ -992,13 +1021,13 @@ else if (field.defaultValue?.kind === "fn") {
992
1021
  this._log(sql, params);
993
1022
  this._log(countSql, countParams);
994
1023
  const [data, countRow] = await Promise.all([this._exec().all(sql, params), this._exec().get(countSql, countParams)]);
995
- const count = parseCount(countRow?.cnt);
996
1024
  return {
997
1025
  data,
998
- count
1026
+ count: parseCount(countRow?.cnt)
999
1027
  };
1000
1028
  }
1001
- /** Resolves vector field and computes shared context for vector search SQL builders. */ _prepareVectorSearch(vector, query, indexName) {
1029
+ /** Resolves vector field and computes shared context for vector search SQL builders. */
1030
+ _prepareVectorSearch(vector, query, indexName) {
1002
1031
  let field;
1003
1032
  let vec;
1004
1033
  if (indexName) {
@@ -1033,10 +1062,10 @@ else if (field.defaultValue?.kind === "fn") {
1033
1062
  }
1034
1063
  _buildVectorSearchQuery(vector, query, indexName) {
1035
1064
  const ctx = this._prepareVectorSearch(vector, query, indexName);
1036
- let inner = `SELECT *, (${qi(ctx.field)} ${ctx.distanceOp} $1::vector) AS _distance FROM ${quoteTableName(ctx.tableName)} WHERE ${offsetPlaceholders((0, __atscript_db_sql_tools.finalizeParams)(pgDialect, ctx.where), 1).sql}`;
1065
+ let inner = `SELECT *, (${qi(ctx.field)} ${ctx.distanceOp} $1::vector) AS _distance FROM ${quoteTableName(ctx.tableName)} WHERE ${offsetPlaceholders((0, _atscript_db_sql_tools.finalizeParams)(pgDialect, ctx.where), 1).sql}`;
1037
1066
  const params = [ctx.vectorStr, ...ctx.where.params];
1038
1067
  let sql = `SELECT * FROM (${inner}) _v`;
1039
- if (ctx.threshold !== undefined) {
1068
+ if (ctx.threshold !== void 0) {
1040
1069
  sql += ` WHERE _distance <= $${params.length + 1}`;
1041
1070
  params.push(thresholdToDistance(ctx.threshold, ctx.vec.similarity));
1042
1071
  }
@@ -1055,10 +1084,10 @@ else if (field.defaultValue?.kind === "fn") {
1055
1084
  }
1056
1085
  _buildVectorSearchCountQuery(vector, query, indexName) {
1057
1086
  const ctx = this._prepareVectorSearch(vector, query, indexName);
1058
- let inner = `SELECT (${qi(ctx.field)} ${ctx.distanceOp} $1::vector) AS _distance FROM ${quoteTableName(ctx.tableName)} WHERE ${offsetPlaceholders((0, __atscript_db_sql_tools.finalizeParams)(pgDialect, ctx.where), 1).sql}`;
1087
+ let inner = `SELECT (${qi(ctx.field)} ${ctx.distanceOp} $1::vector) AS _distance FROM ${quoteTableName(ctx.tableName)} WHERE ${offsetPlaceholders((0, _atscript_db_sql_tools.finalizeParams)(pgDialect, ctx.where), 1).sql}`;
1059
1088
  const params = [ctx.vectorStr, ...ctx.where.params];
1060
1089
  let sql = `SELECT COUNT(*) AS cnt FROM (${inner}) _v`;
1061
- if (ctx.threshold !== undefined) {
1090
+ if (ctx.threshold !== void 0) {
1062
1091
  sql += ` WHERE _distance <= $${params.length + 1}`;
1063
1092
  params.push(thresholdToDistance(ctx.threshold, ctx.vec.similarity));
1064
1093
  }
@@ -1067,26 +1096,19 @@ else if (field.defaultValue?.kind === "fn") {
1067
1096
  params
1068
1097
  };
1069
1098
  }
1070
- /** Resolves threshold: query-time $threshold > schema-level @db.search.vector.threshold. */ _resolveVectorThreshold(controls, indexName) {
1099
+ /** Resolves threshold: query-time $threshold > schema-level @db.search.vector.threshold. */
1100
+ _resolveVectorThreshold(controls, indexName) {
1071
1101
  const queryThreshold = controls.$threshold;
1072
- if (queryThreshold !== undefined) return queryThreshold;
1102
+ if (queryThreshold !== void 0) return queryThreshold;
1073
1103
  return this._vectorThresholds.get(indexName);
1074
1104
  }
1075
- constructor(driver) {
1076
- super(), _define_property$1(this, "driver", void 0), _define_property$1(this, "supportsColumnModify", void 0), _define_property$1(this, "_incrementFields", void 0), _define_property$1(this, "_autoIncrementStart", void 0), _define_property$1(this, "_nocaseColumns", void 0), _define_property$1(this, "_citextProvisioned", void 0), _define_property$1(this, "_supportsVector", void 0), _define_property$1(this, "_vectorFields", void 0), _define_property$1(this, "_vectorThresholds", void 0), this.driver = driver, this.supportsColumnModify = true, this._incrementFields = new Set(), this._nocaseColumns = new Set(), this._citextProvisioned = false, this._vectorFields = new Map(), this._vectorThresholds = new Map();
1077
- }
1078
1105
  };
1079
- _define_property$1(PostgresAdapter, "NATIVE_DEFAULT_FNS", new Set([
1080
- "now",
1081
- "uuid",
1082
- "increment"
1083
- ]));
1084
1106
  /**
1085
1107
  * Normalizes PostgreSQL information_schema data_type values
1086
1108
  * to match the format produced by `pgTypeFromField()`.
1087
- */ function normalizePgType(dataType, maxLength, numericPrecision, numericScale, udtName, formattedType) {
1088
- const dt = dataType.toLowerCase();
1089
- switch (dt) {
1109
+ */
1110
+ function normalizePgType(dataType, maxLength, numericPrecision, numericScale, udtName, formattedType) {
1111
+ switch (dataType.toLowerCase()) {
1090
1112
  case "character varying": return maxLength ? `VARCHAR(${maxLength})` : "VARCHAR(255)";
1091
1113
  case "character": return maxLength ? `CHAR(${maxLength})` : "CHAR(1)";
1092
1114
  case "integer": return "INTEGER";
@@ -1101,20 +1123,20 @@ _define_property$1(PostgresAdapter, "NATIVE_DEFAULT_FNS", new Set([
1101
1123
  case "timestamp with time zone": return "TIMESTAMPTZ";
1102
1124
  case "timestamp without time zone": return "TIMESTAMP";
1103
1125
  case "uuid": return "UUID";
1104
- case "user-defined": {
1126
+ case "user-defined":
1105
1127
  if (udtName === "vector") return formattedType;
1106
1128
  if (udtName === "citext") return "CITEXT";
1107
1129
  return udtName?.toUpperCase() ?? "USER-DEFINED";
1108
- }
1109
1130
  default: return dataType.toUpperCase();
1110
1131
  }
1111
1132
  }
1112
1133
  /**
1113
1134
  * Normalizes PostgreSQL column_default values to match the format
1114
1135
  * produced by `serializeDefaultValue()`.
1115
- */ function normalizePgDefault(value, isIdentity) {
1136
+ */
1137
+ function normalizePgDefault(value, isIdentity) {
1116
1138
  if (isIdentity === "YES") return "fn:increment";
1117
- if (value === null) return undefined;
1139
+ if (value === null) return;
1118
1140
  let cleaned = value;
1119
1141
  while (cleaned.startsWith("(") && cleaned.endsWith(")")) cleaned = cleaned.slice(1, -1);
1120
1142
  const lower = cleaned.toLowerCase();
@@ -1137,60 +1159,58 @@ _define_property$1(PostgresAdapter, "NATIVE_DEFAULT_FNS", new Set([
1137
1159
  * pgvector cosine distance = 1 - cosine_similarity, range [0, 2]
1138
1160
  *
1139
1161
  * Conversion: distance = 2 * (1 - score)
1140
- */ function thresholdToDistance(threshold, similarity) {
1162
+ */
1163
+ function thresholdToDistance(threshold, similarity) {
1141
1164
  switch (similarity) {
1142
1165
  case "euclidean": return threshold;
1143
1166
  case "dotProduct": return -threshold;
1144
1167
  default: return 2 * (1 - threshold);
1145
1168
  }
1146
1169
  }
1147
- /** Maps generic similarity metric to PostgreSQL distance operator. */ function similarityToPgOp(similarity) {
1170
+ /** Maps generic similarity metric to PostgreSQL distance operator. */
1171
+ function similarityToPgOp(similarity) {
1148
1172
  switch (similarity) {
1149
1173
  case "euclidean": return "<->";
1150
1174
  case "dotProduct": return "<#>";
1151
1175
  default: return "<=>";
1152
1176
  }
1153
1177
  }
1154
- /** Maps generic similarity metric to pgvector index ops class. */ function similarityToPgOps(similarity) {
1178
+ /** Maps generic similarity metric to pgvector index ops class. */
1179
+ function similarityToPgOps(similarity) {
1155
1180
  switch (similarity) {
1156
1181
  case "euclidean": return "vector_l2_ops";
1157
1182
  case "dotProduct": return "vector_ip_ops";
1158
1183
  default: return "vector_cosine_ops";
1159
1184
  }
1160
1185
  }
1161
- /** Formats a number[] vector as pgvector input: '[1.0, 2.0, ...]'. */ function vectorToString(vector) {
1186
+ /** Formats a number[] vector as pgvector input: '[1.0, 2.0, ...]'. */
1187
+ function vectorToString(vector) {
1162
1188
  return `[${vector.join(",")}]`;
1163
1189
  }
1164
-
1165
1190
  //#endregion
1166
- //#region packages/db-postgres/src/pg-driver.ts
1167
- function _define_property(obj, key, value) {
1168
- if (key in obj) Object.defineProperty(obj, key, {
1169
- value,
1170
- enumerable: true,
1171
- configurable: true,
1172
- writable: true
1173
- });
1174
- else obj[key] = value;
1175
- return obj;
1176
- }
1177
- /** pg rejects `undefined` in bind arrays — coerce to `null`. */ function sanitizeParams(params) {
1191
+ //#region src/pg-driver.ts
1192
+ /** pg rejects `undefined` in bind arrays — coerce to `null`. */
1193
+ function sanitizeParams(params) {
1178
1194
  if (!params) return [];
1179
- return params.map((v) => v === undefined ? null : v);
1195
+ return params.map((v) => v === void 0 ? null : v);
1180
1196
  }
1181
- /** Parses TIMESTAMP/TIMESTAMPTZ to epoch milliseconds. */ function parseTimestamp(val) {
1197
+ /** Parses TIMESTAMP/TIMESTAMPTZ to epoch milliseconds. */
1198
+ function parseTimestamp(val) {
1182
1199
  const ms = new Date(val).getTime();
1183
1200
  return Number.isNaN(ms) ? val : ms;
1184
1201
  }
1185
- /** Parses NUMERIC to number. */ function parseNumeric(val) {
1202
+ /** Parses NUMERIC to number. */
1203
+ function parseNumeric(val) {
1186
1204
  const n = Number.parseFloat(val);
1187
1205
  return Number.isNaN(n) ? val : n;
1188
1206
  }
1189
- /** Parses INT8/BIGINT to number. Returns string if value exceeds safe integer range. */ function parseBigInt(val) {
1207
+ /** Parses INT8/BIGINT to number. Returns string if value exceeds safe integer range. */
1208
+ function parseBigInt(val) {
1190
1209
  const n = Number.parseInt(val, 10);
1191
1210
  return Number.isNaN(n) || !Number.isSafeInteger(n) ? val : n;
1192
1211
  }
1193
- /** OIDs for types we override. */ const TIMESTAMP_OID = 1114;
1212
+ /** OIDs for types we override. */
1213
+ const TIMESTAMP_OID = 1114;
1194
1214
  const TIMESTAMPTZ_OID = 1184;
1195
1215
  const NUMERIC_OID = 1700;
1196
1216
  const INT8_OID = 20;
@@ -1201,7 +1221,8 @@ const INT8_OID = 20;
1201
1221
  * - TIMESTAMP/TIMESTAMPTZ → epoch milliseconds (number)
1202
1222
  * - NUMERIC → number (not string)
1203
1223
  * - INT8/BIGINT → number (for JS-safe range)
1204
- */ function createCustomTypes(pgTypes) {
1224
+ */
1225
+ function createCustomTypes(pgTypes) {
1205
1226
  const overrides = new Map([
1206
1227
  [TIMESTAMP_OID, parseTimestamp],
1207
1228
  [TIMESTAMPTZ_OID, parseTimestamp],
@@ -1214,35 +1235,78 @@ const INT8_OID = 20;
1214
1235
  return pgTypes.getTypeParser(oid, format);
1215
1236
  } };
1216
1237
  }
1238
+ /**
1239
+ * {@link TPgDriver} implementation backed by `pg` (node-postgres).
1240
+ *
1241
+ * Accepts a connection URI string, a `pg.PoolConfig` object, or a pre-created
1242
+ * `pg.Pool` instance.
1243
+ *
1244
+ * ```typescript
1245
+ * import { PgDriver } from '@atscript/db-postgres'
1246
+ *
1247
+ * // Connection URI
1248
+ * const driver = new PgDriver('postgresql://user:pass@localhost:5432/mydb')
1249
+ *
1250
+ * // Pool options
1251
+ * const driver = new PgDriver({
1252
+ * host: 'localhost',
1253
+ * user: 'postgres',
1254
+ * database: 'mydb',
1255
+ * max: 10,
1256
+ * })
1257
+ *
1258
+ * // Pre-created pool
1259
+ * import pg from 'pg'
1260
+ * const pool = new pg.Pool({ connectionString: '...' })
1261
+ * const driver = new PgDriver(pool)
1262
+ * ```
1263
+ *
1264
+ * Requires `pg` to be installed:
1265
+ * ```bash
1266
+ * pnpm add pg
1267
+ * ```
1268
+ */
1217
1269
  var PgDriver = class {
1270
+ pool;
1271
+ poolInit;
1272
+ constructor(poolOrConfig) {
1273
+ if (typeof poolOrConfig === "object" && typeof poolOrConfig.query === "function") this.pool = poolOrConfig;
1274
+ else this.poolInit = import("pg").then((pg) => {
1275
+ const Pool = pg.default?.Pool ?? pg.Pool;
1276
+ const types = pg.default?.types ?? pg.types;
1277
+ const customTypes = types ? createCustomTypes(types) : void 0;
1278
+ if (typeof poolOrConfig === "string") this.pool = new Pool({
1279
+ connectionString: poolOrConfig,
1280
+ types: customTypes
1281
+ });
1282
+ else this.pool = new Pool({
1283
+ ...poolOrConfig,
1284
+ types: customTypes
1285
+ });
1286
+ return this.pool;
1287
+ });
1288
+ }
1218
1289
  getPool() {
1219
1290
  return this.pool || this.poolInit;
1220
1291
  }
1221
1292
  async run(sql, params) {
1222
- const pool = await this.getPool();
1223
- const result = await pool.query(sql, sanitizeParams(params));
1293
+ const result = await (await this.getPool()).query(sql, sanitizeParams(params));
1224
1294
  return {
1225
1295
  affectedRows: result.rowCount ?? 0,
1226
1296
  rows: result.rows ?? []
1227
1297
  };
1228
1298
  }
1229
1299
  async all(sql, params) {
1230
- const pool = await this.getPool();
1231
- const result = await pool.query(sql, sanitizeParams(params));
1232
- return result.rows;
1300
+ return (await (await this.getPool()).query(sql, sanitizeParams(params))).rows;
1233
1301
  }
1234
1302
  async get(sql, params) {
1235
- const pool = await this.getPool();
1236
- const result = await pool.query(sql, sanitizeParams(params));
1237
- return result.rows[0] ?? null;
1303
+ return (await (await this.getPool()).query(sql, sanitizeParams(params))).rows[0] ?? null;
1238
1304
  }
1239
1305
  async exec(sql) {
1240
- const pool = await this.getPool();
1241
- await pool.query(sql);
1306
+ await (await this.getPool()).query(sql);
1242
1307
  }
1243
1308
  async getConnection() {
1244
- const pool = await this.getPool();
1245
- const client = await pool.connect();
1309
+ const client = await (await this.getPool()).connect();
1246
1310
  return {
1247
1311
  async run(sql, params) {
1248
1312
  const result = await client.query(sql, sanitizeParams(params));
@@ -1252,12 +1316,10 @@ var PgDriver = class {
1252
1316
  };
1253
1317
  },
1254
1318
  async all(sql, params) {
1255
- const result = await client.query(sql, sanitizeParams(params));
1256
- return result.rows;
1319
+ return (await client.query(sql, sanitizeParams(params))).rows;
1257
1320
  },
1258
1321
  async get(sql, params) {
1259
- const result = await client.query(sql, sanitizeParams(params));
1260
- return result.rows[0] ?? null;
1322
+ return (await client.query(sql, sanitizeParams(params))).rows[0] ?? null;
1261
1323
  },
1262
1324
  async exec(sql) {
1263
1325
  await client.query(sql);
@@ -1268,87 +1330,28 @@ var PgDriver = class {
1268
1330
  };
1269
1331
  }
1270
1332
  async close() {
1271
- const pool = await this.getPool();
1272
- await pool.end();
1273
- }
1274
- constructor(poolOrConfig) {
1275
- _define_property(this, "pool", void 0);
1276
- _define_property(this, "poolInit", void 0);
1277
- if (typeof poolOrConfig === "object" && typeof poolOrConfig.query === "function") this.pool = poolOrConfig;
1278
- else this.poolInit = import("pg").then((pg) => {
1279
- const Pool = pg.default?.Pool ?? pg.Pool;
1280
- const types = pg.default?.types ?? pg.types;
1281
- const customTypes = types ? createCustomTypes(types) : undefined;
1282
- if (typeof poolOrConfig === "string") this.pool = new Pool({
1283
- connectionString: poolOrConfig,
1284
- types: customTypes
1285
- });
1286
- else this.pool = new Pool({
1287
- ...poolOrConfig,
1288
- types: customTypes
1289
- });
1290
- return this.pool;
1291
- });
1333
+ await (await this.getPool()).end();
1292
1334
  }
1293
1335
  };
1294
-
1295
1336
  //#endregion
1296
- //#region packages/db-postgres/src/plugin/annotations.ts
1297
- const annotations = {
1298
- type: new __atscript_core.AnnotationSpec({
1299
- description: "Overrides the native PostgreSQL column type.\n\n```atscript\n@db.pg.type \"CITEXT\"\nname: string\n```",
1300
- nodeType: ["prop"],
1301
- multiple: false,
1302
- argument: {
1303
- name: "type",
1304
- type: "string",
1305
- description: "Native PostgreSQL column type (e.g., \"CITEXT\", \"INET\", \"MACADDR\")."
1306
- }
1307
- }),
1308
- schema: new __atscript_core.AnnotationSpec({
1309
- description: "Specifies the PostgreSQL schema for the table.\n\n**Default:** `\"public\"`\n\n```atscript\n@db.pg.schema \"analytics\"\nexport interface Events { ... }\n```",
1310
- nodeType: ["interface"],
1311
- multiple: false,
1312
- argument: {
1313
- name: "schema",
1314
- type: "string",
1315
- description: "PostgreSQL schema name (e.g., \"public\", \"analytics\")."
1316
- }
1317
- }),
1318
- collate: new __atscript_core.AnnotationSpec({
1319
- description: "Specifies a native PostgreSQL collation (overrides portable `@db.column.collate`).\n\n```atscript\n@db.pg.collate \"tr-x-icu\"\nname: string\n```",
1320
- nodeType: ["interface", "prop"],
1321
- multiple: false,
1322
- argument: {
1323
- name: "collation",
1324
- type: "string",
1325
- description: "Native PostgreSQL collation name (e.g., \"tr-x-icu\", \"C\", \"und-x-icu\")."
1326
- }
1327
- })
1328
- };
1329
-
1330
- //#endregion
1331
- //#region packages/db-postgres/src/plugin/index.ts
1332
- const PostgresPlugin = () => ({
1333
- name: "postgres",
1334
- config() {
1335
- return { annotations: { db: { pg: annotations } } };
1336
- }
1337
- });
1338
-
1339
- //#endregion
1340
- //#region packages/db-postgres/src/index.ts
1337
+ //#region src/index.ts
1338
+ /**
1339
+ * Creates a {@link DbSpace} backed by a PostgreSQL connection pool.
1340
+ *
1341
+ * @param uri - PostgreSQL connection URI (e.g., `postgresql://user@localhost:5432/mydb`)
1342
+ * @param options - Additional pool options passed to pg.
1343
+ * @returns A `DbSpace` that creates `PostgresAdapter` instances per table.
1344
+ */
1341
1345
  function createAdapter(uri, options) {
1342
1346
  const driver = new PgDriver({
1343
1347
  connectionString: uri,
1344
1348
  ...options
1345
1349
  });
1346
- return new __atscript_db.DbSpace(() => new PostgresAdapter(driver));
1350
+ return new _atscript_db.DbSpace(() => new PostgresAdapter(driver));
1347
1351
  }
1348
-
1349
1352
  //#endregion
1350
- exports.PgDriver = PgDriver
1351
- exports.PostgresAdapter = PostgresAdapter
1352
- exports.PostgresPlugin = PostgresPlugin
1353
- exports.buildWhere = buildWhere
1354
- exports.createAdapter = createAdapter
1353
+ exports.PgDriver = PgDriver;
1354
+ exports.PostgresAdapter = PostgresAdapter;
1355
+ exports.PostgresPlugin = require_plugin.PostgresPlugin;
1356
+ exports.buildWhere = buildWhere;
1357
+ exports.createAdapter = createAdapter;