@asla/yoursql 0.0.2 → 0.0.3
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 +125 -47
- package/dist/select/selectable.d.ts +24 -7
- package/dist/sql_value/sql_value.d.ts +8 -2
- package/package.json +2 -1
package/dist/mod.js
CHANGED
|
@@ -101,46 +101,61 @@ class SqlValuesCreator {
|
|
|
101
101
|
throw new Error("不支持转换 " + type + " 类型");
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
104
|
+
objectListToValuesList(objectList, keys_types) {
|
|
105
|
+
if (objectList.length <= 0)
|
|
106
|
+
throw new Error("objectList 不能是空数组");
|
|
107
|
+
let keys;
|
|
108
|
+
if (!keys_types) {
|
|
109
|
+
keys = getKeys(objectList);
|
|
110
|
+
}
|
|
111
|
+
else if (keys_types instanceof Array) {
|
|
112
|
+
keys = keys_types;
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
keys = Object.keys(keys_types);
|
|
116
|
+
}
|
|
117
|
+
let str = "(" + this.objectToValues(objectList[0], keys_types ?? keys) + ")";
|
|
118
|
+
let i = 1;
|
|
110
119
|
let j;
|
|
111
120
|
let value;
|
|
112
|
-
|
|
121
|
+
let rows;
|
|
113
122
|
try {
|
|
114
123
|
for (; i < objectList.length; i++) {
|
|
115
124
|
const object = objectList[i];
|
|
116
|
-
|
|
125
|
+
rows = [];
|
|
117
126
|
j = 0;
|
|
118
127
|
for (; j < keys.length; j++) {
|
|
119
|
-
value = object[keys[j]];
|
|
120
|
-
|
|
128
|
+
value = object[keys[j]] ?? null;
|
|
129
|
+
rows[j] = this.toSqlStr(value);
|
|
121
130
|
}
|
|
122
|
-
|
|
131
|
+
str += ",\n(" + rows.join(",") + ")";
|
|
123
132
|
}
|
|
124
133
|
}
|
|
125
134
|
catch (error) {
|
|
126
135
|
let message = error instanceof Error ? error.message : String(error);
|
|
127
136
|
throw new Error("第 " + i + " 项,字段 '" + keys[j] + "' 异常," + message);
|
|
128
137
|
}
|
|
129
|
-
return
|
|
138
|
+
return str;
|
|
130
139
|
}
|
|
131
|
-
objectToValues(object,
|
|
140
|
+
objectToValues(object, keys_types) {
|
|
141
|
+
const { keys, type } = toKeyType(object, keys_types);
|
|
132
142
|
const values = [];
|
|
133
143
|
let i = 0;
|
|
144
|
+
let key;
|
|
134
145
|
let value;
|
|
135
146
|
try {
|
|
136
147
|
for (; i < keys.length; i++) {
|
|
137
|
-
|
|
138
|
-
|
|
148
|
+
key = keys[i];
|
|
149
|
+
value = object[key] ?? null;
|
|
150
|
+
if (type[key])
|
|
151
|
+
values[i] = this.toSqlStr(value) + "::" + type[key];
|
|
152
|
+
else
|
|
153
|
+
values[i] = this.toSqlStr(value);
|
|
139
154
|
}
|
|
140
155
|
}
|
|
141
156
|
catch (error) {
|
|
142
157
|
let message = error instanceof Error ? error.message : String(error);
|
|
143
|
-
throw new Error("字段 '" +
|
|
158
|
+
throw new Error("字段 '" + key + "' 异常," + message);
|
|
144
159
|
}
|
|
145
160
|
return values.join(",");
|
|
146
161
|
}
|
|
@@ -152,6 +167,36 @@ class SqlValuesCreator {
|
|
|
152
167
|
return values.map(this.toSqlStr.bind(this)).join(",");
|
|
153
168
|
}
|
|
154
169
|
}
|
|
170
|
+
function toKeyType(object, keys_types) {
|
|
171
|
+
let type = {};
|
|
172
|
+
let keys;
|
|
173
|
+
if (keys_types instanceof Array) {
|
|
174
|
+
keys = keys_types;
|
|
175
|
+
type = {};
|
|
176
|
+
}
|
|
177
|
+
else if (keys_types) {
|
|
178
|
+
keys = Object.keys(keys_types);
|
|
179
|
+
type = keys_types;
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
keys = Object.keys(object).filter((key) => typeof key === "string" && object[key] !== undefined);
|
|
183
|
+
}
|
|
184
|
+
return { type, keys };
|
|
185
|
+
}
|
|
186
|
+
function getKeys(objectList) {
|
|
187
|
+
let keys = new Set();
|
|
188
|
+
for (let i = 0; i < objectList.length; i++) {
|
|
189
|
+
let obj = objectList[i];
|
|
190
|
+
let hasKeys = Object.keys(obj);
|
|
191
|
+
let k;
|
|
192
|
+
for (let j = 0; j < hasKeys.length; j++) {
|
|
193
|
+
k = hasKeys[j];
|
|
194
|
+
if (obj[k] !== undefined && typeof k === "string")
|
|
195
|
+
keys.add(k);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return Array.from(keys);
|
|
199
|
+
}
|
|
155
200
|
|
|
156
201
|
/**
|
|
157
202
|
* @public
|
|
@@ -172,18 +217,53 @@ class PgSqlValue extends SqlValuesCreator {
|
|
|
172
217
|
}
|
|
173
218
|
}
|
|
174
219
|
|
|
175
|
-
/**
|
|
220
|
+
/**
|
|
221
|
+
* 可选择项。可以是 table、查询结果等,它能被 select 语句选择
|
|
222
|
+
* @example
|
|
223
|
+
* ```ts
|
|
224
|
+
* declare const item: SqlSelectable<any>
|
|
225
|
+
* await query(`select * from ${item.toSelect()}`)
|
|
226
|
+
*
|
|
227
|
+
* ```
|
|
228
|
+
* @public
|
|
229
|
+
*/
|
|
176
230
|
class SqlSelectable {
|
|
231
|
+
constructor(columns) {
|
|
232
|
+
// Reflect.set(this, SQL_SELECTABLE, undefined);
|
|
233
|
+
let readonlyColumns;
|
|
234
|
+
if (typeof columns[Symbol.iterator] === "function") {
|
|
235
|
+
let iterable = columns;
|
|
236
|
+
readonlyColumns = [];
|
|
237
|
+
let iter = iterable[Symbol.iterator]();
|
|
238
|
+
let i = 0;
|
|
239
|
+
let item = iter.next();
|
|
240
|
+
while (!item.done) {
|
|
241
|
+
readonlyColumns[i++] = item.value;
|
|
242
|
+
item = iter.next();
|
|
243
|
+
}
|
|
244
|
+
// readonlyColumns.length = i;
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
let arrayLike = columns;
|
|
248
|
+
readonlyColumns = new Array(arrayLike.length);
|
|
249
|
+
// readonlyColumns.length = arrayLike.length;
|
|
250
|
+
for (let i = 0; i < arrayLike.length; i++) {
|
|
251
|
+
readonlyColumns[i] = arrayLike[i];
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
this.columns = readonlyColumns;
|
|
255
|
+
}
|
|
177
256
|
}
|
|
178
|
-
/**
|
|
257
|
+
/**
|
|
258
|
+
* 数据库表
|
|
259
|
+
* @public
|
|
260
|
+
*/
|
|
179
261
|
class DbTable extends SqlSelectable {
|
|
180
262
|
constructor(name, columns) {
|
|
181
|
-
|
|
263
|
+
if (!(columns instanceof Array))
|
|
264
|
+
columns = Object.keys(columns);
|
|
265
|
+
super(columns);
|
|
182
266
|
this.name = name;
|
|
183
|
-
if (columns instanceof Array)
|
|
184
|
-
this.columns = [...columns];
|
|
185
|
-
else
|
|
186
|
-
this.columns = Object.keys(columns);
|
|
187
267
|
}
|
|
188
268
|
toSelect() {
|
|
189
269
|
return this.name;
|
|
@@ -193,14 +273,13 @@ class DbTable extends SqlSelectable {
|
|
|
193
273
|
}
|
|
194
274
|
}
|
|
195
275
|
/**
|
|
196
|
-
* SELECT
|
|
276
|
+
* SELECT 以及 UPDATE、DELETE、INSERT INTO 带结果的 SQL 语句
|
|
197
277
|
* @public
|
|
198
278
|
*/
|
|
199
279
|
class SqlQueryStatement extends SqlSelectable {
|
|
200
280
|
constructor(sql, columns) {
|
|
201
|
-
super();
|
|
281
|
+
super(columns);
|
|
202
282
|
this.sql = sql;
|
|
203
|
-
this.columns = columns;
|
|
204
283
|
}
|
|
205
284
|
toString() {
|
|
206
285
|
return this.sql;
|
|
@@ -324,18 +403,14 @@ const createSelect = function createSelect(tb, columns, option) {
|
|
|
324
403
|
let select = createSelectMap(tb, columns, option).selects;
|
|
325
404
|
return new SelectImpl(select);
|
|
326
405
|
};
|
|
406
|
+
function* mergeColumns(a, b) {
|
|
407
|
+
for (const { columns } of a)
|
|
408
|
+
yield* columns.keys();
|
|
409
|
+
yield* b;
|
|
410
|
+
}
|
|
327
411
|
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();
|
|
412
|
+
constructor(tableList, addedColumns) {
|
|
413
|
+
super(addedColumns ? mergeColumns(tableList.values(), addedColumns.keys()) : tableList.keys());
|
|
339
414
|
_SelectImpl_instances.add(this);
|
|
340
415
|
this.tableList = tableList;
|
|
341
416
|
this.addedColumns = addedColumns;
|
|
@@ -375,11 +450,13 @@ class SelectImpl extends SqlSelectable {
|
|
|
375
450
|
}
|
|
376
451
|
}
|
|
377
452
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
453
|
+
if (this.addedColumns) {
|
|
454
|
+
for (const [asName, columnStr] of this.addedColumns) {
|
|
455
|
+
if (asName === columnStr)
|
|
456
|
+
selectColumns.push(asName);
|
|
457
|
+
else
|
|
458
|
+
selectColumns.push(columnStr + " AS " + asName);
|
|
459
|
+
}
|
|
383
460
|
}
|
|
384
461
|
if (selectColumns.length === 0)
|
|
385
462
|
throw new Error("Columns 为空");
|
|
@@ -410,12 +487,13 @@ class SelectImpl extends SqlSelectable {
|
|
|
410
487
|
return obj;
|
|
411
488
|
}
|
|
412
489
|
addColumns(add) {
|
|
490
|
+
let addedColumns = this.addedColumns ? new Map(this.addedColumns) : new Map();
|
|
413
491
|
for (const [asNewName, columnStr] of Object.entries(add)) {
|
|
414
|
-
if (
|
|
415
|
-
throw new Error();
|
|
416
|
-
|
|
492
|
+
if (addedColumns.has(asNewName))
|
|
493
|
+
throw new Error(`The column ${asNewName} already exists`);
|
|
494
|
+
addedColumns.set(asNewName, columnStr);
|
|
417
495
|
}
|
|
418
|
-
return this;
|
|
496
|
+
return new _a(this.tableList, addedColumns);
|
|
419
497
|
}
|
|
420
498
|
toQuery(option = {}) {
|
|
421
499
|
const { where, orderNullRule } = option;
|
|
@@ -505,7 +583,7 @@ class DbTableQuery extends DbTable {
|
|
|
505
583
|
if (values.length === 0)
|
|
506
584
|
throw new Error("值不能为空");
|
|
507
585
|
insertCol = Object.keys(values[0]);
|
|
508
|
-
valuesStr = `VALUES
|
|
586
|
+
valuesStr = `VALUES\n${this.statement.objectListToValuesList(values, insertCol)}`;
|
|
509
587
|
}
|
|
510
588
|
else if (values instanceof SqlQueryStatement) {
|
|
511
589
|
// todo 验证 values.columns 和 this.columns 是否匹配
|
|
@@ -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;
|
|
@@ -34,13 +34,19 @@ export declare class SqlValuesCreator {
|
|
|
34
34
|
/**
|
|
35
35
|
* 将对象列表转为 SQL 的 VALUES
|
|
36
36
|
* @example 返回示例: " (...),(...) "
|
|
37
|
+
* @param keys - 选择的键。如果指定了 keys, 值为 undefined 的属性将自动填充为 null; 如果未指定 keys,将选择 objectList 所有不是 undefined 项的键的并集
|
|
37
38
|
*/
|
|
38
|
-
objectListToValuesList<T extends object>(objectList: T[], keys?: (keyof T)[]
|
|
39
|
+
objectListToValuesList<T extends object>(objectList: T[], keys?: readonly (keyof T)[] | {
|
|
40
|
+
[key in keyof T]?: string | undefined;
|
|
41
|
+
}): string;
|
|
39
42
|
/**
|
|
40
43
|
* 将对象转为 SQL 的 value
|
|
41
44
|
* @example 返回示例: " 'abc', '6', 'now()' "
|
|
45
|
+
* @param keys - 如果指定了key, object undefined 的属性值将填充为 null,如果不指定,将自获取 object 所有非 undefined 的属性的key
|
|
42
46
|
*/
|
|
43
|
-
objectToValues(object:
|
|
47
|
+
objectToValues<T extends object>(object: T, keys?: readonly (keyof T)[] | {
|
|
48
|
+
[key in keyof T]?: string | undefined;
|
|
49
|
+
}): string;
|
|
44
50
|
/**
|
|
45
51
|
* 将数组列表转为 SQL 的一个 value
|
|
46
52
|
* @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.3",
|
|
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
|
},
|