neopg 2.2.7 → 2.2.9

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
@@ -418,10 +418,17 @@ class ModelChain {
418
418
  }
419
419
  }
420
420
 
421
- async update(data) {
421
+ /**
422
+ *
423
+ * @param {object} data
424
+ * @param {boolean} one_result - auto return result[0] if only one item, default true
425
+ * @returns
426
+ */
427
+ async update(data, one_result=true) {
422
428
  this._ensureActive()
423
429
  try {
424
- if (!data || Object.keys(data).length === 0) throw new Error('[NeoPG] Update data cannot be empty')
430
+ if (!data || Object.keys(data).length === 0)
431
+ throw new Error('[NeoPG] Update data cannot be empty')
425
432
 
426
433
  if (!this._isRaw) {
427
434
  this._prepareDataForUpdate(data)
@@ -436,7 +443,7 @@ class ModelChain {
436
443
  const result = await this.sql`UPDATE ${fullTable} SET ${this.sql(data)} ${whereFragment} ${retFragment}`
437
444
 
438
445
  if (this._returning && this._returning.length > 0) {
439
- if (result.length === 1) return result[0]
446
+ if (result.length === 1 && one_result) return result[0]
440
447
  return result
441
448
  }
442
449
  return result
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.7",
3
+ "version": "2.2.9",
4
4
  "description": "orm for postgres",
5
5
  "keywords": [
6
6
  "neopg",
@@ -51,6 +51,7 @@ const errorFields = {
51
51
 
52
52
  function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose = noop } = {}) {
53
53
  const {
54
+ sslnegotiation,
54
55
  ssl,
55
56
  max,
56
57
  user,
@@ -77,6 +78,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
77
78
 
78
79
  let socket = null
79
80
  , cancelMessage
81
+ , errorResponse = null
80
82
  , result = new Result()
81
83
  , incoming = Buffer.alloc(0)
82
84
  , needsTypes = options.fetch_types
@@ -84,7 +86,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
84
86
  , statements = {}
85
87
  , statementId = Math.random().toString(36).slice(2)
86
88
  , statementCount = 1
87
- , closedDate = 0
89
+ , closedTime = 0
88
90
  , remaining = 0
89
91
  , hostIndex = 0
90
92
  , retries = 0
@@ -155,6 +157,9 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
155
157
  if (terminated)
156
158
  return queryError(q, Errors.connection('CONNECTION_DESTROYED', options))
157
159
 
160
+ if (stream)
161
+ return queryError(q, Errors.generic('COPY_IN_PROGRESS', 'You cannot execute queries during copy'))
162
+
158
163
  if (q.cancelled)
159
164
  return
160
165
 
@@ -259,25 +264,29 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
259
264
  }
260
265
 
261
266
  async function secure() {
262
- write(SSLRequest)
263
- const canSSL = await new Promise(r => socket.once('data', x => r(x[0] === 83))) // S
267
+ if (sslnegotiation !== 'direct') {
268
+ write(SSLRequest)
269
+ const canSSL = await new Promise(r => socket.once('data', x => r(x[0] === 83))) // S
264
270
 
265
- if (!canSSL && ssl === 'prefer')
266
- return connected()
271
+ if (!canSSL && ssl === 'prefer')
272
+ return connected()
273
+ }
267
274
 
268
- socket.removeAllListeners()
269
- socket = tls.connect({
275
+ const options = {
270
276
  socket,
271
- servername: net.isIP(socket.host) ? undefined : socket.host,
272
- ...(ssl === 'require' || ssl === 'allow' || ssl === 'prefer'
273
- ? { rejectUnauthorized: false }
274
- : ssl === 'verify-full'
275
- ? {}
276
- : typeof ssl === 'object'
277
- ? ssl
278
- : {}
279
- )
280
- })
277
+ servername: net.isIP(socket.host) ? undefined : socket.host
278
+ }
279
+
280
+ if (sslnegotiation === 'direct')
281
+ options.ALPNProtocols = ['postgresql']
282
+
283
+ if (ssl === 'require' || ssl === 'allow' || ssl === 'prefer')
284
+ options.rejectUnauthorized = false
285
+ else if (typeof ssl === 'object')
286
+ Object.assign(options, ssl)
287
+
288
+ socket.removeAllListeners()
289
+ socket = tls.connect(options)
281
290
  socket.on('secureConnect', connected)
282
291
  socket.on('error', error)
283
292
  socket.on('close', closed)
@@ -350,7 +359,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
350
359
  }
351
360
 
352
361
  function reconnect() {
353
- setTimeout(connect, closedDate ? Math.max(0, closedDate + delay - performance.now()) : 0)
362
+ setTimeout(connect, closedTime ? Math.max(0, closedTime + delay - performance.now()) : 0)
354
363
  }
355
364
 
356
365
  function connected() {
@@ -442,7 +451,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
442
451
  return reconnect()
443
452
 
444
453
  !hadError && (query || sent.length) && error(Errors.connection('CONNECTION_CLOSED', options, socket))
445
- closedDate = performance.now()
454
+ closedTime = performance.now()
446
455
  hadError && options.shared.retries++
447
456
  delay = (typeof backoff === 'function' ? backoff(options.shared.retries) : backoff) * 1000
448
457
  onclose(connection, Errors.connection('CONNECTION_CLOSED', options, socket))
@@ -524,8 +533,21 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
524
533
  }
525
534
 
526
535
  function ReadyForQuery(x) {
527
- query && query.options.simple && query.resolve(results || result)
528
- query = results = null
536
+ if (query) {
537
+ if (errorResponse) {
538
+ query.retried
539
+ ? errored(query.retried)
540
+ : query.prepared && retryRoutines.has(errorResponse.routine)
541
+ ? retry(query, errorResponse)
542
+ : errored(errorResponse)
543
+ } else {
544
+ query.resolve(results || result)
545
+ }
546
+ } else if (errorResponse) {
547
+ errored(errorResponse)
548
+ }
549
+
550
+ query = results = errorResponse = null
529
551
  result = new Result()
530
552
  connectTimer.cancel()
531
553
 
@@ -590,8 +612,6 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
590
612
  result.count && query.cursorFn(result)
591
613
  write(Sync)
592
614
  }
593
-
594
- query.resolve(result)
595
615
  }
596
616
 
597
617
  function ParseComplete() {
@@ -790,13 +810,12 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
790
810
  }
791
811
 
792
812
  function ErrorResponse(x) {
793
- query && (query.cursorFn || query.describeFirst) && write(Sync)
794
- const error = Errors.postgres(parseError(x))
795
- query && query.retried
796
- ? errored(query.retried)
797
- : query && query.prepared && retryRoutines.has(error.routine)
798
- ? retry(query, error)
799
- : errored(error)
813
+ if (query) {
814
+ (query.cursorFn || query.describeFirst) && write(Sync)
815
+ errorResponse = Errors.postgres(parseError(x))
816
+ } else {
817
+ errored(Errors.postgres(parseError(x)))
818
+ }
800
819
  }
801
820
 
802
821
  function retry(q, error) {
@@ -849,6 +868,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
849
868
  final(callback) {
850
869
  socket.write(b().c().end())
851
870
  final = callback
871
+ stream = null
852
872
  }
853
873
  })
854
874
  query.resolve(stream)
package/postgres/index.js CHANGED
@@ -446,8 +446,9 @@ function parseOptions(a, b) {
446
446
 
447
447
  const ints = ['idle_timeout', 'connect_timeout', 'max_lifetime', 'max_pipeline', 'backoff', 'keep_alive']
448
448
  const defaults = {
449
- max : 10,
449
+ max : globalThis.Cloudflare ? 3 : 10,
450
450
  ssl : false,
451
+ sslnegotiation : null,
451
452
  idle_timeout : null,
452
453
  connect_timeout : 30,
453
454
  max_lifetime : max_lifetime,
package/test/test-db.js CHANGED
@@ -135,6 +135,10 @@ const User = {
135
135
  role: {
136
136
  type: dataTypes.STRING(16),
137
137
  default: 'user'
138
+ },
139
+ number: {
140
+ type: dataTypes.INT,
141
+ default: 1
138
142
  }
139
143
  },
140
144
 
@@ -286,6 +290,16 @@ db.add(User)
286
290
  let result = await tx.model('User').where(tx.sql`level > 10`).returning('*').update(data)
287
291
  console.log('test update returning *', result)
288
292
 
293
+ console.log('test for update sql fragment')
294
+ let upd_result = await tx.model('User')
295
+ .where('1=1')
296
+ .returning(['id', 'username', 'number'])
297
+ .update({
298
+ number: tx.sql`number + ${(Math.random() * 20) | 0}`
299
+ }, false);
300
+
301
+ console.log(upd_result.count, upd_result.columns, upd_result)
302
+
289
303
  let sex = 3
290
304
  console.log(
291
305
  'test condition or',