@asla/yoursql 0.8.2 → 0.8.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.
@@ -0,0 +1,304 @@
1
+ import { getObjectListKeys } from '../util.js';
2
+ import { SqlStatementDataset } from '../select/query_chain_abstract.js';
3
+
4
+ /**
5
+ * SQL 原始字符类。可以使用 String 类代替,这只是为了推断类型
6
+ * @public
7
+ */
8
+ class SqlRaw extends String {
9
+ }
10
+ /**
11
+ * SQL value 生成器
12
+ * @public
13
+ */
14
+ class SqlValuesCreator {
15
+ static create(map) {
16
+ const obj = new this(map);
17
+ const fn = obj.toSqlStr.bind(obj);
18
+ Reflect.setPrototypeOf(fn, obj);
19
+ return fn;
20
+ }
21
+ /**
22
+ * 将字符串转为 SQL 的字符串值的形式(单引号会被转义)。
23
+ * @example 输入 a'b'c , 返回 a''b''c.
24
+ */
25
+ static string(value) {
26
+ return "'" + value.replaceAll("'", "''") + "'";
27
+ }
28
+ /**
29
+ * @param map - 自定义对象转换
30
+ */
31
+ constructor(map) {
32
+ this._map = new Map(map);
33
+ }
34
+ setTransformer(type_map, encoder) {
35
+ if (typeof type_map === "function") {
36
+ if (encoder)
37
+ this._map.set(type_map, encoder);
38
+ else
39
+ this._map.delete(type_map);
40
+ }
41
+ else {
42
+ for (const [type, encoder] of type_map) {
43
+ if (typeof type === "function" && typeof encoder === "function") {
44
+ this._map.set(type, encoder);
45
+ }
46
+ }
47
+ }
48
+ }
49
+ _map;
50
+ /**
51
+ * 将 JS 对象转为 SQL 的字符值的形式 。 undefined 将被转换为 DEFAULT
52
+ * ```ts
53
+ * const v=SqlValuesCreator.create()
54
+ * v() 和 v.toSqlStr() 是等价的
55
+ * ```
56
+ */
57
+ toSqlStr(value, assertJsType) {
58
+ if (value === null)
59
+ return "NULL";
60
+ else if (value === undefined)
61
+ return "DEFAULT";
62
+ let basicType = typeof value;
63
+ if (assertJsType) {
64
+ if (typeof assertJsType === "function") {
65
+ if (basicType !== "object")
66
+ throw new AssertError("object", basicType);
67
+ let type = this._map.get(assertJsType);
68
+ if (!type) {
69
+ if (assertJsType === Object)
70
+ return this.defaultObject(value);
71
+ throw new Error("类型不存在");
72
+ }
73
+ return type.call(this, value);
74
+ }
75
+ else if (basicType !== assertJsType) {
76
+ throw new AssertError(assertJsType, basicType);
77
+ }
78
+ }
79
+ switch (basicType) {
80
+ case "bigint":
81
+ return value.toString();
82
+ case "number":
83
+ return value.toString();
84
+ case "string":
85
+ return SqlValuesCreator.string(value);
86
+ case "boolean":
87
+ return value.toString();
88
+ case "object": {
89
+ if (value instanceof String)
90
+ return value.toString();
91
+ const Class = this.getClassType(value);
92
+ if (Class)
93
+ return this._map.get(Class).call(this, value);
94
+ return this.defaultObject(value);
95
+ }
96
+ case "undefined":
97
+ return "DEFAULT";
98
+ default:
99
+ //function、symbol
100
+ let type = typeof value;
101
+ throw new Error("不支持 " + type + " 类型");
102
+ }
103
+ }
104
+ /**
105
+ * @deprecated 已废弃
106
+ * 获取值对应的 SqlValueEncoder
107
+ */
108
+ getObjectType(value) {
109
+ for (const Class of this._map.keys()) {
110
+ if (value instanceof Class)
111
+ return this._map.get(Class);
112
+ }
113
+ return this.defaultObject;
114
+ }
115
+ /** 获取值对应已定义的类 */
116
+ getClassType(value) {
117
+ for (const Class of this._map.keys()) {
118
+ if (value instanceof Class)
119
+ return Class;
120
+ }
121
+ }
122
+ defaultObject(value) {
123
+ return SqlValuesCreator.string(JSON.stringify(value));
124
+ }
125
+ objectListToValuesList(objectList, keys_types, keepUndefinedKey) {
126
+ if (objectList.length <= 0)
127
+ throw new Error("objectList 不能是空数组");
128
+ let keys;
129
+ let asserts;
130
+ if (!keys_types) {
131
+ keys = Array.from(getObjectListKeys(objectList, keepUndefinedKey));
132
+ asserts = [];
133
+ }
134
+ else if (keys_types instanceof Array) {
135
+ keys = keys_types;
136
+ asserts = [];
137
+ }
138
+ else {
139
+ keys = Object.keys(keys_types);
140
+ asserts = initColumnAssert(keys, keys_types);
141
+ }
142
+ let str = "(" + this._internalObjectToValues(objectList[0], keys, asserts) + ")";
143
+ let i = 1;
144
+ let j;
145
+ let value;
146
+ let rows;
147
+ try {
148
+ for (; i < objectList.length; i++) {
149
+ const object = objectList[i];
150
+ rows = [];
151
+ j = 0;
152
+ for (; j < keys.length; j++) {
153
+ value = object[keys[j]];
154
+ rows[j] = this.toSqlStr(value, asserts[j]?.assertJsType);
155
+ }
156
+ str += ",\n(" + rows.join(",") + ")";
157
+ }
158
+ }
159
+ catch (error) {
160
+ let message = error instanceof Error ? error.message : String(error);
161
+ throw new Error("第 " + i + " 项,字段 '" + keys[j] + "' 异常," + message);
162
+ }
163
+ return str;
164
+ }
165
+ objectToValues(object, keys_types) {
166
+ let type;
167
+ let keys;
168
+ if (keys_types instanceof Array) {
169
+ keys = keys_types;
170
+ type = [];
171
+ }
172
+ else if (keys_types) {
173
+ keys = Object.keys(keys_types);
174
+ type = initColumnAssert(keys, keys_types);
175
+ }
176
+ else {
177
+ keys = Object.keys(object);
178
+ type = [];
179
+ }
180
+ return this._internalObjectToValues(object, keys, type);
181
+ }
182
+ _internalObjectToValues(object, keys, type) {
183
+ const values = [];
184
+ let i = 0;
185
+ let key;
186
+ let value;
187
+ let assertType;
188
+ try {
189
+ for (; i < keys.length; i++) {
190
+ key = keys[i];
191
+ value = object[key];
192
+ assertType = type[i];
193
+ if (assertType) {
194
+ values[i] = this.toSqlStr(value, assertType.assertJsType);
195
+ if (assertType.sqlType)
196
+ values[i] += "::" + assertType.sqlType;
197
+ }
198
+ else
199
+ values[i] = this.toSqlStr(value);
200
+ }
201
+ }
202
+ catch (error) {
203
+ let message = error instanceof Error ? error.message : String(error);
204
+ throw new Error("字段 '" + key + "' 异常," + message);
205
+ }
206
+ return values.join(",");
207
+ }
208
+ /**
209
+ * 将数组列表转为 SQL 的一个 value
210
+ * @example 返回示例: " 'abc', '6', 'now()' "
211
+ */
212
+ toValues(values) {
213
+ return values.map((v) => this.toSqlStr(v)).join(",");
214
+ }
215
+ createValues(asName, values, valuesTypes) {
216
+ if (values.length === 0)
217
+ throw new Error("values 不能为空");
218
+ const insertKeys = Object.keys(valuesTypes);
219
+ const defaultValues = [];
220
+ const asserts = new Array(insertKeys.length);
221
+ const valuesStr = new Array(values.length);
222
+ {
223
+ const column0 = new Array(insertKeys.length);
224
+ let columnName;
225
+ let item;
226
+ let sqlType;
227
+ let assertJsType;
228
+ let value;
229
+ for (let i = 0; i < insertKeys.length; i++) {
230
+ columnName = insertKeys[i];
231
+ item = valuesTypes[columnName];
232
+ if (typeof item === "string") {
233
+ sqlType = item;
234
+ defaultValues[i] = "NULL";
235
+ }
236
+ else {
237
+ sqlType = item.sqlType;
238
+ assertJsType = item.assertJsType;
239
+ asserts[i] = assertJsType;
240
+ defaultValues[i] = item.sqlDefault ?? "NULL";
241
+ }
242
+ value = values[0][columnName];
243
+ if (value === undefined)
244
+ column0[i] = defaultValues[i] + "::" + sqlType;
245
+ else
246
+ column0[i] = this.toSqlStr(value, assertJsType) + "::" + sqlType;
247
+ }
248
+ valuesStr[0] = "(" + column0.join(",") + ")";
249
+ }
250
+ let items = new Array(insertKeys.length);
251
+ let value;
252
+ for (let i = 1; i < values.length; i++) {
253
+ for (let j = 0; j < insertKeys.length; j++) {
254
+ value = values[i][insertKeys[j]];
255
+ if (value === undefined)
256
+ items[j] = defaultValues[j];
257
+ else
258
+ items[j] = this.toSqlStr(value, asserts[j]);
259
+ }
260
+ valuesStr[i] = "(" + items.join(",") + ")";
261
+ }
262
+ return new YourValuesAs(insertKeys, asName, valuesStr.join(",\n"));
263
+ }
264
+ }
265
+ class YourValuesAs extends SqlStatementDataset {
266
+ constructor(columns, asName, valuesStr) {
267
+ super();
268
+ this.#asName = asName;
269
+ this.#valuesStr = valuesStr;
270
+ this.#sql = `(VALUES\n${this.#valuesStr})\nAS ${this.#asName}(${columns.join(",")})`;
271
+ }
272
+ #asName;
273
+ #valuesStr;
274
+ #sql;
275
+ toSelect() {
276
+ return this.#sql;
277
+ }
278
+ toString() {
279
+ return this.#sql;
280
+ }
281
+ }
282
+ function initColumnAssert(keys, keys_types) {
283
+ let key;
284
+ let value;
285
+ let type = new Array(keys.length);
286
+ for (let i = 0; i < keys.length; i++) {
287
+ key = keys[i];
288
+ value = keys_types[key];
289
+ if (typeof value === "string") {
290
+ type[i] = { sqlType: value };
291
+ }
292
+ else {
293
+ type[i] = value;
294
+ }
295
+ }
296
+ return type;
297
+ }
298
+ class AssertError extends TypeError {
299
+ constructor(assertType, actual) {
300
+ super(`Assert ${assertType} type, Actual ${actual} type`);
301
+ }
302
+ }
303
+
304
+ export { SqlRaw, SqlValuesCreator };
@@ -0,0 +1,166 @@
1
+ import { condition } from './select/_statement.js';
2
+
3
+ /**
4
+ * 获取对象数组中的 key 的集合
5
+ * @public
6
+ * @param keepUndefinedKey - 是否保留值为 undefined 的 key
7
+ */
8
+ function getObjectListKeys(objectList, keepUndefinedKey) {
9
+ let keys = new Set();
10
+ for (let i = 0; i < objectList.length; i++) {
11
+ let obj = objectList[i];
12
+ let hasKeys = Object.keys(obj);
13
+ let k;
14
+ for (let j = 0; j < hasKeys.length; j++) {
15
+ k = hasKeys[j];
16
+ if (typeof k !== "string")
17
+ continue;
18
+ if (!keepUndefinedKey && obj[k] === undefined)
19
+ continue;
20
+ keys.add(k);
21
+ }
22
+ }
23
+ return keys;
24
+ }
25
+ /**
26
+ * 生成 WHERE 语句
27
+ * @public
28
+ * @example
29
+ * ```ts
30
+ * where(['a=1','b=2']) // "\nWHERE a=1 AND b=2"
31
+ * where(['a=1','b=2'],"OR") // "\nWHERE a=1 OR b=2"
32
+ * where("a=1 OR b=2") // "\nWHERE a=1 OR b=2"
33
+ * where(()=>"a=1 OR b=2") // "\nWHERE a=1 AND b=2"
34
+ * where([]) // ""
35
+ * where(undefined) // ""
36
+ * ```
37
+ */
38
+ function where(conditions, type) {
39
+ const sql = condition(conditions, type);
40
+ if (sql)
41
+ return "\nWHERE " + sql;
42
+ return "";
43
+ }
44
+ /**
45
+ *
46
+ * 生成 HAVING 语句
47
+ * @public
48
+ */
49
+ function having(conditions, type) {
50
+ const sql = condition(conditions, type);
51
+ if (sql)
52
+ return "\nHAVING " + sql;
53
+ return "";
54
+ }
55
+ /**
56
+ * @public
57
+ * @example
58
+ * ```ts
59
+ * selectColumns({c1: true, c2: "count(*)", c3: "column"}) // "c1,count(*) AS c2,column as c3"
60
+ * selectColumns("c1,count(*) AS c2,column as c3") // "c1,count(*) AS c2,column as c3"
61
+ * ```
62
+ */
63
+ function selectColumns(columns) {
64
+ if (typeof columns === "function")
65
+ columns = columns();
66
+ switch (typeof columns) {
67
+ case "string":
68
+ return columns;
69
+ case "object": {
70
+ if (columns instanceof Array) {
71
+ if (columns.length === 0)
72
+ throw new Error("没有选择任何列");
73
+ return columns.join(",");
74
+ }
75
+ else {
76
+ let sql = "";
77
+ const keys = Object.keys(columns);
78
+ if (keys.length === 0)
79
+ throw new Error("没有选择任何列");
80
+ let k = keys[0];
81
+ let v = columns[k];
82
+ if (typeof v === "string")
83
+ sql += v + " AS " + k;
84
+ else
85
+ sql += k;
86
+ for (let i = 1; i < keys.length; i++) {
87
+ k = keys[i];
88
+ v = columns[k];
89
+ sql += ",";
90
+ if (typeof v === "string")
91
+ sql += v + " AS " + k;
92
+ else
93
+ sql += k;
94
+ }
95
+ return sql;
96
+ }
97
+ }
98
+ default:
99
+ throw new TypeError("columns 应为 string 或 object 类型");
100
+ }
101
+ }
102
+ /**
103
+ * 生成 ORDER BY 语句, d
104
+ * @public
105
+ * @example
106
+ * ```ts
107
+ * // 以下生成 "\nORDER BY age DESC NULLS FIRST,num ASC"
108
+ * orderBy("age DESC NULLS FIRST,num ASC");
109
+ * orderBy(["age DESC NULLS FIRST", "num ASC"]);
110
+ * orderBy([
111
+ * { key: "age", asc: false, nullLast: false },
112
+ * { key: "num", asc: true },
113
+ * ]);
114
+ * orderBy({ age: "DESC NULLS FIRST", num: true });
115
+ *
116
+ * orderBy([]) // ""
117
+ * orderBy({}) // ""
118
+ * ```
119
+ */
120
+ function orderBy(by) {
121
+ if (typeof by === "function")
122
+ by = by();
123
+ let sql = "";
124
+ if (!by)
125
+ return sql;
126
+ if (typeof by === "string") {
127
+ sql += "\nORDER BY " + by;
128
+ }
129
+ else if (by instanceof Array) {
130
+ if (by.length) {
131
+ sql += "\nORDER BY " + handlerOrderValue(by[0]);
132
+ for (let i = 1; i < by.length; i++)
133
+ sql += "," + handlerOrderValue(by[i]);
134
+ }
135
+ }
136
+ else {
137
+ let keys = Object.keys(by);
138
+ if (keys.length) {
139
+ let key = keys[0];
140
+ let value = by[key];
141
+ sql += "\nORDER BY " + key + " " + (typeof value === "string" ? value : value ? "ASC" : "DESC");
142
+ for (let i = 1; i < keys.length; i++) {
143
+ key = keys[i];
144
+ value = by[key];
145
+ sql += "," + key + " ";
146
+ if (typeof value === "string")
147
+ sql += value;
148
+ else
149
+ sql += value ? "ASC" : "DESC";
150
+ }
151
+ }
152
+ }
153
+ return sql;
154
+ }
155
+ function handlerOrderValue(value) {
156
+ if (typeof value === "string")
157
+ return value;
158
+ else {
159
+ let str = value.key + " " + (value.asc ? "ASC" : "DESC");
160
+ if (value.nullLast !== undefined)
161
+ str += value.nullLast ? " NULLS LAST" : " NULLS FIRST";
162
+ return str;
163
+ }
164
+ }
165
+
166
+ export { getObjectListKeys, having, orderBy, selectColumns, where };
@@ -0,0 +1,82 @@
1
+ import { CustomDbType } from './infer_db_type.js';
2
+
3
+ /** @public */
4
+ class TypeChecker {
5
+ map;
6
+ constructor(map) {
7
+ this.map = map;
8
+ }
9
+ check(value) {
10
+ const map = this.map;
11
+ let v;
12
+ for (const [k, expect] of map) {
13
+ v = value[k];
14
+ let err;
15
+ if (v === null) {
16
+ if (expect.notNull)
17
+ throw new Error(`${k} 不能为空`);
18
+ continue;
19
+ }
20
+ else if (v === undefined) {
21
+ if (expect.sqlDefault === undefined && expect.notNull)
22
+ throw new Error(`${k} 不能为 undefined`);
23
+ continue;
24
+ }
25
+ else if (expect.isArray) {
26
+ if (v instanceof Array)
27
+ err = this.checkArray(v, expect.type);
28
+ else
29
+ err = getErrStr(`Array<${expect.type.name}>`, typeof v);
30
+ }
31
+ else {
32
+ err = this.checkItem(v, expect.type);
33
+ }
34
+ if (err)
35
+ throw new Error(`Key ${k} error: ${err}`);
36
+ }
37
+ return value;
38
+ }
39
+ checkList(value) {
40
+ let i = 0;
41
+ try {
42
+ for (let i = 0; i < value.length; i++) {
43
+ this.check(value[i]);
44
+ }
45
+ return value;
46
+ }
47
+ catch (error) {
48
+ throw new Error(`Item ${i}, ${error.message}`);
49
+ }
50
+ }
51
+ checkArray(v, expect) {
52
+ let err;
53
+ for (let i = 0; i < v.length; i++) {
54
+ err = this.checkItem(v[i], expect);
55
+ if (err)
56
+ return `Item[${i}] ${err}`;
57
+ }
58
+ }
59
+ checkItem(v, expect) {
60
+ if (expect instanceof CustomDbType) {
61
+ if (expect.is(v))
62
+ return;
63
+ }
64
+ else {
65
+ if (v instanceof expect)
66
+ return;
67
+ }
68
+ let actName = typeof v;
69
+ if (actName === "object") {
70
+ if (v === null)
71
+ actName = "null";
72
+ else
73
+ actName = v.constructor?.name ?? "object";
74
+ }
75
+ return getErrStr(expect.name, typeof v);
76
+ }
77
+ }
78
+ function getErrStr(expect, actual) {
79
+ return `Expect ${expect}, Actual ${actual}`;
80
+ }
81
+
82
+ export { TypeChecker };
@@ -0,0 +1,76 @@
1
+ /**
2
+ * 表格列的信息
3
+ * @public
4
+ */
5
+ class ColumnMeta {
6
+ type;
7
+ sqlType;
8
+ notNull;
9
+ isArray;
10
+ sqlDefault;
11
+ constructor(type,
12
+ /** 数据库原始数据类型 */
13
+ sqlType,
14
+ /** 是否非空 */
15
+ notNull = false,
16
+ /** 是否是数组类型 */
17
+ isArray = false,
18
+ /** 数据库原始默认值 */
19
+ sqlDefault) {
20
+ this.type = type;
21
+ this.sqlType = sqlType;
22
+ this.notNull = notNull;
23
+ this.isArray = isArray;
24
+ this.sqlDefault = sqlDefault;
25
+ }
26
+ /** 校验 value 的类型 */
27
+ checkValue(value) {
28
+ if (typeof this.type === "function")
29
+ return value instanceof this.type;
30
+ return this.type.is(value);
31
+ }
32
+ }
33
+ /**
34
+ * 数据库类型到JS类型的映射
35
+ * @public
36
+ */
37
+ class YourTypeMap {
38
+ typeMap;
39
+ static create(rawTypeMap) {
40
+ return new this(rawTypeMap);
41
+ }
42
+ constructor(typeMap = {}) {
43
+ this.typeMap = typeMap;
44
+ }
45
+ genColumn(type, notNull, defaultValue) {
46
+ const constructor = Reflect.get(this.typeMap, type);
47
+ const column = new ColumnMeta(constructor, type, notNull, false, defaultValue);
48
+ return column;
49
+ }
50
+ genArrColumn(type, notNull, defaultValue) {
51
+ const constructor = Reflect.get(this.typeMap, type);
52
+ const column = new ColumnMeta(constructor, type + "[]", notNull, true, defaultValue);
53
+ return column;
54
+ }
55
+ }
56
+ function baseType(v) {
57
+ return typeof v === this.name;
58
+ }
59
+ /**
60
+ * 自定义数据类型
61
+ * @public
62
+ */
63
+ class CustomDbType {
64
+ is;
65
+ name;
66
+ static bigint = new CustomDbType(baseType, "bigint");
67
+ static number = new CustomDbType(baseType, "number");
68
+ static string = new CustomDbType(baseType, "string");
69
+ static boolean = new CustomDbType(baseType, "boolean");
70
+ constructor(is, name) {
71
+ this.is = is;
72
+ this.name = name;
73
+ }
74
+ }
75
+
76
+ export { ColumnMeta, CustomDbType, YourTypeMap };
@@ -0,0 +1,33 @@
1
+ import { DbTableQuery } from '../select/TableQuery.js';
2
+ import { TypeChecker } from './checker.js';
3
+
4
+ /**
5
+ * 完整数据库表数据
6
+ * @public
7
+ */
8
+ class YourTable extends DbTableQuery {
9
+ define;
10
+ constructor(name, define, sqlValue) {
11
+ super(name, sqlValue);
12
+ this.define = define;
13
+ this.columns = Object.keys(define);
14
+ }
15
+ columns;
16
+ getColumnMeta(name) {
17
+ return Reflect.get(this.define, name);
18
+ }
19
+ createTypeChecker(keys) {
20
+ let map = new Map();
21
+ let defined = this.define;
22
+ let k;
23
+ for (let i = 0; i < keys.length; i++) {
24
+ k = keys[i];
25
+ if (defined[k] === undefined)
26
+ throw new Error(`key ${k} 未定义`);
27
+ map.set(k, defined[k]);
28
+ }
29
+ return new TypeChecker(map);
30
+ }
31
+ }
32
+
33
+ export { YourTable };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asla/yoursql",
3
- "version": "0.8.2",
3
+ "version": "0.8.3",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "types": "./dist/mod.d.ts",
@@ -29,8 +29,8 @@
29
29
  "url": "https://github.com/asnowc/yoursql"
30
30
  },
31
31
  "exports": {
32
- ".": "./dist/sql_gen.js",
33
- "./client": "./dist/client.js"
32
+ ".": "./dist/sql_gen/mod.js",
33
+ "./client": "./dist/client/mod.js"
34
34
  },
35
35
  "files": [
36
36
  "dist/**/*.js",