@asla/yoursql 0.0.2 → 0.0.4

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/dist/mod.js CHANGED
@@ -65,6 +65,16 @@ class SqlValuesCreator {
65
65
  */
66
66
  constructor(map = new Map()) {
67
67
  this.map = map;
68
+ const fn = (value) => this.toSqlStr(value);
69
+ Reflect.setPrototypeOf(fn, this);
70
+ return fn;
71
+ }
72
+ /** 设置转换器 */
73
+ setTransformer(type, transformer) {
74
+ if (!transformer)
75
+ this.map.delete(type);
76
+ else
77
+ this.map.set(type, transformer);
68
78
  }
69
79
  string(value) {
70
80
  return SqlValuesCreator.string(value);
@@ -72,7 +82,9 @@ class SqlValuesCreator {
72
82
  number(value) {
73
83
  return value.toString();
74
84
  }
75
- /** 将 JS 对象转为 SQL 的字符值的形式 */
85
+ /**
86
+ * 将 JS 对象转为 SQL 的字符值的形式
87
+ */
76
88
  toSqlStr(value) {
77
89
  switch (typeof value) {
78
90
  case "bigint":
@@ -93,54 +105,73 @@ class SqlValuesCreator {
93
105
  if (value instanceof Class)
94
106
  return this.map.get(Class).call(this, value);
95
107
  }
96
- return this.string(JSON.stringify(value));
108
+ return this.defaultObject(value);
109
+ case "undefined":
110
+ return "NULL";
97
111
  default:
112
+ //function、symbol
98
113
  let type = typeof value;
99
- if (type === "object")
100
- type = value.constructor?.name ?? "object";
101
114
  throw new Error("不支持转换 " + type + " 类型");
102
115
  }
103
116
  }
104
- /**
105
- * 将对象列表转为 SQL 的 VALUES
106
- * @example 返回示例: " (...),(...) "
107
- */
108
- objectListToValuesList(objectList, keys = Object.keys(objectList[0])) {
109
- let i = 0;
117
+ defaultObject(value) {
118
+ return this.string(JSON.stringify(value));
119
+ }
120
+ objectListToValuesList(objectList, keys_types) {
121
+ if (objectList.length <= 0)
122
+ throw new Error("objectList 不能是空数组");
123
+ let keys;
124
+ if (!keys_types) {
125
+ keys = getKeys(objectList);
126
+ }
127
+ else if (keys_types instanceof Array) {
128
+ keys = keys_types;
129
+ }
130
+ else {
131
+ keys = Object.keys(keys_types);
132
+ }
133
+ let str = "(" + this.objectToValues(objectList[0], keys_types ?? keys) + ")";
134
+ let i = 1;
110
135
  let j;
111
136
  let value;
112
- const rowValues = new Array(objectList.length);
137
+ let rows;
113
138
  try {
114
139
  for (; i < objectList.length; i++) {
115
140
  const object = objectList[i];
116
- const values = [];
141
+ rows = [];
117
142
  j = 0;
118
143
  for (; j < keys.length; j++) {
119
- value = object[keys[j]];
120
- values[j] = this.toSqlStr(value);
144
+ value = object[keys[j]] ?? null;
145
+ rows[j] = this.toSqlStr(value);
121
146
  }
122
- rowValues[i] = "\n(" + values.join(",") + ")";
147
+ str += ",\n(" + rows.join(",") + ")";
123
148
  }
124
149
  }
125
150
  catch (error) {
126
151
  let message = error instanceof Error ? error.message : String(error);
127
152
  throw new Error("第 " + i + " 项,字段 '" + keys[j] + "' 异常," + message);
128
153
  }
129
- return rowValues.join(",");
154
+ return str;
130
155
  }
131
- objectToValues(object, keys) {
156
+ objectToValues(object, keys_types) {
157
+ const { keys, type } = toKeyType(object, keys_types);
132
158
  const values = [];
133
159
  let i = 0;
160
+ let key;
134
161
  let value;
135
162
  try {
136
163
  for (; i < keys.length; i++) {
137
- value = object[keys[i]];
138
- values[i] = this.toSqlStr(value);
164
+ key = keys[i];
165
+ value = object[key] ?? null;
166
+ if (type[key])
167
+ values[i] = this.toSqlStr(value) + "::" + type[key];
168
+ else
169
+ values[i] = this.toSqlStr(value);
139
170
  }
140
171
  }
141
172
  catch (error) {
142
173
  let message = error instanceof Error ? error.message : String(error);
143
- throw new Error("字段 '" + keys[i] + "' 异常," + message);
174
+ throw new Error("字段 '" + key + "' 异常," + message);
144
175
  }
145
176
  return values.join(",");
146
177
  }
@@ -152,14 +183,44 @@ class SqlValuesCreator {
152
183
  return values.map(this.toSqlStr.bind(this)).join(",");
153
184
  }
154
185
  }
186
+ function toKeyType(object, keys_types) {
187
+ let type = {};
188
+ let keys;
189
+ if (keys_types instanceof Array) {
190
+ keys = keys_types;
191
+ type = {};
192
+ }
193
+ else if (keys_types) {
194
+ keys = Object.keys(keys_types);
195
+ type = keys_types;
196
+ }
197
+ else {
198
+ keys = Object.keys(object).filter((key) => typeof key === "string" && object[key] !== undefined);
199
+ }
200
+ return { type, keys };
201
+ }
202
+ function getKeys(objectList) {
203
+ let keys = new Set();
204
+ for (let i = 0; i < objectList.length; i++) {
205
+ let obj = objectList[i];
206
+ let hasKeys = Object.keys(obj);
207
+ let k;
208
+ for (let j = 0; j < hasKeys.length; j++) {
209
+ k = hasKeys[j];
210
+ if (obj[k] !== undefined && typeof k === "string")
211
+ keys.add(k);
212
+ }
213
+ }
214
+ return Array.from(keys);
215
+ }
155
216
 
156
217
  /**
157
218
  * @public
158
219
  * PgSql的值转换
159
220
  */
160
221
  class PgSqlValue extends SqlValuesCreator {
161
- constructor() {
162
- const map = new Map();
222
+ constructor(custom) {
223
+ const map = new Map(custom);
163
224
  map.set(Array, PgSqlValue.prototype.array);
164
225
  map.set(Date, PgSqlValue.prototype.timestamp);
165
226
  super(map);
@@ -172,18 +233,53 @@ class PgSqlValue extends SqlValuesCreator {
172
233
  }
173
234
  }
174
235
 
175
- /** @public */
236
+ /**
237
+ * 可选择项。可以是 table、查询结果等,它能被 select 语句选择
238
+ * @example
239
+ * ```ts
240
+ * declare const item: SqlSelectable<any>
241
+ * await query(`select * from ${item.toSelect()}`)
242
+ *
243
+ * ```
244
+ * @public
245
+ */
176
246
  class SqlSelectable {
247
+ constructor(columns) {
248
+ // Reflect.set(this, SQL_SELECTABLE, undefined);
249
+ let readonlyColumns;
250
+ if (typeof columns[Symbol.iterator] === "function") {
251
+ let iterable = columns;
252
+ readonlyColumns = [];
253
+ let iter = iterable[Symbol.iterator]();
254
+ let i = 0;
255
+ let item = iter.next();
256
+ while (!item.done) {
257
+ readonlyColumns[i++] = item.value;
258
+ item = iter.next();
259
+ }
260
+ // readonlyColumns.length = i;
261
+ }
262
+ else {
263
+ let arrayLike = columns;
264
+ readonlyColumns = new Array(arrayLike.length);
265
+ // readonlyColumns.length = arrayLike.length;
266
+ for (let i = 0; i < arrayLike.length; i++) {
267
+ readonlyColumns[i] = arrayLike[i];
268
+ }
269
+ }
270
+ this.columns = readonlyColumns;
271
+ }
177
272
  }
178
- /** @public */
273
+ /**
274
+ * 数据库表
275
+ * @public
276
+ */
179
277
  class DbTable extends SqlSelectable {
180
278
  constructor(name, columns) {
181
- super();
279
+ if (!(columns instanceof Array))
280
+ columns = Object.keys(columns);
281
+ super(columns);
182
282
  this.name = name;
183
- if (columns instanceof Array)
184
- this.columns = [...columns];
185
- else
186
- this.columns = Object.keys(columns);
187
283
  }
188
284
  toSelect() {
189
285
  return this.name;
@@ -193,14 +289,13 @@ class DbTable extends SqlSelectable {
193
289
  }
194
290
  }
195
291
  /**
196
- * SELECTUPDATE、DELETE、INSERT INTO 带结果的返回值
292
+ * SELECT 以及 UPDATE、DELETE、INSERT INTO 带结果的 SQL 语句
197
293
  * @public
198
294
  */
199
295
  class SqlQueryStatement extends SqlSelectable {
200
296
  constructor(sql, columns) {
201
- super();
297
+ super(columns);
202
298
  this.sql = sql;
203
- this.columns = columns;
204
299
  }
205
300
  toString() {
206
301
  return this.sql;
@@ -324,18 +419,14 @@ const createSelect = function createSelect(tb, columns, option) {
324
419
  let select = createSelectMap(tb, columns, option).selects;
325
420
  return new SelectImpl(select);
326
421
  };
422
+ function* mergeColumns(a, b) {
423
+ for (const { columns } of a)
424
+ yield* columns.keys();
425
+ yield* b;
426
+ }
327
427
  class SelectImpl extends SqlSelectable {
328
- get columns() {
329
- return this.getColumns();
330
- }
331
- *getColumns() {
332
- for (const { columns } of this.tableList.values()) {
333
- yield* columns.keys();
334
- }
335
- yield* this.addedColumns.keys();
336
- }
337
- constructor(tableList, addedColumns = new Map()) {
338
- super();
428
+ constructor(tableList, addedColumns) {
429
+ super(addedColumns ? mergeColumns(tableList.values(), addedColumns.keys()) : tableList.keys());
339
430
  _SelectImpl_instances.add(this);
340
431
  this.tableList = tableList;
341
432
  this.addedColumns = addedColumns;
@@ -375,11 +466,13 @@ class SelectImpl extends SqlSelectable {
375
466
  }
376
467
  }
377
468
  }
378
- for (const [asName, columnStr] of this.addedColumns) {
379
- if (asName === columnStr)
380
- selectColumns.push(asName);
381
- else
382
- selectColumns.push(columnStr + " AS " + asName);
469
+ if (this.addedColumns) {
470
+ for (const [asName, columnStr] of this.addedColumns) {
471
+ if (asName === columnStr)
472
+ selectColumns.push(asName);
473
+ else
474
+ selectColumns.push(columnStr + " AS " + asName);
475
+ }
383
476
  }
384
477
  if (selectColumns.length === 0)
385
478
  throw new Error("Columns 为空");
@@ -410,12 +503,13 @@ class SelectImpl extends SqlSelectable {
410
503
  return obj;
411
504
  }
412
505
  addColumns(add) {
506
+ let addedColumns = this.addedColumns ? new Map(this.addedColumns) : new Map();
413
507
  for (const [asNewName, columnStr] of Object.entries(add)) {
414
- if (this.addedColumns.has(asNewName))
415
- throw new Error();
416
- this.addedColumns.set(asNewName, columnStr);
508
+ if (addedColumns.has(asNewName))
509
+ throw new Error(`The column ${asNewName} already exists`);
510
+ addedColumns.set(asNewName, columnStr);
417
511
  }
418
- return this;
512
+ return new _a(this.tableList, addedColumns);
419
513
  }
420
514
  toQuery(option = {}) {
421
515
  const { where, orderNullRule } = option;
@@ -505,11 +599,11 @@ class DbTableQuery extends DbTable {
505
599
  if (values.length === 0)
506
600
  throw new Error("值不能为空");
507
601
  insertCol = Object.keys(values[0]);
508
- valuesStr = `VALUES ${this.statement.objectListToValuesList(values, insertCol)}`;
602
+ valuesStr = `VALUES\n${this.statement.objectListToValuesList(values, insertCol)}`;
509
603
  }
510
604
  else if (values instanceof SqlQueryStatement) {
511
605
  // todo 验证 values.columns 和 this.columns 是否匹配
512
- valuesStr = values.toSelect();
606
+ valuesStr = values.toString();
513
607
  insertCol = values.columns;
514
608
  }
515
609
  else
@@ -1,29 +1,46 @@
1
1
  import { TableType } from "./type.ts";
2
2
  declare const SQL_SELECTABLE: unique symbol;
3
- /** @public */
3
+ /**
4
+ * 可选择项。可以是 table、查询结果等,它能被 select 语句选择
5
+ * @example
6
+ * ```ts
7
+ * declare const item: SqlSelectable<any>
8
+ * await query(`select * from ${item.toSelect()}`)
9
+ *
10
+ * ```
11
+ * @public
12
+ */
4
13
  export declare abstract class SqlSelectable<T extends TableType> {
5
- abstract readonly columns: Iterable<string>;
6
- /** select from xxx 中的 xxx */
14
+ constructor(columns: ArrayLike<string> | Iterable<string>);
15
+ /** 结果列 */
16
+ readonly columns: readonly string[];
17
+ /**
18
+ * 转成子选择语句, 你可以使用 select form xxx 选择
19
+ * 如果是 table 则是 table name
20
+ * 如果是 选择语句,则是 (xxx)
21
+ */
7
22
  abstract toSelect(): string;
23
+ /** 获取 SQL 语句 */
8
24
  abstract toString(): string;
9
25
  /** 保留以推断类型 */
10
26
  [SQL_SELECTABLE]: T;
11
27
  }
12
- /** @public */
28
+ /**
29
+ * 数据库表
30
+ * @public
31
+ */
13
32
  export declare class DbTable<T extends TableType> extends SqlSelectable<T> {
14
33
  readonly name: string;
15
- readonly columns: readonly string[];
16
34
  constructor(name: string, columns: readonly (keyof T)[]);
17
35
  toSelect(): string;
18
36
  toString(): string;
19
37
  }
20
38
  /**
21
- * SELECTUPDATE、DELETE、INSERT INTO 带结果的返回值
39
+ * SELECT 以及 UPDATE、DELETE、INSERT INTO 带结果的 SQL 语句
22
40
  * @public
23
41
  */
24
42
  export declare class SqlQueryStatement<T extends TableType = TableType> extends SqlSelectable<T> {
25
43
  private sql;
26
- readonly columns: readonly string[];
27
44
  constructor(sql: string, columns: readonly string[]);
28
45
  toString(): string;
29
46
  toSelect(): string;
@@ -1,10 +1,10 @@
1
- import { SqlValuesCreator } from "./sql_value.ts";
1
+ import { SqlValuesCreator, JsObjectMapSql } from "./sql_value.ts";
2
2
  /**
3
3
  * @public
4
4
  * PgSql的值转换
5
5
  */
6
6
  export declare class PgSqlValue extends SqlValuesCreator {
7
- constructor();
7
+ constructor(custom?: JsObjectMapSql);
8
8
  timestamp(value: Date): string;
9
9
  array(value: any[]): string;
10
10
  }
@@ -11,7 +11,14 @@ export declare class SqlRaw<T = any> {
11
11
  [SQL_RAW]: T;
12
12
  }
13
13
  /** @public */
14
- export type JsObjectMapSql = Map<new (...args: any[]) => any, (value: object) => string>;
14
+ export type JsObjectMapSql = Map<new (...args: any[]) => any, (value: any) => string>;
15
+ /**
16
+ * @public
17
+ */
18
+ export interface SqlValuesCreator {
19
+ /** 将 JS 对象转为 SQL 的字符值的形式 */
20
+ (value: any): string;
21
+ }
15
22
  /**
16
23
  * SQL value 生成器
17
24
  * @public
@@ -26,21 +33,32 @@ export declare class SqlValuesCreator {
26
33
  * @param map - 自定义对象转换
27
34
  */
28
35
  constructor(map?: JsObjectMapSql);
36
+ /** 设置转换器 */
37
+ setTransformer<T>(type: new (...args: any[]) => T, transformer?: (value: T) => string): void;
29
38
  private readonly map;
30
39
  string(value: string): string;
31
40
  number(value: number | bigint): string;
32
- /** 将 JS 对象转为 SQL 的字符值的形式 */
41
+ /**
42
+ * 将 JS 对象转为 SQL 的字符值的形式
43
+ */
33
44
  toSqlStr(value: any): string;
45
+ protected defaultObject(value: object): string;
34
46
  /**
35
47
  * 将对象列表转为 SQL 的 VALUES
36
48
  * @example 返回示例: " (...),(...) "
49
+ * @param keys - 选择的键。如果指定了 keys, 值为 undefined 的属性将自动填充为 null; 如果未指定 keys,将选择 objectList 所有不是 undefined 项的键的并集
37
50
  */
38
- objectListToValuesList<T extends object>(objectList: T[], keys?: (keyof T)[]): string;
51
+ objectListToValuesList<T extends object>(objectList: T[], keys?: readonly (keyof T)[] | {
52
+ [key in keyof T]?: string | undefined;
53
+ }): string;
39
54
  /**
40
55
  * 将对象转为 SQL 的 value
41
56
  * @example 返回示例: " 'abc', '6', 'now()' "
57
+ * @param keys - 如果指定了key, object undefined 的属性值将填充为 null,如果不指定,将自获取 object 所有非 undefined 的属性的key
42
58
  */
43
- objectToValues(object: object, keys: readonly string[]): string;
59
+ objectToValues<T extends object>(object: T, keys?: readonly (keyof T)[] | {
60
+ [key in keyof T]?: string | undefined;
61
+ }): string;
44
62
  /**
45
63
  * 将数组列表转为 SQL 的一个 value
46
64
  * @example 返回示例: " 'abc', '6', 'now()' "
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asla/yoursql",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "types": "./dist/mod.d.ts",
@@ -17,6 +17,7 @@
17
17
  "@rollup/plugin-typescript": "^12.1.0",
18
18
  "rollup": "^4.22.4",
19
19
  "tslib": "^2.7.0",
20
+ "typescript": "^5.6.2",
20
21
  "typescritp": "^1.0.0",
21
22
  "vitest": "^2.1.1"
22
23
  },