@maiyunnet/kebab 4.1.0 → 5.0.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/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 字段字符串或字段数组
@@ -258,6 +253,7 @@ export class Sql {
258
253
  */
259
254
  select(c, f) {
260
255
  this._data = [];
256
+ this._placeholder = 1;
261
257
  let sql = 'SELECT ';
262
258
  if (typeof c === 'string') {
263
259
  sql += this.field(c);
@@ -267,7 +263,7 @@ export class Sql {
267
263
  for (const i of c) {
268
264
  if (Array.isArray(i)) {
269
265
  // --- i: ['xx', ['x']] ---
270
- sql += this.field(i[0]) + ', ';
266
+ sql += this.field(i[0].replace(/\?/g, () => this.placeholder())) + ', ';
271
267
  this._data.push(...i[1]);
272
268
  }
273
269
  else {
@@ -297,6 +293,7 @@ export class Sql {
297
293
  */
298
294
  update(f, s) {
299
295
  this._data = [];
296
+ this._placeholder = 1;
300
297
  const sql = `UPDATE ${this.field(f, this._pre)} SET ${this._updateSub(s)}`;
301
298
  this._sql = [sql];
302
299
  return this;
@@ -335,10 +332,10 @@ export class Sql {
335
332
  }
336
333
  else {
337
334
  if (v[1] === '=') {
338
- sql += this.field(v[0]) + ' = ?, ';
335
+ sql += this.field(v[0]) + ' = ' + this.placeholder() + ', ';
339
336
  }
340
337
  else {
341
- sql += this.field(v[0]) + ' = ' + this.field(v[0]) + ' ' + v[1] + ' ?, ';
338
+ sql += this.field(v[0]) + ' = ' + this.field(v[0]) + ' ' + v[1] + ' ' + this.placeholder() + ', ';
342
339
  }
343
340
  this._data.push(nv);
344
341
  }
@@ -356,11 +353,11 @@ export class Sql {
356
353
  }
357
354
  else if (typeof v === 'string' || typeof v === 'number') {
358
355
  // --- 2 ---
359
- sql += '?, ';
356
+ sql += this.placeholder() + ', ';
360
357
  this._data.push(v);
361
358
  }
362
359
  else if (Array.isArray(v)) {
363
- if (v[0]?.[0]?.x === undefined && typeof v[0] === 'string' &&
360
+ if (v[0]?.x === undefined && typeof v[0] === 'string' &&
364
361
  v[0].includes('(') && v[0].includes(')')) {
365
362
  // --- 4, 5: ['(CASE `id` WHEN 1 THEN ? WHEN 2 THEN ? END)', ['val1', 'val2']] ---
366
363
  sql += this.field(v[0]) + ', ';
@@ -368,26 +365,42 @@ export class Sql {
368
365
  this._data.push(...v[1]);
369
366
  }
370
367
  }
371
- else if (v[0]?.[0]?.y !== undefined) {
368
+ else if (v[0]?.y !== undefined) {
372
369
  // --- 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(', ')})`);
370
+ if (this._service === ESERVICE.MYSQL) {
371
+ // --- MYSQL ---
372
+ sql += `ST_POLYGONFROMTEXT(${this.placeholder()}), `;
373
+ this._data.push(`POLYGON((${v.map(item => {
374
+ return `${item.x} ${item.y}`;
375
+ }).join(', ')}))`);
376
+ }
377
+ else {
378
+ // --- PGSQL ---
379
+ sql += `${this.placeholder()}, `;
380
+ this._data.push(`(${v.map(item => {
381
+ return `(${item.x}, ${item.y})`;
382
+ }).join(', ')})`);
383
+ }
379
384
  }
380
385
  else {
381
386
  // --- v: json ---
382
- sql += '?, ';
387
+ sql += this.placeholder() + ', ';
383
388
  this._data.push(lText.stringifyJson(v));
384
389
  }
385
390
  }
386
391
  else if (v.x !== undefined) {
387
392
  if (v.y !== undefined) {
388
393
  // --- 6: v: {'x': 1, 'y': 2} ---
389
- sql += 'ST_POINTFROMTEXT(?), ';
390
- this._data.push(`POINT(${v.x} ${v.y})`);
394
+ if (this._service === ESERVICE.MYSQL) {
395
+ // --- MYSQL ---
396
+ sql += `ST_POINTFROMTEXT(${this.placeholder()}), `;
397
+ this._data.push(`POINT(${v.x} ${v.y})`);
398
+ }
399
+ else {
400
+ // --- PGSQL ---
401
+ sql += `${this.placeholder()}, `;
402
+ this._data.push(`(${v.x}, ${v.y})`);
403
+ }
391
404
  }
392
405
  else {
393
406
  // --- v: json ---
@@ -397,14 +410,14 @@ export class Sql {
397
410
  }
398
411
  else {
399
412
  // --- 8 ---
400
- sql += '?, ';
413
+ sql += this.placeholder() + ', ';
401
414
  this._data.push(lText.stringifyJson(v));
402
415
  }
403
416
  }
404
417
  }
405
418
  else if (v instanceof Buffer) {
406
419
  // --- Buffer ---
407
- sql += '?, ';
420
+ sql += this.placeholder() + ', ';
408
421
  this._data.push(v);
409
422
  }
410
423
  else if (this._isField(v)) {
@@ -413,7 +426,7 @@ export class Sql {
413
426
  }
414
427
  else {
415
428
  // --- json ---
416
- sql += '?, ';
429
+ sql += this.placeholder() + ', ';
417
430
  this._data.push(lText.stringifyJson(v));
418
431
  }
419
432
  }
@@ -427,6 +440,7 @@ export class Sql {
427
440
  */
428
441
  delete(f) {
429
442
  this._data = [];
443
+ this._placeholder = 1;
430
444
  this._sql = ['DELETE FROM ' + this.field(f, this._pre)];
431
445
  return this;
432
446
  }
@@ -616,7 +630,7 @@ export class Sql {
616
630
  // --- 3 ---
617
631
  sql += this.field(v[0]) + ' ' + v[1].toUpperCase() + ' (';
618
632
  for (const v1 of v[2]) {
619
- sql += '?, ';
633
+ sql += this.placeholder() + ', ';
620
634
  data.push(v1);
621
635
  }
622
636
  sql = sql.slice(0, -2) + ') AND ';
@@ -630,7 +644,7 @@ export class Sql {
630
644
  sql += this.field(v[0]) + ' ' + v[1] + ' ' + this.field(nv.value) + ' AND ';
631
645
  }
632
646
  else {
633
- sql += this.field(v[0]) + ' ' + v[1] + ' ? AND ';
647
+ sql += this.field(v[0]) + ' ' + v[1] + ' ' + this.placeholder() + ' AND ';
634
648
  data.push(nv);
635
649
  }
636
650
  }
@@ -660,7 +674,7 @@ export class Sql {
660
674
  }
661
675
  else if (typeof v === 'string' || typeof v === 'number') {
662
676
  // --- 1 ---
663
- sql += this.field(k) + ' = ? AND ';
677
+ sql += this.field(k) + ' = ' + this.placeholder() + ' AND ';
664
678
  data.push(v);
665
679
  }
666
680
  else if (this._isField(v)) {
@@ -672,7 +686,7 @@ export class Sql {
672
686
  if (v.length > 0) {
673
687
  sql += this.field(k) + ' IN (';
674
688
  for (const v1 of v) {
675
- sql += '?, ';
689
+ sql += this.placeholder() + ', ';
676
690
  data.push(v1);
677
691
  }
678
692
  sql = sql.slice(0, -2) + ') AND ';
@@ -732,12 +746,19 @@ export class Sql {
732
746
  return this;
733
747
  }
734
748
  /**
735
- * --- LIMIT ---
736
- * @param a 起始
737
- * @param b 长度
749
+ * --- LIMIT(limit、offset, limit) ---
750
+ * @param a 起始(offset)
751
+ * @param b 长度(limit)
738
752
  */
739
753
  limit(a, b = 0) {
740
- this._sql.push(' LIMIT ' + a.toString() + (b > 0 ? ', ' + b.toString() : ''));
754
+ if (b) {
755
+ // --- offset, limit ---
756
+ this._sql.push(` LIMIT ${b} OFFSET ${a}`);
757
+ }
758
+ else {
759
+ // --- limit ---
760
+ this._sql.push(` LIMIT ${a}`);
761
+ }
741
762
  return this;
742
763
  }
743
764
  /**
@@ -816,7 +837,7 @@ export class Sql {
816
837
  }
817
838
  return get(this.getPre(), {
818
839
  'data': data,
819
- 'sql': sql
840
+ 'sql': sql,
820
841
  });
821
842
  }
822
843
  // --- 操作 ---
@@ -824,7 +845,16 @@ export class Sql {
824
845
  * --- 获取 sql 语句 ---
825
846
  */
826
847
  getSql() {
827
- return this._sql.join('');
848
+ let sql = this._sql.join('');
849
+ if (this._pre) {
850
+ return this._alias.reduce((result, item) => {
851
+ if (this._service === ESERVICE.MYSQL) {
852
+ return result.replace(new RegExp('`' + this._pre + item + '`', 'g'), '`' + item + '`');
853
+ }
854
+ return result.replace(new RegExp(`"${this._pre}"."${item}"`, 'g'), '"' + item + '"');
855
+ }, sql);
856
+ }
857
+ return sql;
828
858
  }
829
859
  /**
830
860
  * --- 获取全部 data ---
@@ -844,7 +874,7 @@ export class Sql {
844
874
  * @param data
845
875
  */
846
876
  format(sql, data) {
847
- return mysql2.format(sql ?? this.getSql(), data ?? this.getData());
877
+ return format(sql ?? this.getSql(), data ?? this.getData(), this._service);
848
878
  }
849
879
  // --- 特殊方法 ---
850
880
  /**
@@ -855,15 +885,20 @@ export class Sql {
855
885
  this._sql.push(sql);
856
886
  return this;
857
887
  }
888
+ /** --- 获取占位符 --- */
889
+ placeholder() {
890
+ return this._service === ESERVICE.MYSQL ? '?' : `$${this._placeholder++}`;
891
+ }
858
892
  /**
859
893
  * --- 对字段进行包裹 ---
860
894
  * @param str
861
895
  * @param pre 表前缀,仅请在 field 表名时倒入前缀
862
- * @param suf 表后缀,仅请在 field 表名时倒入后缀,前面加 # 代表要强制 AS
896
+ * @param suf 表后缀,仅请在 field 表名时倒入后缀,前面加 # 代表要强制 AS,可能是分表查询时用
863
897
  */
864
898
  field(str, pre = '', suf = '') {
865
899
  let left = '';
866
900
  let right = '';
901
+ const q = this._service === ESERVICE.MYSQL ? '`' : '"';
867
902
  if (Array.isArray(str)) {
868
903
  this._data.push(...str[1]);
869
904
  return this.field(str[0]);
@@ -896,7 +931,7 @@ export class Sql {
896
931
  }
897
932
  if (spacePos !== -1) {
898
933
  const spaceRight = str.slice(spacePos + 1);
899
- if (/^[a-zA-Z_`][\w`]*$/.test(spaceRight)) {
934
+ if (/^[a-zA-Z_`"][\w`"]*$/.test(spaceRight)) {
900
935
  // --- OK ---
901
936
  left = str.slice(0, spacePos);
902
937
  right = spaceRight;
@@ -918,46 +953,87 @@ export class Sql {
918
953
  }
919
954
  if (right) {
920
955
  // --- 处理右侧 ---
921
- if (right.startsWith('`')) {
922
- right = '`' + pre + right.slice(1);
956
+ if (this._service === ESERVICE.MYSQL) {
957
+ if (right.startsWith('`')) {
958
+ if (!left.includes('.')) {
959
+ // --- 存储表别名 ---
960
+ this._alias.push(right.slice(1, -1));
961
+ }
962
+ right = '`' + pre + right.slice(1);
963
+ }
964
+ else {
965
+ if (!left.includes('.')) {
966
+ // --- 存储表别名 ---
967
+ this._alias.push(right);
968
+ }
969
+ right = '`' + pre + right + '`';
970
+ }
971
+ right = ' AS ' + right;
923
972
  }
924
973
  else {
925
- right = '`' + pre + right + '`';
974
+ if (right.startsWith('"')) {
975
+ if (!left.includes('.')) {
976
+ // --- 存储表别名 ---
977
+ this._alias.push(right.slice(1, -1));
978
+ }
979
+ if (pre) {
980
+ right = `"${pre}".${right}`;
981
+ }
982
+ }
983
+ else {
984
+ if (!left.includes('.')) {
985
+ // --- 存储表别名 ---
986
+ this._alias.push(right);
987
+ }
988
+ right = (pre ? `"${pre}".` : '') + `"${right}"`;
989
+ }
990
+ right = ' AS ' + right;
926
991
  }
927
- right = ' AS ' + right;
928
992
  }
929
993
  else {
930
994
  // --- 没有右侧 ---
931
995
  if (sufAs) {
932
996
  // --- 强制 AS ---
997
+ if (!left.includes('.')) {
998
+ // --- 存储表别名 ---
999
+ this._alias.push(left.startsWith('`') || left.startsWith('"') ? left.slice(1, -1) : left);
1000
+ }
933
1001
  right = ' AS ' + this.field(left, pre);
934
1002
  }
935
1003
  }
936
1004
  // --- 处理 left ---
937
- if (/^[\w`_.*]+$/.test(left)) {
1005
+ if (/^[\w`"_.*]+$/.test(left)) {
938
1006
  const l = left.split('.');
939
1007
  if (l[0] === '*') {
940
1008
  return '*' + right;
941
1009
  }
942
- if (l[0].startsWith('`')) {
943
- l[0] = l[0].replace(/`/g, '');
1010
+ if (l[0].startsWith('`') || l[0].startsWith(`"`)) {
1011
+ l[0] = l[0].replace(/[`"]/g, '');
944
1012
  }
945
1013
  if (l[1] === undefined) {
946
1014
  // --- xxx ---
947
1015
  if (/^[A-Z0-9_]+$/.test(l[0])) {
948
- // --- 纯大写是内置函数,不能加 ` ---
1016
+ // --- 纯大写是内置函数,不能加 `" ---
949
1017
  return l[0] + right;
950
1018
  }
951
- return '`' + pre + l[0] + suf + '`' + right;
1019
+ return this._service === ESERVICE.MYSQL ?
1020
+ '`' + pre + l[0] + suf + '`' + right :
1021
+ (pre ? `"${pre}".` : '') + '"' + l[0] + suf + '"' + right;
952
1022
  }
953
1023
  // --- x.xxx ---
954
1024
  // --- 只有在此模式才知道 . 前面的一定是表名,因此自动加 sql 级的 _pre ---
955
- const w = l[1] === '*' ? '*' : (l[1].startsWith('`') ? l[1] : ('`' + l[1] + '`'));
956
- return '`' + this._pre + l[0] + suf + '`.' + w + right;
1025
+ const w = l[1] === '*'
1026
+ ? '*' :
1027
+ (q + ((l[1].startsWith('`') || l[1].startsWith('"')) ?
1028
+ l[1].slice(1, -1) :
1029
+ l[1]) + q);
1030
+ return this._service === ESERVICE.MYSQL ?
1031
+ '`' + this._pre + l[0] + suf + '`.' + w + right :
1032
+ (this._pre ? `"${this._pre}".` : '') + '"' + l[0] + suf + '".' + w + right;
957
1033
  }
958
1034
  else {
959
- // return left.replace(/([(, ])([a-zA-Z`_][\w`_.]*)(?=[), ])/g, (
960
- return left.replace(/(^|[(, ])([a-zA-Z`_][\w`_.]*)(?=[), ]|$)/g, (t, t1, t2) => {
1035
+ // return left.replace(/([(, ])([a-zA-Z`"_][\w`"_.]*)(?=[), ])/g, (
1036
+ return left.replace(/(^|[(, ])([a-zA-Z`"_][\w`"_.]*)(?=[), ]|$)/g, (t, t1, t2) => {
961
1037
  return t1 + this.field(t2, pre, suf);
962
1038
  }) + right;
963
1039
  }
@@ -982,12 +1058,34 @@ export function get(ctrPre, opt = {}) {
982
1058
  return new Sql(ctrPre instanceof ctr.Ctr ? ctrPre.getPrototype('_config').sql.pre : ctrPre, opt);
983
1059
  }
984
1060
  /**
985
- * --- 返回代入后的完整 SQL 字符串 ---
1061
+ * --- 返回代入后的完整 SQL 字符串,这并不安全不能直接执行,只是用来调试打印 sql 语句 ---
986
1062
  * @param sql SQL 字符串
987
1063
  * @param data DATA 数据
1064
+ * @param service 服务商,默认 MySQL
988
1065
  */
989
- export function format(sql, data) {
990
- return mysql2.format(sql, data);
1066
+ export function format(sql, data, service = ESERVICE.MYSQL) {
1067
+ if (service === ESERVICE.MYSQL) {
1068
+ return mysql2.format(sql, data);
1069
+ }
1070
+ // --- PGSQL ---
1071
+ // --- PostgreSQL 手动替换占位符 ---
1072
+ let index = 0;
1073
+ return sql.replace(/\$\d+/g, () => {
1074
+ const val = data[index++];
1075
+ if (val === null) {
1076
+ return 'NULL';
1077
+ }
1078
+ if (typeof val === 'string') {
1079
+ return `'${lText.stringifyJson(val).slice(1, -1).replace(/'/g, "''").replace(/\\"/g, '"')}'`;
1080
+ }
1081
+ if (typeof val === 'number') {
1082
+ return val.toString();
1083
+ }
1084
+ if (val instanceof Buffer) {
1085
+ return `'\\x${val.toString('hex')}'`;
1086
+ }
1087
+ return `'${JSON.stringify(val).replace(/'/g, "''")}'`;
1088
+ });
991
1089
  }
992
1090
  /**
993
1091
  * --- 将数组兑换为组合的对象(Array/Object mix) ---