neopg 2.2.6 → 2.2.8

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/lib/ModelChain.js CHANGED
@@ -198,8 +198,16 @@ class ModelChain {
198
198
  const v = arg1[k]
199
199
  if (v === undefined) continue
200
200
  if (v === null) this._conditions.push(this.sql`${this.sql(k)} IS NULL`)
201
- else if (Array.isArray(v)) this._conditions.push(this.sql`${this.sql(k)} IN ${this.sql(v)}`)
202
- else this._conditions.push(this.sql`${this.sql(k)} = ${v}`)
201
+ else if (Array.isArray(v)) {
202
+ //this._conditions.push(this.sql`${this.sql(k)} IN ${this.sql(v)}`)
203
+ if (v.length === 0) {
204
+ // 性能优化:空数组直接在应用层生成 FALSE,不触发数据库复杂的数组运算
205
+ this._conditions.push(this.sql`FALSE`)
206
+ } else {
207
+ // 在 postgres.js 中,${v} 会被转换为 Postgres 数组变量 $1
208
+ this._conditions.push(this.sql`${this.sql(k)} = ANY(${v})`)
209
+ }
210
+ } else this._conditions.push(this.sql`${this.sql(k)} = ${v}`)
203
211
  }
204
212
  return this
205
213
  }
package/lib/SchemaSync.js CHANGED
@@ -102,9 +102,9 @@ class SchemaSync {
102
102
  for (const c of cols) inf[c.column_name] = c;
103
103
 
104
104
  await this.syncColumn(sql, def, inf, curTableName, debug, force, dropNotExistCol);
105
+ await this.autoRemoveIndex(sql, def, schema, tableName, debug);
105
106
  await this.syncIndex(sql, def, schema, curTableName, debug);
106
107
  await this.syncUnique(sql, def, schema, curTableName, debug);
107
- await this.autoRemoveIndex(sql, def, schema, tableName, debug);
108
108
  await this.syncReferences(sql, def, schema, curTableName, schemaOid, debug, ctx, options);
109
109
 
110
110
  if (debug) console.log(` - 表结构同步完成 (${tableName}) - `);
@@ -290,6 +290,33 @@ class SchemaSync {
290
290
  const indices = def.index || [];
291
291
  if (!Array.isArray(indices)) return;
292
292
 
293
+ let gen_real_index = indname => {
294
+ let real_indexname
295
+ if (Array.isArray(indname)) {
296
+ real_indexname = indname.sort((a,b) => a.localeCompare(b)).join('_');
297
+ } else if (typeof indname === 'string') {
298
+ if (indname.indexOf(',') >= 0) {
299
+ real_indexname = indname.split(',').map(s=>s.trim()).filter(s=>s)
300
+ .sort((a,b)=>a.localeCompare(b))
301
+ .join('_');
302
+ } else {
303
+ real_indexname = indname.trim();
304
+ }
305
+ }
306
+
307
+ return real_indexname;
308
+ }
309
+
310
+ let unique_indexs = (def.unique || []).map(a => gen_real_index(a));
311
+
312
+ let check_in_unique = (indname) => {
313
+ for (let a of unique_indexs) {
314
+ if (a === gen_real_index(indname)) return true;
315
+ }
316
+
317
+ return false;
318
+ }
319
+
293
320
  for (const indname of indices) {
294
321
  const removeIndex = def.removeIndex || [];
295
322
  if (removeIndex.includes(indname)) continue;
@@ -299,7 +326,21 @@ class SchemaSync {
299
326
  continue;
300
327
  }
301
328
 
302
- let idxCols = Array.isArray(indname) ? indname : indname.split(',').map(s=>s.trim()).filter(s=>s);
329
+ if (!Array.isArray(indname) && typeof indname !== 'string') {
330
+ debug && console.error(`Index ${indname} 不是字符串或数组,跳过。`);
331
+ continue;
332
+ }
333
+
334
+ if (check_in_unique(indname)) {
335
+ debug && console.error(`Index ${indname} 是唯一索引,不会创建index索引,跳过。`);
336
+ continue;
337
+ }
338
+
339
+ let idxCols = Array.isArray(indname)
340
+ ? indname.sort((a,b) => a.localeCompare(b))
341
+ : indname.split(',').map(s=>s.trim()).filter(s=>s)
342
+ .sort((a,b) => a.localeCompare(b));
343
+
303
344
  const idxNamePart = idxCols.join('_');
304
345
  const targetIdxName = `${def.tableName}_${idxNamePart}_idx`;
305
346
 
@@ -339,7 +380,14 @@ class SchemaSync {
339
380
  for (const indname of uniques) {
340
381
  if (!this._checkColumnsExist(indname, def)) continue;
341
382
 
342
- let idxCols = Array.isArray(indname) ? indname : indname.split(',').map(s=>s.trim()).filter(s=>s);
383
+ if (!Array.isArray(indname) && typeof indname !== 'string') {
384
+ debug && console.error(`Index ${indname} 不是字符串或数组,跳过。`);
385
+ continue;
386
+ }
387
+
388
+ let idxCols = Array.isArray(indname)
389
+ ? indname.sort((a,b)=>a.localeCompare(b))
390
+ : indname.split(',').map(s=>s.trim()).filter(s=>s).sort((a,b)=>a.localeCompare(b));
343
391
 
344
392
  // 监测是否等于主键
345
393
  if (pkSet.size > 0 && idxCols.length === pkSet.size) {
@@ -368,7 +416,7 @@ class SchemaSync {
368
416
 
369
417
  static async autoRemoveIndex(sql, def, schema, tableName, debug) {
370
418
  const allIdx = await sql`
371
- SELECT indexname FROM pg_indexes
419
+ SELECT * FROM pg_indexes
372
420
  WHERE tablename = ${tableName}
373
421
  AND schemaname = ${schema}
374
422
  AND indexname != ${tableName + '_pkey'}
@@ -377,22 +425,51 @@ class SchemaSync {
377
425
  if (allIdx.length === 0) return;
378
426
 
379
427
  const currentIdxNames = allIdx.map(i => i.indexname);
428
+ let indexTable = Object.create(null);
429
+ for (let a of allIdx) {
430
+ indexTable[a.indexname] = a;
431
+ }
380
432
 
381
433
  const indices = def.index || [];
382
434
  const uniques = def.unique || [];
383
-
384
- const keepSet = new Set();
385
- const makeName = (n) => `${tableName}_${Array.isArray(n) ? n.map(x=>x.trim()).join('_') : n.split(',').map(x=>x.trim()).filter(x=>x).join('_')}_idx`;
386
435
 
387
- indices.forEach(n => keepSet.add(makeName(n)));
388
- uniques.forEach(n => keepSet.add(makeName(n)));
436
+ const makeName = (n) => `${tableName}_${Array.isArray(n)
437
+ ? n.map(x=>x.trim()).sort((a,b) => a.localeCompare(b)).join('_')
438
+ : n.split(',').map(x=>x.trim()).filter(x=>x).sort((a,b) => a.localeCompare(b)).join('_')}_idx`;
439
+
440
+ let allIndex = Object.create(null);
441
+ for (let k of indices) {
442
+ allIndex[makeName(k)] = k;
443
+ }
444
+
445
+ let allUnique = Object.create(null);
446
+ for (let k of uniques) {
447
+ allUnique[makeName(k)] = k;
448
+ }
389
449
 
390
450
  for (const idxName of currentIdxNames) {
391
- if (!keepSet.has(idxName)) {
451
+ if (!allIndex[idxName] && !allUnique[idxName]) {
392
452
  if (debug) console.log('Auto removing index:', idxName);
393
453
  await sql.unsafe(`DROP INDEX ${schema}.${idxName}`);
394
454
  }
395
455
  }
456
+
457
+ for (let k in allIndex) {
458
+ if (!indexTable[k]) continue;
459
+
460
+ if (indexTable[k].indexdef.toLowerCase().indexOf('create index') !== 0) {
461
+ debug && console.log('Auto remove index with inconsistent type:', k);
462
+ await sql.unsafe(`DROP INDEX ${schema}.${k};`);
463
+ }
464
+ }
465
+
466
+ for (let k in allUnique) {
467
+ if (!indexTable[k]) continue;
468
+ if (indexTable[k].indexdef.toLowerCase().indexOf('create unique') !== 0) {
469
+ debug && console.log('Auto remove index with inconsistent type:', k);
470
+ await sql.unsafe(`DROP INDEX ${schema}.${k};`);
471
+ }
472
+ }
396
473
  }
397
474
 
398
475
  // --- 外键同步 ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neopg",
3
- "version": "2.2.6",
3
+ "version": "2.2.8",
4
4
  "description": "orm for postgres",
5
5
  "keywords": [
6
6
  "neopg",
package/test/test-db.js CHANGED
@@ -130,6 +130,11 @@ const User = {
130
130
  type: dataTypes.POINT,
131
131
  default: '(0,0)',
132
132
  indexType: 'GiST'
133
+ },
134
+
135
+ role: {
136
+ type: dataTypes.STRING(16),
137
+ default: 'user'
133
138
  }
134
139
  },
135
140
 
@@ -213,6 +218,7 @@ db.add(User)
213
218
  console.log('test has', db.has('User'))
214
219
 
215
220
  await db.model('ShopOrder').where('1=1').delete()
221
+
216
222
  await db.model('ShopOrder').insert([
217
223
  {
218
224
  name: 'topbit',
@@ -222,6 +228,10 @@ db.add(User)
222
228
  {
223
229
  name: 'neopg',
224
230
  order_no: Math.random().toString(16)
231
+ },
232
+ {
233
+ name: 'hydra-thread',
234
+ order_no: Math.random().toString(16)
225
235
  }
226
236
  ])
227
237
 
@@ -240,20 +250,23 @@ db.add(User)
240
250
  username: 'Neo',
241
251
  email: '123@w.com',
242
252
  sex: 1,
243
- level: Math.floor((Math.random() * 105))
253
+ level: Math.floor((Math.random() * 105)),
254
+ role: 'user'
244
255
  },
245
256
  {
246
257
  username: 'PG',
247
258
  email: '1234@w.com',
248
259
  sex: 2,
249
- level: Math.floor((Math.random() * 100))
260
+ level: Math.floor((Math.random() * 100)),
261
+ role: 'db'
250
262
  },
251
263
 
252
264
  {
253
265
  username: 'NPG',
254
266
  email: '1235@w.com',
255
267
  sex: 3,
256
- level: 3
268
+ level: 3,
269
+ role: 'test'
257
270
  }
258
271
  ])
259
272
  )
@@ -294,6 +307,16 @@ db.add(User)
294
307
  await tx.model('User').group('level').select(tx.sql`level, MAX(username) as username`).findAndCount()
295
308
  )
296
309
 
310
+ console.log(
311
+ 'test for any (role in ...)',
312
+ await tx.model('User').where({role: ['test', 'db']}).find()
313
+ )
314
+
315
+ console.log(
316
+ 'test for any (empty)',
317
+ await tx.model('User').where({role: []}).find()
318
+ )
319
+
297
320
  console.log(
298
321
  'test avg',
299
322
  await tx.model('User').avg('level')