@maiyunnet/kebab 7.4.1 → 7.5.0

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.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * --- 本文件用来定义每个目录实体地址的常量 ---
6
6
  */
7
7
  /** --- 当前系统版本号 --- */
8
- export declare const VER = "7.4.1";
8
+ export declare const VER = "7.5.0";
9
9
  /** --- 框架根目录,以 / 结尾 --- */
10
10
  export declare const ROOT_PATH: string;
11
11
  export declare const LIB_PATH: string;
package/index.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * --- 本文件用来定义每个目录实体地址的常量 ---
7
7
  */
8
8
  /** --- 当前系统版本号 --- */
9
- export const VER = '7.4.1';
9
+ export const VER = '7.5.0';
10
10
  // --- 服务端用的路径 ---
11
11
  const imu = decodeURIComponent(import.meta.url).replace('file://', '').replace(/^\/(\w:)/, '$1');
12
12
  /** --- /xxx/xxx --- */
package/lib/sql.d.ts CHANGED
@@ -10,6 +10,19 @@ export declare enum ESERVICE {
10
10
  'MYSQL' = 0,
11
11
  'PGSQL' = 1
12
12
  }
13
+ /** --- JSON 查询操作符 --- */
14
+ export declare enum EJSON {
15
+ /** --- 包含 (MySQL: JSON_CONTAINS, PG: @>) --- */
16
+ 'CONTAINS' = "json",
17
+ /** --- 被包含 (MySQL: JSON_CONTAINS, PG: <@) --- */
18
+ 'CONTAINED_BY' = "json_in",
19
+ /** --- 存在 Key (MySQL: JSON_CONTAINS_PATH one, PG: ?) --- */
20
+ 'HAS_KEY' = "json_key",
21
+ /** --- 存在任意 Key (MySQL: JSON_CONTAINS_PATH one, PG: ?|) --- */
22
+ 'HAS_ANY_KEYS' = "json_any",
23
+ /** --- 存在所有 Key (MySQL: JSON_CONTAINS_PATH all, PG: ?&) --- */
24
+ 'HAS_ALL_KEYS' = "json_all"
25
+ }
13
26
  export declare class Sql {
14
27
  /** --- ctr 对象 --- */
15
28
  private readonly _ctr?;
@@ -145,6 +158,7 @@ export declare class Sql {
145
158
  * --- 5. '$or': [{'city': 'bj'}, {'city': 'sh'}, [['age', '>', '10']]], 'type': '2' ---
146
159
  * --- 6. 'city_in': column('city_out') ---
147
160
  * --- 7. ['JSON_CONTAINS(`uid`, ?)', ['hello']] ---
161
+ * --- 8. ['info', 'json', {'a': 1}] ---
148
162
  * @param s 筛选数据
149
163
  */
150
164
  where(s: string | kebab.Json): this;
package/lib/sql.js CHANGED
@@ -8,6 +8,20 @@ export var ESERVICE;
8
8
  ESERVICE[ESERVICE["MYSQL"] = 0] = "MYSQL";
9
9
  ESERVICE[ESERVICE["PGSQL"] = 1] = "PGSQL";
10
10
  })(ESERVICE || (ESERVICE = {}));
11
+ /** --- JSON 查询操作符 --- */
12
+ export var EJSON;
13
+ (function (EJSON) {
14
+ /** --- 包含 (MySQL: JSON_CONTAINS, PG: @>) --- */
15
+ EJSON["CONTAINS"] = "json";
16
+ /** --- 被包含 (MySQL: JSON_CONTAINS, PG: <@) --- */
17
+ EJSON["CONTAINED_BY"] = "json_in";
18
+ /** --- 存在 Key (MySQL: JSON_CONTAINS_PATH one, PG: ?) --- */
19
+ EJSON["HAS_KEY"] = "json_key";
20
+ /** --- 存在任意 Key (MySQL: JSON_CONTAINS_PATH one, PG: ?|) --- */
21
+ EJSON["HAS_ANY_KEYS"] = "json_any";
22
+ /** --- 存在所有 Key (MySQL: JSON_CONTAINS_PATH all, PG: ?&) --- */
23
+ EJSON["HAS_ALL_KEYS"] = "json_all";
24
+ })(EJSON || (EJSON = {}));
11
25
  /** --- field 用 token --- */
12
26
  let columnToken = '';
13
27
  export class Sql {
@@ -388,6 +402,7 @@ export class Sql {
388
402
  * --- 5. '$or': [{'city': 'bj'}, {'city': 'sh'}, [['age', '>', '10']]], 'type': '2' ---
389
403
  * --- 6. 'city_in': column('city_out') ---
390
404
  * --- 7. ['JSON_CONTAINS(`uid`, ?)', ['hello']] ---
405
+ * --- 8. ['info', 'json', {'a': 1}] ---
391
406
  * @param s 筛选数据
392
407
  */
393
408
  where(s) {
@@ -437,6 +452,55 @@ export class Sql {
437
452
  data.push(...v[1]);
438
453
  }
439
454
  }
455
+ else if (typeof v[1] === 'string' && ['json', 'json_in', 'json_key', 'json_any', 'json_all'].includes(v[1].toLowerCase())) {
456
+ // --- json ---
457
+ const op = v[1].toLowerCase();
458
+ const nv = v[2];
459
+ if (op === 'json') {
460
+ if (this._service === ESERVICE.MYSQL) {
461
+ sql += `JSON_CONTAINS(${this.field(v[0])}, ${this._placeholder()}) AND `;
462
+ data.push(lText.stringifyJson(nv));
463
+ }
464
+ else {
465
+ sql += `${this.field(v[0])} @> ${this._placeholder()} AND `;
466
+ data.push(lText.stringifyJson(nv));
467
+ }
468
+ }
469
+ else if (op === 'json_in') {
470
+ if (this._service === ESERVICE.MYSQL) {
471
+ sql += `JSON_CONTAINS(${this._placeholder()}, ${this.field(v[0])}) AND `;
472
+ data.push(lText.stringifyJson(nv));
473
+ }
474
+ else {
475
+ sql += `${this.field(v[0])} <@ ${this._placeholder()} AND `;
476
+ data.push(lText.stringifyJson(nv));
477
+ }
478
+ }
479
+ else {
480
+ // --- json_key, json_any, json_all ---
481
+ const keys = Array.isArray(nv) ? nv : [nv];
482
+ if (this._service === ESERVICE.MYSQL) {
483
+ const type = op === 'json_all' ? 'all' : 'one';
484
+ let pathSql = '';
485
+ for (const k of keys) {
486
+ pathSql += ', ' + this._placeholder();
487
+ data.push(k.startsWith('$') ? k : `$.${k}`);
488
+ }
489
+ sql += `JSON_CONTAINS_PATH(${this.field(v[0])}, '${type}'${pathSql}) AND `;
490
+ }
491
+ else {
492
+ if (op === 'json_key' && keys.length === 1) {
493
+ sql += `${this.field(v[0])} ? ${this._placeholder()} AND `;
494
+ data.push(keys[0]);
495
+ }
496
+ else {
497
+ const pgOp = op === 'json_all' ? '?&' : '?|';
498
+ sql += `${this.field(v[0])} ${pgOp} ${this._placeholder()} AND `;
499
+ data.push(keys);
500
+ }
501
+ }
502
+ }
503
+ }
440
504
  else if (v[2] === null) {
441
505
  // --- 3: null ---
442
506
  let opera = v[1];
@@ -994,6 +1058,15 @@ export function format(sql, data, service = ESERVICE.MYSQL) {
994
1058
  if (val instanceof Buffer) {
995
1059
  return `'\\x${val.toString('hex')}'`;
996
1060
  }
1061
+ if (Array.isArray(val)) {
1062
+ // --- PGSQL Array ---
1063
+ return `ARRAY[${val.map(v => {
1064
+ if (typeof v === 'string') {
1065
+ return `'${v.replace(/'/g, "''")}'`;
1066
+ }
1067
+ return v;
1068
+ }).join(', ')}]`;
1069
+ }
997
1070
  return `'${lText.stringifyJson(val).replace(/'/g, "''")}'`;
998
1071
  });
999
1072
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maiyunnet/kebab",
3
- "version": "7.4.1",
3
+ "version": "7.5.0",
4
4
  "description": "Simple, easy-to-use, and fully-featured Node.js framework that is ready-to-use out of the box.",
5
5
  "type": "module",
6
6
  "keywords": [
package/sys/ctr.js CHANGED
@@ -84,6 +84,11 @@ export class Ctr {
84
84
  if (!this._timer) {
85
85
  return;
86
86
  }
87
+ if (this._res.headersSent) {
88
+ // --- 已经开始输出的,不能设置 timeout ---
89
+ lCore.debug('[CTR][TIMEOUT][SET] headersSent is true, can not set timeout');
90
+ return;
91
+ }
87
92
  this._timer.timeout = num;
88
93
  clearTimeout(this._timer.timer);
89
94
  this._timer.timer = setTimeout(this._timer.callback, num);
@@ -187,6 +187,7 @@ export default class extends sCtr.Ctr {
187
187
  `<br><a href="${this._config.const.urlBase}test/sql?type=upsert">View "test/sql?type=upsert"</a> <a href="${this._config.const.urlBase}test/sql?type=upsert&s=pgsql">pgsql</a>`,
188
188
  `<br><a href="${this._config.const.urlBase}test/sql?type=delete">View "test/sql?type=delete"</a> <a href="${this._config.const.urlBase}test/sql?type=delete&s=pgsql">pgsql</a>`,
189
189
  `<br><a href="${this._config.const.urlBase}test/sql?type=where">View "test/sql?type=where"</a> <a href="${this._config.const.urlBase}test/sql?type=where&s=pgsql">pgsql</a>`,
190
+ `<br><a href="${this._config.const.urlBase}test/sql?type=json">View "test/sql?type=json"</a> <a href="${this._config.const.urlBase}test/sql?type=json&s=pgsql">pgsql</a>`,
190
191
  `<br><a href="${this._config.const.urlBase}test/sql?type=having">View "test/sql?type=having"</a> <a href="${this._config.const.urlBase}test/sql?type=having&s=pgsql">pgsql</a>`,
191
192
  `<br><a href="${this._config.const.urlBase}test/sql?type=by">View "test/sql?type=by"</a> <a href="${this._config.const.urlBase}test/sql?type=by&s=pgsql">pgsql</a>`,
192
193
  `<br><a href="${this._config.const.urlBase}test/sql?type=field">View "test/sql?type=field"</a> <a href="${this._config.const.urlBase}test/sql?type=field&s=pgsql">pgsql</a>`,
@@ -2561,6 +2562,44 @@ Result:<pre id="result">Nothing.</pre>`);
2561
2562
  echo.push(`<pre>sql.delete('user').where({ 'id': '1' });</pre>
2562
2563
  <b>getSql() :</b> ${s}<br>
2563
2564
  <b>getData():</b> <pre>${JSON.stringify(sd, undefined, 4)}</pre>
2565
+ <b>format() :</b> ${sql.format(s, sd)}`);
2566
+ break;
2567
+ }
2568
+ case 'json': {
2569
+ // --- json contains ---
2570
+ let s = sql.select('*', 'user').where([['info', lSql.EJSON.CONTAINS, { 'a': 1 }]]).getSql();
2571
+ let sd = sql.getData();
2572
+ echo.push(`<pre>sql.select('*', 'user').where([['info', lSql.EJSON.CONTAINS, { 'a': 1 }]]);</pre>
2573
+ <b>getSql() :</b> ${s}<br>
2574
+ <b>getData():</b> <pre>${JSON.stringify(sd, undefined, 4)}</pre>
2575
+ <b>format() :</b> ${sql.format(s, sd)}<hr>`);
2576
+ // --- json contained by ---
2577
+ s = sql.select('*', 'user').where([['info', lSql.EJSON.CONTAINED_BY, { 'a': 1, 'b': 2 }]]).getSql();
2578
+ sd = sql.getData();
2579
+ echo.push(`<pre>sql.select('*', 'user').where([['info', lSql.EJSON.CONTAINED_BY, { 'a': 1, 'b': 2 }]]);</pre>
2580
+ <b>getSql() :</b> ${s}<br>
2581
+ <b>getData():</b> <pre>${JSON.stringify(sd, undefined, 4)}</pre>
2582
+ <b>format() :</b> ${sql.format(s, sd)}<hr>`);
2583
+ // --- json key exists ---
2584
+ s = sql.select('*', 'user').where([['info', lSql.EJSON.HAS_KEY, 'age']]).getSql();
2585
+ sd = sql.getData();
2586
+ echo.push(`<pre>sql.select('*', 'user').where([['info', lSql.EJSON.HAS_KEY, 'age']]);</pre>
2587
+ <b>getSql() :</b> ${s}<br>
2588
+ <b>getData():</b> <pre>${JSON.stringify(sd, undefined, 4)}</pre>
2589
+ <b>format() :</b> ${sql.format(s, sd)}<hr>`);
2590
+ // --- json any key exists ---
2591
+ s = sql.select('*', 'user').where([['info', lSql.EJSON.HAS_ANY_KEYS, ['age', 'name']]]).getSql();
2592
+ sd = sql.getData();
2593
+ echo.push(`<pre>sql.select('*', 'user').where([['info', lSql.EJSON.HAS_ANY_KEYS, ['age', 'name']]]);</pre>
2594
+ <b>getSql() :</b> ${s}<br>
2595
+ <b>getData():</b> <pre>${JSON.stringify(sd, undefined, 4)}</pre>
2596
+ <b>format() :</b> ${sql.format(s, sd)}<hr>`);
2597
+ // --- json all keys exist ---
2598
+ s = sql.select('*', 'user').where([['info', lSql.EJSON.HAS_ALL_KEYS, ['age', 'name']]]).getSql();
2599
+ sd = sql.getData();
2600
+ echo.push(`<pre>sql.select('*', 'user').where([['info', lSql.EJSON.HAS_ALL_KEYS, ['age', 'name']]]);</pre>
2601
+ <b>getSql() :</b> ${s}<br>
2602
+ <b>getData():</b> <pre>${JSON.stringify(sd, undefined, 4)}</pre>
2564
2603
  <b>format() :</b> ${sql.format(s, sd)}`);
2565
2604
  break;
2566
2605
  }
@@ -2648,6 +2687,16 @@ Result:<pre id="result">Nothing.</pre>`);
2648
2687
  echo.push(`<pre>sql.select('*', 'user').where([{ 'city': 'la', 'area': null }, ['age', '>', '10'], ['soft', '<>', null], ['ware', 'IS', null]]);</pre>
2649
2688
  <b>getSql() :</b> ${s}<br>
2650
2689
  <b>getData():</b> <pre>${JSON.stringify(sd, undefined, 4)}</pre>
2690
+ <b>format() :</b> ${sql.format(s, sd)}<hr>`);
2691
+ s = sql.select('*', 'user').where([
2692
+ ['info', 'json', { 'a': 1 }]
2693
+ ]).getSql();
2694
+ sd = sql.getData();
2695
+ echo.push(`<pre>sql.select('*', 'user').where([
2696
+ ['info', 'json', { 'a': 1 }]
2697
+ ]);</pre>
2698
+ <b>getSql() :</b> ${s}<br>
2699
+ <b>getData():</b> <pre>${JSON.stringify(sd, undefined, 4)}</pre>
2651
2700
  <b>format() :</b> ${sql.format(s, sd)}`);
2652
2701
  break;
2653
2702
  }