@pi-r/redis 0.6.0 → 0.6.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.
package/client/index.js CHANGED
@@ -229,13 +229,12 @@ async function executeBatchQuery(batch, options = '', outResult) {
229
229
  continue;
230
230
  }
231
231
  item.transactionState = 1 /* DB_TRANSACTION.ACTIVE */;
232
+ const command = (0, types_1.isPlainObject)(clientOptions.command) ? redis.commandOptions(clientOptions.command) : null;
232
233
  const uuidKey = (credential.uuidKey || (credential.uuidKey = (onceCredential ? batch[0] : item).credential?.uuidKey));
233
234
  const targetObject = typeof checkObject === 'string' ? this.hasCoerce("redis" /* STRINGS.MODULE_NAME */, 'options', uuidKey) && (0, types_1.asFunction)(checkObject) : checkObject;
234
- const renewCache = ignoreCache === 0;
235
- const cacheValue = renewCache ? { sessionKey, renewCache } : sessionKey;
236
- const command = (0, types_1.isPlainObject)(clientOptions.command) ? redis.commandOptions(clientOptions.command) : null;
235
+ const cacheValue = ignoreCache === undefined ? sessionKey : Array.isArray(ignoreCache) ? { sessionKey, exclusiveOf: ignoreCache } : { sessionKey, renewCache: ignoreCache === 0 };
237
236
  let queryString = '', rows;
238
- if (caching && ignoreCache !== true || ignoreCache === false || ignoreCache === 1 || renewCache) {
237
+ if (caching && ignoreCache !== true) {
239
238
  if ((0, types_1.isObject)(search)) {
240
239
  queryString = Db.asString(search, true);
241
240
  }
@@ -288,63 +287,128 @@ async function executeBatchQuery(batch, options = '', outResult) {
288
287
  commandType = this.commandType.UPDATE;
289
288
  const values = (!Array.isArray(update) ? [update] : update).map(async (target) => {
290
289
  return new Promise(async (success, failed) => {
291
- let { key: k, value: v, format: f = 'HASH', NX, XX, EX = 0, PX = 0, EXAT = 0, PXAT = 0, options: setOptions = {} } = target;
292
- if (v === undefined) {
290
+ let { key: k, value: v, format: f, NX, XX, options: setOptions = {} } = target;
291
+ f = ((0, types_1.isString)(f) ? f.toUpperCase() : 'HASH');
292
+ if (v === undefined && f !== 'JSON') {
293
293
  success(target);
294
294
  return;
295
295
  }
296
+ const has = (n) => typeof n === 'number' && n > 0;
296
297
  const failKey = () => failed((0, types_1.errorMessage)(f, "Invalid key" /* ERR_DB.KEY */, Db.asString(k) || "Unknown" /* ERR_MESSAGE.UNKNOWN */));
297
298
  const failValue = () => failed((0, types_1.errorMessage)(f, "Invalid value" /* ERR_DB.VALUE */, Db.asString(v) || "Unknown" /* ERR_MESSAGE.UNKNOWN */));
298
299
  const commandSet = (0, types_1.isPlainObject)(setOptions.command) && redis.commandOptions(setOptions.command);
299
- let pending;
300
- if ((f = f.toUpperCase()) === 'JSON') {
300
+ let pending, codeMin = 0, EX, PX, EXAT, PXAT, KEEPTTL;
301
+ if (f === 'JSON') {
301
302
  if (typeof k !== 'string') {
302
303
  failKey();
303
304
  return;
304
305
  }
305
- const path = target.path || '$';
306
306
  if (this.hasCoerce("redis" /* STRINGS.MODULE_NAME */, 'options', uuidKey)) {
307
307
  if ((0, types_1.isString)(v) && v.startsWith('new')) {
308
308
  ({ outV: v } = (0, types_1.coerceObject)({ outV: v }));
309
309
  }
310
310
  }
311
- const flags = NX ? { NX } : XX ? { XX } : undefined;
312
- pending = commandSet ? client.json.set(commandSet, k, path, v, flags) : client.json.set(k, path, v, flags);
311
+ let { path = '$', command: cmd, start, stop, index } = target;
312
+ const name = ((0, types_1.isString)(cmd) ? cmd.toUpperCase() : 'SET');
313
+ if (Array.isArray(v) && name !== 'ARRAPPEND' && name !== 'ARRINSERT' && name !== 'MSET') {
314
+ v = v[0];
315
+ }
316
+ switch (name) {
317
+ case 'ARRAPPEND':
318
+ pending = commandSet ? client.json.arrAppend(commandSet, k, path, ...(Array.isArray(v) ? v : [v])) : client.json.arrAppend(k, path, ...(Array.isArray(v) ? v : [v]));
319
+ break;
320
+ case 'ARRINDEX':
321
+ codeMin = -1;
322
+ pending = commandSet ? client.json.arrIndex(commandSet, k, path, v, start, stop) : client.json.arrIndex(k, path, v, start, stop);
323
+ break;
324
+ case 'ARRINSERT':
325
+ if (typeof index === 'number' || (0, types_1.isString)(index) && !isNaN(index = parseInt(index))) {
326
+ pending = commandSet ? client.json.arrInsert(commandSet, k, path, index, ...(Array.isArray(v) ? v : [v])) : client.json.arrInsert(k, path, index, ...(Array.isArray(v) ? v : [v]));
327
+ }
328
+ break;
329
+ case 'ARRPOP':
330
+ codeMin = -Infinity;
331
+ pending = commandSet ? client.json.arrPop(commandSet, k, path, index) : client.json.arrPop(k, path, index);
332
+ break;
333
+ case 'ARRTRIM':
334
+ if ((typeof start === 'number' || (0, types_1.isString)(start) && !isNaN(start = parseInt(start))) && (typeof stop === 'number' || (0, types_1.isString)(stop) && !isNaN(stop = parseInt(stop)))) {
335
+ pending = commandSet ? client.json.arrTrim(commandSet, k, path, start, stop) : client.json.arrTrim(k, path, start, stop);
336
+ }
337
+ break;
338
+ case 'DEL':
339
+ case 'FORGET':
340
+ pending = commandSet ? client.json[name === 'DEL' ? 'del' : 'forget'](commandSet, k, path) : client.json[name === 'DEL' ? 'del' : 'forget'](k, path);
341
+ break;
342
+ case 'MERGE':
343
+ pending = commandSet ? client.json.merge(commandSet, k, path, v) : client.json.merge(k, path, v);
344
+ break;
345
+ case 'MSET': {
346
+ const data = (Array.isArray(v) ? v : [v])
347
+ .filter((m) => m.value !== undefined)
348
+ .map((m) => {
349
+ m.key || (m.key = k);
350
+ m.path || (m.path = path);
351
+ return m;
352
+ });
353
+ if (data.length) {
354
+ pending = commandSet ? client.json.mSet(commandSet, data) : client.json.mSet(data);
355
+ }
356
+ break;
357
+ }
358
+ case 'NUMINCRBY':
359
+ case 'NUMMULTBY':
360
+ if (typeof v === 'number' || (0, types_1.isString)(v) && !isNaN(v = parseFloat(v))) {
361
+ pending = commandSet ? client.json[name === 'NUMINCRBY' ? 'numIncrBy' : 'numMultBy'](commandSet, k, path, v) : client.json[name === 'NUMINCRBY' ? 'numIncrBy' : 'numMultBy'](k, path, v);
362
+ }
363
+ break;
364
+ case 'STRAPPEND':
365
+ if ((0, types_1.isString)(v)) {
366
+ pending = commandSet ? client.json.strAppend(commandSet, k, path, v) : client.json.strAppend(k, path, v);
367
+ }
368
+ break;
369
+ default: {
370
+ const flags = NX ? { NX } : XX ? { XX } : undefined;
371
+ pending = commandSet ? client.json.set(commandSet, k, path, v, flags) : client.json.set(k, path, v, flags);
372
+ break;
373
+ }
374
+ }
313
375
  }
314
376
  else if (typeof k === 'string' || Buffer.isBuffer(k)) {
377
+ ({ EX, PX, EXAT, PXAT, KEEPTTL } = target);
315
378
  const field = target.field;
316
379
  if (field === undefined && field === null) {
317
380
  if (a(v)) {
318
- const flags = setOptions.set;
319
- if (flags) {
320
- if ('NX' in flags) {
321
- NX ?? (NX = !!flags.NX);
322
- delete flags.NX;
323
- }
324
- if ('XX' in flags) {
325
- XX ?? (XX = !!flags.XX);
326
- delete flags.XX;
327
- }
328
- if ('EX' in flags) {
329
- EX || (EX = flags.EX);
330
- delete flags.EX;
331
- }
332
- if ('PX' in flags) {
333
- PX || (PX = flags.PX);
334
- delete flags.PX;
335
- }
336
- if ('EXAT' in flags) {
337
- EXAT || (EXAT = flags.EXAT);
338
- delete flags.EXAT;
339
- }
340
- if ('PXAT' in flags) {
341
- PXAT || (PXAT = flags.PXAT);
342
- delete flags.PXAT;
343
- }
381
+ const flags = setOptions.set || {};
382
+ if (NX) {
383
+ flags.NX = true;
344
384
  }
345
- pending = (commandSet ? client.set(commandSet, k, v, setOptions.set) : client.set(k, v, setOptions.set));
385
+ if (XX) {
386
+ flags.XX = true;
387
+ }
388
+ if (has(EX)) {
389
+ flags.EX = EX;
390
+ EX = 0;
391
+ }
392
+ if (has(PX)) {
393
+ flags.PX = PX;
394
+ PX = 0;
395
+ }
396
+ if (has(EXAT)) {
397
+ flags.EXAT = EXAT;
398
+ EXAT = 0;
399
+ }
400
+ if (has(PXAT)) {
401
+ flags.PXAT = PXAT;
402
+ PXAT = 0;
403
+ }
404
+ if (KEEPTTL) {
405
+ flags.KEEPTTL = true;
406
+ KEEPTTL = false;
407
+ }
408
+ codeMin = NaN;
409
+ pending = commandSet ? client.set(commandSet, k, v, flags) : client.set(k, v, flags);
346
410
  }
347
- else if (typeof v === 'object') {
411
+ else if ((0, types_1.isObject)(v)) {
348
412
  let valid = true;
349
413
  if (NX || XX) {
350
414
  valid = await client.exists(k) === 1;
@@ -361,6 +425,7 @@ async function executeBatchQuery(batch, options = '', outResult) {
361
425
  }
362
426
  else if (NX) {
363
427
  if (a(field) && a(v)) {
428
+ codeMin = -1;
364
429
  pending = commandSet ? client.hSetNX(commandSet, k, b(field), b(v)) : client.hSetNX(k, b(field), b(v));
365
430
  }
366
431
  }
@@ -383,43 +448,52 @@ async function executeBatchQuery(batch, options = '', outResult) {
383
448
  return;
384
449
  }
385
450
  if (pending) {
386
- pending.then(code => {
387
- if (code === 'OK' || typeof code === 'number' || code === true) {
388
- const has = (n) => typeof n === 'number' && n !== 0;
389
- if (has(EX) || has(PX) || EXAT > 0 || PXAT > 0) {
390
- const expire = setOptions.expire;
391
- let mode;
392
- if (expire) {
393
- if (expire.NX) {
394
- mode = 'NX';
395
- }
396
- else if (expire.XX) {
397
- mode = 'XX';
398
- }
399
- else if (expire.GT) {
400
- mode = 'GT';
401
- }
402
- else if (expire.LT) {
403
- mode = 'LT';
404
- }
451
+ pending.then(async (code) => {
452
+ if (code === undefined || code === null || code !== -Infinity && (0, types_1.isString)(code) && code !== 'OK' || typeof code === 'number' && code <= codeMin || Array.isArray(code) && code.every(resp => resp === null || typeof resp === 'number' && resp <= codeMin)) {
453
+ failValue();
454
+ return;
455
+ }
456
+ let ttl = false;
457
+ if (!isNaN(codeMin) && (has(EX) || has(PX) || has(EXAT) || has(PXAT) || (ttl = !!KEEPTTL))) {
458
+ const expire = setOptions.expire;
459
+ let mode;
460
+ if (expire) {
461
+ if (expire.NX) {
462
+ mode = 'NX';
463
+ }
464
+ else if (expire.XX) {
465
+ mode = 'XX';
466
+ }
467
+ else if (expire.GT) {
468
+ mode = 'GT';
469
+ }
470
+ else if (expire.LT) {
471
+ mode = 'LT';
405
472
  }
406
- (has(EX) ? client.expire(k, EX, mode) : has(PX) ? client.pExpire(k, PX, mode) : EXAT > 0 ? client.expireAt(k, EXAT, mode) : client.pExpireAt(k, PXAT, mode))
407
- .then(valid => {
408
- if (valid) {
409
- success(target);
410
- }
411
- else {
412
- failed((0, types_1.errorMessage)(f, "Invalid value" /* ERR_DB.VALUE */, has(EX) ? 'EX: ' + EX : has(PX) ? 'PX: ' + PX : EXAT > 0 ? 'EXAT: ' + EX : 'PXAT: ' + PXAT));
413
- }
414
- })
415
- .catch(err => failed(err));
416
473
  }
417
- else {
418
- success(target);
474
+ if (ttl) {
475
+ PX = await client.pTTL(k).catch(err => {
476
+ failed(err);
477
+ return 0;
478
+ });
479
+ if (PX <= 0) {
480
+ success(target);
481
+ return;
482
+ }
419
483
  }
484
+ (has(EX) ? client.expire(k, EX, mode) : has(PX) ? client.pExpire(k, PX, mode) : has(EXAT) ? client.expireAt(k, EXAT, mode) : client.pExpireAt(k, PXAT, mode))
485
+ .then(valid => {
486
+ if (valid) {
487
+ success(target);
488
+ }
489
+ else {
490
+ failed((0, types_1.errorMessage)(f, "Invalid value" /* ERR_DB.VALUE */, has(EX) ? 'EX: ' + EX : has(PX) ? 'PX: ' + PX : has(EXAT) ? 'EXAT: ' + EX : 'PXAT: ' + PXAT));
491
+ }
492
+ })
493
+ .catch(err => failed(err));
420
494
  }
421
495
  else {
422
- failValue();
496
+ success(target);
423
497
  }
424
498
  })
425
499
  .catch(err => failed(err));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-r/redis",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Redis client driver for E-mc.",
5
5
  "main": "client/index.js",
6
6
  "types": "client/index.d.ts",
@@ -21,8 +21,8 @@
21
21
  "license": "MIT",
22
22
  "homepage": "https://github.com/anpham6/pi-r#readme",
23
23
  "dependencies": {
24
- "@e-mc/db": "^0.8.0",
25
- "@e-mc/types": "^0.8.0",
24
+ "@e-mc/db": "^0.8.1",
25
+ "@e-mc/types": "^0.8.1",
26
26
  "redis": "^4.6.12"
27
27
  }
28
28
  }
package/types/index.d.ts CHANGED
@@ -3,11 +3,11 @@ import type { DbDataSource } from '@e-mc/types/lib/squared';
3
3
  import type { CascadeAction, ExecuteAction, ServerAuth } from '@e-mc/types/lib/db';
4
4
 
5
5
  import type { CommandOptions } from '@redis/client/dist/lib/command-options';
6
- import type { ClientCommandOptions } from '@redis/client/dist/lib/client';
6
+ import type { ClientCommandOptions, JMSetItem } from '@redis/client/dist/lib/client';
7
7
  import type { RedisClientOptions } from '@redis/client';
8
8
  import type { RedisCommandArgument } from '@redis/client/dist/lib/commands';
9
9
  import type { RedisJSON } from '@redis/json/dist/commands';
10
- import type { AggregateOptions, RediSearchSchema, SearchOptions } from 'redis';
10
+ import type { AggregateOptions, RediSearchSchema, SearchOptions, SetOptions } from 'redis';
11
11
 
12
12
  export interface RedisDataSource extends DbDataSource<string, PlainObject, ArrayOf<RedisSetValue> | ArrayOf<RedisJSONValue>, string | RedisCredential, string>, CascadeAction, AuthValue {
13
13
  source: "redis";
@@ -29,26 +29,35 @@ export interface RedisDataSource extends DbDataSource<string, PlainObject, Array
29
29
 
30
30
  export type RedisCredential = ServerAuth;
31
31
 
32
- export interface RedisSetValue<T = "HASH" | undefined, U = RedisCommandArgument, V = RedisCommandValue | RedisHSETObject> {
32
+ export interface RedisCommand<T = "HASH" | "JSON" | undefined, U = unknown, V = unknown> {
33
33
  format: T;
34
+ command?: string;
34
35
  key?: U;
35
- field?: V;
36
36
  value?: V;
37
37
  NX?: boolean;
38
38
  XX?: boolean;
39
- EX?: number;
40
- PX?: number;
41
- EXAT?: number;
42
- PXAT?: number;
43
39
  options?: {
44
- set?: PlainObject;
40
+ set?: SetOptions;
45
41
  expire?: { [K in RedisExpireCondition]?: boolean; };
46
42
  command?: RedisCommandOptions;
47
43
  };
48
44
  }
49
45
 
50
- export interface RedisJSONValue extends Omit<RedisSetValue<"JSON", string, RedisJSON>, "field" | "EX" | "PX" | "EXAT" | "PXAT"> {
46
+ export interface RedisSetValue extends RedisCommand<"HASH", RedisCommandArgument, RedisCommandValue | RedisHSETObject> {
47
+ field?: RedisCommandValue | RedisHSETObject;
48
+ EX?: number;
49
+ PX?: number;
50
+ EXAT?: number;
51
+ PXAT?: number;
52
+ KEEPTTL?: boolean;
53
+ }
54
+
55
+ export interface RedisJSONValue extends RedisCommand<"JSON", string, ArrayOf<RedisJSON>> {
56
+ command?: RedisCommandJSON;
51
57
  path?: string;
58
+ start?: NumString;
59
+ stop?: NumString;
60
+ index?: NumString;
52
61
  }
53
62
 
54
63
  export interface RedisQuery {
@@ -58,7 +67,14 @@ export interface RedisQuery {
58
67
  options?: PlainObject;
59
68
  }
60
69
 
70
+ export interface JsonMSetItem {
71
+ key: RedisCommandArgument;
72
+ path: RedisCommandArgument;
73
+ value: RedisJSON;
74
+ }
75
+
61
76
  export type RedisFormat = "HASH" | "JSON";
77
+ export type RedisCommandJSON = "ARRAPPEND" | "ARRINDEX" | "ARRINSERT" | "ARRPOP" | "ARRTRIM" | "DEL" | "FORGET" | "MERGE" | "MSET" | "NUMINCRBY" | "NUMMULTBY" | "SET" | "STRAPPEND";
62
78
  export type RedisExpireCondition = "NX" | "XX" | "GT" | "LT";
63
79
  export type RedisCommandValue = RedisCommandArgument | number;
64
80
  export type RedisCommandOptions = CommandOptions<ClientCommandOptions>;