imodel-pg 0.14.0 → 0.15.1

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.
Files changed (3) hide show
  1. package/index.d.mts +1 -1
  2. package/index.mjs +87 -45
  3. package/package.json +1 -1
package/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * imodel v0.14.0
2
+ * imodel v0.15.1
3
3
  * (c) 2019-2026 undefined
4
4
  * @license undefined
5
5
  */
package/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * imodel v0.14.0
2
+ * imodel v0.15.1
3
3
  * (c) 2019-2026 undefined
4
4
  * @license undefined
5
5
  */
@@ -340,14 +340,14 @@ function renameColumn(table, column, newName) {
340
340
  */
341
341
  function addIndex(table, name, columns, {
342
342
  unique,
343
- include
343
+ includes
344
344
  } = {}) {
345
345
  const create = unique ? Sql`CREATE UNIQUE INDEX` : Sql`CREATE INDEX`;
346
346
  const id = Sql.Id(`${table}#${name}`);
347
347
  const allColumns = Sql`, `.glue(...columns.map(v => Sql.Field(v)));
348
348
  const fieldSqls = Sql`ON ${Sql.Table(table)}(${allColumns})`;
349
- const includes = include?.length ? Sql`INCLUDE (${Sql`, `.glue(...include.map(v => Sql.Field(v)))})` : undefined;
350
- return Sql(create, id, fieldSqls, includes);
349
+ const includesSql = includes?.length ? Sql`INCLUDE (${Sql`, `.glue(...includes.map(v => Sql.Field(v)))})` : undefined;
350
+ return Sql(create, id, fieldSqls, includesSql);
351
351
  }
352
352
 
353
353
  /**
@@ -874,11 +874,13 @@ function insertSql(env, table, columns, list, keys, conflict, conflictSet) {
874
874
  const setList = conflictSet && typeof conflictSet === 'object' ? getSet(conflictSet, columns, env) : [];
875
875
  if (fields?.length) {
876
876
  conflictSql = Sql(['ON CONFLICT (', ...Array(fields.length - 1).fill(','), ')'], ...fields.map(f => Sql.Field(f)));
877
- for (const f of key) {
878
- if (fields.includes(f)) {
879
- continue;
877
+ if (!setList.length) {
878
+ for (const f of key) {
879
+ if (fields.includes(f)) {
880
+ continue;
881
+ }
882
+ setList.push(Sql`${Sql.Field(f)} = EXCLUDED.${Sql.Field(f)}`);
880
883
  }
881
- setList.push(Sql`${Sql.Field(f)} = EXCLUDED.${Sql.Field(f)}`);
882
884
  }
883
885
  } else {
884
886
  conflictSql = Sql`ON CONFLICT`;
@@ -950,25 +952,29 @@ FROM (values${Sql`,`.glue(list.map(data => Sql`(${Sql`,`.glue(dataFieldType.map(
950
952
  WHERE ${Sql`AND`.glue([pKeys.map(f => Sql`${main.field(f)}=${tmp.field(f)}`), getWhere2(env, where)].flat().filter(Boolean))}${returnSql}`;
951
953
  }
952
954
 
955
+ const defaultSchema = Sql`(SELECT (current_schemas(false))[1])`;
956
+
953
957
  /** @import { Environment, IConnection } from 'imodel' */
954
958
  /** @import { PgEnvTrans } from '../index.mjs' */
955
959
  /** @import { DBIndex, DBTable, DBColumn } from 'imodel' */
956
960
  const tableType = 'BASE TABLE';
961
+ // eslint-disable-next-line max-len
962
+ const textRegex = /^'(?<text>(?:[^']|'')+)'(?:::(?<type>character varying|text|jsonb?))?$/;
957
963
  /**
958
964
  *
959
965
  * @param {Environment<PgEnvTrans>} env
960
- * @param {string} schema
961
966
  * @param {<T extends pg.QueryResultRow>(env: Environment<PgEnvTrans>, sql: Sql) => Promise<T[]>} query
962
967
  * @param {string[]} tables
963
- * @returns {Promise<(DBColumn & {table: string; name: string})[]>}
968
+ * @param {string?} [schema]
969
+ * @returns {Promise<(DBColumn & {table: string; name: string; defaultExp: string?})[]>}
964
970
  */
965
- async function loadFields(env, schema, query, tables) {
971
+ async function loadFields(env, query, tables, schema) {
966
972
  const sql = Sql`
967
973
  SELECT *
968
974
  FROM
969
975
  information_schema.columns t
970
976
  WHERE
971
- table_schema = ${schema}
977
+ table_schema = ${defaultSchema}
972
978
  AND
973
979
  t.table_name IN (${Sql`,`.glue(tables.map(t => Sql`${t}`))})
974
980
  `;
@@ -984,7 +990,7 @@ WHERE
984
990
  let scale = 0;
985
991
  const nullable = column.is_nullable === 'YES';
986
992
  /** @type {any} */
987
- let defaultValue = column.column_default;
993
+ let defaultExp = column.column_default;
988
994
  switch (type) {
989
995
  case 'int2':
990
996
  type = 'i16';
@@ -1057,26 +1063,58 @@ WHERE
1057
1063
  case 'json':
1058
1064
  type = 'json';
1059
1065
  }
1060
- if (defaultValue === 'CURRENT_TIMESTAMP' || defaultValue === 'now()') {
1066
+ let defaultValue;
1067
+ const regexResult = textRegex.exec(defaultExp)?.groups;
1068
+ if (regexResult) {
1069
+ const {
1070
+ text,
1071
+ type
1072
+ } = regexResult;
1073
+ if (typeof text === 'string') {
1074
+ const str = text.replaceAll("''", '');
1075
+ switch (type) {
1076
+ case 'json':
1077
+ case 'jsonb':
1078
+ try {
1079
+ defaultValue = JSON.parse(str);
1080
+ } catch {}
1081
+ break;
1082
+ default:
1083
+ defaultValue = str;
1084
+ break;
1085
+ }
1086
+ defaultExp = null;
1087
+ }
1088
+ } else if (defaultExp === 'CURRENT_TIMESTAMP' || defaultExp === 'now()') {
1061
1089
  defaultValue = env.values.now;
1062
- } else if (defaultValue === 'gen_random_uuid()') {
1090
+ defaultExp = null;
1091
+ } else if (defaultExp === 'gen_random_uuid()') {
1063
1092
  defaultValue = env.values.uuid;
1064
- } else if (defaultValue === 'false') {
1093
+ defaultExp = null;
1094
+ } else if (defaultExp === 'false') {
1065
1095
  defaultValue = false;
1066
- } else if (defaultValue === 'true') {
1096
+ defaultExp = null;
1097
+ } else if (defaultExp === 'true') {
1067
1098
  defaultValue = true;
1068
- } else if (defaultValue === `''::character varying`) {
1099
+ defaultExp = null;
1100
+ } else if (defaultExp === `''::character varying`) {
1069
1101
  defaultValue = '';
1070
- } else if (defaultValue === `''::text`) {
1102
+ defaultExp = null;
1103
+ } else if (defaultExp === `''::text`) {
1071
1104
  defaultValue = '';
1072
- } else if (defaultValue === `'[]'::json`) {
1105
+ defaultExp = null;
1106
+ } else if (defaultExp === `'[]'::json`) {
1073
1107
  defaultValue = [];
1074
- } else if (defaultValue === `'{}'::json`) {
1108
+ defaultExp = null;
1109
+ } else if (defaultExp === `'{}'::json`) {
1075
1110
  defaultValue = {};
1076
- } else if (/^ARRAY\[\]::[a-z \d]+\[\]$/.test(defaultValue)) {
1111
+ defaultExp = null;
1112
+ } else if (/^ARRAY\[\]::[a-z \d]+\[\]$/.test(defaultExp)) {
1077
1113
  defaultValue = [];
1078
- } else if (/^\d+(.\d+)?(?:::[a-z \d]+)?$/.test(defaultValue)) {
1079
- defaultValue = Number(defaultValue);
1114
+ defaultExp = null;
1115
+ } else if (/^\d+(.\d+)?(?:::[a-z \d]+)?$/.test(defaultExp)) {
1116
+ defaultValue = Number(defaultExp);
1117
+ defaultExp = null;
1080
1118
  }
1081
1119
  return {
1082
1120
  table: column.table_name,
@@ -1086,6 +1124,7 @@ WHERE
1086
1124
  scale,
1087
1125
  nullable,
1088
1126
  default: defaultValue,
1127
+ defaultExp,
1089
1128
  array
1090
1129
  };
1091
1130
  });
@@ -1094,16 +1133,16 @@ WHERE
1094
1133
  *
1095
1134
  * @param {Environment<PgEnvTrans>} env
1096
1135
  * @param {<T extends pg.QueryResultRow>(env: Environment<PgEnvTrans>, sql: Sql) => Promise<T[]>} query
1097
- * @param {(DBColumn & {table: string; name: string})[]} fields
1136
+ * @param {(DBColumn & {table: string; name: string; defaultExp: string?})[]} fields
1098
1137
  * @returns {Promise<(DBColumn & {table: string; name: string})[]>}
1099
1138
  */
1100
1139
  async function loadDefault(env, query, fields) {
1101
- const data = fields.filter(v => v.default && typeof v.default === 'string');
1140
+ const data = fields.filter(v => v.defaultExp);
1102
1141
  if (!data.length) {
1103
1142
  return fields;
1104
1143
  }
1105
1144
  const sql = Sql`
1106
- SELECT ${Sql`,`.glue(data.map((v, k) => Sql(`${v.default} as a${k}`)))}
1145
+ SELECT ${Sql`,`.glue(data.map((v, k) => Sql(`${v.defaultExp} as a${k}`)))}
1107
1146
  `;
1108
1147
  const [values = {}] = await query(env, sql);
1109
1148
  for (const [index, column] of data.entries()) {
@@ -1114,12 +1153,12 @@ SELECT ${Sql`,`.glue(data.map((v, k) => Sql(`${v.default} as a${k}`)))}
1114
1153
  /**
1115
1154
  *
1116
1155
  * @param {Environment<PgEnvTrans>} env
1117
- * @param {string} schema
1118
1156
  * @param {<T extends pg.QueryResultRow>(env: Environment<PgEnvTrans>, sql: Sql) => Promise<T[]>} query
1119
1157
  * @param {string[]} tables
1158
+ * @param {string?} [schema]
1120
1159
  * @returns {Promise<[(DBIndex & {table: string})[], ({fields: string[], name: string, table: string})[]]>}
1121
1160
  */
1122
- async function loadIndex(env, schema, query, tables) {
1161
+ async function loadIndex(env, query, tables, schema) {
1123
1162
  const sql = Sql`
1124
1163
  SELECT
1125
1164
  t.relname AS table,
@@ -1140,6 +1179,10 @@ JOIN
1140
1179
  JOIN
1141
1180
  pg_class i ON ix.indexrelid = i.oid
1142
1181
  WHERE
1182
+ t.relnamespace IN (
1183
+ SELECT oid FROM pg_namespace WHERE nspname = ${defaultSchema}
1184
+ )
1185
+ AND
1143
1186
  t.relname IN (${Sql`,`.glue(tables.map(t => Sql`${t}`))})
1144
1187
  AND
1145
1188
  t.relkind = 'r'; -- 只匹配普通表
@@ -1170,16 +1213,16 @@ WHERE
1170
1213
  /**
1171
1214
  *
1172
1215
  * @param {Environment<PgEnvTrans>} env
1173
- * @param {string} schema
1174
1216
  * @param {<T extends pg.QueryResultRow>(env: Environment<PgEnvTrans>, sql: Sql) => Promise<T[]>} query
1175
1217
  * @param {string[]} tables
1218
+ * @param {string?} [schema]
1176
1219
  * @returns {Promise<string[]>}
1177
1220
  */
1178
- async function loadBaseTables(env, schema, query, tables) {
1221
+ async function loadBaseTables(env, query, tables, schema) {
1179
1222
  const sql = Sql`SELECT *
1180
1223
  FROM information_schema.tables
1181
1224
  WHERE
1182
- table_schema = ${schema}
1225
+ table_schema = ${defaultSchema}
1183
1226
  AND
1184
1227
  table_type = ${tableType}
1185
1228
  AND
@@ -1190,13 +1233,13 @@ async function loadBaseTables(env, schema, query, tables) {
1190
1233
  /**
1191
1234
  *
1192
1235
  * @param {Environment<PgEnvTrans>} env
1193
- * @param {string} schema
1194
1236
  * @param {<T extends pg.QueryResultRow>(env: Environment<PgEnvTrans>, sql: Sql) => Promise<T[]>} query
1195
1237
  * @param {string[]} tables
1238
+ * @param {string?} [schema]
1196
1239
  * @returns {Promise<DBTable[]>}
1197
1240
  */
1198
- async function loadTables(env, schema, query, tables) {
1199
- const [baseTables, allFields, [allIndexes, allPrimary]] = await Promise.all([loadBaseTables(env, schema, query, tables), loadFields(env, schema, query, tables).then(fields => loadDefault(env, query, fields)), loadIndex(env, schema, query, tables)]);
1241
+ async function loadTables(env, query, tables, schema) {
1242
+ const [baseTables, allFields, [allIndexes, allPrimary]] = await Promise.all([loadBaseTables(env, query, tables), loadFields(env, query, tables).then(fields => loadDefault(env, query, fields)), loadIndex(env, query, tables)]);
1200
1243
  const allTables = new Set(baseTables);
1201
1244
  const fieldsGroup = Object.groupBy(allFields, f => f.table);
1202
1245
  const indexesGroup = Object.groupBy(allIndexes, f => f.table);
@@ -1591,14 +1634,13 @@ ADD PRIMARY KEY (${Sql`,`.glue(primary.map(f => Sql.Field(f)))})
1591
1634
  /**
1592
1635
  *
1593
1636
  * @param {Environment<PgEnvTrans>} env
1594
- * @param {string} schema
1595
1637
  * @param {<T extends pg.QueryResultRow>(env: Environment<PgEnvTrans>, sql: Sql) => Promise<T[]>} query
1596
1638
  * @param {DBTable[]} tables
1597
- * @param {boolean} [del]
1639
+ * @param {string} [schema]
1598
1640
  */
1599
- async function syncTables(env, schema, query, tables, del) {
1641
+ async function syncTables(env, query, tables, schema) {
1600
1642
  const tableNames = tables.map(v => v.table);
1601
- const dbTables = await loadTables(env, schema, query, tableNames);
1643
+ const dbTables = await loadTables(env, query, tableNames);
1602
1644
  const tableMap = new Map(dbTables.map(v => [v.table, v]));
1603
1645
  for (const table of tables) {
1604
1646
  const old = tableMap.get(table.table);
@@ -1691,7 +1733,6 @@ function toPoolConnection(pool) {
1691
1733
  */
1692
1734
  function index (pool, version) {
1693
1735
  const connect = toPoolConnection(pool);
1694
- const schema = 'public';
1695
1736
  const dbVersion = typeof version === 'function' ? version : createVersion(connect);
1696
1737
  /**
1697
1738
  * @template {pg.QueryResultRow} T
@@ -1762,7 +1803,8 @@ function index (pool, version) {
1762
1803
  async type(env, table) {
1763
1804
  const sql = Sql`SELECT table_type as type
1764
1805
  FROM information_schema.tables
1765
- WHERE table_schema = ${schema} AND table_name = ${table} LIMIT 1`;
1806
+ WHERE table_schema = (SELECT (current_schemas(false))[1])
1807
+ AND table_name = ${table} LIMIT 1`;
1766
1808
  /** @type {pg.QueryResult<{ type: string; }>} */
1767
1809
  const {
1768
1810
  rows: [row]
@@ -1779,8 +1821,8 @@ function index (pool, version) {
1779
1821
  return '';
1780
1822
  }
1781
1823
  },
1782
- insert(env, table, columns, data, keys) {
1783
- return query(env, insertSql(env, table, columns, data, keys));
1824
+ insert(env, table, columns, data, keys, ignore) {
1825
+ return query(env, insertSql(env, table, columns, data, keys, ignore));
1784
1826
  },
1785
1827
  upsert(env, table, columns, data, keys, conflict, conflictSet) {
1786
1828
  return query(env, insertSql(env, table, columns, data, keys, conflict, conflictSet));
@@ -1851,10 +1893,10 @@ function index (pool, version) {
1851
1893
  return exec(env, renameTable(table, newName));
1852
1894
  },
1853
1895
  loadTables(env, tables) {
1854
- return loadTables(env, schema, query, tables);
1896
+ return loadTables(env, query, tables);
1855
1897
  },
1856
1898
  syncTables(env, tables) {
1857
- return syncTables(env, schema, query, tables);
1899
+ return syncTables(env, query, tables);
1858
1900
  },
1859
1901
  async transaction(env, fn) {
1860
1902
  if (env?.transaction?.client) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imodel-pg",
3
- "version": "0.14.0",
3
+ "version": "0.15.1",
4
4
  "dependencies": {
5
5
  "pg": "^8.13.3",
6
6
  "tagged-sql": "^0.9.0"