@asla/yoursql 0.8.8 → 0.8.10

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/README.md CHANGED
@@ -18,17 +18,16 @@ SQL 生成器
18
18
 
19
19
  [API 文档](https://jsr.io/@asla/yoursql/doc)
20
20
 
21
- ### 安全转将 JS 值转换为 SQL 值,避免 SQL 注入
21
+ ### v()
22
22
 
23
- 导入
23
+ 安全转将 JS 值转换为 SQL 值,避免 SQL 注入
24
+
25
+ `v` 函数能够将 JS 值转换为 SQL 的文本形式。\
26
+ 默认情况下,支持 PostgresSQL, 因为不同数据库的值转换有些差异,如果使用其他数据库,可能需要配置对象到字符串的自定义转换器
24
27
 
25
28
  ```ts
26
29
  import { v } from "@asla/yoursql";
27
- ```
28
30
 
29
- 默认情况下,支持 PostgresSQL, 因为不同数据库的值转换有些差异,如果使用其他数据库,可能需要配置对象转换器
30
-
31
- ```ts
32
31
  v(1); // "1"
33
32
  v(1n); // "1"
34
33
  v("te'xt"); // "'te''xt'"
@@ -37,32 +36,86 @@ v([1, 2, 3]); // "ARRAY[1,2,3]"
37
36
  v({ id: "abc", size: 1 }); // "'{\"id\":\"abc\",\"size\":1}'"
38
37
  v(null); // "NULL"
39
38
  v(undefined); // "DEFAULT"
39
+
40
+ const params = { id: 3 };
41
+ const sql = `SELECT * FROM user WHERE user_id=${v(params.id)}`;
40
42
  ```
41
43
 
42
- 如果传入 String 对象,将保留其字符串值,不会进行任何转换
44
+ 如果传入 String 对象,将保留其字符串值,不会进行任何转换, 这在有些需要原生SQL操作的场景下非常有用
43
45
 
44
46
  ```ts
47
+ import { v } from "@asla/yoursql";
48
+
45
49
  v(new String("1+1")); // "1+1"
46
50
  ```
47
51
 
48
52
  你可以自定义对象到字符串的转换, 例如,你想将 Set 转换为 PostgresSql 的 ARRAY[] 输入格式
49
53
 
50
54
  ```ts
55
+ import { v } from "@asla/yoursql";
56
+
51
57
  v.setTransformer(Set, function (value: Set) {
52
58
  return this.v(Array.from(value));
53
59
  });
60
+
61
+ v(new Set([1, 2, 3])); // "ARRAY[1,2,3]"
54
62
  ```
55
63
 
56
- 转换对象数组
64
+ #### v.toValues()
65
+
66
+ 转换数组为 values 的单个值
57
67
 
58
68
  ```ts
69
+ import { v } from "@asla/yoursql";
70
+ v.toValues([1, "abc", null, undefined, { key: "value" }]); // `1,'abc',NULL,DEFAULT,'{"key":"value"}'`
71
+ ```
72
+
73
+ #### v.objectToValues()
74
+
75
+ 转换对象为 values 的单个值
76
+
77
+ ```ts
78
+ import { v } from "@asla/yoursql";
79
+ const obj = { a: "a1", b: "b1", c: undefined, d: "d1" };
80
+ v.objectToValues(obj); // "'a1','b1',DEFAULT,'d1'"
81
+ v.objectToValues(obj, ["b", "a"]); // "'b1','a1'"
82
+ v.objectToValues(obj, [{ a: "TEXT", b: {} }]); // 'a1'::TEXT,'b1'"
83
+ ```
84
+
85
+ #### v.objectListToValuesList()
86
+
87
+ 转换对象数组为 values
88
+
89
+ ```ts
90
+ import { v } from "@asla/yoursql";
91
+
59
92
  const values = [{ a: 1, b: 2 }, { c: 3 }];
60
93
 
61
94
  // 这将自动选择数组中所有键的并集
62
95
  v.objectListToValuesList(values); // "(1,2,null),(null,null,3)"
63
96
 
64
97
  // 或者你可以指定选择键并指定顺序
65
- v.objectListToValuesList(values, ["c", "b"]); // "(null,2),(3,3)"
98
+ const valueStr = v.objectListToValuesList(values, ["c", "b"]); // "(null,2),(3,3)"
99
+
100
+ const sql = `INSERT INTO user(name, role) VALUES ${valueStr}`;
101
+ ```
102
+
103
+ #### v.createValues()
104
+
105
+ ```ts
106
+ const objectList = [{ age: 1, name: "hhh" }, { age: 2, name: "row2" }, { age: 3, name: "row3" }, {}];
107
+
108
+ v.createValues("customName", objectList, {
109
+ age: { sqlType: "INT", sqlDefault: "MAXIMUM(1,2)" },
110
+ name: "TEXT",
111
+ });
112
+ //这将返回
113
+ `(VALUES
114
+ (1::INT,'hhh'::TEXT),
115
+ (2,'row2'),
116
+ (3,'row3'),
117
+ (MAXIMUM(1,2),NULL))
118
+ AS customName(age,name)`;
66
119
  ```
67
120
 
68
121
  ### 生成 SQL 语句
@@ -78,6 +131,17 @@ const s = Selection.from("user", "u")
78
131
  .toString();
79
132
  ```
80
133
 
134
+ 查看 [select](./docs/select.md) 用法
135
+ 查看 [insert/update/delete](./docs/table.md) 用法
136
+
137
+ #### Constructable
138
+
139
+ toto
140
+
141
+ #### ConditionParam
142
+
143
+ toto
144
+
81
145
  ### client 抽象类
82
146
 
83
147
  yoursql 还导出了一些抽象类,实现抽象类后可以方便的进行数据查询
@@ -98,7 +162,12 @@ import {
98
162
 
99
163
  ```ts
100
164
  class YourQuery extends DbQuery {
101
- // implement
165
+ query<T = any>(sql: StringLike): Promise<QueryRowsResult<T>> {
166
+ // implement
167
+ }
168
+ multipleQuery<T extends MultipleQueryResult = MultipleQueryResult>(sql: StringLike): Promise<T> {
169
+ // implement
170
+ }
102
171
  }
103
172
  const db: DbQuery = new YourQuery();
104
173
  ```
@@ -190,3 +259,62 @@ for await (const element of cursor) {
190
259
  if (conditions) break; //提前关闭游标
191
260
  }
192
261
  ```
262
+
263
+ ### 扩展查询链
264
+
265
+ ```ts
266
+ import { v, SqlStatement, SqlStatementDataset, SqlValuesCreator } from "@asla/yoursql";
267
+ import type { DbCursor, QueryResult, QueryRowsResult } from "@asla/yoursql/client";
268
+
269
+ declare const pool: DbQueryPool = new YourPool(); // 你需要实现一个 DbQueryPool
270
+
271
+ export interface QueryableSql {
272
+ query(): Promise<QueryResult>;
273
+ queryCount(): Promise<number>;
274
+ }
275
+ export interface QueryableDataSql<T> extends QueryableSql {
276
+ queryRows(): Promise<T[]>;
277
+ queryMap<K>(key: string): Promise<Map<K, T>>;
278
+ cursor(): Promise<DbCursor<T>>;
279
+ }
280
+ declare module "@asla/yoursql" {
281
+ interface SqlStatement extends QueryableSql {}
282
+ interface SqlStatementDataset<T> extends QueryableDataSql<T> {}
283
+ }
284
+ const base: QueryableSql = {
285
+ queryCount(): Promise<number> {
286
+ return dbPool.queryCount(this.toString());
287
+ },
288
+ query(): Promise<QueryRowsResult<any>> {
289
+ return dbPool.query<any>(this);
290
+ },
291
+ };
292
+ const obj: QueryableDataSql<any> = {
293
+ ...base,
294
+ cursor(): Promise<DbCursor<any>> {
295
+ return dbPool.cursor(this.toString());
296
+ },
297
+ queryMap<K>(key: string): Promise<Map<K, any>> {
298
+ return dbPool.queryMap(this.toString(), key);
299
+ },
300
+ queryRows(): Promise<any[]> {
301
+ return dbPool.queryRows(this.toString());
302
+ },
303
+ };
304
+
305
+ Object.assign(SqlStatement.prototype, base);
306
+ Object.assign(SqlStatementDataset.prototype, obj);
307
+ ```
308
+
309
+ 现在,以及扩展了 SqlStatement 和 SqlStatementDataset 类的原型链,你可以从 select 等语句直接调用查询方法了
310
+
311
+ ```ts
312
+ import { Selection, v } from "@asla/yoursql";
313
+
314
+ const searchName = "Bob";
315
+ const rows = await Selection.from("user", "u")
316
+ .innerJoin("role", "r", "u.id=r.user_id")
317
+ .select({ uid: "u.id", rid: "r.id", example: "u.id||r.id" })
318
+ .where(`u.name LIKE %${v(searchName)}%`)
319
+ .queryRows();
320
+ ```
@@ -1,6 +1,5 @@
1
1
  import { pgSqlTransformer } from './sql_value/db_type.js';
2
2
  import { SqlValuesCreator } from './sql_value/sql_value.js';
3
- export { SqlRaw } from './sql_value/sql_value.js';
4
3
  export { DbTable } from './select/DbTable.js';
5
4
  export { Selection, SqlSelectChain } from './select/query_chain_select.js';
6
5
  export { SqlStatement, SqlStatementDataset, SqlTextStatementDataset } from './select/chain_base.js';
@@ -1,5 +1,5 @@
1
- import { SqlRaw } from "../sql_value/sql_value.ts";
2
1
  /**
2
+ * @deprecated 已废弃,改用 ToInsertType
3
3
  * @public
4
4
  * @param T - 表格查询类型
5
5
  * @param Rq - 默认选择
@@ -14,9 +14,22 @@ export type PickColumn<T extends {
14
14
  } & {
15
15
  [key in Pa]?: T[key];
16
16
  };
17
+ /**
18
+ * 推断表插入类型
19
+ * @public
20
+ * @param T - 表格创建类型
21
+ * @param Pa - 可选列
22
+ */
23
+ export type ToInsertType<T extends {
24
+ [key: string]: any;
25
+ }, Pa extends keyof T = never> = {
26
+ [key in keyof T as key extends Pa ? never : null extends T[key] ? never : key]: T[key];
27
+ } & {
28
+ [key in keyof T as null extends T[key] ? key : key extends Pa ? key : never]?: T[key];
29
+ };
17
30
  /** @public */
18
31
  export type UpdateRowValue<T extends object> = {
19
- [key in keyof T]?: T[key] | SqlRaw;
32
+ [key in keyof T]?: T[key] | String;
20
33
  };
21
34
  /** @public */
22
35
  export type OrderValue = "ASC" | "DESC";
@@ -1,13 +1,4 @@
1
1
  import { SqlStatementDataset } from "../select/chain_base.ts";
2
- declare const SQL_RAW: unique symbol;
3
- /**
4
- * SQL 原始字符类。可以使用 String 类代替,这只是为了推断类型
5
- * @public
6
- */
7
- export declare class SqlRaw<T = any> extends String {
8
- /** 保留以推断类型 */
9
- protected [SQL_RAW]: T;
10
- }
11
2
  /** @public js 对象到编码函数的映射*/
12
3
  export type JsObjectMapSql = Map<new (...args: any[]) => any, SqlValueEncoder>;
13
4
  /** @public 将 js 值转为 SQl 字符串的函数*/
@@ -62,6 +53,7 @@ export declare class SqlValuesCreator {
62
53
  * 将对象列表转为 SQL 的 VALUES。
63
54
  * @example 返回示例: " (...),(...) "
64
55
  * @param keys - 选择的键。如果指定了 keys, 值为 undefined 的属性将自动填充为 null; 如果未指定 keys,将选择 objectList 所有不是 undefined 项的键的并集
56
+ * @param keepUndefinedKey - 是否保留 undefined 的键。默认值为 false,如果为 true , 数组的某一个字段均为 undefined时,将忽略字段,
65
57
  */
66
58
  objectListToValuesList<T extends object>(objectList: T[], keys?: readonly (keyof T)[] | {
67
59
  [key in keyof T]?: string | undefined | ColumnToValueConfig;
@@ -77,7 +69,10 @@ export declare class SqlValuesCreator {
77
69
  private _internalObjectToValues;
78
70
  /**
79
71
  * 将数组列表转为 SQL 的一个 value
80
- * @example 返回示例: " 'abc', '6', 'now()' "
72
+ * @example
73
+ * ```ts
74
+ * v.toValues([1, "abc", null, undefined, { key: "value" }]) // `1,'abc',NULL,DEFAULT,'{"key":"value"}'`
75
+ * ```
81
76
  */
82
77
  toValues(values: readonly any[]): string;
83
78
  /**
@@ -103,5 +98,4 @@ export type ColumnToValueConfig = {
103
98
  sqlType?: string;
104
99
  assertJsType?: AssertJsType;
105
100
  };
106
- export {};
107
101
  //# sourceMappingURL=sql_value.d.ts.map
@@ -1,12 +1,6 @@
1
1
  import { getObjectListKeys } from '../util.js';
2
2
  import { SqlStatementDataset } from '../select/chain_base.js';
3
3
 
4
- /**
5
- * SQL 原始字符类。可以使用 String 类代替,这只是为了推断类型
6
- * @public
7
- */
8
- class SqlRaw extends String {
9
- }
10
4
  /**
11
5
  * SQL value 生成器
12
6
  * @public
@@ -84,7 +78,7 @@ class SqlValuesCreator {
84
78
  case "string":
85
79
  return SqlValuesCreator.string(value);
86
80
  case "boolean":
87
- return value.toString();
81
+ return value ? "TRUE" : "FALSE";
88
82
  case "object": {
89
83
  if (value instanceof String)
90
84
  return value.toString();
@@ -203,13 +197,20 @@ class SqlValuesCreator {
203
197
  let message = error instanceof Error ? error.message : String(error);
204
198
  throw new Error("字段 '" + key + "' 异常," + message);
205
199
  }
200
+ if (values.length === 0)
201
+ throw new Error("object 不能为空");
206
202
  return values.join(",");
207
203
  }
208
204
  /**
209
205
  * 将数组列表转为 SQL 的一个 value
210
- * @example 返回示例: " 'abc', '6', 'now()' "
206
+ * @example
207
+ * ```ts
208
+ * v.toValues([1, "abc", null, undefined, { key: "value" }]) // `1,'abc',NULL,DEFAULT,'{"key":"value"}'`
209
+ * ```
211
210
  */
212
211
  toValues(values) {
212
+ if (values.length === 0)
213
+ throw new Error("values 不能为空");
213
214
  return values.map((v) => this.toSqlStr(v)).join(",");
214
215
  }
215
216
  createValues(asName, values, valuesTypes) {
@@ -301,4 +302,4 @@ class AssertError extends TypeError {
301
302
  }
302
303
  }
303
304
 
304
- export { SqlRaw, SqlValuesCreator };
305
+ export { SqlValuesCreator };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asla/yoursql",
3
- "version": "0.8.8",
3
+ "version": "0.8.10",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "types": "./dist/mod.d.ts",