@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 +148 -54
- package/dist/select/selectable.d.ts +24 -7
- package/dist/sql_value/db_type.d.ts +2 -2
- package/dist/sql_value/sql_value.d.ts +22 -4
- package/package.json +2 -1
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
|
-
/**
|
|
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.
|
|
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
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
-
|
|
137
|
+
let rows;
|
|
113
138
|
try {
|
|
114
139
|
for (; i < objectList.length; i++) {
|
|
115
140
|
const object = objectList[i];
|
|
116
|
-
|
|
141
|
+
rows = [];
|
|
117
142
|
j = 0;
|
|
118
143
|
for (; j < keys.length; j++) {
|
|
119
|
-
value = object[keys[j]];
|
|
120
|
-
|
|
144
|
+
value = object[keys[j]] ?? null;
|
|
145
|
+
rows[j] = this.toSqlStr(value);
|
|
121
146
|
}
|
|
122
|
-
|
|
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
|
|
154
|
+
return str;
|
|
130
155
|
}
|
|
131
|
-
objectToValues(object,
|
|
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
|
-
|
|
138
|
-
|
|
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("字段 '" +
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
273
|
+
/**
|
|
274
|
+
* 数据库表
|
|
275
|
+
* @public
|
|
276
|
+
*/
|
|
179
277
|
class DbTable extends SqlSelectable {
|
|
180
278
|
constructor(name, columns) {
|
|
181
|
-
|
|
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
|
-
* SELECT
|
|
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
|
-
|
|
329
|
-
|
|
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
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
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 (
|
|
415
|
-
throw new Error();
|
|
416
|
-
|
|
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
|
|
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.
|
|
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
|
-
/**
|
|
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
|
-
|
|
6
|
-
/**
|
|
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
|
-
/**
|
|
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
|
-
* SELECT
|
|
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:
|
|
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
|
-
/**
|
|
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)[]
|
|
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:
|
|
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.
|
|
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
|
},
|