@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,21 @@
1
+ /** @public */
2
+ class DbCursor {
3
+ // implement
4
+ [Symbol.asyncDispose]() {
5
+ return this.close();
6
+ }
7
+ async *[Symbol.asyncIterator]() {
8
+ let data = await this.read();
9
+ try {
10
+ while (data.length) {
11
+ yield* data;
12
+ data = await this.read();
13
+ }
14
+ }
15
+ finally {
16
+ await this.close();
17
+ }
18
+ }
19
+ }
20
+
21
+ export { DbCursor };
@@ -0,0 +1,56 @@
1
+ import { DbQuery } from './DbQuery.js';
2
+ import { ConnectionNotAvailableError } from './errors.js';
3
+
4
+ /**
5
+
6
+ /**
7
+ * 池连接
8
+ * @public
9
+ */
10
+ class DbPoolConnection extends DbQuery {
11
+ constructor(conn, onRelease) {
12
+ super();
13
+ this.#conn = conn;
14
+ this.#onRelease = onRelease;
15
+ }
16
+ #onRelease;
17
+ //implement
18
+ async begin(mode) {
19
+ await this.query("BEGIN" + (mode ? " TRANSACTION ISOLATION LEVEL " + mode : ""));
20
+ }
21
+ #conn;
22
+ query(sql) {
23
+ if (!this.#conn)
24
+ return Promise.reject(new ConnectionNotAvailableError("Connection already release"));
25
+ return this.#conn.query(sql);
26
+ }
27
+ multipleQuery(sql) {
28
+ if (!this.#conn)
29
+ return Promise.reject(new ConnectionNotAvailableError("Connection already release"));
30
+ return this.#conn.multipleQuery(sql);
31
+ }
32
+ //implement
33
+ async rollback() {
34
+ await this.query("ROLLBACK");
35
+ }
36
+ //implement
37
+ async commit() {
38
+ await this.query("COMMIT");
39
+ }
40
+ get released() {
41
+ return !this.#conn;
42
+ }
43
+ /** 调用 release() 时,如果事务未提交,则抛出异常 */
44
+ release() {
45
+ if (this.#conn) {
46
+ this.#conn = undefined;
47
+ this.#onRelease();
48
+ }
49
+ }
50
+ //implement
51
+ [Symbol.dispose]() {
52
+ return this.release();
53
+ }
54
+ }
55
+
56
+ export { DbPoolConnection };
@@ -0,0 +1,98 @@
1
+ import { DbQuery } from './DbQuery.js';
2
+ import { ParallelQueryError, ConnectionNotAvailableError } from './errors.js';
3
+
4
+ /**
5
+ * @public
6
+ * 池连接事务
7
+ */
8
+ class DbPoolTransaction extends DbQuery {
9
+ mode;
10
+ constructor(connect, mode) {
11
+ super();
12
+ this.mode = mode;
13
+ this.#query = (sql) => {
14
+ return new Promise((resolve, reject) => {
15
+ this.#pending = connect()
16
+ .then((conn) => {
17
+ this.#conn = conn;
18
+ const promise = conn.multipleQuery("BEGIN" + (this.mode ? " TRANSACTION ISOLATION LEVEL " + this.mode : "") + ";\n" + sql);
19
+ this.#pending = promise;
20
+ this.#query = this.#queryAfter;
21
+ return promise;
22
+ })
23
+ .then((res) => {
24
+ this.#pending = undefined;
25
+ resolve(res[1]);
26
+ }, (e) => {
27
+ this.#pending = undefined;
28
+ reject(e);
29
+ if (this.#conn)
30
+ this.#release(this.#conn, e);
31
+ });
32
+ });
33
+ };
34
+ }
35
+ #pending;
36
+ #conn;
37
+ async commit() {
38
+ if (this.#pending)
39
+ throw new ParallelQueryError();
40
+ if (this.#conn) {
41
+ const promise = this.#conn.query("COMMIT");
42
+ this.#release(this.#conn);
43
+ await promise;
44
+ }
45
+ }
46
+ async rollback() {
47
+ if (this.#pending)
48
+ throw new ParallelQueryError();
49
+ if (this.#conn) {
50
+ const promise = this.#conn.query("ROLLBACK");
51
+ this.#release(this.#conn);
52
+ await promise;
53
+ }
54
+ }
55
+ savePoint(savePoint) {
56
+ return this.query("SAVEPOINT" + savePoint).then(() => { });
57
+ }
58
+ rollbackTo(savePoint) {
59
+ return this.query("ROLLBACK TO " + savePoint).then(() => { });
60
+ }
61
+ /** 拿到连接后执行这个 */
62
+ #queryAfter(sql) {
63
+ return this.#conn.query(sql).then((res) => {
64
+ this.#pending = undefined;
65
+ return res;
66
+ }, (e) => {
67
+ this.#pending = undefined;
68
+ this.#release(this.#conn, e);
69
+ throw e;
70
+ });
71
+ }
72
+ #query;
73
+ query(sql) {
74
+ if (this.#pending)
75
+ return Promise.reject(new ParallelQueryError());
76
+ return this.#query(sql.toString());
77
+ }
78
+ multipleQuery(sql) {
79
+ if (this.#pending)
80
+ return Promise.reject(new ParallelQueryError());
81
+ return this.#query(sql.toString());
82
+ }
83
+ #error;
84
+ #release(conn, error = new ConnectionNotAvailableError("Connection already release")) {
85
+ this.#error = error;
86
+ this.#query = () => Promise.reject(this.#error);
87
+ this.#conn = undefined;
88
+ conn.release();
89
+ }
90
+ get released() {
91
+ return !!this.#error;
92
+ }
93
+ [Symbol.asyncDispose]() {
94
+ return this.rollback();
95
+ }
96
+ }
97
+
98
+ export { DbPoolTransaction };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * SQL 查询相关操作
3
+ * @public
4
+ */
5
+ class DbQuery {
6
+ /** 单语句查询受影响的行 */
7
+ queryCount(sql) {
8
+ return this.query(sql.toString()).then((res) => {
9
+ if (res.rowCount === null)
10
+ return 0;
11
+ return res.rowCount;
12
+ });
13
+ }
14
+ queryRows(sql) {
15
+ return this.query(sql.toString()).then((res) => res.rows);
16
+ }
17
+ multipleQueryRows(sql) {
18
+ return this.multipleQuery(sql.toString()).then((res) => res.map((item) => item.rows ?? []));
19
+ }
20
+ async queryMap(sql, key) {
21
+ const { rows } = await this.query(sql.toString());
22
+ let map = new Map();
23
+ for (let i = 0; i < rows.length; i++) {
24
+ map.set(rows[i][key], rows[i]);
25
+ }
26
+ return map;
27
+ }
28
+ }
29
+
30
+ export { DbQuery };
@@ -0,0 +1,14 @@
1
+ /** @public */
2
+ class ParallelQueryError extends Error {
3
+ constructor() {
4
+ super("The previous query was not completed and cannot be executed");
5
+ }
6
+ }
7
+ /** @public */
8
+ class ConnectionNotAvailableError extends Error {
9
+ constructor(message) {
10
+ super(message);
11
+ }
12
+ }
13
+
14
+ export { ConnectionNotAvailableError, ParallelQueryError };
@@ -0,0 +1,5 @@
1
+ export { ConnectionNotAvailableError, ParallelQueryError } from './errors.js';
2
+ export { DbQuery } from './DbQuery.js';
3
+ export { DbCursor } from './DbCursor.js';
4
+ export { DbPoolConnection } from './DbPoolConnection.js';
5
+ export { DbPoolTransaction } from './DbPoolTransaction.js';
@@ -0,0 +1,19 @@
1
+ import { pgSqlTransformer } from './sql_value/db_type.js';
2
+ import { SqlValuesCreator } from './sql_value/sql_value.js';
3
+ export { SqlRaw } from './sql_value/sql_value.js';
4
+ export { DbTable } from './select/DbTable.js';
5
+ export { Selection, SqlSelectChain } from './select/query_chain_select.js';
6
+ export { SqlStatement, SqlStatementDataset, SqlTextStatementDataset } from './select/query_chain_abstract.js';
7
+ export { DbTableQuery } from './select/TableQuery.js';
8
+ export { getObjectListKeys, having, orderBy, selectColumns, where } from './util.js';
9
+ export { TypeChecker } from './your_table/checker.js';
10
+ export { ColumnMeta, CustomDbType, YourTypeMap } from './your_table/infer_db_type.js';
11
+ export { YourTable } from './your_table/table.js';
12
+
13
+ /**
14
+ * 默认的 SqlValuesCreator 实列
15
+ * @public
16
+ */
17
+ const v = SqlValuesCreator.create(pgSqlTransformer);
18
+
19
+ export { SqlValuesCreator, pgSqlTransformer, v };
@@ -0,0 +1,70 @@
1
+ import { where } from '../util.js';
2
+ import { Selection } from './query_chain_select.js';
3
+ import { SqlChainModify } from './query_chain_insert.js';
4
+ import { createUpdateSetFromObject } from './_statement.js';
5
+
6
+ /**
7
+ * 数据库表
8
+ * @public
9
+ */
10
+ class DbTable {
11
+ name;
12
+ constructor(name) {
13
+ this.name = name;
14
+ }
15
+ fromAs(as) {
16
+ return new Selection(this.name, as);
17
+ }
18
+ select(columns, as) {
19
+ return this.fromAs(as).select(columns);
20
+ }
21
+ /**
22
+ * INSERT 语句,需要注意 SQL 注入
23
+ * @example
24
+ * ```ts
25
+ * table.insert(["age","name"], "VALUES (18, 'hi'), (17, 'hh')") // INSERT INTO table(age,name) VALUES(18, 'hi'), (17, 'hh')
26
+ * ```
27
+ */
28
+ insert(columns, values) {
29
+ if (typeof columns !== "string" || !columns)
30
+ throw new TypeError("columns 必须是有效的 string 类型");
31
+ if (typeof values === "function")
32
+ values = values();
33
+ if (typeof values !== "string")
34
+ throw new TypeError("values 必须是 string 或 function 类型");
35
+ let sql = `INSERT INTO ${this.name}(${columns})\n${values}`;
36
+ return new SqlChainModify(sql);
37
+ }
38
+ /**
39
+ * UPDATE 语句,需要注意 SQL 注入
40
+ * @example
41
+ * ```ts
42
+ * table.update("age=3, name='hi'") // "UPDATE table SET age=3, name='hi'"
43
+ * table.update({age: "3", name: "'hi'", k1: undefined, k2: ""}) // "UPDATE table SET age=3, name='hi'"
44
+ * ```
45
+ */
46
+ update(values) {
47
+ if (typeof values === "function")
48
+ values = values();
49
+ switch (typeof values) {
50
+ case "object": {
51
+ let sql = createUpdateSetFromObject(values);
52
+ return new SqlChainModify("UPDATE " + this.name + " " + sql);
53
+ }
54
+ case "string":
55
+ return new SqlChainModify("UPDATE " + this.name + " SET\n" + values);
56
+ default:
57
+ throw new TypeError("参数 values 错误");
58
+ }
59
+ }
60
+ delete(option = {}) {
61
+ let sql = "DELETE FROM " + this.name;
62
+ sql += where(option.where);
63
+ return new SqlChainModify(sql);
64
+ }
65
+ toSelect() {
66
+ return this.name;
67
+ }
68
+ }
69
+
70
+ export { DbTable };
@@ -0,0 +1,68 @@
1
+ import { getObjectListKeys } from '../util.js';
2
+ import { SqlChainModify } from './query_chain_insert.js';
3
+ import { DbTable } from './DbTable.js';
4
+
5
+ /** @public */
6
+ class DbTableQuery extends DbTable {
7
+ statement;
8
+ constructor(name, statement) {
9
+ super(name);
10
+ this.statement = statement;
11
+ }
12
+ insert(values_column, _values) {
13
+ if (_values)
14
+ return super.insert(values_column, _values);
15
+ let values = values_column;
16
+ if (typeof values === "function")
17
+ values = values();
18
+ if (typeof values !== "object")
19
+ throw new TypeError("values 类型错误");
20
+ let valuesStr;
21
+ let insertCol;
22
+ if (values instanceof Array) {
23
+ if (values.length === 0)
24
+ throw new Error("值不能为空");
25
+ insertCol = Array.from(getObjectListKeys(values));
26
+ valuesStr = `VALUES\n${this.statement.objectListToValuesList(values, insertCol)}`;
27
+ }
28
+ else {
29
+ insertCol = Object.keys(values);
30
+ valuesStr = `VALUES\n(${this.statement.objectToValues(values, insertCol)})`;
31
+ }
32
+ if (insertCol.length === 0)
33
+ throw new Error("插入列不能为空");
34
+ const columnStr = insertCol.join(",");
35
+ let sql = `INSERT INTO ${this.name} (${columnStr})\n${valuesStr}`;
36
+ return new SqlChainModify(sql);
37
+ }
38
+ /**
39
+ * UPDATE 语句,与 update() 不同的是,它会将值进行安全转换
40
+ * @example
41
+ * ```ts
42
+ * table.update({age:3, name:"hi"}, true) // "UPDATE table SET age=3, name='hi'"
43
+ * ```
44
+ */
45
+ updateFrom(values) {
46
+ if (typeof values === "function")
47
+ values = values();
48
+ let setStr;
49
+ if (typeof values === "string")
50
+ setStr = values;
51
+ else {
52
+ const updateKey = Object.entries(values);
53
+ let setList = [];
54
+ for (const [k, v] of updateKey) {
55
+ if (v === undefined)
56
+ continue;
57
+ setList.push(k + "= " + this.statement.toSqlStr(v));
58
+ }
59
+ setStr = setList.join(",\n");
60
+ }
61
+ if (!setStr)
62
+ throw new Error("值不能为空");
63
+ let sql = `UPDATE ${this.name} SET\n${setStr}`;
64
+ return new SqlChainModify(sql);
65
+ }
66
+ }
67
+
68
+ export { DbTableQuery };
@@ -0,0 +1,60 @@
1
+ function condition(conditions, type = "AND") {
2
+ if (typeof conditions === "function")
3
+ conditions = conditions();
4
+ if (!conditions)
5
+ return;
6
+ if (typeof conditions === "string")
7
+ return conditions;
8
+ else {
9
+ if (conditions.length) {
10
+ let sql = "";
11
+ type = " " + type + " ";
12
+ sql += conditions[0];
13
+ for (let i = 1; i < conditions.length; i++)
14
+ sql += type + conditions[i];
15
+ return sql;
16
+ }
17
+ return;
18
+ }
19
+ }
20
+ function createUpdateSetFromObject(set) {
21
+ const updateKey = Object.keys(set);
22
+ let i = 0;
23
+ let key;
24
+ let value;
25
+ let sql;
26
+ for (; i < updateKey.length; i++) {
27
+ key = updateKey[i];
28
+ value = set[key];
29
+ if (value === undefined)
30
+ continue;
31
+ if (typeof value === "string") {
32
+ if (value) {
33
+ sql = "SET\n" + key + "= " + value;
34
+ break;
35
+ }
36
+ }
37
+ else
38
+ throw new TypeError(`key ${key} 类型错误(${typeof value})`);
39
+ }
40
+ if (sql) {
41
+ i++;
42
+ for (; i < updateKey.length; i++) {
43
+ key = updateKey[i];
44
+ value = set[key];
45
+ if (value === undefined)
46
+ continue;
47
+ if (typeof value === "string") {
48
+ if (value)
49
+ sql += "," + key + "= " + value;
50
+ }
51
+ else
52
+ throw new TypeError(`key ${key} 类型错误(${typeof value})`);
53
+ }
54
+ return sql;
55
+ }
56
+ else
57
+ throw new Error("值不能为空");
58
+ }
59
+
60
+ export { condition, createUpdateSetFromObject };
@@ -0,0 +1,27 @@
1
+ /** @public */
2
+ class SqlStatement {
3
+ }
4
+ /** @public */
5
+ class SqlStatementDataset extends SqlStatement {
6
+ /**
7
+ * 转成子选择语句, 你可以使用 select form xxx 选择
8
+ * 如果是 table 则是 table name
9
+ * 如果是 选择语句,则是 (xxx)
10
+ */
11
+ toSelect() {
12
+ return "(" + this.toString() + ")";
13
+ }
14
+ }
15
+ /** @public */
16
+ class SqlTextStatementDataset extends SqlStatementDataset {
17
+ sql;
18
+ constructor(sql) {
19
+ super();
20
+ this.sql = sql;
21
+ }
22
+ toString() {
23
+ return this.sql;
24
+ }
25
+ }
26
+
27
+ export { SqlStatement, SqlStatementDataset, SqlTextStatementDataset };
@@ -0,0 +1,64 @@
1
+ import { selectColumns, where } from '../util.js';
2
+ import { createUpdateSetFromObject } from './_statement.js';
3
+ import { SqlStatement, SqlTextStatementDataset } from './query_chain_abstract.js';
4
+
5
+ class SqlChainModify extends SqlStatement {
6
+ sql;
7
+ constructor(sql) {
8
+ super();
9
+ this.sql = sql;
10
+ }
11
+ returning(returns) {
12
+ if (typeof returns === "function")
13
+ returns = returns();
14
+ let columnsStr;
15
+ if (returns === "*") {
16
+ columnsStr = "*";
17
+ }
18
+ else {
19
+ columnsStr = selectColumns(returns);
20
+ }
21
+ let sql = this.toString() + "\nRETURNING " + columnsStr;
22
+ return new SqlTextStatementDataset(sql);
23
+ }
24
+ onConflict(onConflict) {
25
+ if (typeof onConflict === "function")
26
+ onConflict = onConflict();
27
+ if (typeof onConflict !== "string")
28
+ onConflict = onConflict.join(",");
29
+ let sql = this.toString() + `\nON CONFLICT (${onConflict})`;
30
+ return new SqlInsertConflictBranch(sql);
31
+ }
32
+ where(where$1) {
33
+ const sql = where(where$1);
34
+ return new SqlChainModify(this.toString() + sql);
35
+ }
36
+ toString() {
37
+ return this.sql;
38
+ }
39
+ }
40
+ class SqlInsertConflictBranch {
41
+ sql;
42
+ constructor(sql) {
43
+ this.sql = sql;
44
+ }
45
+ doUpdate(set) {
46
+ if (typeof set === "function")
47
+ set = set();
48
+ let sql = this.sql;
49
+ if (typeof set === "object") {
50
+ sql += "\nDO UPDATE ";
51
+ sql += createUpdateSetFromObject(set);
52
+ }
53
+ else if (set)
54
+ sql += "DO UPDATE SET\n" + set;
55
+ else
56
+ sql += "DO NOTHING";
57
+ return new SqlChainModify(sql);
58
+ }
59
+ doNotThing() {
60
+ return new SqlChainModify(this.sql + " DO NOTHING");
61
+ }
62
+ }
63
+
64
+ export { SqlChainModify, SqlInsertConflictBranch };
@@ -0,0 +1,105 @@
1
+ import { SqlTextStatementDataset } from './query_chain_abstract.js';
2
+ import { where, having, orderBy, selectColumns } from '../util.js';
3
+ import { condition } from './_statement.js';
4
+
5
+ var _a;
6
+ /**
7
+ * @public ChainSelectWhere 的默认实现
8
+ */
9
+ class SqlSelectChain extends SqlTextStatementDataset {
10
+ where(param) {
11
+ return new SqlSelectChain(this.toString() + where(param));
12
+ }
13
+ groupBy(columns) {
14
+ let sql = this.toString();
15
+ if (typeof columns === "string")
16
+ sql += " GROUP BY " + columns;
17
+ else
18
+ sql += " GROUP BY " + columns.join(",");
19
+ return new SqlSelectChain(sql);
20
+ }
21
+ having(param) {
22
+ return new SqlSelectChain(this.toString() + having(param));
23
+ }
24
+ orderBy(param) {
25
+ return new SqlSelectChain(this.toString() + orderBy(param));
26
+ }
27
+ limit(limit, offset) {
28
+ let sql = this.toString();
29
+ let type;
30
+ if (limit) {
31
+ type = typeof limit;
32
+ if (type === "number" || type === "bigint")
33
+ sql += "\nLIMIT " + limit;
34
+ else
35
+ throw new TypeError("limit 必须是个整数:" + limit);
36
+ }
37
+ if (offset) {
38
+ type = typeof offset;
39
+ if (type === "number" || type === "bigint")
40
+ sql += "\nOFFSET " + offset;
41
+ else
42
+ throw new TypeError("offset 必须是个整数:" + limit);
43
+ }
44
+ return new SqlTextStatementDataset(sql);
45
+ }
46
+ }
47
+ function fromAs(selectable, as) {
48
+ if (typeof selectable === "function")
49
+ selectable = selectable();
50
+ let sql = typeof selectable === "string" ? selectable : selectable.toSelect();
51
+ if (as)
52
+ sql += " AS " + as;
53
+ return sql;
54
+ }
55
+ /** @public */
56
+ class Selection {
57
+ static from(selectable, as) {
58
+ return new this(selectable, as);
59
+ }
60
+ #sql;
61
+ constructor(selectable, as) {
62
+ this.#sql = fromAs(selectable, as);
63
+ }
64
+ toString() {
65
+ return "FROM " + this.#sql;
66
+ }
67
+ #join(type, selectable, as, on) {
68
+ let sql = this.#sql + "\n" + type + " " + fromAs(selectable, as);
69
+ if (on) {
70
+ sql += " ON " + condition(on);
71
+ }
72
+ return new _a(sql);
73
+ }
74
+ fullJoin(selectable, as, on) {
75
+ return this.#join("FULL JOIN", selectable, as, on);
76
+ }
77
+ innerJoin(selectable, as, on) {
78
+ return this.#join("INNER JOIN", selectable, as, on);
79
+ }
80
+ leftJoin(selectable, as, on) {
81
+ return this.#join("LEFT JOIN", selectable, as, on);
82
+ }
83
+ rightJoin(selectable, as, on) {
84
+ return this.#join("RIGHT JOIN", selectable, as, on);
85
+ }
86
+ naturalJoin(selectable, as) {
87
+ return this.#join("NATURAL JOIN", selectable, as);
88
+ }
89
+ crossJoin(selectable, as) {
90
+ return this.#join("CROSS JOIN", selectable, as);
91
+ }
92
+ from(selectable, as) {
93
+ return new _a(this.#sql + "," + fromAs(selectable, as));
94
+ }
95
+ select(columnsIn) {
96
+ if (typeof columnsIn === "function")
97
+ columnsIn = columnsIn();
98
+ let sql = "SELECT " + selectColumns(columnsIn);
99
+ sql += "\n" + this.toString();
100
+ return new SqlSelectChain(sql);
101
+ }
102
+ }
103
+ _a = Selection;
104
+
105
+ export { Selection, SqlSelectChain };
@@ -0,0 +1,40 @@
1
+ import { SqlValuesCreator } from './sql_value.js';
2
+
3
+ /** @public PgSql 转换器 */
4
+ const pgSqlTransformer = new Map([
5
+ [
6
+ Array,
7
+ function encodePgArray(value) {
8
+ if (value.length === 0)
9
+ return "NULL";
10
+ const valueStr = [];
11
+ let type;
12
+ let basicType;
13
+ for (let i = 0; i < value.length; i++) {
14
+ if (value[i] === null || value[i] === undefined)
15
+ valueStr[i] = this.toSqlStr(value[i]);
16
+ else if (type) {
17
+ valueStr[i] = this.toSqlStr(value[i], type);
18
+ }
19
+ else {
20
+ basicType = typeof value[i];
21
+ if (basicType === "object") {
22
+ type = this.getClassType(value[i]);
23
+ }
24
+ else
25
+ type = basicType;
26
+ valueStr[i] = this.toSqlStr(value[i], type);
27
+ }
28
+ }
29
+ return "ARRAY[" + valueStr.join(",") + "]";
30
+ },
31
+ ],
32
+ [
33
+ Date,
34
+ function (value) {
35
+ return SqlValuesCreator.string(value.toISOString());
36
+ },
37
+ ],
38
+ ]);
39
+
40
+ export { pgSqlTransformer };