@maiyunnet/kebab 4.0.2 → 5.0.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/lib/sql.js CHANGED
@@ -4,7 +4,13 @@ import * as lCore from '#kebab/lib/core.js';
4
4
  import * as mysql2 from 'mysql2/promise';
5
5
  // --- 库和定义 ---
6
6
  import * as ctr from '#kebab/sys/ctr.js';
7
- /** --- filed 用 token --- */
7
+ /** --- 服务商定义 --- */
8
+ export var ESERVICE;
9
+ (function (ESERVICE) {
10
+ ESERVICE[ESERVICE["MYSQL"] = 0] = "MYSQL";
11
+ ESERVICE[ESERVICE["PGSQL"] = 1] = "PGSQL";
12
+ })(ESERVICE || (ESERVICE = {}));
13
+ /** --- field 用 token --- */
8
14
  let columnToken = '';
9
15
  export class Sql {
10
16
  // --- 实例化 ---
@@ -15,9 +21,14 @@ export class Sql {
15
21
  this._sql = [];
16
22
  /** --- 所有 data 数据 --- */
17
23
  this._data = [];
24
+ /** --- 表别名列表 --- */
25
+ this._alias = [];
26
+ /** --- PostgreSQL 占位符计数器 --- */
27
+ this._placeholder = 1;
18
28
  /** --- where 的 data 的开始处和结束处 --- */
19
29
  this._whereDataPosition = [0, 0];
20
30
  this._pre = pre ?? '';
31
+ this._service = opt.service ?? ESERVICE.MYSQL;
21
32
  if (opt.data) {
22
33
  this._data = opt.data;
23
34
  }
@@ -32,20 +43,12 @@ export class Sql {
32
43
  */
33
44
  insert(table) {
34
45
  this._data = [];
46
+ this._placeholder = 1;
47
+ this._alias.length = 0;
35
48
  const sql = 'INSERT INTO ' + this.field(table, this._pre);
36
49
  this._sql = [sql];
37
50
  return this;
38
51
  }
39
- /**
40
- * --- 替换已经存在的唯一索引数据,不存在则插入 ---
41
- * @param table 表名
42
- */
43
- replace(table) {
44
- this._data = [];
45
- const sql = 'REPLACE INTO ' + this.field(table, this._pre);
46
- this._sql = [sql];
47
- return this;
48
- }
49
52
  /**
50
53
  * --- 实际插入数据的数据 ---
51
54
  * @param cs [] 数据列或字段列
@@ -78,48 +81,64 @@ export class Sql {
78
81
  sql += 'NULL, ';
79
82
  }
80
83
  else if (typeof v1 === 'string' || typeof v1 === 'number') {
81
- sql += '?, ';
84
+ sql += this.placeholder() + ', ';
82
85
  this._data.push(v1);
83
86
  }
84
87
  else if (Array.isArray(v1)) {
85
- if (v1[0]?.[0]?.x === undefined && typeof v1[0] === 'string' &&
88
+ if (v1[0]?.x === undefined && typeof v1[0] === 'string' &&
86
89
  v1[0].includes('(') && v1[0].includes(')')) {
87
90
  // --- v1: ['POINT(?)', ['20']] ---
88
- sql += this.field(v1[0]) + ', ';
91
+ sql += this.field(v1[0].replace(/\?/g, () => this.placeholder())) + ', ';
89
92
  if (v1[1]) {
90
93
  this._data.push(...v1[1]);
91
94
  }
92
95
  }
93
- else if (v1[0]?.[0]?.y !== undefined) {
94
- // --- v1: [[{'x': 1, 'y': 2}, { ... }], [{ ... }, { ... }]] ---
95
- sql += 'ST_POLYGONFROMTEXT(?), ';
96
- this._data.push(`POLYGON(${v1.map((item) => {
97
- return `(${item.map((it) => {
98
- return `${it.x} ${it.y}`;
99
- }).join(', ')})`;
100
- }).join(', ')})`);
96
+ else if (v1[0]?.y !== undefined) {
97
+ // --- v1: [{'x': 1, 'y': 2}, { ... }, { ... }, ... ]---
98
+ if (this._service === ESERVICE.MYSQL) {
99
+ // --- MYSQL ---
100
+ sql += `ST_POLYGONFROMTEXT(${this.placeholder()}), `;
101
+ this._data.push(`POLYGON((${v1.map(item => {
102
+ return `${item.x} ${item.y}`;
103
+ }).join(', ')}))`);
104
+ }
105
+ else {
106
+ // --- PGSQL ---
107
+ sql += `${this.placeholder()}, `;
108
+ this._data.push(`(${v1.map(item => {
109
+ return `(${item.x}, ${item.y})`;
110
+ }).join(', ')})`);
111
+ }
101
112
  }
102
113
  else {
103
114
  // --- v1: json ---
104
- sql += '?, ';
115
+ sql += this.placeholder() + ', ';
105
116
  this._data.push(lText.stringifyJson(v1));
106
117
  }
107
118
  }
108
119
  else if (v1.x !== undefined) {
109
120
  if (v1.y !== undefined) {
110
121
  // --- v1: {'x': 1, 'y': 2} ---
111
- sql += 'ST_POINTFROMTEXT(?), ';
112
- this._data.push(`POINT(${v1.x} ${v1.y})`);
122
+ if (this._service === ESERVICE.MYSQL) {
123
+ // --- MYSQL ---
124
+ sql += `ST_POINTFROMTEXT(${this.placeholder()}), `;
125
+ this._data.push(`POINT(${v1.x} ${v1.y})`);
126
+ }
127
+ else {
128
+ // --- PGSQL ---
129
+ sql += `${this.placeholder()}, `;
130
+ this._data.push(`(${v1.x}, ${v1.y})`);
131
+ }
113
132
  }
114
133
  else {
115
134
  // --- v1: json ---
116
- sql += '?, ';
135
+ sql += this.placeholder() + ', ';
117
136
  this._data.push(lText.stringifyJson(v1));
118
137
  }
119
138
  }
120
139
  else if (v1 instanceof Buffer) {
121
140
  // --- Buffer ---
122
- sql += '?, ';
141
+ sql += this.placeholder() + ', ';
123
142
  this._data.push(v);
124
143
  }
125
144
  else if (this._isField(v1)) {
@@ -128,7 +147,7 @@ export class Sql {
128
147
  }
129
148
  else {
130
149
  // --- json ---
131
- sql += '?, ';
150
+ sql += this.placeholder() + ', ';
132
151
  this._data.push(lText.stringifyJson(v1));
133
152
  }
134
153
  }
@@ -152,48 +171,64 @@ export class Sql {
152
171
  values += 'NULL, ';
153
172
  }
154
173
  else if (typeof v === 'string' || typeof v === 'number') {
155
- values += '?, ';
174
+ values += this.placeholder() + ', ';
156
175
  this._data.push(v);
157
176
  }
158
177
  else if (Array.isArray(v)) {
159
- if (v[0]?.[0]?.x === undefined && typeof v[0] === 'string' &&
178
+ if (v[0]?.x === undefined && typeof v[0] === 'string' &&
160
179
  v[0].includes('(') && v[0].includes(')')) {
161
180
  // --- v: ['POINT(?)', ['20']] ---
162
- values += this.field(v[0]) + ', ';
181
+ values += this.field(v[0].replace(/\?/g, () => this.placeholder())) + ', ';
163
182
  if (v[1] !== undefined) {
164
183
  this._data.push(...v[1]);
165
184
  }
166
185
  }
167
- else if (v[0]?.[0]?.y !== undefined) {
168
- // --- v: [[{'x': 1, 'y': 2}, { ... }], [{ ... }, { ... }]] ---
169
- values += 'ST_POLYGONFROMTEXT(?), ';
170
- this._data.push(`POLYGON(${v.map((item) => {
171
- return `(${item.map((it) => {
172
- return `${it.x} ${it.y}`;
173
- }).join(', ')})`;
174
- }).join(', ')})`);
186
+ else if (v[0]?.y !== undefined) {
187
+ // --- v: [{'x': 1, 'y': 2}, { ... }, { ... }, ... ]---
188
+ if (this._service === ESERVICE.MYSQL) {
189
+ // --- MYSQL ---
190
+ values += `ST_POLYGONFROMTEXT(${this.placeholder()}), `;
191
+ this._data.push(`POLYGON((${v.map(item => {
192
+ return `${item.x} ${item.y}`;
193
+ }).join(', ')}))`);
194
+ }
195
+ else {
196
+ // --- PGSQL ---
197
+ values += `${this.placeholder()}, `;
198
+ this._data.push(`(${v.map(item => {
199
+ return `(${item.x}, ${item.y})`;
200
+ }).join(', ')})`);
201
+ }
175
202
  }
176
203
  else {
177
204
  // --- v: json ---
178
- values += '?, ';
205
+ values += this.placeholder() + ', ';
179
206
  this._data.push(lText.stringifyJson(v));
180
207
  }
181
208
  }
182
209
  else if (v.x !== undefined) {
183
210
  if (v.y !== undefined) {
184
211
  // --- v: {'x': 1, 'y': 2} ---
185
- values += 'ST_POINTFROMTEXT(?), ';
186
- this._data.push(`POINT(${v.x} ${v.y})`);
212
+ if (this._service === ESERVICE.MYSQL) {
213
+ // --- MYSQL ---
214
+ values += `ST_POINTFROMTEXT(${this.placeholder()}), `;
215
+ this._data.push(`POINT(${v.x} ${v.y})`);
216
+ }
217
+ else {
218
+ // --- PGSQL ---
219
+ values += `${this.placeholder()}, `;
220
+ this._data.push(`(${v.x}, ${v.y})`);
221
+ }
187
222
  }
188
223
  else {
189
224
  // --- v: json ---
190
- values += '?, ';
225
+ values += this.placeholder() + ', ';
191
226
  this._data.push(lText.stringifyJson(v));
192
227
  }
193
228
  }
194
229
  else if (v instanceof Buffer) {
195
230
  // --- Buffer ---
196
- values += '?, ';
231
+ values += this.placeholder() + ', ';
197
232
  this._data.push(v);
198
233
  }
199
234
  else if (this._isField(v)) {
@@ -202,7 +237,7 @@ export class Sql {
202
237
  }
203
238
  else {
204
239
  // --- json ---
205
- values += '?, ';
240
+ values += this.placeholder() + ', ';
206
241
  this._data.push(lText.stringifyJson(v));
207
242
  }
208
243
  }
@@ -211,46 +246,6 @@ export class Sql {
211
246
  this._sql.push(sql);
212
247
  return this;
213
248
  }
214
- /**
215
- * --- 不存在则插入,衔接在 insert 之后 ---
216
- * @param table 表名
217
- * @param insert {'xx': 'xx', 'xx': 'xx'}
218
- * @param where [{'xx': 'xx', 'xx': 'xx'}], {'xx': 'xx'}
219
- */
220
- notExists(table, insert, where) {
221
- let sql = '(';
222
- const values = [];
223
- for (const field in insert) {
224
- const val = insert[field];
225
- sql += this.field(field) + ', ';
226
- values.push(val);
227
- }
228
- sql = sql.slice(0, -2) + ') SELECT ';
229
- for (const value of values) {
230
- if (Array.isArray(value)) {
231
- sql += value[0] + ', ';
232
- this._data.push(...value[1]);
233
- }
234
- else {
235
- sql += '?, ';
236
- this._data.push(value);
237
- }
238
- }
239
- sql = sql.slice(0, -2) + ' FROM DUAL WHERE NOT EXISTS (SELECT `id` FROM ' + this.field(table, this._pre) + ' WHERE ' + this._whereSub(where) + ')';
240
- this._sql.push(sql);
241
- return this;
242
- }
243
- /**
244
- * --- 当不能 insert 时,update(仅能配合 insert 方法用) ---
245
- * @param s 更新数据
246
- */
247
- duplicate(s) {
248
- if (Array.isArray(s) ? s.length : Object.keys(s).length) {
249
- const sql = ' ON DUPLICATE KEY UPDATE ' + this._updateSub(s);
250
- this._sql.push(sql);
251
- }
252
- return this;
253
- }
254
249
  /**
255
250
  * --- '*', 'xx' ---
256
251
  * @param c 字段字符串或字段数组
@@ -267,7 +262,7 @@ export class Sql {
267
262
  for (const i of c) {
268
263
  if (Array.isArray(i)) {
269
264
  // --- i: ['xx', ['x']] ---
270
- sql += this.field(i[0]) + ', ';
265
+ sql += this.field(i[0].replace(/\?/g, () => this.placeholder())) + ', ';
271
266
  this._data.push(...i[1]);
272
267
  }
273
268
  else {
@@ -335,10 +330,10 @@ export class Sql {
335
330
  }
336
331
  else {
337
332
  if (v[1] === '=') {
338
- sql += this.field(v[0]) + ' = ?, ';
333
+ sql += this.field(v[0]) + ' = ' + this.placeholder() + ', ';
339
334
  }
340
335
  else {
341
- sql += this.field(v[0]) + ' = ' + this.field(v[0]) + ' ' + v[1] + ' ?, ';
336
+ sql += this.field(v[0]) + ' = ' + this.field(v[0]) + ' ' + v[1] + ' ' + this.placeholder() + ', ';
342
337
  }
343
338
  this._data.push(nv);
344
339
  }
@@ -356,11 +351,11 @@ export class Sql {
356
351
  }
357
352
  else if (typeof v === 'string' || typeof v === 'number') {
358
353
  // --- 2 ---
359
- sql += '?, ';
354
+ sql += this.placeholder() + ', ';
360
355
  this._data.push(v);
361
356
  }
362
357
  else if (Array.isArray(v)) {
363
- if (v[0]?.[0]?.x === undefined && typeof v[0] === 'string' &&
358
+ if (v[0]?.x === undefined && typeof v[0] === 'string' &&
364
359
  v[0].includes('(') && v[0].includes(')')) {
365
360
  // --- 4, 5: ['(CASE `id` WHEN 1 THEN ? WHEN 2 THEN ? END)', ['val1', 'val2']] ---
366
361
  sql += this.field(v[0]) + ', ';
@@ -368,26 +363,42 @@ export class Sql {
368
363
  this._data.push(...v[1]);
369
364
  }
370
365
  }
371
- else if (v[0]?.[0]?.y !== undefined) {
366
+ else if (v[0]?.y !== undefined) {
372
367
  // --- 7 ---
373
- sql += 'ST_POLYGONFROMTEXT(?), ';
374
- this._data.push(`POLYGON(${v.map((item) => {
375
- return `(${item.map((it) => {
376
- return `${it.x} ${it.y}`;
377
- }).join(', ')})`;
378
- }).join(', ')})`);
368
+ if (this._service === ESERVICE.MYSQL) {
369
+ // --- MYSQL ---
370
+ sql += `ST_POLYGONFROMTEXT(${this.placeholder()}), `;
371
+ this._data.push(`POLYGON((${v.map(item => {
372
+ return `${item.x} ${item.y}`;
373
+ }).join(', ')}))`);
374
+ }
375
+ else {
376
+ // --- PGSQL ---
377
+ sql += `${this.placeholder()}, `;
378
+ this._data.push(`(${v.map(item => {
379
+ return `(${item.x}, ${item.y})`;
380
+ }).join(', ')})`);
381
+ }
379
382
  }
380
383
  else {
381
384
  // --- v: json ---
382
- sql += '?, ';
385
+ sql += this.placeholder() + ', ';
383
386
  this._data.push(lText.stringifyJson(v));
384
387
  }
385
388
  }
386
389
  else if (v.x !== undefined) {
387
390
  if (v.y !== undefined) {
388
391
  // --- 6: v: {'x': 1, 'y': 2} ---
389
- sql += 'ST_POINTFROMTEXT(?), ';
390
- this._data.push(`POINT(${v.x} ${v.y})`);
392
+ if (this._service === ESERVICE.MYSQL) {
393
+ // --- MYSQL ---
394
+ sql += `ST_POINTFROMTEXT(${this.placeholder()}), `;
395
+ this._data.push(`POINT(${v.x} ${v.y})`);
396
+ }
397
+ else {
398
+ // --- PGSQL ---
399
+ sql += `${this.placeholder()}, `;
400
+ this._data.push(`(${v.x}, ${v.y})`);
401
+ }
391
402
  }
392
403
  else {
393
404
  // --- v: json ---
@@ -397,14 +408,14 @@ export class Sql {
397
408
  }
398
409
  else {
399
410
  // --- 8 ---
400
- sql += '?, ';
411
+ sql += this.placeholder() + ', ';
401
412
  this._data.push(lText.stringifyJson(v));
402
413
  }
403
414
  }
404
415
  }
405
416
  else if (v instanceof Buffer) {
406
417
  // --- Buffer ---
407
- sql += '?, ';
418
+ sql += this.placeholder() + ', ';
408
419
  this._data.push(v);
409
420
  }
410
421
  else if (this._isField(v)) {
@@ -413,7 +424,7 @@ export class Sql {
413
424
  }
414
425
  else {
415
426
  // --- json ---
416
- sql += '?, ';
427
+ sql += this.placeholder() + ', ';
417
428
  this._data.push(lText.stringifyJson(v));
418
429
  }
419
430
  }
@@ -616,7 +627,7 @@ export class Sql {
616
627
  // --- 3 ---
617
628
  sql += this.field(v[0]) + ' ' + v[1].toUpperCase() + ' (';
618
629
  for (const v1 of v[2]) {
619
- sql += '?, ';
630
+ sql += this.placeholder() + ', ';
620
631
  data.push(v1);
621
632
  }
622
633
  sql = sql.slice(0, -2) + ') AND ';
@@ -630,7 +641,7 @@ export class Sql {
630
641
  sql += this.field(v[0]) + ' ' + v[1] + ' ' + this.field(nv.value) + ' AND ';
631
642
  }
632
643
  else {
633
- sql += this.field(v[0]) + ' ' + v[1] + ' ? AND ';
644
+ sql += this.field(v[0]) + ' ' + v[1] + ' ' + this.placeholder() + ' AND ';
634
645
  data.push(nv);
635
646
  }
636
647
  }
@@ -660,7 +671,7 @@ export class Sql {
660
671
  }
661
672
  else if (typeof v === 'string' || typeof v === 'number') {
662
673
  // --- 1 ---
663
- sql += this.field(k) + ' = ? AND ';
674
+ sql += this.field(k) + ' = ' + this.placeholder() + ' AND ';
664
675
  data.push(v);
665
676
  }
666
677
  else if (this._isField(v)) {
@@ -672,7 +683,7 @@ export class Sql {
672
683
  if (v.length > 0) {
673
684
  sql += this.field(k) + ' IN (';
674
685
  for (const v1 of v) {
675
- sql += '?, ';
686
+ sql += this.placeholder() + ', ';
676
687
  data.push(v1);
677
688
  }
678
689
  sql = sql.slice(0, -2) + ') AND ';
@@ -732,12 +743,19 @@ export class Sql {
732
743
  return this;
733
744
  }
734
745
  /**
735
- * --- LIMIT ---
736
- * @param a 起始
737
- * @param b 长度
746
+ * --- LIMIT(limit、offset, limit) ---
747
+ * @param a 起始(offset)
748
+ * @param b 长度(limit)
738
749
  */
739
750
  limit(a, b = 0) {
740
- this._sql.push(' LIMIT ' + a.toString() + (b > 0 ? ', ' + b.toString() : ''));
751
+ if (b) {
752
+ // --- offset, limit ---
753
+ this._sql.push(` LIMIT ${b} OFFSET ${a}`);
754
+ }
755
+ else {
756
+ // --- limit ---
757
+ this._sql.push(` LIMIT ${a}`);
758
+ }
741
759
  return this;
742
760
  }
743
761
  /**
@@ -816,7 +834,7 @@ export class Sql {
816
834
  }
817
835
  return get(this.getPre(), {
818
836
  'data': data,
819
- 'sql': sql
837
+ 'sql': sql,
820
838
  });
821
839
  }
822
840
  // --- 操作 ---
@@ -824,7 +842,16 @@ export class Sql {
824
842
  * --- 获取 sql 语句 ---
825
843
  */
826
844
  getSql() {
827
- return this._sql.join('');
845
+ let sql = this._sql.join('');
846
+ if (this._pre) {
847
+ return this._alias.reduce((result, item) => {
848
+ if (this._service === ESERVICE.MYSQL) {
849
+ return result.replace(new RegExp('`' + this._pre + item + '`', 'g'), '`' + item + '`');
850
+ }
851
+ return result.replace(new RegExp(`"${this._pre}"."${item}"`, 'g'), '"' + item + '"');
852
+ }, sql);
853
+ }
854
+ return sql;
828
855
  }
829
856
  /**
830
857
  * --- 获取全部 data ---
@@ -844,7 +871,7 @@ export class Sql {
844
871
  * @param data
845
872
  */
846
873
  format(sql, data) {
847
- return mysql2.format(sql ?? this.getSql(), data ?? this.getData());
874
+ return format(sql ?? this.getSql(), data ?? this.getData(), this._service);
848
875
  }
849
876
  // --- 特殊方法 ---
850
877
  /**
@@ -855,15 +882,20 @@ export class Sql {
855
882
  this._sql.push(sql);
856
883
  return this;
857
884
  }
885
+ /** --- 获取占位符 --- */
886
+ placeholder() {
887
+ return this._service === ESERVICE.MYSQL ? '?' : `$${this._placeholder++}`;
888
+ }
858
889
  /**
859
890
  * --- 对字段进行包裹 ---
860
891
  * @param str
861
892
  * @param pre 表前缀,仅请在 field 表名时倒入前缀
862
- * @param suf 表后缀,仅请在 field 表名时倒入后缀,前面加 # 代表要强制 AS
893
+ * @param suf 表后缀,仅请在 field 表名时倒入后缀,前面加 # 代表要强制 AS,可能是分表查询时用
863
894
  */
864
895
  field(str, pre = '', suf = '') {
865
896
  let left = '';
866
897
  let right = '';
898
+ const q = this._service === ESERVICE.MYSQL ? '`' : '"';
867
899
  if (Array.isArray(str)) {
868
900
  this._data.push(...str[1]);
869
901
  return this.field(str[0]);
@@ -896,7 +928,7 @@ export class Sql {
896
928
  }
897
929
  if (spacePos !== -1) {
898
930
  const spaceRight = str.slice(spacePos + 1);
899
- if (/^[a-zA-Z_`][\w`]*$/.test(spaceRight)) {
931
+ if (/^[a-zA-Z_`"][\w`"]*$/.test(spaceRight)) {
900
932
  // --- OK ---
901
933
  left = str.slice(0, spacePos);
902
934
  right = spaceRight;
@@ -918,46 +950,87 @@ export class Sql {
918
950
  }
919
951
  if (right) {
920
952
  // --- 处理右侧 ---
921
- if (right.startsWith('`')) {
922
- right = '`' + pre + right.slice(1);
953
+ if (this._service === ESERVICE.MYSQL) {
954
+ if (right.startsWith('`')) {
955
+ if (!left.includes('.')) {
956
+ // --- 存储表别名 ---
957
+ this._alias.push(right.slice(1, -1));
958
+ }
959
+ right = '`' + pre + right.slice(1);
960
+ }
961
+ else {
962
+ if (!left.includes('.')) {
963
+ // --- 存储表别名 ---
964
+ this._alias.push(right);
965
+ }
966
+ right = '`' + pre + right + '`';
967
+ }
968
+ right = ' AS ' + right;
923
969
  }
924
970
  else {
925
- right = '`' + pre + right + '`';
971
+ if (right.startsWith('"')) {
972
+ if (!left.includes('.')) {
973
+ // --- 存储表别名 ---
974
+ this._alias.push(right.slice(1, -1));
975
+ }
976
+ if (pre) {
977
+ right = `"${pre}".${right}`;
978
+ }
979
+ }
980
+ else {
981
+ if (!left.includes('.')) {
982
+ // --- 存储表别名 ---
983
+ this._alias.push(right);
984
+ }
985
+ right = (pre ? `"${pre}".` : '') + `"${right}"`;
986
+ }
987
+ right = ' AS ' + right;
926
988
  }
927
- right = ' AS ' + right;
928
989
  }
929
990
  else {
930
991
  // --- 没有右侧 ---
931
992
  if (sufAs) {
932
993
  // --- 强制 AS ---
994
+ if (!left.includes('.')) {
995
+ // --- 存储表别名 ---
996
+ this._alias.push(left.startsWith('`') || left.startsWith('"') ? left.slice(1, -1) : left);
997
+ }
933
998
  right = ' AS ' + this.field(left, pre);
934
999
  }
935
1000
  }
936
1001
  // --- 处理 left ---
937
- if (/^[\w`_.*]+$/.test(left)) {
1002
+ if (/^[\w`"_.*]+$/.test(left)) {
938
1003
  const l = left.split('.');
939
1004
  if (l[0] === '*') {
940
1005
  return '*' + right;
941
1006
  }
942
- if (l[0].startsWith('`')) {
943
- l[0] = l[0].replace(/`/g, '');
1007
+ if (l[0].startsWith('`') || l[0].startsWith(`"`)) {
1008
+ l[0] = l[0].replace(/[`"]/g, '');
944
1009
  }
945
1010
  if (l[1] === undefined) {
946
1011
  // --- xxx ---
947
1012
  if (/^[A-Z0-9_]+$/.test(l[0])) {
948
- // --- 纯大写是内置函数,不能加 ` ---
1013
+ // --- 纯大写是内置函数,不能加 `" ---
949
1014
  return l[0] + right;
950
1015
  }
951
- return '`' + pre + l[0] + suf + '`' + right;
1016
+ return this._service === ESERVICE.MYSQL ?
1017
+ '`' + pre + l[0] + suf + '`' + right :
1018
+ (pre ? `"${pre}".` : '') + '"' + l[0] + suf + '"' + right;
952
1019
  }
953
1020
  // --- x.xxx ---
954
1021
  // --- 只有在此模式才知道 . 前面的一定是表名,因此自动加 sql 级的 _pre ---
955
- const w = l[1] === '*' ? '*' : (l[1].startsWith('`') ? l[1] : ('`' + l[1] + '`'));
956
- return '`' + this._pre + l[0] + suf + '`.' + w + right;
1022
+ const w = l[1] === '*'
1023
+ ? '*' :
1024
+ (q + ((l[1].startsWith('`') || l[1].startsWith('"')) ?
1025
+ l[1].slice(1, -1) :
1026
+ l[1]) + q);
1027
+ return this._service === ESERVICE.MYSQL ?
1028
+ '`' + this._pre + l[0] + suf + '`.' + w + right :
1029
+ (this._pre ? `"${this._pre}".` : '') + '"' + l[0] + suf + '".' + w + right;
957
1030
  }
958
1031
  else {
959
- // return left.replace(/([(, ])([a-zA-Z`_][\w`_.]*)(?=[), ])/g, (
960
- return left.replace(/(^|[(, ])([a-zA-Z`_][\w`_.]*)(?=[), ]|$)/g, (t, t1, t2) => {
1032
+ // return left.replace(/([(, ])([a-zA-Z`"_][\w`"_.]*)(?=[), ])/g, (
1033
+ return left.replace(/(^|[(, ])([a-zA-Z`"_][\w`"_.]*)(?=[), ]|$)/g, (t, t1, t2) => {
961
1034
  return t1 + this.field(t2, pre, suf);
962
1035
  }) + right;
963
1036
  }
@@ -982,12 +1055,34 @@ export function get(ctrPre, opt = {}) {
982
1055
  return new Sql(ctrPre instanceof ctr.Ctr ? ctrPre.getPrototype('_config').sql.pre : ctrPre, opt);
983
1056
  }
984
1057
  /**
985
- * --- 返回代入后的完整 SQL 字符串 ---
1058
+ * --- 返回代入后的完整 SQL 字符串,这并不安全不能直接执行,只是用来调试打印 sql 语句 ---
986
1059
  * @param sql SQL 字符串
987
1060
  * @param data DATA 数据
1061
+ * @param service 服务商,默认 MySQL
988
1062
  */
989
- export function format(sql, data) {
990
- return mysql2.format(sql, data);
1063
+ export function format(sql, data, service = ESERVICE.MYSQL) {
1064
+ if (service === ESERVICE.MYSQL) {
1065
+ return mysql2.format(sql, data);
1066
+ }
1067
+ // --- PGSQL ---
1068
+ // --- PostgreSQL 手动替换占位符 ---
1069
+ let index = 0;
1070
+ return sql.replace(/\$\d+/g, () => {
1071
+ const val = data[index++];
1072
+ if (val === null) {
1073
+ return 'NULL';
1074
+ }
1075
+ if (typeof val === 'string') {
1076
+ return `'${lText.stringifyJson(val).slice(1, -1).replace(/'/g, "''").replace(/\\"/g, '"')}'`;
1077
+ }
1078
+ if (typeof val === 'number') {
1079
+ return val.toString();
1080
+ }
1081
+ if (val instanceof Buffer) {
1082
+ return `'\\x${val.toString('hex')}'`;
1083
+ }
1084
+ return `'${JSON.stringify(val).replace(/'/g, "''")}'`;
1085
+ });
991
1086
  }
992
1087
  /**
993
1088
  * --- 将数组兑换为组合的对象(Array/Object mix) ---
package/lib/time.d.ts CHANGED
@@ -70,6 +70,6 @@ export declare function isMs(time: number): boolean;
70
70
  * --- 将时间对象转换为时间字符串 ---
71
71
  * @param zone 时区小时或 ctr 对象,如 8,设置 null 则以系统时区为准
72
72
  * @param f 转换格式
73
- * @param date 时间对象或秒/毫秒级数字,如果是秒请乘以 1000
73
+ * @param date 时间对象秒/毫秒级数字均可
74
74
  */
75
75
  export declare function format(zone: number | sCtr.Ctr | null, f: string, date?: Date | number): string;