imodel-pg 0.19.1 → 0.19.3
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/index.d.mts +1 -1
- package/index.mjs +187 -16
- package/package.json +1 -1
package/index.d.mts
CHANGED
package/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* imodel v0.19.
|
|
2
|
+
* imodel v0.19.3
|
|
3
3
|
* (c) 2019-2026 undefined
|
|
4
4
|
* @license undefined
|
|
5
5
|
*/
|
|
@@ -80,6 +80,7 @@ function getBaseType(s, {
|
|
|
80
80
|
case 'json':
|
|
81
81
|
return 'json';
|
|
82
82
|
}
|
|
83
|
+
return s;
|
|
83
84
|
}
|
|
84
85
|
/**
|
|
85
86
|
*
|
|
@@ -522,14 +523,17 @@ function buildSelect(env, selectList) {
|
|
|
522
523
|
offset,
|
|
523
524
|
limit,
|
|
524
525
|
group,
|
|
525
|
-
having
|
|
526
|
+
having,
|
|
527
|
+
lock
|
|
526
528
|
} of selectList) {
|
|
527
529
|
const Table = Sql.Table(table);
|
|
528
530
|
const selectSql = getSelect(Table, select);
|
|
529
531
|
const orderSql = getOrder(sort);
|
|
530
532
|
const limitSql = limit && limit > 0 ? Sql('LIMIT', limit) : undefined;
|
|
531
533
|
const offsetSql = offset && offset > 0 ? Sql('OFFSET', offset) : undefined;
|
|
532
|
-
list.push(Sql(Sql`SELECT`, distinct ? Sql`DISTINCT` : undefined, Sql`${selectSql}`, Sql`FROM ${Table}`, getWhere(env, where), orderSql, limitSql, offsetSql, group?.length ? Sql`GROUP BY ${Sql`,`.glue(group.map(v => Sql.Field(v)))}` : undefined, getWhere(env, having, 'HAVING')
|
|
534
|
+
list.push(Sql(Sql`SELECT`, distinct ? Sql`DISTINCT` : undefined, Sql`${selectSql}`, Sql`FROM ${Table}`, getWhere(env, where), orderSql, limitSql, offsetSql, group?.length ? Sql`GROUP BY ${Sql`,`.glue(group.map(v => Sql.Field(v)))}` : undefined, getWhere(env, having, 'HAVING'),
|
|
535
|
+
// eslint-disable-next-line no-nested-ternary
|
|
536
|
+
lock === 'X' ? Sql`FOR UPDATE` : lock === 'S' ? Sql`FOR SHARE` : undefined));
|
|
533
537
|
}
|
|
534
538
|
if (!list.length) {
|
|
535
539
|
return null;
|
|
@@ -1316,6 +1320,35 @@ async function loadTables(env, query, tables, schema) {
|
|
|
1316
1320
|
return dbTables;
|
|
1317
1321
|
}
|
|
1318
1322
|
|
|
1323
|
+
/**
|
|
1324
|
+
* 生成 PostgreSQL ALTER TABLE 语句中强制类型转换的 USING 子句
|
|
1325
|
+
* @param {Sql} COLUMN - 列名
|
|
1326
|
+
* @param {boolean?} [array]
|
|
1327
|
+
* @param {boolean?} [nullable]
|
|
1328
|
+
* @param {boolean?} [oldArray]
|
|
1329
|
+
* @param {Sql?} [def]
|
|
1330
|
+
* @returns {Sql}
|
|
1331
|
+
*/
|
|
1332
|
+
function generateUsingClause(COLUMN, array, nullable, oldArray, def) {
|
|
1333
|
+
if (array && !oldArray) {
|
|
1334
|
+
if (nullable) {
|
|
1335
|
+
return Sql`(CASE
|
|
1336
|
+
WHEN ${COLUMN} IS NULL THEN NULL
|
|
1337
|
+
ELSE ARRAY[${COLUMN}]
|
|
1338
|
+
END)`;
|
|
1339
|
+
}
|
|
1340
|
+
return Sql`(CASE
|
|
1341
|
+
WHEN ${COLUMN} IS NULL THEN ARRAY[]
|
|
1342
|
+
ELSE ARRAY[${COLUMN}]
|
|
1343
|
+
END)`;
|
|
1344
|
+
}
|
|
1345
|
+
const val = oldArray && !array ? Sql`${COLUMN}[1]` : Sql`${COLUMN}`;
|
|
1346
|
+
if (nullable || !def) {
|
|
1347
|
+
return val;
|
|
1348
|
+
}
|
|
1349
|
+
return Sql`COALESCE(${val}, ${def})`;
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1319
1352
|
/** @import { Environment, IConnection } from 'imodel' */
|
|
1320
1353
|
/** @import { PgEnvTrans } from '../index.mjs' */
|
|
1321
1354
|
/** @import { DBIndex, DBTable, DBColumn } from 'imodel' */
|
|
@@ -1639,15 +1672,18 @@ WHERE table_name = ${table} AND constraint_type = 'PRIMARY KEY'
|
|
|
1639
1672
|
size
|
|
1640
1673
|
}, array);
|
|
1641
1674
|
const oldType = getType(old.type, old, old.array);
|
|
1642
|
-
|
|
1643
|
-
|
|
1675
|
+
const def = getDefault(env, defaultValue, type, array);
|
|
1676
|
+
if (newType !== oldType || !nullable && old.nullable) {
|
|
1677
|
+
console.log(newType, oldType);
|
|
1678
|
+
const usingClause = generateUsingClause(Sql.Field(fieldName), array, nullable, old.array, def);
|
|
1679
|
+
const type = Sql(newType);
|
|
1680
|
+
COLUMNs.push(Sql`${COLUMN} TYPE ${type} USING ${usingClause}::${type}`);
|
|
1644
1681
|
// TODO: USING "description"::int2
|
|
1645
1682
|
}
|
|
1646
1683
|
if (Boolean(nullable) !== Boolean(old.nullable)) {
|
|
1647
1684
|
COLUMNs.push(nullable ? Sql`${COLUMN} DROP NOT NULL` : Sql`${COLUMN} SET NOT NULL`);
|
|
1648
1685
|
}
|
|
1649
1686
|
if (!defaultIsQe(defaultValue, old.default)) {
|
|
1650
|
-
const def = getDefault(env, defaultValue, type, array);
|
|
1651
1687
|
COLUMNs.push(def ? Sql`${COLUMN} SET DEFAULT ${def}` : Sql`${COLUMN} DROP DEFAULT`);
|
|
1652
1688
|
}
|
|
1653
1689
|
}
|
|
@@ -1698,6 +1734,144 @@ async function syncTables(env, query, tables, schema) {
|
|
|
1698
1734
|
}
|
|
1699
1735
|
}
|
|
1700
1736
|
|
|
1737
|
+
/** @import { Environment } from 'imodel' */
|
|
1738
|
+
/** @import { PgEnvTrans } from './index.mjs' */
|
|
1739
|
+
/**
|
|
1740
|
+
*
|
|
1741
|
+
* @param {string?} [detail]
|
|
1742
|
+
* @returns
|
|
1743
|
+
*/
|
|
1744
|
+
function parseUniqueViolationErrorColumns(detail) {
|
|
1745
|
+
const match = /^[^"]*"(.*)"[^"]*$/.exec(detail || '');
|
|
1746
|
+
const colsStr = match?.[1];
|
|
1747
|
+
if (!colsStr) {
|
|
1748
|
+
return [];
|
|
1749
|
+
}
|
|
1750
|
+
const cols = [];
|
|
1751
|
+
let i = 1;
|
|
1752
|
+
for (; i < colsStr.length; i++) {
|
|
1753
|
+
const char = colsStr[i];
|
|
1754
|
+
if (char === ' ' || char === ',') {
|
|
1755
|
+
continue;
|
|
1756
|
+
}
|
|
1757
|
+
if (char === ')') {
|
|
1758
|
+
break;
|
|
1759
|
+
}
|
|
1760
|
+
const list = [];
|
|
1761
|
+
if (char === '"') {
|
|
1762
|
+
i++;
|
|
1763
|
+
for (; i < colsStr.length; i++) {
|
|
1764
|
+
const char = colsStr[i];
|
|
1765
|
+
if (char === '"') {
|
|
1766
|
+
if (colsStr[i + 1] !== '"') {
|
|
1767
|
+
break;
|
|
1768
|
+
}
|
|
1769
|
+
i++;
|
|
1770
|
+
}
|
|
1771
|
+
list.push(char);
|
|
1772
|
+
}
|
|
1773
|
+
} else {
|
|
1774
|
+
for (; i < colsStr.length; i++) {
|
|
1775
|
+
const char = colsStr[i];
|
|
1776
|
+
if (char === ' ') {
|
|
1777
|
+
continue;
|
|
1778
|
+
}
|
|
1779
|
+
if (char === ')' || char === ',') {
|
|
1780
|
+
i--;
|
|
1781
|
+
break;
|
|
1782
|
+
}
|
|
1783
|
+
list.push(char);
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
cols.push(list.join(''));
|
|
1787
|
+
continue;
|
|
1788
|
+
}
|
|
1789
|
+
return cols;
|
|
1790
|
+
}
|
|
1791
|
+
/** @type {Record<string, (e: pg.DatabaseError, env: Environment<PgEnvTrans>) => any>} */
|
|
1792
|
+
const errors = {
|
|
1793
|
+
'22P02'(error, {
|
|
1794
|
+
errors
|
|
1795
|
+
}) {
|
|
1796
|
+
return new errors.InvalidInputSyntaxError(error.message);
|
|
1797
|
+
},
|
|
1798
|
+
23502(error, {
|
|
1799
|
+
errors
|
|
1800
|
+
}) {
|
|
1801
|
+
const {
|
|
1802
|
+
table,
|
|
1803
|
+
column
|
|
1804
|
+
} = error;
|
|
1805
|
+
if (!table || !column) {
|
|
1806
|
+
return;
|
|
1807
|
+
}
|
|
1808
|
+
return new errors.NotNullViolationError(table, column);
|
|
1809
|
+
},
|
|
1810
|
+
23505(error, {
|
|
1811
|
+
errors
|
|
1812
|
+
}) {
|
|
1813
|
+
const {
|
|
1814
|
+
table,
|
|
1815
|
+
detail
|
|
1816
|
+
} = error;
|
|
1817
|
+
if (!table) {
|
|
1818
|
+
return;
|
|
1819
|
+
}
|
|
1820
|
+
return new errors.UniqueViolationError(table, parseUniqueViolationErrorColumns(detail));
|
|
1821
|
+
},
|
|
1822
|
+
23503(error, {
|
|
1823
|
+
errors
|
|
1824
|
+
}) {
|
|
1825
|
+
const {
|
|
1826
|
+
table,
|
|
1827
|
+
column,
|
|
1828
|
+
constraint
|
|
1829
|
+
} = error;
|
|
1830
|
+
if (!table || !column) {
|
|
1831
|
+
return;
|
|
1832
|
+
}
|
|
1833
|
+
return new errors.ForeignKeyViolationError(table, column, constraint);
|
|
1834
|
+
},
|
|
1835
|
+
42883(error, {
|
|
1836
|
+
errors
|
|
1837
|
+
}) {
|
|
1838
|
+
return new errors.OperatorMismatchError(error.message);
|
|
1839
|
+
}
|
|
1840
|
+
};
|
|
1841
|
+
const errorGroup = {
|
|
1842
|
+
22: 'data',
|
|
1843
|
+
23: 'constraint',
|
|
1844
|
+
24: 'cursor',
|
|
1845
|
+
25: 'transaction'
|
|
1846
|
+
};
|
|
1847
|
+
/**
|
|
1848
|
+
*
|
|
1849
|
+
* @param {pg.DatabaseError} error
|
|
1850
|
+
* @param {Environment<PgEnvTrans>} env
|
|
1851
|
+
*/
|
|
1852
|
+
function errorConvert(error, env) {
|
|
1853
|
+
if (!(error instanceof pg.DatabaseError)) {
|
|
1854
|
+
return error;
|
|
1855
|
+
}
|
|
1856
|
+
const {
|
|
1857
|
+
code
|
|
1858
|
+
} = error;
|
|
1859
|
+
if (!code) {
|
|
1860
|
+
throw error;
|
|
1861
|
+
}
|
|
1862
|
+
const convert = Object.hasOwn(errors, code) ? errors[code] : null;
|
|
1863
|
+
const converted = convert?.(error, env);
|
|
1864
|
+
if (converted) {
|
|
1865
|
+
return converted;
|
|
1866
|
+
}
|
|
1867
|
+
if (typeof code !== 'string' || code.length !== 5) {
|
|
1868
|
+
return error;
|
|
1869
|
+
}
|
|
1870
|
+
const group = code.slice(0, 2);
|
|
1871
|
+
const groupCode = Object.hasOwn(errorGroup, group) && errorGroup[group];
|
|
1872
|
+
return new env.errors.ConnectionError(groupCode ? `${groupCode}::pg:${code}` : `:pg:${code}`, error.message);
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1701
1875
|
/** @import { Environment, IConnection } from 'imodel' */
|
|
1702
1876
|
const {
|
|
1703
1877
|
types
|
|
@@ -1826,22 +2000,19 @@ function index (pool, version) {
|
|
|
1826
2000
|
const {
|
|
1827
2001
|
transaction
|
|
1828
2002
|
} = env;
|
|
1829
|
-
const transactionClient = transaction?.client;
|
|
1830
|
-
|
|
1831
|
-
const client = await Promise.resolve(transactionClient);
|
|
1832
|
-
return client.query({
|
|
1833
|
-
text,
|
|
1834
|
-
values: [...values]
|
|
1835
|
-
});
|
|
1836
|
-
}
|
|
1837
|
-
const client = await connect();
|
|
2003
|
+
const transactionClient = await Promise.resolve(transaction?.client);
|
|
2004
|
+
const client = transactionClient || (await connect());
|
|
1838
2005
|
try {
|
|
1839
2006
|
return await client.query({
|
|
1840
2007
|
text,
|
|
1841
2008
|
values: [...values]
|
|
1842
2009
|
});
|
|
2010
|
+
} catch (error) {
|
|
2011
|
+
throw errorConvert(error, env) || error;
|
|
1843
2012
|
} finally {
|
|
1844
|
-
|
|
2013
|
+
if (!transactionClient) {
|
|
2014
|
+
client.release();
|
|
2015
|
+
}
|
|
1845
2016
|
}
|
|
1846
2017
|
}
|
|
1847
2018
|
/**
|