@atscript/db-postgres 0.1.136 → 0.1.137
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 +34 -21
- package/dist/index.d.cts +2 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +35 -22
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -853,15 +853,19 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
853
853
|
return this.getExistingColumnsForTable(this._table.tableName);
|
|
854
854
|
}
|
|
855
855
|
async getExistingColumnsForTable(tableName) {
|
|
856
|
+
return this._readColumns(this._exec(), tableName);
|
|
857
|
+
}
|
|
858
|
+
/** Live columns of `tableName`, read through `exec` (the recreate's own connection, or the pool). */
|
|
859
|
+
async _readColumns(exec, tableName) {
|
|
856
860
|
const schema = this._schema;
|
|
857
|
-
const rows = await
|
|
861
|
+
const rows = await exec.all(`SELECT c.column_name, c.data_type, c.udt_name, c.character_maximum_length, c.numeric_precision, c.numeric_scale, c.is_nullable, c.column_default, c.is_identity,
|
|
858
862
|
format_type(a.atttypid, a.atttypmod) AS formatted_type
|
|
859
863
|
FROM information_schema.columns c
|
|
860
864
|
JOIN pg_attribute a ON a.attname = c.column_name
|
|
861
865
|
AND a.attrelid = (SELECT oid FROM pg_class WHERE relname = $1 AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = COALESCE($2, 'public')))
|
|
862
866
|
WHERE c.table_name = $1 AND c.table_schema = COALESCE($2, 'public')
|
|
863
867
|
ORDER BY c.ordinal_position`, [tableName, schema]);
|
|
864
|
-
const pkRows = await
|
|
868
|
+
const pkRows = await exec.all(`SELECT kcu.column_name
|
|
865
869
|
FROM information_schema.table_constraints tc
|
|
866
870
|
JOIN information_schema.key_column_usage kcu
|
|
867
871
|
ON tc.constraint_name = kcu.constraint_name AND tc.table_schema = kcu.table_schema
|
|
@@ -914,9 +918,7 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
914
918
|
for (const { field } of diff.typeChanged ?? []) {
|
|
915
919
|
const sqlType = this.typeMapper(field);
|
|
916
920
|
const col = qi(field.physicalName);
|
|
917
|
-
|
|
918
|
-
if (field.isGeoPoint && sqlType.startsWith("geography")) ddl = `ALTER TABLE ${quoteTableName(tableName)} ALTER COLUMN ${col} TYPE ${sqlType} USING CASE WHEN ${col} IS NULL THEN NULL ELSE ST_SetSRID(ST_MakePoint((${col}->>0)::float8, (${col}->>1)::float8), 4326)::geography END`;
|
|
919
|
-
else ddl = `ALTER TABLE ${quoteTableName(tableName)} ALTER COLUMN ${col} TYPE ${sqlType} USING ${col}::text::${sqlType}`;
|
|
921
|
+
const ddl = `ALTER TABLE ${quoteTableName(tableName)} ALTER COLUMN ${col} TYPE ${sqlType} USING ${convertColumnExpr(col, field, sqlType)}`;
|
|
920
922
|
this._log(ddl);
|
|
921
923
|
await this._exec().exec(ddl);
|
|
922
924
|
}
|
|
@@ -1017,22 +1019,17 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
1017
1019
|
});
|
|
1018
1020
|
this._log(createSql);
|
|
1019
1021
|
await conn.exec(createSql);
|
|
1020
|
-
const
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
if (field && !field.optional && !field.isPrimaryKey) {
|
|
1032
|
-
const fallback = field.defaultValue?.kind === "value" ? defaultValueToSqlLiteral(field.designType, field.defaultValue.value) : defaultValueForType(field.designType);
|
|
1033
|
-
return `COALESCE(${qi(c)}, ${fallback}) AS ${qi(c)}`;
|
|
1034
|
-
}
|
|
1035
|
-
return qi(c);
|
|
1022
|
+
const oldTypes = new Map((await this._readColumns(conn, this._table.tableName)).map((c) => [c.name, c.type]));
|
|
1023
|
+
const commonFields = this._table.fieldDescriptors.filter((f) => !f.ignored && oldTypes.has(f.physicalName));
|
|
1024
|
+
if (commonFields.length > 0) {
|
|
1025
|
+
const colNames = commonFields.map((f) => qi(f.physicalName)).join(", ");
|
|
1026
|
+
const selectExprs = commonFields.map((field) => {
|
|
1027
|
+
const c = qi(field.physicalName);
|
|
1028
|
+
const sqlType = this.typeMapper(field);
|
|
1029
|
+
const changed = (0, _atscript_db.isColumnTypeChanged)(oldTypes.get(field.physicalName), sqlType);
|
|
1030
|
+
const value = changed ? convertColumnExpr(c, field, sqlType) : c;
|
|
1031
|
+
if (!field.optional && !field.isPrimaryKey) return `COALESCE(${value}, ${field.defaultValue?.kind === "value" ? defaultValueToSqlLiteral(field.designType, field.defaultValue.value) : defaultValueForType(field.designType)}) AS ${c}`;
|
|
1032
|
+
return changed ? `${value} AS ${c}` : c;
|
|
1036
1033
|
}).join(", ");
|
|
1037
1034
|
const copySql = `INSERT INTO ${quoteTableName(tempName)} (${colNames}) SELECT ${selectExprs} FROM ${quoteTableName(tableName)}`;
|
|
1038
1035
|
this._log(copySql);
|
|
@@ -1553,6 +1550,22 @@ var PostgresAdapter = class PostgresAdapter extends _atscript_db.BaseDbAdapter {
|
|
|
1553
1550
|
});
|
|
1554
1551
|
}
|
|
1555
1552
|
};
|
|
1553
|
+
/** A text / character type: the value is converted by the assignment into the column. */
|
|
1554
|
+
const CHARACTER_TYPE = /^\s*(?:text|varchar|character varying|char|character|bpchar)\b/i;
|
|
1555
|
+
/**
|
|
1556
|
+
* The expression converting column `col` (quoted) to `sqlType`, the field's
|
|
1557
|
+
* new type — one rule for `ALTER COLUMN … TYPE … USING` and the recreate copy.
|
|
1558
|
+
* The value goes through text, so one that does not parse as the new type
|
|
1559
|
+
* fails the statement instead of being coerced. A TEXT / VARCHAR(n) / CHAR(n)
|
|
1560
|
+
* target stops at `::text`: an explicit cast to VARCHAR(n) / CHAR(n) would
|
|
1561
|
+
* truncate an over-long value, the assignment into the column rejects it
|
|
1562
|
+
* (since 0.1.137).
|
|
1563
|
+
*/
|
|
1564
|
+
function convertColumnExpr(col, field, sqlType) {
|
|
1565
|
+
if (field.isGeoPoint && sqlType.startsWith("geography")) return `CASE WHEN ${col} IS NULL THEN NULL ELSE ST_SetSRID(ST_MakePoint((${col}->>0)::float8, (${col}->>1)::float8), 4326)::geography END`;
|
|
1566
|
+
if (CHARACTER_TYPE.test(sqlType)) return `${col}::text`;
|
|
1567
|
+
return `${col}::text::${sqlType}`;
|
|
1568
|
+
}
|
|
1556
1569
|
/**
|
|
1557
1570
|
* Normalizes PostgreSQL information_schema data_type values
|
|
1558
1571
|
* to match the format produced by `pgTypeFromField()`.
|
package/dist/index.d.cts
CHANGED
|
@@ -188,6 +188,8 @@ declare class PostgresAdapter extends BaseDbAdapter {
|
|
|
188
188
|
private _ensureView;
|
|
189
189
|
getExistingColumns(): Promise<TExistingColumn[]>;
|
|
190
190
|
getExistingColumnsForTable(tableName: string): Promise<TExistingColumn[]>;
|
|
191
|
+
/** Live columns of `tableName`, read through `exec` (the recreate's own connection, or the pool). */
|
|
192
|
+
private _readColumns;
|
|
191
193
|
syncColumns(diff: TColumnDiff): Promise<TSyncColumnResult>;
|
|
192
194
|
recreateTable(): Promise<void>;
|
|
193
195
|
/**
|
package/dist/index.d.mts
CHANGED
|
@@ -188,6 +188,8 @@ declare class PostgresAdapter extends BaseDbAdapter {
|
|
|
188
188
|
private _ensureView;
|
|
189
189
|
getExistingColumns(): Promise<TExistingColumn[]>;
|
|
190
190
|
getExistingColumnsForTable(tableName: string): Promise<TExistingColumn[]>;
|
|
191
|
+
/** Live columns of `tableName`, read through `exec` (the recreate's own connection, or the pool). */
|
|
192
|
+
private _readColumns;
|
|
191
193
|
syncColumns(diff: TColumnDiff): Promise<TSyncColumnResult>;
|
|
192
194
|
recreateTable(): Promise<void>;
|
|
193
195
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ALL_AGGREGATE_FNS, ALL_BUCKET_UNITS, BaseDbAdapter, DbError, DbSpace, bucketTimeZoneUnavailable } from "@atscript/db";
|
|
1
|
+
import { ALL_AGGREGATE_FNS, ALL_BUCKET_UNITS, BaseDbAdapter, DbError, DbSpace, bucketTimeZoneUnavailable, isColumnTypeChanged } from "@atscript/db";
|
|
2
2
|
import { resolveAggregateSearch } from "@atscript/db/agg";
|
|
3
3
|
import { buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildInsertMany, buildSelect, buildUpdate, buildWhere as buildWhere$1, defaultValueForType, defaultValueToSqlLiteral, fillReplacePayload, finalizeParams, geoWindowFromControls, insertManyColumns, normalizeGeoPointValue, parseRegexString, quotedJsonPathSegments, refActionToSql, renameGeoDistance, replaceColumnsFor, sqlStringLiteral, sqlTimeZoneLiteral } from "@atscript/db-sql-tools";
|
|
4
4
|
import { BUCKET_MAX_INSTANT, BUCKET_MIN_INSTANT } from "@uniqu/core";
|
|
@@ -852,15 +852,19 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
852
852
|
return this.getExistingColumnsForTable(this._table.tableName);
|
|
853
853
|
}
|
|
854
854
|
async getExistingColumnsForTable(tableName) {
|
|
855
|
+
return this._readColumns(this._exec(), tableName);
|
|
856
|
+
}
|
|
857
|
+
/** Live columns of `tableName`, read through `exec` (the recreate's own connection, or the pool). */
|
|
858
|
+
async _readColumns(exec, tableName) {
|
|
855
859
|
const schema = this._schema;
|
|
856
|
-
const rows = await
|
|
860
|
+
const rows = await exec.all(`SELECT c.column_name, c.data_type, c.udt_name, c.character_maximum_length, c.numeric_precision, c.numeric_scale, c.is_nullable, c.column_default, c.is_identity,
|
|
857
861
|
format_type(a.atttypid, a.atttypmod) AS formatted_type
|
|
858
862
|
FROM information_schema.columns c
|
|
859
863
|
JOIN pg_attribute a ON a.attname = c.column_name
|
|
860
864
|
AND a.attrelid = (SELECT oid FROM pg_class WHERE relname = $1 AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = COALESCE($2, 'public')))
|
|
861
865
|
WHERE c.table_name = $1 AND c.table_schema = COALESCE($2, 'public')
|
|
862
866
|
ORDER BY c.ordinal_position`, [tableName, schema]);
|
|
863
|
-
const pkRows = await
|
|
867
|
+
const pkRows = await exec.all(`SELECT kcu.column_name
|
|
864
868
|
FROM information_schema.table_constraints tc
|
|
865
869
|
JOIN information_schema.key_column_usage kcu
|
|
866
870
|
ON tc.constraint_name = kcu.constraint_name AND tc.table_schema = kcu.table_schema
|
|
@@ -913,9 +917,7 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
913
917
|
for (const { field } of diff.typeChanged ?? []) {
|
|
914
918
|
const sqlType = this.typeMapper(field);
|
|
915
919
|
const col = qi(field.physicalName);
|
|
916
|
-
|
|
917
|
-
if (field.isGeoPoint && sqlType.startsWith("geography")) ddl = `ALTER TABLE ${quoteTableName(tableName)} ALTER COLUMN ${col} TYPE ${sqlType} USING CASE WHEN ${col} IS NULL THEN NULL ELSE ST_SetSRID(ST_MakePoint((${col}->>0)::float8, (${col}->>1)::float8), 4326)::geography END`;
|
|
918
|
-
else ddl = `ALTER TABLE ${quoteTableName(tableName)} ALTER COLUMN ${col} TYPE ${sqlType} USING ${col}::text::${sqlType}`;
|
|
920
|
+
const ddl = `ALTER TABLE ${quoteTableName(tableName)} ALTER COLUMN ${col} TYPE ${sqlType} USING ${convertColumnExpr(col, field, sqlType)}`;
|
|
919
921
|
this._log(ddl);
|
|
920
922
|
await this._exec().exec(ddl);
|
|
921
923
|
}
|
|
@@ -1016,22 +1018,17 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
1016
1018
|
});
|
|
1017
1019
|
this._log(createSql);
|
|
1018
1020
|
await conn.exec(createSql);
|
|
1019
|
-
const
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
if (field && !field.optional && !field.isPrimaryKey) {
|
|
1031
|
-
const fallback = field.defaultValue?.kind === "value" ? defaultValueToSqlLiteral$1(field.designType, field.defaultValue.value) : defaultValueForType$1(field.designType);
|
|
1032
|
-
return `COALESCE(${qi(c)}, ${fallback}) AS ${qi(c)}`;
|
|
1033
|
-
}
|
|
1034
|
-
return qi(c);
|
|
1021
|
+
const oldTypes = new Map((await this._readColumns(conn, this._table.tableName)).map((c) => [c.name, c.type]));
|
|
1022
|
+
const commonFields = this._table.fieldDescriptors.filter((f) => !f.ignored && oldTypes.has(f.physicalName));
|
|
1023
|
+
if (commonFields.length > 0) {
|
|
1024
|
+
const colNames = commonFields.map((f) => qi(f.physicalName)).join(", ");
|
|
1025
|
+
const selectExprs = commonFields.map((field) => {
|
|
1026
|
+
const c = qi(field.physicalName);
|
|
1027
|
+
const sqlType = this.typeMapper(field);
|
|
1028
|
+
const changed = isColumnTypeChanged(oldTypes.get(field.physicalName), sqlType);
|
|
1029
|
+
const value = changed ? convertColumnExpr(c, field, sqlType) : c;
|
|
1030
|
+
if (!field.optional && !field.isPrimaryKey) return `COALESCE(${value}, ${field.defaultValue?.kind === "value" ? defaultValueToSqlLiteral$1(field.designType, field.defaultValue.value) : defaultValueForType$1(field.designType)}) AS ${c}`;
|
|
1031
|
+
return changed ? `${value} AS ${c}` : c;
|
|
1035
1032
|
}).join(", ");
|
|
1036
1033
|
const copySql = `INSERT INTO ${quoteTableName(tempName)} (${colNames}) SELECT ${selectExprs} FROM ${quoteTableName(tableName)}`;
|
|
1037
1034
|
this._log(copySql);
|
|
@@ -1552,6 +1549,22 @@ var PostgresAdapter = class PostgresAdapter extends BaseDbAdapter {
|
|
|
1552
1549
|
});
|
|
1553
1550
|
}
|
|
1554
1551
|
};
|
|
1552
|
+
/** A text / character type: the value is converted by the assignment into the column. */
|
|
1553
|
+
const CHARACTER_TYPE = /^\s*(?:text|varchar|character varying|char|character|bpchar)\b/i;
|
|
1554
|
+
/**
|
|
1555
|
+
* The expression converting column `col` (quoted) to `sqlType`, the field's
|
|
1556
|
+
* new type — one rule for `ALTER COLUMN … TYPE … USING` and the recreate copy.
|
|
1557
|
+
* The value goes through text, so one that does not parse as the new type
|
|
1558
|
+
* fails the statement instead of being coerced. A TEXT / VARCHAR(n) / CHAR(n)
|
|
1559
|
+
* target stops at `::text`: an explicit cast to VARCHAR(n) / CHAR(n) would
|
|
1560
|
+
* truncate an over-long value, the assignment into the column rejects it
|
|
1561
|
+
* (since 0.1.137).
|
|
1562
|
+
*/
|
|
1563
|
+
function convertColumnExpr(col, field, sqlType) {
|
|
1564
|
+
if (field.isGeoPoint && sqlType.startsWith("geography")) return `CASE WHEN ${col} IS NULL THEN NULL ELSE ST_SetSRID(ST_MakePoint((${col}->>0)::float8, (${col}->>1)::float8), 4326)::geography END`;
|
|
1565
|
+
if (CHARACTER_TYPE.test(sqlType)) return `${col}::text`;
|
|
1566
|
+
return `${col}::text::${sqlType}`;
|
|
1567
|
+
}
|
|
1555
1568
|
/**
|
|
1556
1569
|
* Normalizes PostgreSQL information_schema data_type values
|
|
1557
1570
|
* to match the format produced by `pgTypeFromField()`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/db-postgres",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.137",
|
|
4
4
|
"description": "PostgreSQL adapter for @atscript/db with pg (node-postgres) driver support.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"atscript",
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"@atscript/typescript": "^0.1.92",
|
|
56
56
|
"@uniqu/core": "^0.1.11",
|
|
57
57
|
"pg": ">=8.0.0",
|
|
58
|
-
"@atscript/db": "^0.1.
|
|
59
|
-
"@atscript/db-sql-tools": "^0.1.
|
|
58
|
+
"@atscript/db": "^0.1.137",
|
|
59
|
+
"@atscript/db-sql-tools": "^0.1.137"
|
|
60
60
|
},
|
|
61
61
|
"peerDependenciesMeta": {
|
|
62
62
|
"pg": {
|