@atscript/db-postgres 0.1.127 → 0.1.129
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 +223 -25
- package/dist/index.d.cts +52 -19
- package/dist/index.d.mts +52 -19
- package/dist/index.mjs +225 -27
- package/package.json +10 -10
package/dist/index.cjs
CHANGED
|
@@ -241,6 +241,7 @@ function buildCreateTable(table, fields, foreignKeys, options) {
|
|
|
241
241
|
colDefs.push(`PRIMARY KEY (${pkCols})`);
|
|
242
242
|
}
|
|
243
243
|
if (foreignKeys) for (const fk of foreignKeys.values()) {
|
|
244
|
+
if (options?.deferForeignKeysTo?.has(fk.targetTable)) continue;
|
|
244
245
|
const localCols = fk.fields.map((f) => qi(f)).join(", ");
|
|
245
246
|
const targetCols = fk.targetFields.map((f) => qi(f)).join(", ");
|
|
246
247
|
let constraint = `FOREIGN KEY (${localCols}) REFERENCES ${qi(fk.targetTable)} (${targetCols})`;
|
|
@@ -299,6 +300,40 @@ function parseCount(value) {
|
|
|
299
300
|
* const users = space.getTable(UsersType)
|
|
300
301
|
* ```
|
|
301
302
|
*/
|
|
303
|
+
/** The suffix PostgreSQL gives an auto-named constraint of each `pg_constraint.contype`. */
|
|
304
|
+
const PG_CONSTRAINT_LABELS = {
|
|
305
|
+
p: "pkey",
|
|
306
|
+
u: "key",
|
|
307
|
+
f: "fkey",
|
|
308
|
+
n: "not_null"
|
|
309
|
+
};
|
|
310
|
+
/** UTF-8 byte length of `s`. */
|
|
311
|
+
function byteLength(s) {
|
|
312
|
+
return Buffer.byteLength(s, "utf8");
|
|
313
|
+
}
|
|
314
|
+
/** Cuts `s` to at most `bytes` UTF-8 bytes (whole characters only). */
|
|
315
|
+
function truncateBytes(s, bytes) {
|
|
316
|
+
let out = s;
|
|
317
|
+
while (byteLength(out) > bytes) out = out.slice(0, -1);
|
|
318
|
+
return out;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* The name PostgreSQL generates for an unnamed constraint (`makeObjectName`):
|
|
322
|
+
* `<table>_<columns joined by _>_<label>`, with the table and column parts
|
|
323
|
+
* shortened — the longer one first — until the whole fits 63 bytes
|
|
324
|
+
* (`NAMEDATALEN - 1`). Used to recognise and to rename the recreated table's
|
|
325
|
+
* constraints. Ignores the `1`, `2`, … suffix PostgreSQL appends on a clash.
|
|
326
|
+
*/
|
|
327
|
+
function pgObjectName(table, columns, label) {
|
|
328
|
+
const name2 = columns.join("_");
|
|
329
|
+
const avail = 63 - (label.length + 1 + (name2 ? 1 : 0));
|
|
330
|
+
let n1 = byteLength(table);
|
|
331
|
+
let n2 = byteLength(name2);
|
|
332
|
+
while (n1 + n2 > avail) if (n1 > n2) n1--;
|
|
333
|
+
else n2--;
|
|
334
|
+
const head = truncateBytes(table, n1);
|
|
335
|
+
return name2 ? `${head}_${truncateBytes(name2, n2)}_${label}` : `${head}_${label}`;
|
|
336
|
+
}
|
|
302
337
|
var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
303
338
|
driver;
|
|
304
339
|
supportsColumnModify = true;
|
|
@@ -321,14 +356,28 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
321
356
|
_vectorFields = /* @__PURE__ */ new Map();
|
|
322
357
|
/** Default similarity thresholds per vector field (from @db.search.vector.threshold). */
|
|
323
358
|
_vectorThresholds = /* @__PURE__ */ new Map();
|
|
324
|
-
/**
|
|
359
|
+
/**
|
|
360
|
+
* Schema name for catalog queries and qualification — `@db.schema` of the
|
|
361
|
+
* bound table, or `null` (→ `'public'`, the same default the bound path
|
|
362
|
+
* uses) when the table declares none or the adapter is an administrative
|
|
363
|
+
* one with no readable (the name-taking schema-sync primitives run on such
|
|
364
|
+
* an adapter).
|
|
365
|
+
*/
|
|
325
366
|
get _schema() {
|
|
326
|
-
return this._table
|
|
367
|
+
return this._table?.schema ?? null;
|
|
327
368
|
}
|
|
328
369
|
constructor(driver) {
|
|
329
370
|
super();
|
|
330
371
|
this.driver = driver;
|
|
331
372
|
}
|
|
373
|
+
/** Every adapter over this pool shares one transaction (since 0.1.128). */
|
|
374
|
+
_transactionOwner() {
|
|
375
|
+
return this.driver;
|
|
376
|
+
}
|
|
377
|
+
/** The dedicated connection of this pool's open transaction, if any. */
|
|
378
|
+
_txConnection() {
|
|
379
|
+
return this._getTransactionState();
|
|
380
|
+
}
|
|
332
381
|
async _beginTransaction() {
|
|
333
382
|
const conn = await this.driver.getConnection();
|
|
334
383
|
try {
|
|
@@ -363,7 +412,7 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
363
412
|
* otherwise the pool-based driver.
|
|
364
413
|
*/
|
|
365
414
|
_exec() {
|
|
366
|
-
return this.
|
|
415
|
+
return this._txConnection() ?? this.driver;
|
|
367
416
|
}
|
|
368
417
|
/** PostgreSQL enforces FK constraints natively. */
|
|
369
418
|
supportsNativeForeignKeys() {
|
|
@@ -597,7 +646,8 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
597
646
|
};
|
|
598
647
|
}
|
|
599
648
|
async replaceOne(filter, data, expectedVersion) {
|
|
600
|
-
|
|
649
|
+
const full = (0, _atscript_db_sql_tools.fillReplacePayload)(data, (0, _atscript_db_sql_tools.replaceColumnsFor)(this._table.fieldDescriptors, this.nativeDefaultFns()), this._table.versionColumn);
|
|
650
|
+
return this.updateOne(filter, full, void 0, expectedVersion);
|
|
601
651
|
}
|
|
602
652
|
async replaceMany(filter, data) {
|
|
603
653
|
return this.updateMany(filter, data);
|
|
@@ -626,7 +676,7 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
626
676
|
_hasGeoPointFields() {
|
|
627
677
|
return this._table.fieldDescriptors.some((fd) => fd.isGeoPoint && !fd.encrypted);
|
|
628
678
|
}
|
|
629
|
-
async ensureTable() {
|
|
679
|
+
async ensureTable(opts) {
|
|
630
680
|
if (this._nocaseColumns.size > 0 && !this._citextProvisioned) try {
|
|
631
681
|
await this._exec().exec("CREATE EXTENSION IF NOT EXISTS citext");
|
|
632
682
|
this._citextProvisioned = true;
|
|
@@ -636,15 +686,89 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
636
686
|
}
|
|
637
687
|
await this.prepareTypeMapper();
|
|
638
688
|
if (this._schema) await this._exec().exec(`CREATE SCHEMA IF NOT EXISTS ${qi(this._schema)}`);
|
|
639
|
-
if (this._table
|
|
689
|
+
if (this._table.isView) return this._ensureView();
|
|
640
690
|
const sql = buildCreateTable(this.resolveTableName(), this._table.fieldDescriptors, this._table.foreignKeys, {
|
|
641
691
|
incrementFields: this._incrementFields,
|
|
642
692
|
autoIncrementStart: this._autoIncrementStart,
|
|
643
|
-
typeMapper: (field) => this.typeMapper(field)
|
|
693
|
+
typeMapper: (field) => this.typeMapper(field),
|
|
694
|
+
deferForeignKeysTo: opts?.deferForeignKeysTo
|
|
644
695
|
});
|
|
645
696
|
this._log(sql);
|
|
646
697
|
await this._exec().exec(sql);
|
|
647
698
|
}
|
|
699
|
+
/** `schema.name` when the adapter targets a named schema. */
|
|
700
|
+
_qualify(name) {
|
|
701
|
+
return quoteTableName(this._schema ? `${this._schema}.${name}` : name);
|
|
702
|
+
}
|
|
703
|
+
async hasRows(tableName) {
|
|
704
|
+
const sql = `SELECT EXISTS (SELECT 1 FROM ${tableName ? this._qualify(tableName) : quoteTableName(this.resolveTableName())}) AS "present"`;
|
|
705
|
+
this._log(sql);
|
|
706
|
+
return (await this._exec().get(sql, []))?.present ?? false;
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Live foreign keys referencing `tableName`, via `pg_constraint` — exact for
|
|
710
|
+
* composite keys (`conkey`/`confkey` are positionally aligned, unlike the
|
|
711
|
+
* `key_column_usage` ordinal join).
|
|
712
|
+
*/
|
|
713
|
+
async getReferencingForeignKeys(tableName) {
|
|
714
|
+
return (await this._exec().all(`SELECT cl.relname AS table_name, c.conname AS constraint_name,
|
|
715
|
+
(SELECT array_agg(a.attname::text ORDER BY k.ord)
|
|
716
|
+
FROM unnest(c.conkey) WITH ORDINALITY AS k(attnum, ord)
|
|
717
|
+
JOIN pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = k.attnum) AS columns,
|
|
718
|
+
(SELECT array_agg(a.attname::text ORDER BY k.ord)
|
|
719
|
+
FROM unnest(c.confkey) WITH ORDINALITY AS k(attnum, ord)
|
|
720
|
+
JOIN pg_attribute a ON a.attrelid = c.confrelid AND a.attnum = k.attnum) AS ref_columns
|
|
721
|
+
FROM pg_constraint c
|
|
722
|
+
JOIN pg_class cl ON cl.oid = c.conrelid
|
|
723
|
+
JOIN pg_class rcl ON rcl.oid = c.confrelid
|
|
724
|
+
JOIN pg_namespace rn ON rn.oid = rcl.relnamespace
|
|
725
|
+
WHERE c.contype = 'f' AND rcl.relname = $1 AND rn.nspname = COALESCE($2, 'public')
|
|
726
|
+
ORDER BY cl.relname, c.conname`, [tableName, this._schema])).map((r) => ({
|
|
727
|
+
table: r.table_name,
|
|
728
|
+
fields: r.columns ?? [],
|
|
729
|
+
targetFields: r.ref_columns ?? []
|
|
730
|
+
}));
|
|
731
|
+
}
|
|
732
|
+
async getObjectKind(name) {
|
|
733
|
+
switch ((await this._exec().get(`SELECT c.relkind FROM pg_class c
|
|
734
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
735
|
+
WHERE c.relname = $1 AND n.nspname = COALESCE($2, 'public')
|
|
736
|
+
AND c.relkind IN ('r', 'p', 'v', 'm')`, [name, this._schema]))?.relkind) {
|
|
737
|
+
case "r":
|
|
738
|
+
case "p": return "table";
|
|
739
|
+
case "v": return "view";
|
|
740
|
+
case "m": return "materialized";
|
|
741
|
+
default: return;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
/** One multi-table `DROP TABLE a, b` — PostgreSQL resolves the mutual FKs inside the set. No CASCADE. */
|
|
745
|
+
async dropTablesByName(tableNames) {
|
|
746
|
+
if (tableNames.length === 0) return;
|
|
747
|
+
const ddl = `DROP TABLE IF EXISTS ${tableNames.map((n) => this._qualify(n)).join(", ")}`;
|
|
748
|
+
this._log(ddl);
|
|
749
|
+
await this._exec().exec(ddl);
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* `ALTER TABLE … DROP CONSTRAINT <pk>, ADD PRIMARY KEY (…)` in ONE statement
|
|
753
|
+
* (atomic). Called on an empty table only; `ADD PRIMARY KEY` makes the new
|
|
754
|
+
* key columns NOT NULL. A demoted identity column is handled by the
|
|
755
|
+
* `defaultChanged` diff (`DROP IDENTITY`).
|
|
756
|
+
*/
|
|
757
|
+
async rebuildPrimaryKey(change) {
|
|
758
|
+
const clauses = [];
|
|
759
|
+
if (change.from.length > 0) {
|
|
760
|
+
const row = await this._exec().get(`SELECT c.conname FROM pg_constraint c
|
|
761
|
+
JOIN pg_class cl ON cl.oid = c.conrelid
|
|
762
|
+
JOIN pg_namespace n ON n.oid = cl.relnamespace
|
|
763
|
+
WHERE c.contype = 'p' AND cl.relname = $1 AND n.nspname = COALESCE($2, 'public')`, [this._table.tableName, this._schema]);
|
|
764
|
+
if (row?.conname) clauses.push(`DROP CONSTRAINT ${qi(row.conname)}`);
|
|
765
|
+
}
|
|
766
|
+
if (change.to.length > 0) clauses.push(`ADD PRIMARY KEY (${change.to.map((c) => qi(c)).join(", ")})`);
|
|
767
|
+
if (clauses.length === 0) return;
|
|
768
|
+
const ddl = `ALTER TABLE ${quoteTableName(this.resolveTableName())} ${clauses.join(", ")}`;
|
|
769
|
+
this._log(ddl);
|
|
770
|
+
await this._exec().exec(ddl);
|
|
771
|
+
}
|
|
648
772
|
async _ensureView() {
|
|
649
773
|
const view = this._table;
|
|
650
774
|
const sql = buildCreateView(this.resolveTableName(), view.viewPlan, view.getViewColumnMappings(), (ref) => view.resolveFieldRef(ref, qi));
|
|
@@ -734,15 +858,27 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
734
858
|
this._log(ddl);
|
|
735
859
|
await this._exec().exec(ddl);
|
|
736
860
|
}
|
|
737
|
-
for (const { field } of diff.defaultChanged ?? []) {
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
861
|
+
for (const { field, oldDefault } of diff.defaultChanged ?? []) {
|
|
862
|
+
const col = `ALTER TABLE ${quoteTableName(tableName)} ALTER COLUMN ${qi(field.physicalName)}`;
|
|
863
|
+
const wasIdentity = oldDefault === "fn:increment";
|
|
864
|
+
const statements = [];
|
|
865
|
+
if (field.defaultValue?.kind === "fn" && field.defaultValue.fn === "increment") {
|
|
866
|
+
if (!wasIdentity) {
|
|
867
|
+
if (oldDefault !== void 0) statements.push(`${col} DROP DEFAULT`);
|
|
868
|
+
statements.push(`${col} SET NOT NULL`, `${col} ADD GENERATED BY DEFAULT AS IDENTITY`);
|
|
869
|
+
}
|
|
870
|
+
} else {
|
|
871
|
+
if (wasIdentity) statements.push(`${col} DROP IDENTITY IF EXISTS`);
|
|
872
|
+
if (field.defaultValue?.kind === "value") statements.push(`${col} SET DEFAULT ${defaultValueToSqlLiteral(field.designType, field.defaultValue.value)}`);
|
|
873
|
+
else if (field.defaultValue?.kind === "fn") {
|
|
874
|
+
const fnExpr = field.defaultValue.fn === "now" ? "(extract(epoch from now()) * 1000)::bigint" : "gen_random_uuid()";
|
|
875
|
+
statements.push(`${col} SET DEFAULT ${fnExpr}`);
|
|
876
|
+
} else if (!wasIdentity) statements.push(`${col} DROP DEFAULT`);
|
|
877
|
+
}
|
|
878
|
+
for (const ddl of statements) {
|
|
879
|
+
this._log(ddl);
|
|
880
|
+
await this._exec().exec(ddl);
|
|
881
|
+
}
|
|
746
882
|
}
|
|
747
883
|
return {
|
|
748
884
|
added,
|
|
@@ -767,14 +903,18 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
767
903
|
ON kcu.constraint_name = tc.constraint_name AND kcu.table_schema = tc.table_schema
|
|
768
904
|
JOIN information_schema.key_column_usage kcur
|
|
769
905
|
ON kcur.constraint_name = rc.unique_constraint_name AND kcur.table_schema = rc.unique_constraint_schema
|
|
770
|
-
AND kcur.ordinal_position = kcu.
|
|
906
|
+
AND kcur.ordinal_position = kcu.position_in_unique_constraint
|
|
771
907
|
WHERE rc.unique_constraint_schema = COALESCE($1, 'public')
|
|
772
908
|
AND rc.unique_constraint_name IN (
|
|
773
909
|
SELECT constraint_name FROM information_schema.table_constraints
|
|
774
|
-
WHERE table_name = $2 AND table_schema = COALESCE($1, 'public')
|
|
775
|
-
|
|
910
|
+
WHERE table_name = $2 AND table_schema = COALESCE($1, 'public')
|
|
911
|
+
AND constraint_type IN ('PRIMARY KEY', 'UNIQUE')
|
|
912
|
+
)
|
|
913
|
+
ORDER BY tc.table_schema, tc.table_name, tc.constraint_name, kcu.ordinal_position`, [schema, this._table.tableName]);
|
|
776
914
|
const fkByName = /* @__PURE__ */ new Map();
|
|
915
|
+
const ownSchema = schema ?? "public";
|
|
777
916
|
for (const fk of fkRefs) {
|
|
917
|
+
if (fk.table_schema === ownSchema && fk.table_name === this._table.tableName) continue;
|
|
778
918
|
let entry = fkByName.get(fk.constraint_name);
|
|
779
919
|
if (!entry) {
|
|
780
920
|
entry = {
|
|
@@ -798,7 +938,8 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
798
938
|
const createSql = buildCreateTable(tempName, this._table.fieldDescriptors, this._table.foreignKeys, {
|
|
799
939
|
incrementFields: this._incrementFields,
|
|
800
940
|
autoIncrementStart: this._autoIncrementStart,
|
|
801
|
-
typeMapper: (field) => this.typeMapper(field)
|
|
941
|
+
typeMapper: (field) => this.typeMapper(field),
|
|
942
|
+
deferForeignKeysTo: new Set([this._table.tableName])
|
|
802
943
|
});
|
|
803
944
|
this._log(createSql);
|
|
804
945
|
await conn.exec(createSql);
|
|
@@ -823,13 +964,16 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
823
964
|
this._log(copySql);
|
|
824
965
|
await conn.exec(copySql);
|
|
825
966
|
}
|
|
826
|
-
|
|
967
|
+
const dropSql = `DROP TABLE IF EXISTS ${quoteTableName(tableName)}`;
|
|
968
|
+
this._log(dropSql);
|
|
969
|
+
await conn.exec(dropSql);
|
|
827
970
|
await conn.exec(`ALTER TABLE ${quoteTableName(tempName)} RENAME TO ${qi(this._table.tableName)}`);
|
|
971
|
+
await this._renameTempConstraints(conn, baseTempName);
|
|
828
972
|
const resolvedTable = this.resolveTableName();
|
|
829
|
-
for (const [, fk] of fkByName) {
|
|
973
|
+
for (const [name, fk] of fkByName) {
|
|
830
974
|
const localCols = fk.cols.map((c) => qi(c)).join(", ");
|
|
831
975
|
const refCols = fk.refCols.map((c) => qi(c)).join(", ");
|
|
832
|
-
let ddl = `ALTER TABLE ${qi(fk.schema)}.${qi(fk.table)} ADD FOREIGN KEY (${localCols}) REFERENCES ${quoteTableName(resolvedTable)} (${refCols})`;
|
|
976
|
+
let ddl = `ALTER TABLE ${qi(fk.schema)}.${qi(fk.table)} ADD CONSTRAINT ${qi(name)} FOREIGN KEY (${localCols}) REFERENCES ${quoteTableName(resolvedTable)} (${refCols})`;
|
|
833
977
|
if (fk.onDelete !== "NO ACTION") ddl += ` ON DELETE ${fk.onDelete}`;
|
|
834
978
|
if (fk.onUpdate !== "NO ACTION") ddl += ` ON UPDATE ${fk.onUpdate}`;
|
|
835
979
|
this._log(ddl);
|
|
@@ -839,11 +983,59 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
839
983
|
await this._resetIdentitySequences();
|
|
840
984
|
} catch (err) {
|
|
841
985
|
await conn.exec("ROLLBACK").catch(() => {});
|
|
986
|
+
const detail = err.detail;
|
|
987
|
+
if (err instanceof Error && typeof detail === "string" && detail.length > 0) err.message = `${err.message} — ${detail}`;
|
|
842
988
|
throw err;
|
|
843
989
|
} finally {
|
|
844
990
|
conn.release();
|
|
845
991
|
}
|
|
846
992
|
}
|
|
993
|
+
/**
|
|
994
|
+
* Renames the recreated table's auto-named constraints from the temp
|
|
995
|
+
* table's names to the final table's: `<tmp>_pkey` → `<table>_pkey`,
|
|
996
|
+
* `<tmp>_<cols>_fkey` → `<table>_<cols>_fkey`, and so on. Runs inside the
|
|
997
|
+
* recreate transaction, after the RENAME. A constraint is recognised by
|
|
998
|
+
* its kind and columns — its name equals the one PostgreSQL generates for
|
|
999
|
+
* the temp table ({@link pgObjectName}, 63-byte truncation included) — so
|
|
1000
|
+
* a long table name matches too. A target name already taken (a primary /
|
|
1001
|
+
* unique constraint's index shares its name with every relation in the
|
|
1002
|
+
* schema; other kinds with the table's constraints) is skipped and logged.
|
|
1003
|
+
*/
|
|
1004
|
+
async _renameTempConstraints(conn, baseTempName) {
|
|
1005
|
+
const table = this._table.tableName;
|
|
1006
|
+
const rows = await conn.all(`SELECT c.conname, c.contype,
|
|
1007
|
+
(SELECT array_agg(a.attname::text ORDER BY k.ord)
|
|
1008
|
+
FROM unnest(c.conkey) WITH ORDINALITY AS k(attnum, ord)
|
|
1009
|
+
JOIN pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = k.attnum) AS columns
|
|
1010
|
+
FROM pg_constraint c
|
|
1011
|
+
JOIN pg_class cl ON cl.oid = c.conrelid
|
|
1012
|
+
JOIN pg_namespace n ON n.oid = cl.relnamespace
|
|
1013
|
+
WHERE cl.relname = $1 AND n.nspname = COALESCE($2, 'public')
|
|
1014
|
+
ORDER BY c.conname`, [table, this._schema]);
|
|
1015
|
+
const taken = new Set(rows.map((r) => r.conname));
|
|
1016
|
+
for (const { conname, contype, columns } of rows) {
|
|
1017
|
+
const label = PG_CONSTRAINT_LABELS[contype];
|
|
1018
|
+
if (!label) continue;
|
|
1019
|
+
const cols = contype === "p" ? [] : columns ?? [];
|
|
1020
|
+
if (conname !== pgObjectName(baseTempName, cols, label)) continue;
|
|
1021
|
+
const target = pgObjectName(table, cols, label);
|
|
1022
|
+
if (target === conname) continue;
|
|
1023
|
+
if (contype === "p" || contype === "u" ? await this._relationExists(conn, target) : taken.has(target)) {
|
|
1024
|
+
this._log(`-- constraint "${conname}" keeps its name: "${target}" already exists`);
|
|
1025
|
+
continue;
|
|
1026
|
+
}
|
|
1027
|
+
const ddl = `ALTER TABLE ${quoteTableName(this.resolveTableName())} RENAME CONSTRAINT ${qi(conname)} TO ${qi(target)}`;
|
|
1028
|
+
this._log(ddl);
|
|
1029
|
+
await conn.exec(ddl);
|
|
1030
|
+
taken.add(target);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
/** Whether a relation (table, index, view, …) named `name` exists in this adapter's schema. */
|
|
1034
|
+
async _relationExists(conn, name) {
|
|
1035
|
+
return (await conn.get(`SELECT true AS present FROM pg_class c
|
|
1036
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1037
|
+
WHERE c.relname = $1 AND n.nspname = COALESCE($2, 'public')`, [name, this._schema]))?.present ?? false;
|
|
1038
|
+
}
|
|
847
1039
|
async afterSyncTable() {
|
|
848
1040
|
await this._resetIdentitySequences();
|
|
849
1041
|
}
|
|
@@ -867,8 +1059,14 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
867
1059
|
async tableExists() {
|
|
868
1060
|
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;
|
|
869
1061
|
}
|
|
1062
|
+
/**
|
|
1063
|
+
* No CASCADE: when something outside the sync inventory (a user view, an
|
|
1064
|
+
* unmanaged FK) still depends on the table PostgreSQL refuses, and schema
|
|
1065
|
+
* sync reports that as an error entry instead of silently dropping the
|
|
1066
|
+
* dependents.
|
|
1067
|
+
*/
|
|
870
1068
|
async dropTable() {
|
|
871
|
-
const ddl = `DROP TABLE IF EXISTS ${quoteTableName(this.resolveTableName())}
|
|
1069
|
+
const ddl = `DROP TABLE IF EXISTS ${quoteTableName(this.resolveTableName())}`;
|
|
872
1070
|
this._log(ddl);
|
|
873
1071
|
await this._exec().exec(ddl);
|
|
874
1072
|
}
|
|
@@ -901,7 +1099,7 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
901
1099
|
}
|
|
902
1100
|
}
|
|
903
1101
|
async dropTableByName(tableName) {
|
|
904
|
-
const ddl = `DROP TABLE IF EXISTS ${quoteTableName(tableName)}
|
|
1102
|
+
const ddl = `DROP TABLE IF EXISTS ${quoteTableName(tableName)}`;
|
|
905
1103
|
this._log(ddl);
|
|
906
1104
|
await this._exec().exec(ddl);
|
|
907
1105
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BaseDbAdapter, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbDefaultFn, TDbDeleteResult, TDbFieldMeta, TDbInsertManyResult, TDbInsertResult, TDbUpdateResult, TExistingColumn, TFieldOps, TSearchIndexInfo, TSyncColumnResult, TValueFormatterPair } from "@atscript/db";
|
|
1
|
+
import { BaseDbAdapter, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbDefaultFn, TDbDeleteResult, TDbFieldMeta, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbUpdateResult, TEnsureTableOptions, TExistingColumn, TFieldOps, TPrimaryKeyChange, TReferencingForeignKey, TSearchIndexInfo, TSyncColumnResult, TValueFormatterPair } from "@atscript/db";
|
|
2
2
|
import { TMetadataMap } from "@atscript/typescript/utils";
|
|
3
3
|
import { TSqlFragment } from "@atscript/db-sql-tools";
|
|
4
4
|
|
|
@@ -69,22 +69,6 @@ interface TPgConnection {
|
|
|
69
69
|
}
|
|
70
70
|
//#endregion
|
|
71
71
|
//#region src/postgres-adapter.d.ts
|
|
72
|
-
/**
|
|
73
|
-
* PostgreSQL adapter for {@link AtscriptDbTable}.
|
|
74
|
-
*
|
|
75
|
-
* Accepts any {@link TPgDriver} implementation — the actual PostgreSQL driver
|
|
76
|
-
* is fully swappable (pg Pool, custom implementations, etc.).
|
|
77
|
-
*
|
|
78
|
-
* Usage:
|
|
79
|
-
* ```typescript
|
|
80
|
-
* import { PgDriver, PostgresAdapter } from '@atscript/db-postgres'
|
|
81
|
-
* import { DbSpace } from '@atscript/db'
|
|
82
|
-
*
|
|
83
|
-
* const driver = new PgDriver('postgresql://user@localhost:5432/mydb')
|
|
84
|
-
* const space = new DbSpace(() => new PostgresAdapter(driver))
|
|
85
|
-
* const users = space.getTable(UsersType)
|
|
86
|
-
* ```
|
|
87
|
-
*/
|
|
88
72
|
declare class PostgresAdapter extends BaseDbAdapter {
|
|
89
73
|
protected readonly driver: TPgDriver;
|
|
90
74
|
supportsColumnModify: boolean;
|
|
@@ -103,9 +87,19 @@ declare class PostgresAdapter extends BaseDbAdapter {
|
|
|
103
87
|
private _vectorFields;
|
|
104
88
|
/** Default similarity thresholds per vector field (from @db.search.vector.threshold). */
|
|
105
89
|
private _vectorThresholds;
|
|
106
|
-
/**
|
|
90
|
+
/**
|
|
91
|
+
* Schema name for catalog queries and qualification — `@db.schema` of the
|
|
92
|
+
* bound table, or `null` (→ `'public'`, the same default the bound path
|
|
93
|
+
* uses) when the table declares none or the adapter is an administrative
|
|
94
|
+
* one with no readable (the name-taking schema-sync primitives run on such
|
|
95
|
+
* an adapter).
|
|
96
|
+
*/
|
|
107
97
|
private get _schema();
|
|
108
98
|
constructor(driver: TPgDriver);
|
|
99
|
+
/** Every adapter over this pool shares one transaction (since 0.1.128). */
|
|
100
|
+
protected _transactionOwner(): unknown;
|
|
101
|
+
/** The dedicated connection of this pool's open transaction, if any. */
|
|
102
|
+
private _txConnection;
|
|
109
103
|
protected _beginTransaction(): Promise<TPgConnection>;
|
|
110
104
|
protected _commitTransaction(state: unknown): Promise<void>;
|
|
111
105
|
protected _rollbackTransaction(state: unknown): Promise<void>;
|
|
@@ -156,12 +150,45 @@ declare class PostgresAdapter extends BaseDbAdapter {
|
|
|
156
150
|
prepareTypeMapper(): Promise<void>;
|
|
157
151
|
/** Whether the table declares any `db.geoPoint` fields (unencrypted). */
|
|
158
152
|
private _hasGeoPointFields;
|
|
159
|
-
ensureTable(): Promise<void>;
|
|
153
|
+
ensureTable(opts?: TEnsureTableOptions): Promise<void>;
|
|
154
|
+
/** `schema.name` when the adapter targets a named schema. */
|
|
155
|
+
private _qualify;
|
|
156
|
+
hasRows(tableName?: string): Promise<boolean>;
|
|
157
|
+
/**
|
|
158
|
+
* Live foreign keys referencing `tableName`, via `pg_constraint` — exact for
|
|
159
|
+
* composite keys (`conkey`/`confkey` are positionally aligned, unlike the
|
|
160
|
+
* `key_column_usage` ordinal join).
|
|
161
|
+
*/
|
|
162
|
+
getReferencingForeignKeys(tableName: string): Promise<TReferencingForeignKey[]>;
|
|
163
|
+
getObjectKind(name: string): Promise<TDbObjectKind | undefined>;
|
|
164
|
+
/** One multi-table `DROP TABLE a, b` — PostgreSQL resolves the mutual FKs inside the set. No CASCADE. */
|
|
165
|
+
dropTablesByName(tableNames: string[]): Promise<void>;
|
|
166
|
+
/**
|
|
167
|
+
* `ALTER TABLE … DROP CONSTRAINT <pk>, ADD PRIMARY KEY (…)` in ONE statement
|
|
168
|
+
* (atomic). Called on an empty table only; `ADD PRIMARY KEY` makes the new
|
|
169
|
+
* key columns NOT NULL. A demoted identity column is handled by the
|
|
170
|
+
* `defaultChanged` diff (`DROP IDENTITY`).
|
|
171
|
+
*/
|
|
172
|
+
rebuildPrimaryKey(change: TPrimaryKeyChange): Promise<void>;
|
|
160
173
|
private _ensureView;
|
|
161
174
|
getExistingColumns(): Promise<TExistingColumn[]>;
|
|
162
175
|
getExistingColumnsForTable(tableName: string): Promise<TExistingColumn[]>;
|
|
163
176
|
syncColumns(diff: TColumnDiff): Promise<TSyncColumnResult>;
|
|
164
177
|
recreateTable(): Promise<void>;
|
|
178
|
+
/**
|
|
179
|
+
* Renames the recreated table's auto-named constraints from the temp
|
|
180
|
+
* table's names to the final table's: `<tmp>_pkey` → `<table>_pkey`,
|
|
181
|
+
* `<tmp>_<cols>_fkey` → `<table>_<cols>_fkey`, and so on. Runs inside the
|
|
182
|
+
* recreate transaction, after the RENAME. A constraint is recognised by
|
|
183
|
+
* its kind and columns — its name equals the one PostgreSQL generates for
|
|
184
|
+
* the temp table ({@link pgObjectName}, 63-byte truncation included) — so
|
|
185
|
+
* a long table name matches too. A target name already taken (a primary /
|
|
186
|
+
* unique constraint's index shares its name with every relation in the
|
|
187
|
+
* schema; other kinds with the table's constraints) is skipped and logged.
|
|
188
|
+
*/
|
|
189
|
+
private _renameTempConstraints;
|
|
190
|
+
/** Whether a relation (table, index, view, …) named `name` exists in this adapter's schema. */
|
|
191
|
+
private _relationExists;
|
|
165
192
|
afterSyncTable(): Promise<void>;
|
|
166
193
|
/**
|
|
167
194
|
* Resets IDENTITY sequences to MAX(column) so that the next auto-generated
|
|
@@ -171,6 +198,12 @@ declare class PostgresAdapter extends BaseDbAdapter {
|
|
|
171
198
|
*/
|
|
172
199
|
private _resetIdentitySequences;
|
|
173
200
|
tableExists(): Promise<boolean>;
|
|
201
|
+
/**
|
|
202
|
+
* No CASCADE: when something outside the sync inventory (a user view, an
|
|
203
|
+
* unmanaged FK) still depends on the table PostgreSQL refuses, and schema
|
|
204
|
+
* sync reports that as an error entry instead of silently dropping the
|
|
205
|
+
* dependents.
|
|
206
|
+
*/
|
|
174
207
|
dropTable(): Promise<void>;
|
|
175
208
|
dropColumns(columns: string[]): Promise<void>;
|
|
176
209
|
dropIndexesForColumns(columns: string[]): Promise<void>;
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BaseDbAdapter, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbDefaultFn, TDbDeleteResult, TDbFieldMeta, TDbInsertManyResult, TDbInsertResult, TDbUpdateResult, TExistingColumn, TFieldOps, TSearchIndexInfo, TSyncColumnResult, TValueFormatterPair } from "@atscript/db";
|
|
1
|
+
import { BaseDbAdapter, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbDefaultFn, TDbDeleteResult, TDbFieldMeta, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbUpdateResult, TEnsureTableOptions, TExistingColumn, TFieldOps, TPrimaryKeyChange, TReferencingForeignKey, TSearchIndexInfo, TSyncColumnResult, TValueFormatterPair } from "@atscript/db";
|
|
2
2
|
import { TSqlFragment } from "@atscript/db-sql-tools";
|
|
3
3
|
import { TMetadataMap } from "@atscript/typescript/utils";
|
|
4
4
|
|
|
@@ -69,22 +69,6 @@ interface TPgConnection {
|
|
|
69
69
|
}
|
|
70
70
|
//#endregion
|
|
71
71
|
//#region src/postgres-adapter.d.ts
|
|
72
|
-
/**
|
|
73
|
-
* PostgreSQL adapter for {@link AtscriptDbTable}.
|
|
74
|
-
*
|
|
75
|
-
* Accepts any {@link TPgDriver} implementation — the actual PostgreSQL driver
|
|
76
|
-
* is fully swappable (pg Pool, custom implementations, etc.).
|
|
77
|
-
*
|
|
78
|
-
* Usage:
|
|
79
|
-
* ```typescript
|
|
80
|
-
* import { PgDriver, PostgresAdapter } from '@atscript/db-postgres'
|
|
81
|
-
* import { DbSpace } from '@atscript/db'
|
|
82
|
-
*
|
|
83
|
-
* const driver = new PgDriver('postgresql://user@localhost:5432/mydb')
|
|
84
|
-
* const space = new DbSpace(() => new PostgresAdapter(driver))
|
|
85
|
-
* const users = space.getTable(UsersType)
|
|
86
|
-
* ```
|
|
87
|
-
*/
|
|
88
72
|
declare class PostgresAdapter extends BaseDbAdapter {
|
|
89
73
|
protected readonly driver: TPgDriver;
|
|
90
74
|
supportsColumnModify: boolean;
|
|
@@ -103,9 +87,19 @@ declare class PostgresAdapter extends BaseDbAdapter {
|
|
|
103
87
|
private _vectorFields;
|
|
104
88
|
/** Default similarity thresholds per vector field (from @db.search.vector.threshold). */
|
|
105
89
|
private _vectorThresholds;
|
|
106
|
-
/**
|
|
90
|
+
/**
|
|
91
|
+
* Schema name for catalog queries and qualification — `@db.schema` of the
|
|
92
|
+
* bound table, or `null` (→ `'public'`, the same default the bound path
|
|
93
|
+
* uses) when the table declares none or the adapter is an administrative
|
|
94
|
+
* one with no readable (the name-taking schema-sync primitives run on such
|
|
95
|
+
* an adapter).
|
|
96
|
+
*/
|
|
107
97
|
private get _schema();
|
|
108
98
|
constructor(driver: TPgDriver);
|
|
99
|
+
/** Every adapter over this pool shares one transaction (since 0.1.128). */
|
|
100
|
+
protected _transactionOwner(): unknown;
|
|
101
|
+
/** The dedicated connection of this pool's open transaction, if any. */
|
|
102
|
+
private _txConnection;
|
|
109
103
|
protected _beginTransaction(): Promise<TPgConnection>;
|
|
110
104
|
protected _commitTransaction(state: unknown): Promise<void>;
|
|
111
105
|
protected _rollbackTransaction(state: unknown): Promise<void>;
|
|
@@ -156,12 +150,45 @@ declare class PostgresAdapter extends BaseDbAdapter {
|
|
|
156
150
|
prepareTypeMapper(): Promise<void>;
|
|
157
151
|
/** Whether the table declares any `db.geoPoint` fields (unencrypted). */
|
|
158
152
|
private _hasGeoPointFields;
|
|
159
|
-
ensureTable(): Promise<void>;
|
|
153
|
+
ensureTable(opts?: TEnsureTableOptions): Promise<void>;
|
|
154
|
+
/** `schema.name` when the adapter targets a named schema. */
|
|
155
|
+
private _qualify;
|
|
156
|
+
hasRows(tableName?: string): Promise<boolean>;
|
|
157
|
+
/**
|
|
158
|
+
* Live foreign keys referencing `tableName`, via `pg_constraint` — exact for
|
|
159
|
+
* composite keys (`conkey`/`confkey` are positionally aligned, unlike the
|
|
160
|
+
* `key_column_usage` ordinal join).
|
|
161
|
+
*/
|
|
162
|
+
getReferencingForeignKeys(tableName: string): Promise<TReferencingForeignKey[]>;
|
|
163
|
+
getObjectKind(name: string): Promise<TDbObjectKind | undefined>;
|
|
164
|
+
/** One multi-table `DROP TABLE a, b` — PostgreSQL resolves the mutual FKs inside the set. No CASCADE. */
|
|
165
|
+
dropTablesByName(tableNames: string[]): Promise<void>;
|
|
166
|
+
/**
|
|
167
|
+
* `ALTER TABLE … DROP CONSTRAINT <pk>, ADD PRIMARY KEY (…)` in ONE statement
|
|
168
|
+
* (atomic). Called on an empty table only; `ADD PRIMARY KEY` makes the new
|
|
169
|
+
* key columns NOT NULL. A demoted identity column is handled by the
|
|
170
|
+
* `defaultChanged` diff (`DROP IDENTITY`).
|
|
171
|
+
*/
|
|
172
|
+
rebuildPrimaryKey(change: TPrimaryKeyChange): Promise<void>;
|
|
160
173
|
private _ensureView;
|
|
161
174
|
getExistingColumns(): Promise<TExistingColumn[]>;
|
|
162
175
|
getExistingColumnsForTable(tableName: string): Promise<TExistingColumn[]>;
|
|
163
176
|
syncColumns(diff: TColumnDiff): Promise<TSyncColumnResult>;
|
|
164
177
|
recreateTable(): Promise<void>;
|
|
178
|
+
/**
|
|
179
|
+
* Renames the recreated table's auto-named constraints from the temp
|
|
180
|
+
* table's names to the final table's: `<tmp>_pkey` → `<table>_pkey`,
|
|
181
|
+
* `<tmp>_<cols>_fkey` → `<table>_<cols>_fkey`, and so on. Runs inside the
|
|
182
|
+
* recreate transaction, after the RENAME. A constraint is recognised by
|
|
183
|
+
* its kind and columns — its name equals the one PostgreSQL generates for
|
|
184
|
+
* the temp table ({@link pgObjectName}, 63-byte truncation included) — so
|
|
185
|
+
* a long table name matches too. A target name already taken (a primary /
|
|
186
|
+
* unique constraint's index shares its name with every relation in the
|
|
187
|
+
* schema; other kinds with the table's constraints) is skipped and logged.
|
|
188
|
+
*/
|
|
189
|
+
private _renameTempConstraints;
|
|
190
|
+
/** Whether a relation (table, index, view, …) named `name` exists in this adapter's schema. */
|
|
191
|
+
private _relationExists;
|
|
165
192
|
afterSyncTable(): Promise<void>;
|
|
166
193
|
/**
|
|
167
194
|
* Resets IDENTITY sequences to MAX(column) so that the next auto-generated
|
|
@@ -171,6 +198,12 @@ declare class PostgresAdapter extends BaseDbAdapter {
|
|
|
171
198
|
*/
|
|
172
199
|
private _resetIdentitySequences;
|
|
173
200
|
tableExists(): Promise<boolean>;
|
|
201
|
+
/**
|
|
202
|
+
* No CASCADE: when something outside the sync inventory (a user view, an
|
|
203
|
+
* unmanaged FK) still depends on the table PostgreSQL refuses, and schema
|
|
204
|
+
* sync reports that as an error entry instead of silently dropping the
|
|
205
|
+
* dependents.
|
|
206
|
+
*/
|
|
174
207
|
dropTable(): Promise<void>;
|
|
175
208
|
dropColumns(columns: string[]): Promise<void>;
|
|
176
209
|
dropIndexesForColumns(columns: string[]): Promise<void>;
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildSelect, buildUpdate, buildWhere as buildWhere$1, defaultValueForType, defaultValueToSqlLiteral, finalizeParams, geoWindowFromControls, normalizeGeoPointValue, parseRegexString, refActionToSql, renameGeoDistance } from "@atscript/db-sql-tools";
|
|
1
|
+
import { BaseDbAdapter, DbError, DbSpace } from "@atscript/db";
|
|
2
|
+
import { buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildSelect, buildUpdate, buildWhere as buildWhere$1, defaultValueForType, defaultValueToSqlLiteral, fillReplacePayload, finalizeParams, geoWindowFromControls, normalizeGeoPointValue, parseRegexString, refActionToSql, renameGeoDistance, replaceColumnsFor } from "@atscript/db-sql-tools";
|
|
3
3
|
//#region src/sql-builder.ts
|
|
4
4
|
/**
|
|
5
5
|
* PostgreSQL-aware default value for a given design type.
|
|
@@ -240,6 +240,7 @@ function buildCreateTable(table, fields, foreignKeys, options) {
|
|
|
240
240
|
colDefs.push(`PRIMARY KEY (${pkCols})`);
|
|
241
241
|
}
|
|
242
242
|
if (foreignKeys) for (const fk of foreignKeys.values()) {
|
|
243
|
+
if (options?.deferForeignKeysTo?.has(fk.targetTable)) continue;
|
|
243
244
|
const localCols = fk.fields.map((f) => qi(f)).join(", ");
|
|
244
245
|
const targetCols = fk.targetFields.map((f) => qi(f)).join(", ");
|
|
245
246
|
let constraint = `FOREIGN KEY (${localCols}) REFERENCES ${qi(fk.targetTable)} (${targetCols})`;
|
|
@@ -298,6 +299,40 @@ function parseCount(value) {
|
|
|
298
299
|
* const users = space.getTable(UsersType)
|
|
299
300
|
* ```
|
|
300
301
|
*/
|
|
302
|
+
/** The suffix PostgreSQL gives an auto-named constraint of each `pg_constraint.contype`. */
|
|
303
|
+
const PG_CONSTRAINT_LABELS = {
|
|
304
|
+
p: "pkey",
|
|
305
|
+
u: "key",
|
|
306
|
+
f: "fkey",
|
|
307
|
+
n: "not_null"
|
|
308
|
+
};
|
|
309
|
+
/** UTF-8 byte length of `s`. */
|
|
310
|
+
function byteLength(s) {
|
|
311
|
+
return Buffer.byteLength(s, "utf8");
|
|
312
|
+
}
|
|
313
|
+
/** Cuts `s` to at most `bytes` UTF-8 bytes (whole characters only). */
|
|
314
|
+
function truncateBytes(s, bytes) {
|
|
315
|
+
let out = s;
|
|
316
|
+
while (byteLength(out) > bytes) out = out.slice(0, -1);
|
|
317
|
+
return out;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* The name PostgreSQL generates for an unnamed constraint (`makeObjectName`):
|
|
321
|
+
* `<table>_<columns joined by _>_<label>`, with the table and column parts
|
|
322
|
+
* shortened — the longer one first — until the whole fits 63 bytes
|
|
323
|
+
* (`NAMEDATALEN - 1`). Used to recognise and to rename the recreated table's
|
|
324
|
+
* constraints. Ignores the `1`, `2`, … suffix PostgreSQL appends on a clash.
|
|
325
|
+
*/
|
|
326
|
+
function pgObjectName(table, columns, label) {
|
|
327
|
+
const name2 = columns.join("_");
|
|
328
|
+
const avail = 63 - (label.length + 1 + (name2 ? 1 : 0));
|
|
329
|
+
let n1 = byteLength(table);
|
|
330
|
+
let n2 = byteLength(name2);
|
|
331
|
+
while (n1 + n2 > avail) if (n1 > n2) n1--;
|
|
332
|
+
else n2--;
|
|
333
|
+
const head = truncateBytes(table, n1);
|
|
334
|
+
return name2 ? `${head}_${truncateBytes(name2, n2)}_${label}` : `${head}_${label}`;
|
|
335
|
+
}
|
|
301
336
|
var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
302
337
|
driver;
|
|
303
338
|
supportsColumnModify = true;
|
|
@@ -320,14 +355,28 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
320
355
|
_vectorFields = /* @__PURE__ */ new Map();
|
|
321
356
|
/** Default similarity thresholds per vector field (from @db.search.vector.threshold). */
|
|
322
357
|
_vectorThresholds = /* @__PURE__ */ new Map();
|
|
323
|
-
/**
|
|
358
|
+
/**
|
|
359
|
+
* Schema name for catalog queries and qualification — `@db.schema` of the
|
|
360
|
+
* bound table, or `null` (→ `'public'`, the same default the bound path
|
|
361
|
+
* uses) when the table declares none or the adapter is an administrative
|
|
362
|
+
* one with no readable (the name-taking schema-sync primitives run on such
|
|
363
|
+
* an adapter).
|
|
364
|
+
*/
|
|
324
365
|
get _schema() {
|
|
325
|
-
return this._table
|
|
366
|
+
return this._table?.schema ?? null;
|
|
326
367
|
}
|
|
327
368
|
constructor(driver) {
|
|
328
369
|
super();
|
|
329
370
|
this.driver = driver;
|
|
330
371
|
}
|
|
372
|
+
/** Every adapter over this pool shares one transaction (since 0.1.128). */
|
|
373
|
+
_transactionOwner() {
|
|
374
|
+
return this.driver;
|
|
375
|
+
}
|
|
376
|
+
/** The dedicated connection of this pool's open transaction, if any. */
|
|
377
|
+
_txConnection() {
|
|
378
|
+
return this._getTransactionState();
|
|
379
|
+
}
|
|
331
380
|
async _beginTransaction() {
|
|
332
381
|
const conn = await this.driver.getConnection();
|
|
333
382
|
try {
|
|
@@ -362,7 +411,7 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
362
411
|
* otherwise the pool-based driver.
|
|
363
412
|
*/
|
|
364
413
|
_exec() {
|
|
365
|
-
return this.
|
|
414
|
+
return this._txConnection() ?? this.driver;
|
|
366
415
|
}
|
|
367
416
|
/** PostgreSQL enforces FK constraints natively. */
|
|
368
417
|
supportsNativeForeignKeys() {
|
|
@@ -596,7 +645,8 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
596
645
|
};
|
|
597
646
|
}
|
|
598
647
|
async replaceOne(filter, data, expectedVersion) {
|
|
599
|
-
|
|
648
|
+
const full = fillReplacePayload(data, replaceColumnsFor(this._table.fieldDescriptors, this.nativeDefaultFns()), this._table.versionColumn);
|
|
649
|
+
return this.updateOne(filter, full, void 0, expectedVersion);
|
|
600
650
|
}
|
|
601
651
|
async replaceMany(filter, data) {
|
|
602
652
|
return this.updateMany(filter, data);
|
|
@@ -625,7 +675,7 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
625
675
|
_hasGeoPointFields() {
|
|
626
676
|
return this._table.fieldDescriptors.some((fd) => fd.isGeoPoint && !fd.encrypted);
|
|
627
677
|
}
|
|
628
|
-
async ensureTable() {
|
|
678
|
+
async ensureTable(opts) {
|
|
629
679
|
if (this._nocaseColumns.size > 0 && !this._citextProvisioned) try {
|
|
630
680
|
await this._exec().exec("CREATE EXTENSION IF NOT EXISTS citext");
|
|
631
681
|
this._citextProvisioned = true;
|
|
@@ -635,15 +685,89 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
635
685
|
}
|
|
636
686
|
await this.prepareTypeMapper();
|
|
637
687
|
if (this._schema) await this._exec().exec(`CREATE SCHEMA IF NOT EXISTS ${qi(this._schema)}`);
|
|
638
|
-
if (this._table
|
|
688
|
+
if (this._table.isView) return this._ensureView();
|
|
639
689
|
const sql = buildCreateTable(this.resolveTableName(), this._table.fieldDescriptors, this._table.foreignKeys, {
|
|
640
690
|
incrementFields: this._incrementFields,
|
|
641
691
|
autoIncrementStart: this._autoIncrementStart,
|
|
642
|
-
typeMapper: (field) => this.typeMapper(field)
|
|
692
|
+
typeMapper: (field) => this.typeMapper(field),
|
|
693
|
+
deferForeignKeysTo: opts?.deferForeignKeysTo
|
|
643
694
|
});
|
|
644
695
|
this._log(sql);
|
|
645
696
|
await this._exec().exec(sql);
|
|
646
697
|
}
|
|
698
|
+
/** `schema.name` when the adapter targets a named schema. */
|
|
699
|
+
_qualify(name) {
|
|
700
|
+
return quoteTableName(this._schema ? `${this._schema}.${name}` : name);
|
|
701
|
+
}
|
|
702
|
+
async hasRows(tableName) {
|
|
703
|
+
const sql = `SELECT EXISTS (SELECT 1 FROM ${tableName ? this._qualify(tableName) : quoteTableName(this.resolveTableName())}) AS "present"`;
|
|
704
|
+
this._log(sql);
|
|
705
|
+
return (await this._exec().get(sql, []))?.present ?? false;
|
|
706
|
+
}
|
|
707
|
+
/**
|
|
708
|
+
* Live foreign keys referencing `tableName`, via `pg_constraint` — exact for
|
|
709
|
+
* composite keys (`conkey`/`confkey` are positionally aligned, unlike the
|
|
710
|
+
* `key_column_usage` ordinal join).
|
|
711
|
+
*/
|
|
712
|
+
async getReferencingForeignKeys(tableName) {
|
|
713
|
+
return (await this._exec().all(`SELECT cl.relname AS table_name, c.conname AS constraint_name,
|
|
714
|
+
(SELECT array_agg(a.attname::text ORDER BY k.ord)
|
|
715
|
+
FROM unnest(c.conkey) WITH ORDINALITY AS k(attnum, ord)
|
|
716
|
+
JOIN pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = k.attnum) AS columns,
|
|
717
|
+
(SELECT array_agg(a.attname::text ORDER BY k.ord)
|
|
718
|
+
FROM unnest(c.confkey) WITH ORDINALITY AS k(attnum, ord)
|
|
719
|
+
JOIN pg_attribute a ON a.attrelid = c.confrelid AND a.attnum = k.attnum) AS ref_columns
|
|
720
|
+
FROM pg_constraint c
|
|
721
|
+
JOIN pg_class cl ON cl.oid = c.conrelid
|
|
722
|
+
JOIN pg_class rcl ON rcl.oid = c.confrelid
|
|
723
|
+
JOIN pg_namespace rn ON rn.oid = rcl.relnamespace
|
|
724
|
+
WHERE c.contype = 'f' AND rcl.relname = $1 AND rn.nspname = COALESCE($2, 'public')
|
|
725
|
+
ORDER BY cl.relname, c.conname`, [tableName, this._schema])).map((r) => ({
|
|
726
|
+
table: r.table_name,
|
|
727
|
+
fields: r.columns ?? [],
|
|
728
|
+
targetFields: r.ref_columns ?? []
|
|
729
|
+
}));
|
|
730
|
+
}
|
|
731
|
+
async getObjectKind(name) {
|
|
732
|
+
switch ((await this._exec().get(`SELECT c.relkind FROM pg_class c
|
|
733
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
734
|
+
WHERE c.relname = $1 AND n.nspname = COALESCE($2, 'public')
|
|
735
|
+
AND c.relkind IN ('r', 'p', 'v', 'm')`, [name, this._schema]))?.relkind) {
|
|
736
|
+
case "r":
|
|
737
|
+
case "p": return "table";
|
|
738
|
+
case "v": return "view";
|
|
739
|
+
case "m": return "materialized";
|
|
740
|
+
default: return;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
/** One multi-table `DROP TABLE a, b` — PostgreSQL resolves the mutual FKs inside the set. No CASCADE. */
|
|
744
|
+
async dropTablesByName(tableNames) {
|
|
745
|
+
if (tableNames.length === 0) return;
|
|
746
|
+
const ddl = `DROP TABLE IF EXISTS ${tableNames.map((n) => this._qualify(n)).join(", ")}`;
|
|
747
|
+
this._log(ddl);
|
|
748
|
+
await this._exec().exec(ddl);
|
|
749
|
+
}
|
|
750
|
+
/**
|
|
751
|
+
* `ALTER TABLE … DROP CONSTRAINT <pk>, ADD PRIMARY KEY (…)` in ONE statement
|
|
752
|
+
* (atomic). Called on an empty table only; `ADD PRIMARY KEY` makes the new
|
|
753
|
+
* key columns NOT NULL. A demoted identity column is handled by the
|
|
754
|
+
* `defaultChanged` diff (`DROP IDENTITY`).
|
|
755
|
+
*/
|
|
756
|
+
async rebuildPrimaryKey(change) {
|
|
757
|
+
const clauses = [];
|
|
758
|
+
if (change.from.length > 0) {
|
|
759
|
+
const row = await this._exec().get(`SELECT c.conname FROM pg_constraint c
|
|
760
|
+
JOIN pg_class cl ON cl.oid = c.conrelid
|
|
761
|
+
JOIN pg_namespace n ON n.oid = cl.relnamespace
|
|
762
|
+
WHERE c.contype = 'p' AND cl.relname = $1 AND n.nspname = COALESCE($2, 'public')`, [this._table.tableName, this._schema]);
|
|
763
|
+
if (row?.conname) clauses.push(`DROP CONSTRAINT ${qi(row.conname)}`);
|
|
764
|
+
}
|
|
765
|
+
if (change.to.length > 0) clauses.push(`ADD PRIMARY KEY (${change.to.map((c) => qi(c)).join(", ")})`);
|
|
766
|
+
if (clauses.length === 0) return;
|
|
767
|
+
const ddl = `ALTER TABLE ${quoteTableName(this.resolveTableName())} ${clauses.join(", ")}`;
|
|
768
|
+
this._log(ddl);
|
|
769
|
+
await this._exec().exec(ddl);
|
|
770
|
+
}
|
|
647
771
|
async _ensureView() {
|
|
648
772
|
const view = this._table;
|
|
649
773
|
const sql = buildCreateView$1(this.resolveTableName(), view.viewPlan, view.getViewColumnMappings(), (ref) => view.resolveFieldRef(ref, qi));
|
|
@@ -733,15 +857,27 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
733
857
|
this._log(ddl);
|
|
734
858
|
await this._exec().exec(ddl);
|
|
735
859
|
}
|
|
736
|
-
for (const { field } of diff.defaultChanged ?? []) {
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
860
|
+
for (const { field, oldDefault } of diff.defaultChanged ?? []) {
|
|
861
|
+
const col = `ALTER TABLE ${quoteTableName(tableName)} ALTER COLUMN ${qi(field.physicalName)}`;
|
|
862
|
+
const wasIdentity = oldDefault === "fn:increment";
|
|
863
|
+
const statements = [];
|
|
864
|
+
if (field.defaultValue?.kind === "fn" && field.defaultValue.fn === "increment") {
|
|
865
|
+
if (!wasIdentity) {
|
|
866
|
+
if (oldDefault !== void 0) statements.push(`${col} DROP DEFAULT`);
|
|
867
|
+
statements.push(`${col} SET NOT NULL`, `${col} ADD GENERATED BY DEFAULT AS IDENTITY`);
|
|
868
|
+
}
|
|
869
|
+
} else {
|
|
870
|
+
if (wasIdentity) statements.push(`${col} DROP IDENTITY IF EXISTS`);
|
|
871
|
+
if (field.defaultValue?.kind === "value") statements.push(`${col} SET DEFAULT ${defaultValueToSqlLiteral$1(field.designType, field.defaultValue.value)}`);
|
|
872
|
+
else if (field.defaultValue?.kind === "fn") {
|
|
873
|
+
const fnExpr = field.defaultValue.fn === "now" ? "(extract(epoch from now()) * 1000)::bigint" : "gen_random_uuid()";
|
|
874
|
+
statements.push(`${col} SET DEFAULT ${fnExpr}`);
|
|
875
|
+
} else if (!wasIdentity) statements.push(`${col} DROP DEFAULT`);
|
|
876
|
+
}
|
|
877
|
+
for (const ddl of statements) {
|
|
878
|
+
this._log(ddl);
|
|
879
|
+
await this._exec().exec(ddl);
|
|
880
|
+
}
|
|
745
881
|
}
|
|
746
882
|
return {
|
|
747
883
|
added,
|
|
@@ -766,14 +902,18 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
766
902
|
ON kcu.constraint_name = tc.constraint_name AND kcu.table_schema = tc.table_schema
|
|
767
903
|
JOIN information_schema.key_column_usage kcur
|
|
768
904
|
ON kcur.constraint_name = rc.unique_constraint_name AND kcur.table_schema = rc.unique_constraint_schema
|
|
769
|
-
AND kcur.ordinal_position = kcu.
|
|
905
|
+
AND kcur.ordinal_position = kcu.position_in_unique_constraint
|
|
770
906
|
WHERE rc.unique_constraint_schema = COALESCE($1, 'public')
|
|
771
907
|
AND rc.unique_constraint_name IN (
|
|
772
908
|
SELECT constraint_name FROM information_schema.table_constraints
|
|
773
|
-
WHERE table_name = $2 AND table_schema = COALESCE($1, 'public')
|
|
774
|
-
|
|
909
|
+
WHERE table_name = $2 AND table_schema = COALESCE($1, 'public')
|
|
910
|
+
AND constraint_type IN ('PRIMARY KEY', 'UNIQUE')
|
|
911
|
+
)
|
|
912
|
+
ORDER BY tc.table_schema, tc.table_name, tc.constraint_name, kcu.ordinal_position`, [schema, this._table.tableName]);
|
|
775
913
|
const fkByName = /* @__PURE__ */ new Map();
|
|
914
|
+
const ownSchema = schema ?? "public";
|
|
776
915
|
for (const fk of fkRefs) {
|
|
916
|
+
if (fk.table_schema === ownSchema && fk.table_name === this._table.tableName) continue;
|
|
777
917
|
let entry = fkByName.get(fk.constraint_name);
|
|
778
918
|
if (!entry) {
|
|
779
919
|
entry = {
|
|
@@ -797,7 +937,8 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
797
937
|
const createSql = buildCreateTable(tempName, this._table.fieldDescriptors, this._table.foreignKeys, {
|
|
798
938
|
incrementFields: this._incrementFields,
|
|
799
939
|
autoIncrementStart: this._autoIncrementStart,
|
|
800
|
-
typeMapper: (field) => this.typeMapper(field)
|
|
940
|
+
typeMapper: (field) => this.typeMapper(field),
|
|
941
|
+
deferForeignKeysTo: new Set([this._table.tableName])
|
|
801
942
|
});
|
|
802
943
|
this._log(createSql);
|
|
803
944
|
await conn.exec(createSql);
|
|
@@ -822,13 +963,16 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
822
963
|
this._log(copySql);
|
|
823
964
|
await conn.exec(copySql);
|
|
824
965
|
}
|
|
825
|
-
|
|
966
|
+
const dropSql = `DROP TABLE IF EXISTS ${quoteTableName(tableName)}`;
|
|
967
|
+
this._log(dropSql);
|
|
968
|
+
await conn.exec(dropSql);
|
|
826
969
|
await conn.exec(`ALTER TABLE ${quoteTableName(tempName)} RENAME TO ${qi(this._table.tableName)}`);
|
|
970
|
+
await this._renameTempConstraints(conn, baseTempName);
|
|
827
971
|
const resolvedTable = this.resolveTableName();
|
|
828
|
-
for (const [, fk] of fkByName) {
|
|
972
|
+
for (const [name, fk] of fkByName) {
|
|
829
973
|
const localCols = fk.cols.map((c) => qi(c)).join(", ");
|
|
830
974
|
const refCols = fk.refCols.map((c) => qi(c)).join(", ");
|
|
831
|
-
let ddl = `ALTER TABLE ${qi(fk.schema)}.${qi(fk.table)} ADD FOREIGN KEY (${localCols}) REFERENCES ${quoteTableName(resolvedTable)} (${refCols})`;
|
|
975
|
+
let ddl = `ALTER TABLE ${qi(fk.schema)}.${qi(fk.table)} ADD CONSTRAINT ${qi(name)} FOREIGN KEY (${localCols}) REFERENCES ${quoteTableName(resolvedTable)} (${refCols})`;
|
|
832
976
|
if (fk.onDelete !== "NO ACTION") ddl += ` ON DELETE ${fk.onDelete}`;
|
|
833
977
|
if (fk.onUpdate !== "NO ACTION") ddl += ` ON UPDATE ${fk.onUpdate}`;
|
|
834
978
|
this._log(ddl);
|
|
@@ -838,11 +982,59 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
838
982
|
await this._resetIdentitySequences();
|
|
839
983
|
} catch (err) {
|
|
840
984
|
await conn.exec("ROLLBACK").catch(() => {});
|
|
985
|
+
const detail = err.detail;
|
|
986
|
+
if (err instanceof Error && typeof detail === "string" && detail.length > 0) err.message = `${err.message} — ${detail}`;
|
|
841
987
|
throw err;
|
|
842
988
|
} finally {
|
|
843
989
|
conn.release();
|
|
844
990
|
}
|
|
845
991
|
}
|
|
992
|
+
/**
|
|
993
|
+
* Renames the recreated table's auto-named constraints from the temp
|
|
994
|
+
* table's names to the final table's: `<tmp>_pkey` → `<table>_pkey`,
|
|
995
|
+
* `<tmp>_<cols>_fkey` → `<table>_<cols>_fkey`, and so on. Runs inside the
|
|
996
|
+
* recreate transaction, after the RENAME. A constraint is recognised by
|
|
997
|
+
* its kind and columns — its name equals the one PostgreSQL generates for
|
|
998
|
+
* the temp table ({@link pgObjectName}, 63-byte truncation included) — so
|
|
999
|
+
* a long table name matches too. A target name already taken (a primary /
|
|
1000
|
+
* unique constraint's index shares its name with every relation in the
|
|
1001
|
+
* schema; other kinds with the table's constraints) is skipped and logged.
|
|
1002
|
+
*/
|
|
1003
|
+
async _renameTempConstraints(conn, baseTempName) {
|
|
1004
|
+
const table = this._table.tableName;
|
|
1005
|
+
const rows = await conn.all(`SELECT c.conname, c.contype,
|
|
1006
|
+
(SELECT array_agg(a.attname::text ORDER BY k.ord)
|
|
1007
|
+
FROM unnest(c.conkey) WITH ORDINALITY AS k(attnum, ord)
|
|
1008
|
+
JOIN pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = k.attnum) AS columns
|
|
1009
|
+
FROM pg_constraint c
|
|
1010
|
+
JOIN pg_class cl ON cl.oid = c.conrelid
|
|
1011
|
+
JOIN pg_namespace n ON n.oid = cl.relnamespace
|
|
1012
|
+
WHERE cl.relname = $1 AND n.nspname = COALESCE($2, 'public')
|
|
1013
|
+
ORDER BY c.conname`, [table, this._schema]);
|
|
1014
|
+
const taken = new Set(rows.map((r) => r.conname));
|
|
1015
|
+
for (const { conname, contype, columns } of rows) {
|
|
1016
|
+
const label = PG_CONSTRAINT_LABELS[contype];
|
|
1017
|
+
if (!label) continue;
|
|
1018
|
+
const cols = contype === "p" ? [] : columns ?? [];
|
|
1019
|
+
if (conname !== pgObjectName(baseTempName, cols, label)) continue;
|
|
1020
|
+
const target = pgObjectName(table, cols, label);
|
|
1021
|
+
if (target === conname) continue;
|
|
1022
|
+
if (contype === "p" || contype === "u" ? await this._relationExists(conn, target) : taken.has(target)) {
|
|
1023
|
+
this._log(`-- constraint "${conname}" keeps its name: "${target}" already exists`);
|
|
1024
|
+
continue;
|
|
1025
|
+
}
|
|
1026
|
+
const ddl = `ALTER TABLE ${quoteTableName(this.resolveTableName())} RENAME CONSTRAINT ${qi(conname)} TO ${qi(target)}`;
|
|
1027
|
+
this._log(ddl);
|
|
1028
|
+
await conn.exec(ddl);
|
|
1029
|
+
taken.add(target);
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
/** Whether a relation (table, index, view, …) named `name` exists in this adapter's schema. */
|
|
1033
|
+
async _relationExists(conn, name) {
|
|
1034
|
+
return (await conn.get(`SELECT true AS present FROM pg_class c
|
|
1035
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1036
|
+
WHERE c.relname = $1 AND n.nspname = COALESCE($2, 'public')`, [name, this._schema]))?.present ?? false;
|
|
1037
|
+
}
|
|
846
1038
|
async afterSyncTable() {
|
|
847
1039
|
await this._resetIdentitySequences();
|
|
848
1040
|
}
|
|
@@ -866,8 +1058,14 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
866
1058
|
async tableExists() {
|
|
867
1059
|
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;
|
|
868
1060
|
}
|
|
1061
|
+
/**
|
|
1062
|
+
* No CASCADE: when something outside the sync inventory (a user view, an
|
|
1063
|
+
* unmanaged FK) still depends on the table PostgreSQL refuses, and schema
|
|
1064
|
+
* sync reports that as an error entry instead of silently dropping the
|
|
1065
|
+
* dependents.
|
|
1066
|
+
*/
|
|
869
1067
|
async dropTable() {
|
|
870
|
-
const ddl = `DROP TABLE IF EXISTS ${quoteTableName(this.resolveTableName())}
|
|
1068
|
+
const ddl = `DROP TABLE IF EXISTS ${quoteTableName(this.resolveTableName())}`;
|
|
871
1069
|
this._log(ddl);
|
|
872
1070
|
await this._exec().exec(ddl);
|
|
873
1071
|
}
|
|
@@ -900,7 +1098,7 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
900
1098
|
}
|
|
901
1099
|
}
|
|
902
1100
|
async dropTableByName(tableName) {
|
|
903
|
-
const ddl = `DROP TABLE IF EXISTS ${quoteTableName(tableName)}
|
|
1101
|
+
const ddl = `DROP TABLE IF EXISTS ${quoteTableName(tableName)}`;
|
|
904
1102
|
this._log(ddl);
|
|
905
1103
|
await this._exec().exec(ddl);
|
|
906
1104
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/db-postgres",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.129",
|
|
4
4
|
"description": "PostgreSQL adapter for @atscript/db with pg (node-postgres) driver support.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"atscript",
|
|
@@ -43,20 +43,20 @@
|
|
|
43
43
|
"access": "public"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@atscript/core": "^0.1.
|
|
47
|
-
"@atscript/typescript": "^0.1.
|
|
46
|
+
"@atscript/core": "^0.1.92",
|
|
47
|
+
"@atscript/typescript": "^0.1.92",
|
|
48
48
|
"@types/pg": "^8.11.0",
|
|
49
|
-
"@uniqu/core": "^0.1.
|
|
49
|
+
"@uniqu/core": "^0.1.8",
|
|
50
50
|
"pg": "^8.13.0",
|
|
51
|
-
"unplugin-atscript": "^0.1.
|
|
51
|
+
"unplugin-atscript": "^0.1.92"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
|
-
"@atscript/core": "^0.1.
|
|
55
|
-
"@atscript/typescript": "^0.1.
|
|
56
|
-
"@uniqu/core": "^0.1.
|
|
54
|
+
"@atscript/core": "^0.1.92",
|
|
55
|
+
"@atscript/typescript": "^0.1.92",
|
|
56
|
+
"@uniqu/core": "^0.1.8",
|
|
57
57
|
"pg": ">=8.0.0",
|
|
58
|
-
"@atscript/db": "^0.1.
|
|
59
|
-
"@atscript/db-sql-tools": "^0.1.
|
|
58
|
+
"@atscript/db": "^0.1.129",
|
|
59
|
+
"@atscript/db-sql-tools": "^0.1.129"
|
|
60
60
|
},
|
|
61
61
|
"peerDependenciesMeta": {
|
|
62
62
|
"pg": {
|