@atscript/db-postgres 0.1.146 → 0.1.147
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 +89 -49
- package/dist/index.d.cts +26 -4
- package/dist/index.d.mts +26 -4
- package/dist/index.mjs +91 -51
- package/package.json +10 -10
package/dist/index.cjs
CHANGED
|
@@ -79,6 +79,8 @@ const pgDialect = {
|
|
|
79
79
|
},
|
|
80
80
|
calendarBucket: pgCalendarBucket,
|
|
81
81
|
jsonExtract: pgJsonExtract,
|
|
82
|
+
castDouble: (expr) => `CAST(${expr} AS DOUBLE PRECISION)`,
|
|
83
|
+
nullsSortLargest: true,
|
|
82
84
|
createViewPrefix: "CREATE OR REPLACE VIEW",
|
|
83
85
|
paramPlaceholder(index) {
|
|
84
86
|
return `$${index}`;
|
|
@@ -105,33 +107,47 @@ function pgJsonExtract(quotedCol, path, type) {
|
|
|
105
107
|
/**
|
|
106
108
|
* Calendar-bucket label over an epoch-ms column (BIGINT for
|
|
107
109
|
* `@db.default.now`, DOUBLE PRECISION otherwise): TEXT `'YYYY-MM-DD'` — the
|
|
108
|
-
* local date of the bucket's first day in `b.tz` — or
|
|
109
|
-
* or
|
|
110
|
+
* local date of the bucket's first day in `b.tz` — or, for `hour`,
|
|
111
|
+
* `'YYYY-MM-DDTHH:00'` — the local wall-clock hour — or NULL for a NULL
|
|
112
|
+
* source or one outside `[BUCKET_MIN_INSTANT, BUCKET_MAX_INSTANT)`.
|
|
110
113
|
*
|
|
111
|
-
* The
|
|
112
|
-
* `timestamptz AT TIME ZONE` yields the wall time in that zone,
|
|
113
|
-
* of the session `TimeZone
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
114
|
+
* The wall time is `to_timestamp(col / 1000) AT TIME ZONE '<tz>'`:
|
|
115
|
+
* `timestamptz AT TIME ZONE` yields the (zone-less) wall time in that zone,
|
|
116
|
+
* independent of the session `TimeZone` — so a `+05:30` zone's hour starts at
|
|
117
|
+
* :30 UTC and a DST fall-back's repeated hour is one label. The hour is
|
|
118
|
+
* formatted from it; the other units truncate its `::date` with calendar
|
|
119
|
+
* arithmetic — the week uses the generic `(isodow - weekStart + 7) % 7`
|
|
120
|
+
* formula (`date_trunc('week')` is Monday-only). `date_trunc` and `to_char`
|
|
121
|
+
* get an explicit `::timestamp`: a bare `date` resolves to their
|
|
122
|
+
* `timestamptz` overloads, which would route through the session zone.
|
|
118
123
|
*
|
|
119
124
|
* Parameter-free (the zone is an inlined, charset-checked literal), so the
|
|
120
125
|
* SELECT and GROUP BY renderings match structurally.
|
|
121
126
|
*/
|
|
122
127
|
function pgCalendarBucket(quotedCol, b) {
|
|
123
|
-
const
|
|
124
|
-
|
|
128
|
+
const wall = `(to_timestamp(${quotedCol}::double precision / 1000) AT TIME ZONE ${(0, _atscript_db_sql_tools.sqlTimeZoneLiteral)(b.tz)})`;
|
|
129
|
+
const local = `${wall}::date`;
|
|
130
|
+
let value;
|
|
131
|
+
let format = "YYYY-MM-DD";
|
|
125
132
|
switch (b.unit) {
|
|
133
|
+
case "hour":
|
|
134
|
+
value = wall;
|
|
135
|
+
format = "YYYY-MM-DD\"T\"HH24\":00\"";
|
|
136
|
+
break;
|
|
126
137
|
case "day":
|
|
127
|
-
|
|
138
|
+
value = local;
|
|
128
139
|
break;
|
|
129
140
|
case "week":
|
|
130
|
-
|
|
141
|
+
value = `(${local} - ((EXTRACT(ISODOW FROM ${local})::int - ${b.weekStartIso} + 7) % 7))`;
|
|
142
|
+
break;
|
|
143
|
+
case "month":
|
|
144
|
+
case "quarter":
|
|
145
|
+
case "year":
|
|
146
|
+
value = `date_trunc('${b.unit}', ${local}::timestamp)`;
|
|
131
147
|
break;
|
|
132
|
-
default:
|
|
148
|
+
default: throw new Error(`Unhandled calendar bucket unit "${String(b.unit)}"`);
|
|
133
149
|
}
|
|
134
|
-
return `CASE WHEN ${quotedCol} >= ${_uniqu_core.BUCKET_MIN_INSTANT} AND ${quotedCol} < ${_uniqu_core.BUCKET_MAX_INSTANT} THEN ${`to_char(${
|
|
150
|
+
return `CASE WHEN ${quotedCol} >= ${_uniqu_core.BUCKET_MIN_INSTANT} AND ${quotedCol} < ${_uniqu_core.BUCKET_MAX_INSTANT} THEN ${`to_char(${value}::timestamp, '${format}')`} END`;
|
|
135
151
|
}
|
|
136
152
|
/**
|
|
137
153
|
* Distance-in-meters expression from a geography column to a query point.
|
|
@@ -321,12 +337,7 @@ function buildCreateTable(table, fields, foreignKeys, options) {
|
|
|
321
337
|
}
|
|
322
338
|
if (foreignKeys) for (const fk of foreignKeys.values()) {
|
|
323
339
|
if (options?.deferForeignKeysTo?.has(fk.targetTable)) continue;
|
|
324
|
-
|
|
325
|
-
const targetCols = fk.targetFields.map((f) => qi(f)).join(", ");
|
|
326
|
-
let constraint = `FOREIGN KEY (${localCols}) REFERENCES ${qi(fk.targetTable)} (${targetCols})`;
|
|
327
|
-
if (fk.onDelete) constraint += ` ON DELETE ${(0, _atscript_db_sql_tools.refActionToSql)(fk.onDelete)}`;
|
|
328
|
-
if (fk.onUpdate) constraint += ` ON UPDATE ${(0, _atscript_db_sql_tools.refActionToSql)(fk.onUpdate)}`;
|
|
329
|
-
colDefs.push(constraint);
|
|
340
|
+
colDefs.push((0, _atscript_db_sql_tools.foreignKeySql)(qi, fk));
|
|
330
341
|
}
|
|
331
342
|
return `CREATE TABLE IF NOT EXISTS ${quoteTableName(table)} (${colDefs.join(", ")})`;
|
|
332
343
|
}
|
|
@@ -341,9 +352,15 @@ function buildCreateTable(table, fields, foreignKeys, options) {
|
|
|
341
352
|
*
|
|
342
353
|
* Case-insensitive columns (`@db.collate 'nocase'`) are handled by CITEXT
|
|
343
354
|
* column type at the storage level — no query-side wrapping needed.
|
|
355
|
+
*
|
|
356
|
+
* Relational predicates (`$some` / `$none`) render as correlated `EXISTS`
|
|
357
|
+
* subqueries referencing the outer table by `opts.qualifier` (default: the
|
|
358
|
+
* source table) — a statement with an aliased FROM must pass its alias.
|
|
359
|
+
*
|
|
360
|
+
* @param opts - since 0.1.147
|
|
344
361
|
*/
|
|
345
|
-
function buildWhere(filter) {
|
|
346
|
-
return (0, _atscript_db_sql_tools.buildWhere)(pgDialect, filter);
|
|
362
|
+
function buildWhere(filter, opts) {
|
|
363
|
+
return (0, _atscript_db_sql_tools.buildWhere)(pgDialect, filter, opts);
|
|
347
364
|
}
|
|
348
365
|
//#endregion
|
|
349
366
|
//#region src/postgres-adapter.ts
|
|
@@ -426,7 +443,7 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
426
443
|
_vectorThresholds = /* @__PURE__ */ new Map();
|
|
427
444
|
/**
|
|
428
445
|
* Schema name for catalog queries and qualification — `@db.schema` of the
|
|
429
|
-
* bound table, or `null` (→ `
|
|
446
|
+
* bound table, or `null` (→ the connection's `current_schema()`, the same default the bound path
|
|
430
447
|
* uses) when the table declares none or the adapter is an administrative
|
|
431
448
|
* one with no readable (the name-taking schema-sync primitives run on such
|
|
432
449
|
* an adapter).
|
|
@@ -482,6 +499,15 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
482
499
|
_exec() {
|
|
483
500
|
return this._txConnection() ?? this.driver;
|
|
484
501
|
}
|
|
502
|
+
/**
|
|
503
|
+
* Relational predicates (`$some` / `$none`) render as correlated
|
|
504
|
+
* `[NOT] EXISTS` subqueries — in reads and in mutation filters alike.
|
|
505
|
+
*
|
|
506
|
+
* @since 0.1.147
|
|
507
|
+
*/
|
|
508
|
+
supportsRelationFilters(_mode) {
|
|
509
|
+
return true;
|
|
510
|
+
}
|
|
485
511
|
/** PostgreSQL enforces FK constraints natively. */
|
|
486
512
|
supportsNativeForeignKeys() {
|
|
487
513
|
return true;
|
|
@@ -506,6 +532,10 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
506
532
|
aggregateFns() {
|
|
507
533
|
return _atscript_db.ALL_AGGREGATE_FNS;
|
|
508
534
|
}
|
|
535
|
+
/** Computed view columns and first-row joins. */
|
|
536
|
+
viewCapabilities() {
|
|
537
|
+
return _atscript_db.ALL_VIEW_CAPABILITIES;
|
|
538
|
+
}
|
|
509
539
|
onBeforeFlatten(_type) {}
|
|
510
540
|
onAfterFlatten() {
|
|
511
541
|
for (const fd of this._table.fieldDescriptors) if (fd.collate === "nocase") this._nocaseColumns.add(fd.physicalName);
|
|
@@ -608,7 +638,7 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
608
638
|
}
|
|
609
639
|
async insertOne(data) {
|
|
610
640
|
let { sql, params } = buildInsert(this.resolveTableName(), data);
|
|
611
|
-
const pkCols = this.
|
|
641
|
+
const pkCols = this._pkColumns().map((pk) => qi(pk));
|
|
612
642
|
if (pkCols.length > 0) sql += ` RETURNING ${pkCols.join(", ")}`;
|
|
613
643
|
this._log(sql, params);
|
|
614
644
|
const returned = (await this._wrapConstraintError(() => this._exec().run(sql, params))).rows?.[0];
|
|
@@ -621,7 +651,7 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
621
651
|
};
|
|
622
652
|
return this.withTransaction(async () => {
|
|
623
653
|
const tableName = this.resolveTableName();
|
|
624
|
-
const pkCols = this.
|
|
654
|
+
const pkCols = this._pkColumns();
|
|
625
655
|
const returningSuffix = pkCols.length > 0 ? ` RETURNING ${pkCols.map((pk) => qi(pk)).join(", ")}` : "";
|
|
626
656
|
const columns = (0, _atscript_db_sql_tools.insertManyColumns)(data);
|
|
627
657
|
const maxRowsPerBatch = columns.length > 0 ? Math.floor(6e4 / columns.length) : data.length;
|
|
@@ -660,6 +690,16 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
660
690
|
this._log(sql, params);
|
|
661
691
|
return this._exec().all(sql, params);
|
|
662
692
|
}
|
|
693
|
+
/**
|
|
694
|
+
* `$skip` / `$limit` per partition in one statement: a `ROW_NUMBER()`
|
|
695
|
+
* window over `partitionBy` (the generic `$with` loader's per-parent page).
|
|
696
|
+
*/
|
|
697
|
+
async findManyPerPartition(query, partitionBy) {
|
|
698
|
+
const where = buildWhere(query.filter);
|
|
699
|
+
const { sql, params } = (0, _atscript_db_sql_tools.buildPartitionedSelect)(pgDialect, this.resolveTableName(), where, query.controls, partitionBy);
|
|
700
|
+
this._log(sql, params);
|
|
701
|
+
return (0, _atscript_db_sql_tools.stripPartitionRowNumber)(await this._exec().all(sql, params));
|
|
702
|
+
}
|
|
663
703
|
async count(query) {
|
|
664
704
|
const where = buildWhere(query.filter);
|
|
665
705
|
const { sql, params } = (0, _atscript_db_sql_tools.finalizeParams)(pgDialect, {
|
|
@@ -699,6 +739,10 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
699
739
|
throw error;
|
|
700
740
|
}
|
|
701
741
|
}
|
|
742
|
+
/** Physical primary-key columns (`@db.column` renames applied). */
|
|
743
|
+
_pkColumns() {
|
|
744
|
+
return this._table.primaryKeys.map((key) => this._table.physicalPath(key));
|
|
745
|
+
}
|
|
702
746
|
/**
|
|
703
747
|
* The predicate that narrows a single-row UPDATE/DELETE to the first row
|
|
704
748
|
* matching `whereSql`: `<key> <op> (SELECT <cols> … LIMIT 1)`. Single-col
|
|
@@ -708,7 +752,7 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
708
752
|
* existing behavior rather than guess.
|
|
709
753
|
*/
|
|
710
754
|
_limitOnePredicate(quotedTable, whereSql) {
|
|
711
|
-
const pkCols = this.
|
|
755
|
+
const pkCols = this._pkColumns();
|
|
712
756
|
const quotedKeys = pkCols.length > 0 ? pkCols.map((c) => qi(c)) : ["ctid"];
|
|
713
757
|
const colList = quotedKeys.join(", ");
|
|
714
758
|
return `${quotedKeys.length === 1 ? `${colList} =` : `(${colList}) IN`} (SELECT ${colList} FROM ${quotedTable} WHERE ${whereSql} LIMIT 1)`;
|
|
@@ -818,7 +862,7 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
818
862
|
JOIN pg_class cl ON cl.oid = c.conrelid
|
|
819
863
|
JOIN pg_class rcl ON rcl.oid = c.confrelid
|
|
820
864
|
JOIN pg_namespace rn ON rn.oid = rcl.relnamespace
|
|
821
|
-
WHERE c.contype = 'f' AND rcl.relname = $1 AND rn.nspname = COALESCE($2,
|
|
865
|
+
WHERE c.contype = 'f' AND rcl.relname = $1 AND rn.nspname = COALESCE($2, current_schema())
|
|
822
866
|
ORDER BY cl.relname, c.conname`, [tableName, this._schema])).map((r) => ({
|
|
823
867
|
table: r.table_name,
|
|
824
868
|
fields: r.columns ?? [],
|
|
@@ -828,7 +872,7 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
828
872
|
async getObjectKind(name) {
|
|
829
873
|
switch ((await this._exec().get(`SELECT c.relkind FROM pg_class c
|
|
830
874
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
831
|
-
WHERE c.relname = $1 AND n.nspname = COALESCE($2,
|
|
875
|
+
WHERE c.relname = $1 AND n.nspname = COALESCE($2, current_schema())
|
|
832
876
|
AND c.relkind IN ('r', 'p', 'v', 'm')`, [name, this._schema]))?.relkind) {
|
|
833
877
|
case "r":
|
|
834
878
|
case "p": return "table";
|
|
@@ -856,7 +900,7 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
856
900
|
const row = await this._exec().get(`SELECT c.conname FROM pg_constraint c
|
|
857
901
|
JOIN pg_class cl ON cl.oid = c.conrelid
|
|
858
902
|
JOIN pg_namespace n ON n.oid = cl.relnamespace
|
|
859
|
-
WHERE c.contype = 'p' AND cl.relname = $1 AND n.nspname = COALESCE($2,
|
|
903
|
+
WHERE c.contype = 'p' AND cl.relname = $1 AND n.nspname = COALESCE($2, current_schema())`, [this._table.tableName, this._schema]);
|
|
860
904
|
if (row?.conname) clauses.push(`DROP CONSTRAINT ${qi(row.conname)}`);
|
|
861
905
|
}
|
|
862
906
|
if (change.to.length > 0) clauses.push(`ADD PRIMARY KEY (${change.to.map((c) => qi(c)).join(", ")})`);
|
|
@@ -888,8 +932,8 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
888
932
|
) AS is_pk
|
|
889
933
|
FROM information_schema.columns c
|
|
890
934
|
JOIN pg_attribute a ON a.attname = c.column_name
|
|
891
|
-
AND a.attrelid = (SELECT oid FROM pg_class WHERE relname = $1 AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = COALESCE($2,
|
|
892
|
-
WHERE c.table_name = $1 AND c.table_schema = COALESCE($2,
|
|
935
|
+
AND a.attrelid = (SELECT oid FROM pg_class WHERE relname = $1 AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = COALESCE($2, current_schema())))
|
|
936
|
+
WHERE c.table_name = $1 AND c.table_schema = COALESCE($2, current_schema())
|
|
893
937
|
ORDER BY c.ordinal_position`, [tableName, schema])).map((r) => {
|
|
894
938
|
const column = {
|
|
895
939
|
name: r.column_name,
|
|
@@ -1009,10 +1053,10 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
1009
1053
|
CROSS JOIN LATERAL unnest(c.conkey, c.confkey) WITH ORDINALITY AS k(attnum, refattnum, ord)
|
|
1010
1054
|
JOIN pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = k.attnum
|
|
1011
1055
|
JOIN pg_attribute ra ON ra.attrelid = c.confrelid AND ra.attnum = k.refattnum
|
|
1012
|
-
WHERE c.contype = 'f' AND rcl.relname = $2 AND rn.nspname = COALESCE($1,
|
|
1056
|
+
WHERE c.contype = 'f' AND rcl.relname = $2 AND rn.nspname = COALESCE($1, current_schema())
|
|
1013
1057
|
ORDER BY n.nspname, cl.relname, c.conname, k.ord`, [schema, this._table.tableName]);
|
|
1014
1058
|
const inboundFks = /* @__PURE__ */ new Map();
|
|
1015
|
-
const ownSchema = schema ?? "public";
|
|
1059
|
+
const ownSchema = schema ?? (await conn.get("SELECT current_schema() AS s"))?.s ?? "public";
|
|
1016
1060
|
for (const fk of fkRefs) {
|
|
1017
1061
|
if (fk.table_schema === ownSchema && fk.table_name === this._table.tableName) continue;
|
|
1018
1062
|
const key = `${fk.table_schema}.${fk.table_name}.${fk.constraint_name}`;
|
|
@@ -1107,7 +1151,7 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
1107
1151
|
FROM pg_constraint c
|
|
1108
1152
|
JOIN pg_class cl ON cl.oid = c.conrelid
|
|
1109
1153
|
JOIN pg_namespace n ON n.oid = cl.relnamespace
|
|
1110
|
-
WHERE cl.relname = $1 AND n.nspname = COALESCE($2,
|
|
1154
|
+
WHERE cl.relname = $1 AND n.nspname = COALESCE($2, current_schema())
|
|
1111
1155
|
ORDER BY c.conname`, [table, this._schema]);
|
|
1112
1156
|
const taken = new Set(rows.map((r) => r.conname));
|
|
1113
1157
|
for (const { conname, contype, columns } of rows) {
|
|
@@ -1131,7 +1175,7 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
1131
1175
|
async _relationExists(conn, name) {
|
|
1132
1176
|
return (await conn.get(`SELECT true AS present FROM pg_class c
|
|
1133
1177
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1134
|
-
WHERE c.relname = $1 AND n.nspname = COALESCE($2,
|
|
1178
|
+
WHERE c.relname = $1 AND n.nspname = COALESCE($2, current_schema())`, [name, this._schema]))?.present ?? false;
|
|
1135
1179
|
}
|
|
1136
1180
|
async afterSyncTable() {
|
|
1137
1181
|
await this._resetIdentitySequences();
|
|
@@ -1154,7 +1198,7 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
1154
1198
|
}
|
|
1155
1199
|
}
|
|
1156
1200
|
async tableExists() {
|
|
1157
|
-
return (await this._exec().get(`SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = $1 AND table_schema = COALESCE($2,
|
|
1201
|
+
return (await this._exec().get(`SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = $1 AND table_schema = COALESCE($2, current_schema())) AS "exists"`, [this._table.tableName, this._schema]))?.exists ?? false;
|
|
1158
1202
|
}
|
|
1159
1203
|
/**
|
|
1160
1204
|
* No CASCADE: when something outside the sync inventory (a user view, an
|
|
@@ -1183,7 +1227,7 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
1183
1227
|
JOIN pg_class i ON i.oid = x.indexrelid
|
|
1184
1228
|
JOIN pg_namespace n ON n.oid = t.relnamespace
|
|
1185
1229
|
JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(x.indkey)
|
|
1186
|
-
WHERE t.relname = $1 AND n.nspname = COALESCE($2,
|
|
1230
|
+
WHERE t.relname = $1 AND n.nspname = COALESCE($2, current_schema())
|
|
1187
1231
|
AND i.relname LIKE 'atscript__%' AND a.attname = ANY($3)`, [
|
|
1188
1232
|
tableName,
|
|
1189
1233
|
schema,
|
|
@@ -1235,7 +1279,7 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
1235
1279
|
JOIN pg_class t ON t.oid = x.indrelid
|
|
1236
1280
|
JOIN pg_class i ON i.oid = x.indexrelid
|
|
1237
1281
|
JOIN pg_namespace n ON n.oid = t.relnamespace
|
|
1238
|
-
WHERE t.relname = $1 AND n.nspname = COALESCE($2,
|
|
1282
|
+
WHERE t.relname = $1 AND n.nspname = COALESCE($2, current_schema())`, [tableName, schema])).map((r) => ({
|
|
1239
1283
|
name: r.name,
|
|
1240
1284
|
columns: r.columns ?? void 0
|
|
1241
1285
|
}));
|
|
@@ -1281,7 +1325,7 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
1281
1325
|
async syncForeignKeys() {
|
|
1282
1326
|
const existingByName = await this._getExistingFkConstraints();
|
|
1283
1327
|
const desiredFkKeys = /* @__PURE__ */ new Set();
|
|
1284
|
-
for (const fk of this._table.foreignKeys.values()) desiredFkKeys.add([...fk.fields].toSorted().join(","));
|
|
1328
|
+
for (const fk of this._table.foreignKeys.values()) desiredFkKeys.add([...(0, _atscript_db.fkColumns)(fk).fields].toSorted().join(","));
|
|
1285
1329
|
for (const [constraintName, columns] of existingByName) {
|
|
1286
1330
|
const key = [...columns].toSorted().join(",");
|
|
1287
1331
|
if (!desiredFkKeys.has(key)) {
|
|
@@ -1292,13 +1336,9 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
1292
1336
|
}
|
|
1293
1337
|
const existingKeys = new Set([...existingByName.values()].map((cols) => cols.toSorted().join(",")));
|
|
1294
1338
|
for (const fk of this._table.foreignKeys.values()) {
|
|
1295
|
-
const key = [...fk.fields].toSorted().join(",");
|
|
1339
|
+
const key = [...(0, _atscript_db.fkColumns)(fk).fields].toSorted().join(",");
|
|
1296
1340
|
if (!existingKeys.has(key)) {
|
|
1297
|
-
const
|
|
1298
|
-
const targetCols = fk.targetFields.map((f) => qi(f)).join(", ");
|
|
1299
|
-
let ddl = `ALTER TABLE ${quoteTableName(this.resolveTableName())} ADD FOREIGN KEY (${localCols}) REFERENCES ${qi(fk.targetTable)} (${targetCols})`;
|
|
1300
|
-
if (fk.onDelete) ddl += ` ON DELETE ${(0, _atscript_db_sql_tools.refActionToSql)(fk.onDelete)}`;
|
|
1301
|
-
if (fk.onUpdate) ddl += ` ON UPDATE ${(0, _atscript_db_sql_tools.refActionToSql)(fk.onUpdate)}`;
|
|
1341
|
+
const ddl = `ALTER TABLE ${quoteTableName(this.resolveTableName())} ADD ${(0, _atscript_db_sql_tools.foreignKeySql)(qi, fk)}`;
|
|
1302
1342
|
this._log(ddl);
|
|
1303
1343
|
await this._exec().exec(ddl);
|
|
1304
1344
|
}
|
|
@@ -1325,7 +1365,7 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
1325
1365
|
JOIN pg_namespace n ON n.oid = cl.relnamespace
|
|
1326
1366
|
CROSS JOIN LATERAL unnest(c.conkey) WITH ORDINALITY AS k(attnum, ord)
|
|
1327
1367
|
JOIN pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = k.attnum
|
|
1328
|
-
WHERE c.contype = 'f' AND cl.relname = $1 AND n.nspname = COALESCE($2,
|
|
1368
|
+
WHERE c.contype = 'f' AND cl.relname = $1 AND n.nspname = COALESCE($2, current_schema())
|
|
1329
1369
|
ORDER BY c.conname, k.ord`, [this._table.tableName, this._schema]);
|
|
1330
1370
|
const byName = /* @__PURE__ */ new Map();
|
|
1331
1371
|
for (const row of rows) {
|
|
@@ -1470,7 +1510,7 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
1470
1510
|
vec = first.value[1];
|
|
1471
1511
|
}
|
|
1472
1512
|
const distanceOp = similarityToPgOp(vec.similarity);
|
|
1473
|
-
const where = buildWhere(query.filter);
|
|
1513
|
+
const where = buildWhere(query.filter, { qualifier: pgDialect.quoteTable(_atscript_db_sql_tools.SEARCH_SOURCE_ALIAS) });
|
|
1474
1514
|
const controls = query.controls || {};
|
|
1475
1515
|
const threshold = this._resolveVectorThreshold(controls, vec.indexName);
|
|
1476
1516
|
return {
|
|
@@ -1563,7 +1603,7 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
1563
1603
|
const controls = query.controls ?? {};
|
|
1564
1604
|
return {
|
|
1565
1605
|
tableName: this.resolveTableName(),
|
|
1566
|
-
where: buildWhere(query.filter),
|
|
1606
|
+
where: buildWhere(query.filter, { qualifier: pgDialect.quoteTable(_atscript_db_sql_tools.SEARCH_SOURCE_ALIAS) }),
|
|
1567
1607
|
dist: pgGeoDistanceExpr(qi(column), point),
|
|
1568
1608
|
window: (0, _atscript_db_sql_tools.geoWindowFromControls)(controls),
|
|
1569
1609
|
controls
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { AggregateFn, BaseDbAdapter, BucketUnit, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbDefaultFn, TDbDeleteResult, TDbFieldMeta, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbUpdateResult, TEnsureTableOptions, TExistingColumn, TFieldOps, TPrimaryKeyChange, TReferencingForeignKey, TSearchIndexInfo, TSyncColumnResult, TValueFormatterPair } from "@atscript/db";
|
|
1
|
+
import { AggregateFn, BaseDbAdapter, BucketUnit, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbDefaultFn, TDbDeleteResult, TDbFieldMeta, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbUpdateResult, TEnsureTableOptions, TExistingColumn, TFieldOps, TPrimaryKeyChange, TReferencingForeignKey, TSearchIndexInfo, TSyncColumnResult, TValueFormatterPair, TViewCapability } from "@atscript/db";
|
|
2
2
|
import { TMetadataMap } from "@atscript/typescript/utils";
|
|
3
|
-
import { TSqlFragment } from "@atscript/db-sql-tools";
|
|
3
|
+
import { TFilterVisitorOptions, TSqlFragment } from "@atscript/db-sql-tools";
|
|
4
4
|
|
|
5
5
|
//#region src/types.d.ts
|
|
6
6
|
/**
|
|
@@ -89,7 +89,7 @@ declare class PostgresAdapter extends BaseDbAdapter {
|
|
|
89
89
|
private _vectorThresholds;
|
|
90
90
|
/**
|
|
91
91
|
* Schema name for catalog queries and qualification — `@db.schema` of the
|
|
92
|
-
* bound table, or `null` (→ `
|
|
92
|
+
* bound table, or `null` (→ the connection's `current_schema()`, the same default the bound path
|
|
93
93
|
* uses) when the table declares none or the adapter is an administrative
|
|
94
94
|
* one with no readable (the name-taking schema-sync primitives run on such
|
|
95
95
|
* an adapter).
|
|
@@ -108,6 +108,13 @@ declare class PostgresAdapter extends BaseDbAdapter {
|
|
|
108
108
|
* otherwise the pool-based driver.
|
|
109
109
|
*/
|
|
110
110
|
private _exec;
|
|
111
|
+
/**
|
|
112
|
+
* Relational predicates (`$some` / `$none`) render as correlated
|
|
113
|
+
* `[NOT] EXISTS` subqueries — in reads and in mutation filters alike.
|
|
114
|
+
*
|
|
115
|
+
* @since 0.1.147
|
|
116
|
+
*/
|
|
117
|
+
supportsRelationFilters(_mode: "read" | "write"): boolean;
|
|
111
118
|
/** PostgreSQL enforces FK constraints natively. */
|
|
112
119
|
supportsNativeForeignKeys(): boolean;
|
|
113
120
|
prepareId(id: unknown, _fieldType: unknown): unknown;
|
|
@@ -120,6 +127,8 @@ declare class PostgresAdapter extends BaseDbAdapter {
|
|
|
120
127
|
calendarBucketUnits(): ReadonlySet<BucketUnit>;
|
|
121
128
|
/** Every aggregate function, `countDistinct` included. */
|
|
122
129
|
aggregateFns(): ReadonlySet<AggregateFn>;
|
|
130
|
+
/** Computed view columns and first-row joins. */
|
|
131
|
+
viewCapabilities(): ReadonlySet<TViewCapability>;
|
|
123
132
|
onBeforeFlatten(_type: unknown): void;
|
|
124
133
|
onAfterFlatten(): void;
|
|
125
134
|
onFieldScanned(field: string, _type: unknown, metadata: TMetadataMap<AtscriptMetadata>): void;
|
|
@@ -146,6 +155,11 @@ declare class PostgresAdapter extends BaseDbAdapter {
|
|
|
146
155
|
insertMany(data: Array<Record<string, unknown>>): Promise<TDbInsertManyResult>;
|
|
147
156
|
findOne(query: DbQuery): Promise<Record<string, unknown> | null>;
|
|
148
157
|
findMany(query: DbQuery): Promise<Array<Record<string, unknown>>>;
|
|
158
|
+
/**
|
|
159
|
+
* `$skip` / `$limit` per partition in one statement: a `ROW_NUMBER()`
|
|
160
|
+
* window over `partitionBy` (the generic `$with` loader's per-parent page).
|
|
161
|
+
*/
|
|
162
|
+
findManyPerPartition(query: DbQuery, partitionBy: readonly string[]): Promise<Array<Record<string, unknown>>>;
|
|
149
163
|
count(query: DbQuery): Promise<number>;
|
|
150
164
|
aggregate(query: DbQuery): Promise<Array<Record<string, unknown>>>;
|
|
151
165
|
/**
|
|
@@ -156,6 +170,8 @@ declare class PostgresAdapter extends BaseDbAdapter {
|
|
|
156
170
|
* older than the runtime's. Other errors propagate unchanged.
|
|
157
171
|
*/
|
|
158
172
|
private _wrapBucketZoneError;
|
|
173
|
+
/** Physical primary-key columns (`@db.column` renames applied). */
|
|
174
|
+
private _pkColumns;
|
|
159
175
|
/**
|
|
160
176
|
* The predicate that narrows a single-row UPDATE/DELETE to the first row
|
|
161
177
|
* matching `whereSql`: `<key> <op> (SELECT <cols> … LIMIT 1)`. Single-col
|
|
@@ -342,8 +358,14 @@ declare class PgDriver implements TPgDriver {
|
|
|
342
358
|
*
|
|
343
359
|
* Case-insensitive columns (`@db.collate 'nocase'`) are handled by CITEXT
|
|
344
360
|
* column type at the storage level — no query-side wrapping needed.
|
|
361
|
+
*
|
|
362
|
+
* Relational predicates (`$some` / `$none`) render as correlated `EXISTS`
|
|
363
|
+
* subqueries referencing the outer table by `opts.qualifier` (default: the
|
|
364
|
+
* source table) — a statement with an aliased FROM must pass its alias.
|
|
365
|
+
*
|
|
366
|
+
* @param opts - since 0.1.147
|
|
345
367
|
*/
|
|
346
|
-
declare function buildWhere(filter: FilterExpr): TSqlFragment;
|
|
368
|
+
declare function buildWhere(filter: FilterExpr, opts?: TFilterVisitorOptions): TSqlFragment;
|
|
347
369
|
//#endregion
|
|
348
370
|
//#region src/index.d.ts
|
|
349
371
|
/**
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AggregateFn, BaseDbAdapter, BucketUnit, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbDefaultFn, TDbDeleteResult, TDbFieldMeta, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbUpdateResult, TEnsureTableOptions, TExistingColumn, TFieldOps, TPrimaryKeyChange, TReferencingForeignKey, TSearchIndexInfo, TSyncColumnResult, TValueFormatterPair } from "@atscript/db";
|
|
2
|
-
import { TSqlFragment } from "@atscript/db-sql-tools";
|
|
1
|
+
import { AggregateFn, BaseDbAdapter, BucketUnit, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbDefaultFn, TDbDeleteResult, TDbFieldMeta, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbUpdateResult, TEnsureTableOptions, TExistingColumn, TFieldOps, TPrimaryKeyChange, TReferencingForeignKey, TSearchIndexInfo, TSyncColumnResult, TValueFormatterPair, TViewCapability } from "@atscript/db";
|
|
2
|
+
import { TFilterVisitorOptions, TSqlFragment } from "@atscript/db-sql-tools";
|
|
3
3
|
import { TMetadataMap } from "@atscript/typescript/utils";
|
|
4
4
|
|
|
5
5
|
//#region src/types.d.ts
|
|
@@ -89,7 +89,7 @@ declare class PostgresAdapter extends BaseDbAdapter {
|
|
|
89
89
|
private _vectorThresholds;
|
|
90
90
|
/**
|
|
91
91
|
* Schema name for catalog queries and qualification — `@db.schema` of the
|
|
92
|
-
* bound table, or `null` (→ `
|
|
92
|
+
* bound table, or `null` (→ the connection's `current_schema()`, the same default the bound path
|
|
93
93
|
* uses) when the table declares none or the adapter is an administrative
|
|
94
94
|
* one with no readable (the name-taking schema-sync primitives run on such
|
|
95
95
|
* an adapter).
|
|
@@ -108,6 +108,13 @@ declare class PostgresAdapter extends BaseDbAdapter {
|
|
|
108
108
|
* otherwise the pool-based driver.
|
|
109
109
|
*/
|
|
110
110
|
private _exec;
|
|
111
|
+
/**
|
|
112
|
+
* Relational predicates (`$some` / `$none`) render as correlated
|
|
113
|
+
* `[NOT] EXISTS` subqueries — in reads and in mutation filters alike.
|
|
114
|
+
*
|
|
115
|
+
* @since 0.1.147
|
|
116
|
+
*/
|
|
117
|
+
supportsRelationFilters(_mode: "read" | "write"): boolean;
|
|
111
118
|
/** PostgreSQL enforces FK constraints natively. */
|
|
112
119
|
supportsNativeForeignKeys(): boolean;
|
|
113
120
|
prepareId(id: unknown, _fieldType: unknown): unknown;
|
|
@@ -120,6 +127,8 @@ declare class PostgresAdapter extends BaseDbAdapter {
|
|
|
120
127
|
calendarBucketUnits(): ReadonlySet<BucketUnit>;
|
|
121
128
|
/** Every aggregate function, `countDistinct` included. */
|
|
122
129
|
aggregateFns(): ReadonlySet<AggregateFn>;
|
|
130
|
+
/** Computed view columns and first-row joins. */
|
|
131
|
+
viewCapabilities(): ReadonlySet<TViewCapability>;
|
|
123
132
|
onBeforeFlatten(_type: unknown): void;
|
|
124
133
|
onAfterFlatten(): void;
|
|
125
134
|
onFieldScanned(field: string, _type: unknown, metadata: TMetadataMap<AtscriptMetadata>): void;
|
|
@@ -146,6 +155,11 @@ declare class PostgresAdapter extends BaseDbAdapter {
|
|
|
146
155
|
insertMany(data: Array<Record<string, unknown>>): Promise<TDbInsertManyResult>;
|
|
147
156
|
findOne(query: DbQuery): Promise<Record<string, unknown> | null>;
|
|
148
157
|
findMany(query: DbQuery): Promise<Array<Record<string, unknown>>>;
|
|
158
|
+
/**
|
|
159
|
+
* `$skip` / `$limit` per partition in one statement: a `ROW_NUMBER()`
|
|
160
|
+
* window over `partitionBy` (the generic `$with` loader's per-parent page).
|
|
161
|
+
*/
|
|
162
|
+
findManyPerPartition(query: DbQuery, partitionBy: readonly string[]): Promise<Array<Record<string, unknown>>>;
|
|
149
163
|
count(query: DbQuery): Promise<number>;
|
|
150
164
|
aggregate(query: DbQuery): Promise<Array<Record<string, unknown>>>;
|
|
151
165
|
/**
|
|
@@ -156,6 +170,8 @@ declare class PostgresAdapter extends BaseDbAdapter {
|
|
|
156
170
|
* older than the runtime's. Other errors propagate unchanged.
|
|
157
171
|
*/
|
|
158
172
|
private _wrapBucketZoneError;
|
|
173
|
+
/** Physical primary-key columns (`@db.column` renames applied). */
|
|
174
|
+
private _pkColumns;
|
|
159
175
|
/**
|
|
160
176
|
* The predicate that narrows a single-row UPDATE/DELETE to the first row
|
|
161
177
|
* matching `whereSql`: `<key> <op> (SELECT <cols> … LIMIT 1)`. Single-col
|
|
@@ -342,8 +358,14 @@ declare class PgDriver implements TPgDriver {
|
|
|
342
358
|
*
|
|
343
359
|
* Case-insensitive columns (`@db.collate 'nocase'`) are handled by CITEXT
|
|
344
360
|
* column type at the storage level — no query-side wrapping needed.
|
|
361
|
+
*
|
|
362
|
+
* Relational predicates (`$some` / `$none`) render as correlated `EXISTS`
|
|
363
|
+
* subqueries referencing the outer table by `opts.qualifier` (default: the
|
|
364
|
+
* source table) — a statement with an aliased FROM must pass its alias.
|
|
365
|
+
*
|
|
366
|
+
* @param opts - since 0.1.147
|
|
345
367
|
*/
|
|
346
|
-
declare function buildWhere(filter: FilterExpr): TSqlFragment;
|
|
368
|
+
declare function buildWhere(filter: FilterExpr, opts?: TFilterVisitorOptions): TSqlFragment;
|
|
347
369
|
//#endregion
|
|
348
370
|
//#region src/index.d.ts
|
|
349
371
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ALL_AGGREGATE_FNS, ALL_BUCKET_UNITS, BaseDbAdapter, DbError, DbSpace, bucketTimeZoneUnavailable, isColumnTypeChanged, vectorIndexNotFoundMessage } from "@atscript/db";
|
|
1
|
+
import { ALL_AGGREGATE_FNS, ALL_BUCKET_UNITS, ALL_VIEW_CAPABILITIES, BaseDbAdapter, DbError, DbSpace, bucketTimeZoneUnavailable, fkColumns, isColumnTypeChanged, vectorIndexNotFoundMessage } from "@atscript/db";
|
|
2
2
|
import { resolveAggregateSearch } from "@atscript/db/agg";
|
|
3
|
-
import { buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildInsertMany, buildSelect, buildUpdate, buildVectorSearchCount, buildVectorSearchSelect, buildWhere as buildWhere$1, defaultValueForType, defaultValueToSqlLiteral, derivedColumnExpr, fillReplacePayload, finalizeParams, geoWindowFromControls, insertManyColumns, normalizeGeoPointValue, parseRegexString, quotedJsonPathSegments,
|
|
3
|
+
import { SEARCH_SOURCE_ALIAS, buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildInsertMany, buildPartitionedSelect, buildSelect, buildUpdate, buildVectorSearchCount, buildVectorSearchSelect, buildWhere as buildWhere$1, defaultValueForType, defaultValueToSqlLiteral, derivedColumnExpr, fillReplacePayload, finalizeParams, foreignKeySql, geoWindowFromControls, insertManyColumns, normalizeGeoPointValue, parseRegexString, quotedJsonPathSegments, renameGeoDistance, replaceColumnsFor, sqlStringLiteral, sqlTimeZoneLiteral, stripPartitionRowNumber, vectorDistanceSource } from "@atscript/db-sql-tools";
|
|
4
4
|
import { BUCKET_MAX_INSTANT, BUCKET_MIN_INSTANT } from "@uniqu/core";
|
|
5
5
|
//#region src/sql-builder.ts
|
|
6
6
|
/**
|
|
@@ -78,6 +78,8 @@ const pgDialect = {
|
|
|
78
78
|
},
|
|
79
79
|
calendarBucket: pgCalendarBucket,
|
|
80
80
|
jsonExtract: pgJsonExtract,
|
|
81
|
+
castDouble: (expr) => `CAST(${expr} AS DOUBLE PRECISION)`,
|
|
82
|
+
nullsSortLargest: true,
|
|
81
83
|
createViewPrefix: "CREATE OR REPLACE VIEW",
|
|
82
84
|
paramPlaceholder(index) {
|
|
83
85
|
return `$${index}`;
|
|
@@ -104,33 +106,47 @@ function pgJsonExtract(quotedCol, path, type) {
|
|
|
104
106
|
/**
|
|
105
107
|
* Calendar-bucket label over an epoch-ms column (BIGINT for
|
|
106
108
|
* `@db.default.now`, DOUBLE PRECISION otherwise): TEXT `'YYYY-MM-DD'` — the
|
|
107
|
-
* local date of the bucket's first day in `b.tz` — or
|
|
108
|
-
* or
|
|
109
|
+
* local date of the bucket's first day in `b.tz` — or, for `hour`,
|
|
110
|
+
* `'YYYY-MM-DDTHH:00'` — the local wall-clock hour — or NULL for a NULL
|
|
111
|
+
* source or one outside `[BUCKET_MIN_INSTANT, BUCKET_MAX_INSTANT)`.
|
|
109
112
|
*
|
|
110
|
-
* The
|
|
111
|
-
* `timestamptz AT TIME ZONE` yields the wall time in that zone,
|
|
112
|
-
* of the session `TimeZone
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
113
|
+
* The wall time is `to_timestamp(col / 1000) AT TIME ZONE '<tz>'`:
|
|
114
|
+
* `timestamptz AT TIME ZONE` yields the (zone-less) wall time in that zone,
|
|
115
|
+
* independent of the session `TimeZone` — so a `+05:30` zone's hour starts at
|
|
116
|
+
* :30 UTC and a DST fall-back's repeated hour is one label. The hour is
|
|
117
|
+
* formatted from it; the other units truncate its `::date` with calendar
|
|
118
|
+
* arithmetic — the week uses the generic `(isodow - weekStart + 7) % 7`
|
|
119
|
+
* formula (`date_trunc('week')` is Monday-only). `date_trunc` and `to_char`
|
|
120
|
+
* get an explicit `::timestamp`: a bare `date` resolves to their
|
|
121
|
+
* `timestamptz` overloads, which would route through the session zone.
|
|
117
122
|
*
|
|
118
123
|
* Parameter-free (the zone is an inlined, charset-checked literal), so the
|
|
119
124
|
* SELECT and GROUP BY renderings match structurally.
|
|
120
125
|
*/
|
|
121
126
|
function pgCalendarBucket(quotedCol, b) {
|
|
122
|
-
const
|
|
123
|
-
|
|
127
|
+
const wall = `(to_timestamp(${quotedCol}::double precision / 1000) AT TIME ZONE ${sqlTimeZoneLiteral(b.tz)})`;
|
|
128
|
+
const local = `${wall}::date`;
|
|
129
|
+
let value;
|
|
130
|
+
let format = "YYYY-MM-DD";
|
|
124
131
|
switch (b.unit) {
|
|
132
|
+
case "hour":
|
|
133
|
+
value = wall;
|
|
134
|
+
format = "YYYY-MM-DD\"T\"HH24\":00\"";
|
|
135
|
+
break;
|
|
125
136
|
case "day":
|
|
126
|
-
|
|
137
|
+
value = local;
|
|
127
138
|
break;
|
|
128
139
|
case "week":
|
|
129
|
-
|
|
140
|
+
value = `(${local} - ((EXTRACT(ISODOW FROM ${local})::int - ${b.weekStartIso} + 7) % 7))`;
|
|
141
|
+
break;
|
|
142
|
+
case "month":
|
|
143
|
+
case "quarter":
|
|
144
|
+
case "year":
|
|
145
|
+
value = `date_trunc('${b.unit}', ${local}::timestamp)`;
|
|
130
146
|
break;
|
|
131
|
-
default:
|
|
147
|
+
default: throw new Error(`Unhandled calendar bucket unit "${String(b.unit)}"`);
|
|
132
148
|
}
|
|
133
|
-
return `CASE WHEN ${quotedCol} >= ${BUCKET_MIN_INSTANT} AND ${quotedCol} < ${BUCKET_MAX_INSTANT} THEN ${`to_char(${
|
|
149
|
+
return `CASE WHEN ${quotedCol} >= ${BUCKET_MIN_INSTANT} AND ${quotedCol} < ${BUCKET_MAX_INSTANT} THEN ${`to_char(${value}::timestamp, '${format}')`} END`;
|
|
134
150
|
}
|
|
135
151
|
/**
|
|
136
152
|
* Distance-in-meters expression from a geography column to a query point.
|
|
@@ -320,12 +336,7 @@ function buildCreateTable(table, fields, foreignKeys, options) {
|
|
|
320
336
|
}
|
|
321
337
|
if (foreignKeys) for (const fk of foreignKeys.values()) {
|
|
322
338
|
if (options?.deferForeignKeysTo?.has(fk.targetTable)) continue;
|
|
323
|
-
|
|
324
|
-
const targetCols = fk.targetFields.map((f) => qi(f)).join(", ");
|
|
325
|
-
let constraint = `FOREIGN KEY (${localCols}) REFERENCES ${qi(fk.targetTable)} (${targetCols})`;
|
|
326
|
-
if (fk.onDelete) constraint += ` ON DELETE ${refActionToSql(fk.onDelete)}`;
|
|
327
|
-
if (fk.onUpdate) constraint += ` ON UPDATE ${refActionToSql(fk.onUpdate)}`;
|
|
328
|
-
colDefs.push(constraint);
|
|
339
|
+
colDefs.push(foreignKeySql(qi, fk));
|
|
329
340
|
}
|
|
330
341
|
return `CREATE TABLE IF NOT EXISTS ${quoteTableName(table)} (${colDefs.join(", ")})`;
|
|
331
342
|
}
|
|
@@ -340,9 +351,15 @@ function buildCreateTable(table, fields, foreignKeys, options) {
|
|
|
340
351
|
*
|
|
341
352
|
* Case-insensitive columns (`@db.collate 'nocase'`) are handled by CITEXT
|
|
342
353
|
* column type at the storage level — no query-side wrapping needed.
|
|
354
|
+
*
|
|
355
|
+
* Relational predicates (`$some` / `$none`) render as correlated `EXISTS`
|
|
356
|
+
* subqueries referencing the outer table by `opts.qualifier` (default: the
|
|
357
|
+
* source table) — a statement with an aliased FROM must pass its alias.
|
|
358
|
+
*
|
|
359
|
+
* @param opts - since 0.1.147
|
|
343
360
|
*/
|
|
344
|
-
function buildWhere(filter) {
|
|
345
|
-
return buildWhere$1(pgDialect, filter);
|
|
361
|
+
function buildWhere(filter, opts) {
|
|
362
|
+
return buildWhere$1(pgDialect, filter, opts);
|
|
346
363
|
}
|
|
347
364
|
//#endregion
|
|
348
365
|
//#region src/postgres-adapter.ts
|
|
@@ -425,7 +442,7 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
425
442
|
_vectorThresholds = /* @__PURE__ */ new Map();
|
|
426
443
|
/**
|
|
427
444
|
* Schema name for catalog queries and qualification — `@db.schema` of the
|
|
428
|
-
* bound table, or `null` (→ `
|
|
445
|
+
* bound table, or `null` (→ the connection's `current_schema()`, the same default the bound path
|
|
429
446
|
* uses) when the table declares none or the adapter is an administrative
|
|
430
447
|
* one with no readable (the name-taking schema-sync primitives run on such
|
|
431
448
|
* an adapter).
|
|
@@ -481,6 +498,15 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
481
498
|
_exec() {
|
|
482
499
|
return this._txConnection() ?? this.driver;
|
|
483
500
|
}
|
|
501
|
+
/**
|
|
502
|
+
* Relational predicates (`$some` / `$none`) render as correlated
|
|
503
|
+
* `[NOT] EXISTS` subqueries — in reads and in mutation filters alike.
|
|
504
|
+
*
|
|
505
|
+
* @since 0.1.147
|
|
506
|
+
*/
|
|
507
|
+
supportsRelationFilters(_mode) {
|
|
508
|
+
return true;
|
|
509
|
+
}
|
|
484
510
|
/** PostgreSQL enforces FK constraints natively. */
|
|
485
511
|
supportsNativeForeignKeys() {
|
|
486
512
|
return true;
|
|
@@ -505,6 +531,10 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
505
531
|
aggregateFns() {
|
|
506
532
|
return ALL_AGGREGATE_FNS;
|
|
507
533
|
}
|
|
534
|
+
/** Computed view columns and first-row joins. */
|
|
535
|
+
viewCapabilities() {
|
|
536
|
+
return ALL_VIEW_CAPABILITIES;
|
|
537
|
+
}
|
|
508
538
|
onBeforeFlatten(_type) {}
|
|
509
539
|
onAfterFlatten() {
|
|
510
540
|
for (const fd of this._table.fieldDescriptors) if (fd.collate === "nocase") this._nocaseColumns.add(fd.physicalName);
|
|
@@ -607,7 +637,7 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
607
637
|
}
|
|
608
638
|
async insertOne(data) {
|
|
609
639
|
let { sql, params } = buildInsert$1(this.resolveTableName(), data);
|
|
610
|
-
const pkCols = this.
|
|
640
|
+
const pkCols = this._pkColumns().map((pk) => qi(pk));
|
|
611
641
|
if (pkCols.length > 0) sql += ` RETURNING ${pkCols.join(", ")}`;
|
|
612
642
|
this._log(sql, params);
|
|
613
643
|
const returned = (await this._wrapConstraintError(() => this._exec().run(sql, params))).rows?.[0];
|
|
@@ -620,7 +650,7 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
620
650
|
};
|
|
621
651
|
return this.withTransaction(async () => {
|
|
622
652
|
const tableName = this.resolveTableName();
|
|
623
|
-
const pkCols = this.
|
|
653
|
+
const pkCols = this._pkColumns();
|
|
624
654
|
const returningSuffix = pkCols.length > 0 ? ` RETURNING ${pkCols.map((pk) => qi(pk)).join(", ")}` : "";
|
|
625
655
|
const columns = insertManyColumns(data);
|
|
626
656
|
const maxRowsPerBatch = columns.length > 0 ? Math.floor(6e4 / columns.length) : data.length;
|
|
@@ -659,6 +689,16 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
659
689
|
this._log(sql, params);
|
|
660
690
|
return this._exec().all(sql, params);
|
|
661
691
|
}
|
|
692
|
+
/**
|
|
693
|
+
* `$skip` / `$limit` per partition in one statement: a `ROW_NUMBER()`
|
|
694
|
+
* window over `partitionBy` (the generic `$with` loader's per-parent page).
|
|
695
|
+
*/
|
|
696
|
+
async findManyPerPartition(query, partitionBy) {
|
|
697
|
+
const where = buildWhere(query.filter);
|
|
698
|
+
const { sql, params } = buildPartitionedSelect(pgDialect, this.resolveTableName(), where, query.controls, partitionBy);
|
|
699
|
+
this._log(sql, params);
|
|
700
|
+
return stripPartitionRowNumber(await this._exec().all(sql, params));
|
|
701
|
+
}
|
|
662
702
|
async count(query) {
|
|
663
703
|
const where = buildWhere(query.filter);
|
|
664
704
|
const { sql, params } = finalizeParams(pgDialect, {
|
|
@@ -698,6 +738,10 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
698
738
|
throw error;
|
|
699
739
|
}
|
|
700
740
|
}
|
|
741
|
+
/** Physical primary-key columns (`@db.column` renames applied). */
|
|
742
|
+
_pkColumns() {
|
|
743
|
+
return this._table.primaryKeys.map((key) => this._table.physicalPath(key));
|
|
744
|
+
}
|
|
701
745
|
/**
|
|
702
746
|
* The predicate that narrows a single-row UPDATE/DELETE to the first row
|
|
703
747
|
* matching `whereSql`: `<key> <op> (SELECT <cols> … LIMIT 1)`. Single-col
|
|
@@ -707,7 +751,7 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
707
751
|
* existing behavior rather than guess.
|
|
708
752
|
*/
|
|
709
753
|
_limitOnePredicate(quotedTable, whereSql) {
|
|
710
|
-
const pkCols = this.
|
|
754
|
+
const pkCols = this._pkColumns();
|
|
711
755
|
const quotedKeys = pkCols.length > 0 ? pkCols.map((c) => qi(c)) : ["ctid"];
|
|
712
756
|
const colList = quotedKeys.join(", ");
|
|
713
757
|
return `${quotedKeys.length === 1 ? `${colList} =` : `(${colList}) IN`} (SELECT ${colList} FROM ${quotedTable} WHERE ${whereSql} LIMIT 1)`;
|
|
@@ -817,7 +861,7 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
817
861
|
JOIN pg_class cl ON cl.oid = c.conrelid
|
|
818
862
|
JOIN pg_class rcl ON rcl.oid = c.confrelid
|
|
819
863
|
JOIN pg_namespace rn ON rn.oid = rcl.relnamespace
|
|
820
|
-
WHERE c.contype = 'f' AND rcl.relname = $1 AND rn.nspname = COALESCE($2,
|
|
864
|
+
WHERE c.contype = 'f' AND rcl.relname = $1 AND rn.nspname = COALESCE($2, current_schema())
|
|
821
865
|
ORDER BY cl.relname, c.conname`, [tableName, this._schema])).map((r) => ({
|
|
822
866
|
table: r.table_name,
|
|
823
867
|
fields: r.columns ?? [],
|
|
@@ -827,7 +871,7 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
827
871
|
async getObjectKind(name) {
|
|
828
872
|
switch ((await this._exec().get(`SELECT c.relkind FROM pg_class c
|
|
829
873
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
830
|
-
WHERE c.relname = $1 AND n.nspname = COALESCE($2,
|
|
874
|
+
WHERE c.relname = $1 AND n.nspname = COALESCE($2, current_schema())
|
|
831
875
|
AND c.relkind IN ('r', 'p', 'v', 'm')`, [name, this._schema]))?.relkind) {
|
|
832
876
|
case "r":
|
|
833
877
|
case "p": return "table";
|
|
@@ -855,7 +899,7 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
855
899
|
const row = await this._exec().get(`SELECT c.conname FROM pg_constraint c
|
|
856
900
|
JOIN pg_class cl ON cl.oid = c.conrelid
|
|
857
901
|
JOIN pg_namespace n ON n.oid = cl.relnamespace
|
|
858
|
-
WHERE c.contype = 'p' AND cl.relname = $1 AND n.nspname = COALESCE($2,
|
|
902
|
+
WHERE c.contype = 'p' AND cl.relname = $1 AND n.nspname = COALESCE($2, current_schema())`, [this._table.tableName, this._schema]);
|
|
859
903
|
if (row?.conname) clauses.push(`DROP CONSTRAINT ${qi(row.conname)}`);
|
|
860
904
|
}
|
|
861
905
|
if (change.to.length > 0) clauses.push(`ADD PRIMARY KEY (${change.to.map((c) => qi(c)).join(", ")})`);
|
|
@@ -887,8 +931,8 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
887
931
|
) AS is_pk
|
|
888
932
|
FROM information_schema.columns c
|
|
889
933
|
JOIN pg_attribute a ON a.attname = c.column_name
|
|
890
|
-
AND a.attrelid = (SELECT oid FROM pg_class WHERE relname = $1 AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = COALESCE($2,
|
|
891
|
-
WHERE c.table_name = $1 AND c.table_schema = COALESCE($2,
|
|
934
|
+
AND a.attrelid = (SELECT oid FROM pg_class WHERE relname = $1 AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = COALESCE($2, current_schema())))
|
|
935
|
+
WHERE c.table_name = $1 AND c.table_schema = COALESCE($2, current_schema())
|
|
892
936
|
ORDER BY c.ordinal_position`, [tableName, schema])).map((r) => {
|
|
893
937
|
const column = {
|
|
894
938
|
name: r.column_name,
|
|
@@ -1008,10 +1052,10 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
1008
1052
|
CROSS JOIN LATERAL unnest(c.conkey, c.confkey) WITH ORDINALITY AS k(attnum, refattnum, ord)
|
|
1009
1053
|
JOIN pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = k.attnum
|
|
1010
1054
|
JOIN pg_attribute ra ON ra.attrelid = c.confrelid AND ra.attnum = k.refattnum
|
|
1011
|
-
WHERE c.contype = 'f' AND rcl.relname = $2 AND rn.nspname = COALESCE($1,
|
|
1055
|
+
WHERE c.contype = 'f' AND rcl.relname = $2 AND rn.nspname = COALESCE($1, current_schema())
|
|
1012
1056
|
ORDER BY n.nspname, cl.relname, c.conname, k.ord`, [schema, this._table.tableName]);
|
|
1013
1057
|
const inboundFks = /* @__PURE__ */ new Map();
|
|
1014
|
-
const ownSchema = schema ?? "public";
|
|
1058
|
+
const ownSchema = schema ?? (await conn.get("SELECT current_schema() AS s"))?.s ?? "public";
|
|
1015
1059
|
for (const fk of fkRefs) {
|
|
1016
1060
|
if (fk.table_schema === ownSchema && fk.table_name === this._table.tableName) continue;
|
|
1017
1061
|
const key = `${fk.table_schema}.${fk.table_name}.${fk.constraint_name}`;
|
|
@@ -1106,7 +1150,7 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
1106
1150
|
FROM pg_constraint c
|
|
1107
1151
|
JOIN pg_class cl ON cl.oid = c.conrelid
|
|
1108
1152
|
JOIN pg_namespace n ON n.oid = cl.relnamespace
|
|
1109
|
-
WHERE cl.relname = $1 AND n.nspname = COALESCE($2,
|
|
1153
|
+
WHERE cl.relname = $1 AND n.nspname = COALESCE($2, current_schema())
|
|
1110
1154
|
ORDER BY c.conname`, [table, this._schema]);
|
|
1111
1155
|
const taken = new Set(rows.map((r) => r.conname));
|
|
1112
1156
|
for (const { conname, contype, columns } of rows) {
|
|
@@ -1130,7 +1174,7 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
1130
1174
|
async _relationExists(conn, name) {
|
|
1131
1175
|
return (await conn.get(`SELECT true AS present FROM pg_class c
|
|
1132
1176
|
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
1133
|
-
WHERE c.relname = $1 AND n.nspname = COALESCE($2,
|
|
1177
|
+
WHERE c.relname = $1 AND n.nspname = COALESCE($2, current_schema())`, [name, this._schema]))?.present ?? false;
|
|
1134
1178
|
}
|
|
1135
1179
|
async afterSyncTable() {
|
|
1136
1180
|
await this._resetIdentitySequences();
|
|
@@ -1153,7 +1197,7 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
1153
1197
|
}
|
|
1154
1198
|
}
|
|
1155
1199
|
async tableExists() {
|
|
1156
|
-
return (await this._exec().get(`SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = $1 AND table_schema = COALESCE($2,
|
|
1200
|
+
return (await this._exec().get(`SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = $1 AND table_schema = COALESCE($2, current_schema())) AS "exists"`, [this._table.tableName, this._schema]))?.exists ?? false;
|
|
1157
1201
|
}
|
|
1158
1202
|
/**
|
|
1159
1203
|
* No CASCADE: when something outside the sync inventory (a user view, an
|
|
@@ -1182,7 +1226,7 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
1182
1226
|
JOIN pg_class i ON i.oid = x.indexrelid
|
|
1183
1227
|
JOIN pg_namespace n ON n.oid = t.relnamespace
|
|
1184
1228
|
JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(x.indkey)
|
|
1185
|
-
WHERE t.relname = $1 AND n.nspname = COALESCE($2,
|
|
1229
|
+
WHERE t.relname = $1 AND n.nspname = COALESCE($2, current_schema())
|
|
1186
1230
|
AND i.relname LIKE 'atscript__%' AND a.attname = ANY($3)`, [
|
|
1187
1231
|
tableName,
|
|
1188
1232
|
schema,
|
|
@@ -1234,7 +1278,7 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
1234
1278
|
JOIN pg_class t ON t.oid = x.indrelid
|
|
1235
1279
|
JOIN pg_class i ON i.oid = x.indexrelid
|
|
1236
1280
|
JOIN pg_namespace n ON n.oid = t.relnamespace
|
|
1237
|
-
WHERE t.relname = $1 AND n.nspname = COALESCE($2,
|
|
1281
|
+
WHERE t.relname = $1 AND n.nspname = COALESCE($2, current_schema())`, [tableName, schema])).map((r) => ({
|
|
1238
1282
|
name: r.name,
|
|
1239
1283
|
columns: r.columns ?? void 0
|
|
1240
1284
|
}));
|
|
@@ -1280,7 +1324,7 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
1280
1324
|
async syncForeignKeys() {
|
|
1281
1325
|
const existingByName = await this._getExistingFkConstraints();
|
|
1282
1326
|
const desiredFkKeys = /* @__PURE__ */ new Set();
|
|
1283
|
-
for (const fk of this._table.foreignKeys.values()) desiredFkKeys.add([...fk.fields].toSorted().join(","));
|
|
1327
|
+
for (const fk of this._table.foreignKeys.values()) desiredFkKeys.add([...fkColumns(fk).fields].toSorted().join(","));
|
|
1284
1328
|
for (const [constraintName, columns] of existingByName) {
|
|
1285
1329
|
const key = [...columns].toSorted().join(",");
|
|
1286
1330
|
if (!desiredFkKeys.has(key)) {
|
|
@@ -1291,13 +1335,9 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
1291
1335
|
}
|
|
1292
1336
|
const existingKeys = new Set([...existingByName.values()].map((cols) => cols.toSorted().join(",")));
|
|
1293
1337
|
for (const fk of this._table.foreignKeys.values()) {
|
|
1294
|
-
const key = [...fk.fields].toSorted().join(",");
|
|
1338
|
+
const key = [...fkColumns(fk).fields].toSorted().join(",");
|
|
1295
1339
|
if (!existingKeys.has(key)) {
|
|
1296
|
-
const
|
|
1297
|
-
const targetCols = fk.targetFields.map((f) => qi(f)).join(", ");
|
|
1298
|
-
let ddl = `ALTER TABLE ${quoteTableName(this.resolveTableName())} ADD FOREIGN KEY (${localCols}) REFERENCES ${qi(fk.targetTable)} (${targetCols})`;
|
|
1299
|
-
if (fk.onDelete) ddl += ` ON DELETE ${refActionToSql(fk.onDelete)}`;
|
|
1300
|
-
if (fk.onUpdate) ddl += ` ON UPDATE ${refActionToSql(fk.onUpdate)}`;
|
|
1340
|
+
const ddl = `ALTER TABLE ${quoteTableName(this.resolveTableName())} ADD ${foreignKeySql(qi, fk)}`;
|
|
1301
1341
|
this._log(ddl);
|
|
1302
1342
|
await this._exec().exec(ddl);
|
|
1303
1343
|
}
|
|
@@ -1324,7 +1364,7 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
1324
1364
|
JOIN pg_namespace n ON n.oid = cl.relnamespace
|
|
1325
1365
|
CROSS JOIN LATERAL unnest(c.conkey) WITH ORDINALITY AS k(attnum, ord)
|
|
1326
1366
|
JOIN pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = k.attnum
|
|
1327
|
-
WHERE c.contype = 'f' AND cl.relname = $1 AND n.nspname = COALESCE($2,
|
|
1367
|
+
WHERE c.contype = 'f' AND cl.relname = $1 AND n.nspname = COALESCE($2, current_schema())
|
|
1328
1368
|
ORDER BY c.conname, k.ord`, [this._table.tableName, this._schema]);
|
|
1329
1369
|
const byName = /* @__PURE__ */ new Map();
|
|
1330
1370
|
for (const row of rows) {
|
|
@@ -1469,7 +1509,7 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
1469
1509
|
vec = first.value[1];
|
|
1470
1510
|
}
|
|
1471
1511
|
const distanceOp = similarityToPgOp(vec.similarity);
|
|
1472
|
-
const where = buildWhere(query.filter);
|
|
1512
|
+
const where = buildWhere(query.filter, { qualifier: pgDialect.quoteTable(SEARCH_SOURCE_ALIAS) });
|
|
1473
1513
|
const controls = query.controls || {};
|
|
1474
1514
|
const threshold = this._resolveVectorThreshold(controls, vec.indexName);
|
|
1475
1515
|
return {
|
|
@@ -1562,7 +1602,7 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
1562
1602
|
const controls = query.controls ?? {};
|
|
1563
1603
|
return {
|
|
1564
1604
|
tableName: this.resolveTableName(),
|
|
1565
|
-
where: buildWhere(query.filter),
|
|
1605
|
+
where: buildWhere(query.filter, { qualifier: pgDialect.quoteTable(SEARCH_SOURCE_ALIAS) }),
|
|
1566
1606
|
dist: pgGeoDistanceExpr(qi(column), point),
|
|
1567
1607
|
window: geoWindowFromControls(controls),
|
|
1568
1608
|
controls
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/db-postgres",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.147",
|
|
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.99",
|
|
47
|
+
"@atscript/typescript": "^0.1.99",
|
|
48
48
|
"@types/pg": "^8.11.0",
|
|
49
|
-
"@uniqu/core": "^0.1.
|
|
49
|
+
"@uniqu/core": "^0.1.12",
|
|
50
50
|
"pg": "^8.13.0",
|
|
51
|
-
"unplugin-atscript": "^0.1.
|
|
51
|
+
"unplugin-atscript": "^0.1.99"
|
|
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.99",
|
|
55
|
+
"@atscript/typescript": "^0.1.99",
|
|
56
|
+
"@uniqu/core": "^0.1.12",
|
|
57
57
|
"pg": ">=8.0.0",
|
|
58
|
-
"@atscript/db": "^0.1.
|
|
59
|
-
"@atscript/db-sql-tools": "^0.1.
|
|
58
|
+
"@atscript/db": "^0.1.147",
|
|
59
|
+
"@atscript/db-sql-tools": "^0.1.147"
|
|
60
60
|
},
|
|
61
61
|
"peerDependenciesMeta": {
|
|
62
62
|
"pg": {
|