@maiyunnet/kebab 9.15.1 → 9.15.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/doc/kebab-rag.md +454 -184
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/lib/db/conn.js +3 -0
- package/lib/db/value.d.ts +43 -0
- package/lib/db/value.js +59 -0
- package/lib/s3.d.ts +7 -0
- package/lib/s3.js +23 -0
- package/lib/sql/value.d.ts +43 -0
- package/lib/sql/value.js +59 -0
- package/lib/sql.d.ts +11 -16
- package/lib/sql.js +72 -90
- package/lib/undici/response.d.ts +1 -1
- package/package.json +1 -1
- package/sys/mod.d.ts +12 -3
- package/sys/mod.js +56 -16
- package/www/example/ctr/test.js +21 -9
package/index.d.ts
CHANGED
package/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* --- 本文件用来定义每个目录实体地址的常量 ---
|
|
7
7
|
*/
|
|
8
8
|
/** --- 当前系统版本号 --- */
|
|
9
|
-
export const VER = '9.15.
|
|
9
|
+
export const VER = '9.15.3';
|
|
10
10
|
// --- 服务端用的路径 ---
|
|
11
11
|
const imu = decodeURIComponent(import.meta.url).replace('file://', '').replace(/^\/(\w:)/, '$1');
|
|
12
12
|
/** --- /xxx/xxx --- */
|
package/lib/db/conn.js
CHANGED
|
@@ -2,6 +2,7 @@ import * as pg from 'pg';
|
|
|
2
2
|
import * as lCore from '#kebab/lib/core.js';
|
|
3
3
|
import * as lTime from '#kebab/lib/time.js';
|
|
4
4
|
import * as lDb from '#kebab/lib/db.js';
|
|
5
|
+
import * as lSqlValue from '#kebab/lib/sql/value.js';
|
|
5
6
|
// --- 注册解析器 ---
|
|
6
7
|
// --- pg 库对以下类型默认返回 string,为与 MySQL 行为保持一致,在此注册解析器转为 JS 原生类型 ---
|
|
7
8
|
// --- POLYGON: 返回如 ((1,1),(2,2)) 的字符串,解析为 {x, y}[] ---
|
|
@@ -155,6 +156,7 @@ export class Connection {
|
|
|
155
156
|
'result': 1,
|
|
156
157
|
};
|
|
157
158
|
try {
|
|
159
|
+
values = lSqlValue.serializeList(values);
|
|
158
160
|
this.refreshLast();
|
|
159
161
|
if (this._lastSql.length === 2) {
|
|
160
162
|
this._lastSql.splice(0, 1);
|
|
@@ -212,6 +214,7 @@ export class Connection {
|
|
|
212
214
|
'result': 1,
|
|
213
215
|
};
|
|
214
216
|
try {
|
|
217
|
+
values = lSqlValue.serializeList(values);
|
|
215
218
|
this.refreshLast();
|
|
216
219
|
if (this._lastSql.length === 2) {
|
|
217
220
|
this._lastSql.splice(0, 1);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project: Kebab, User: JianSuoQiYue
|
|
3
|
+
* --- 数据库特殊值的运行时包装与序列化 ---
|
|
4
|
+
*/
|
|
5
|
+
import * as kebab from '#kebab/index.js';
|
|
6
|
+
/** --- JSON 数据的内部标记,不污染原始对象,也不会参与 JSON 序列化 --- */
|
|
7
|
+
declare const jsonValueSymbol: unique symbol;
|
|
8
|
+
/** --- 延迟到数据库边界序列化的 JSON 值 --- */
|
|
9
|
+
export interface IJsonValue<T> {
|
|
10
|
+
readonly [jsonValueSymbol]: true;
|
|
11
|
+
readonly 'value': T;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* --- 创建延迟序列化的 JSON 值 ---
|
|
15
|
+
* @param value 原始 JSON 值
|
|
16
|
+
* @returns JSON 包装值
|
|
17
|
+
*/
|
|
18
|
+
export declare function json<T>(value: T): IJsonValue<T>;
|
|
19
|
+
/**
|
|
20
|
+
* --- 判断是否为 JSON 包装值 ---
|
|
21
|
+
* @param value 待判断的值
|
|
22
|
+
* @returns 是否为 JSON 包装值
|
|
23
|
+
*/
|
|
24
|
+
export declare function isJson(value: unknown): value is IJsonValue<unknown>;
|
|
25
|
+
/**
|
|
26
|
+
* --- 获取 JSON 包装值内的原始值;普通值保持不变 ---
|
|
27
|
+
* @param value 待解包的值
|
|
28
|
+
* @returns 原始值
|
|
29
|
+
*/
|
|
30
|
+
export declare function unwrapJson<T>(value: T): T;
|
|
31
|
+
/**
|
|
32
|
+
* --- 将单个数据库参数转换为驱动可识别的值 ---
|
|
33
|
+
* @param value 数据库参数
|
|
34
|
+
* @returns 序列化后的数据库参数
|
|
35
|
+
*/
|
|
36
|
+
export declare function serialize(value: kebab.Json): kebab.Json;
|
|
37
|
+
/**
|
|
38
|
+
* --- 在进入数据库驱动前序列化特殊参数,不修改调用方数组 ---
|
|
39
|
+
* @param values 数据库参数列表
|
|
40
|
+
* @returns 可直接交给数据库驱动的参数列表
|
|
41
|
+
*/
|
|
42
|
+
export declare function serializeList(values?: kebab.DbValue[]): kebab.DbValue[] | undefined;
|
|
43
|
+
export {};
|
package/lib/db/value.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as lText from '#kebab/lib/text.js';
|
|
2
|
+
/** --- JSON 数据的内部标记,不污染原始对象,也不会参与 JSON 序列化 --- */
|
|
3
|
+
const jsonValueSymbol = Symbol('kebab.db.json');
|
|
4
|
+
/**
|
|
5
|
+
* --- 创建延迟序列化的 JSON 值 ---
|
|
6
|
+
* @param value 原始 JSON 值
|
|
7
|
+
* @returns JSON 包装值
|
|
8
|
+
*/
|
|
9
|
+
export function json(value) {
|
|
10
|
+
return {
|
|
11
|
+
[jsonValueSymbol]: true,
|
|
12
|
+
'value': value,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* --- 判断是否为 JSON 包装值 ---
|
|
17
|
+
* @param value 待判断的值
|
|
18
|
+
* @returns 是否为 JSON 包装值
|
|
19
|
+
*/
|
|
20
|
+
export function isJson(value) {
|
|
21
|
+
return value !== null && typeof value === 'object' &&
|
|
22
|
+
!!value[jsonValueSymbol];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* --- 获取 JSON 包装值内的原始值;普通值保持不变 ---
|
|
26
|
+
* @param value 待解包的值
|
|
27
|
+
* @returns 原始值
|
|
28
|
+
*/
|
|
29
|
+
export function unwrapJson(value) {
|
|
30
|
+
return (isJson(value) ? value.value : value);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* --- 将单个数据库参数转换为驱动可识别的值 ---
|
|
34
|
+
* @param value 数据库参数
|
|
35
|
+
* @returns 序列化后的数据库参数
|
|
36
|
+
*/
|
|
37
|
+
export function serialize(value) {
|
|
38
|
+
return isJson(value) ? lText.stringifyJson(value.value) : value;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* --- 在进入数据库驱动前序列化特殊参数,不修改调用方数组 ---
|
|
42
|
+
* @param values 数据库参数列表
|
|
43
|
+
* @returns 可直接交给数据库驱动的参数列表
|
|
44
|
+
*/
|
|
45
|
+
export function serializeList(values) {
|
|
46
|
+
if (!values) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
let serialized;
|
|
50
|
+
for (let i = 0; i < values.length; ++i) {
|
|
51
|
+
const value = values[i];
|
|
52
|
+
if (!isJson(value)) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
serialized ??= [...values];
|
|
56
|
+
serialized[i] = lText.stringifyJson(value.value);
|
|
57
|
+
}
|
|
58
|
+
return serialized ?? values;
|
|
59
|
+
}
|
package/lib/s3.d.ts
CHANGED
|
@@ -101,6 +101,13 @@ export declare class S3 {
|
|
|
101
101
|
* @param bucket bucket 名
|
|
102
102
|
*/
|
|
103
103
|
getObject(key: string, bucket?: string): Promise<false | (stream.Readable & import("@smithy/types").SdkStreamMixin) | (Blob & import("@smithy/types").SdkStreamMixin) | (ReadableStream<any> & import("@smithy/types").SdkStreamMixin) | undefined>;
|
|
104
|
+
/**
|
|
105
|
+
* --- 获取对象 Buffer ---
|
|
106
|
+
* @param key 对象路径
|
|
107
|
+
* @param bucket bucket 名
|
|
108
|
+
* @returns 对象内容,获取失败或对象无内容时返回 false
|
|
109
|
+
*/
|
|
110
|
+
getObjectBuffer(key: string, bucket?: string): Promise<Buffer | false>;
|
|
104
111
|
/**
|
|
105
112
|
* --- 删除对象 ---
|
|
106
113
|
* @param key 对象路径
|
package/lib/s3.js
CHANGED
|
@@ -163,6 +163,29 @@ export class S3 {
|
|
|
163
163
|
return false;
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* --- 获取对象 Buffer ---
|
|
168
|
+
* @param key 对象路径
|
|
169
|
+
* @param bucket bucket 名
|
|
170
|
+
* @returns 对象内容,获取失败或对象无内容时返回 false
|
|
171
|
+
*/
|
|
172
|
+
async getObjectBuffer(key, bucket) {
|
|
173
|
+
try {
|
|
174
|
+
const go = new s3.GetObjectCommand({
|
|
175
|
+
'Bucket': bucket ?? this._bucket,
|
|
176
|
+
'Key': key
|
|
177
|
+
});
|
|
178
|
+
const r = await this._link.send(go);
|
|
179
|
+
if (!r.Body) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
return Buffer.from(await r.Body.transformToByteArray());
|
|
183
|
+
}
|
|
184
|
+
catch (e) {
|
|
185
|
+
lCore.log(this._ctr, '[LIB][S3][getObjectBuffer] ' + lText.stringifyJson(e.message ?? '').slice(1, -1).replace(/"/g, '""'), '-error');
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
166
189
|
/**
|
|
167
190
|
* --- 删除对象 ---
|
|
168
191
|
* @param key 对象路径
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project: Kebab, User: JianSuoQiYue
|
|
3
|
+
* --- SQL 特殊参数的运行时包装与序列化 ---
|
|
4
|
+
*/
|
|
5
|
+
import * as kebab from '#kebab/index.js';
|
|
6
|
+
/** --- JSON 参数的内部标记,不污染原始对象,也不会参与 JSON 序列化 --- */
|
|
7
|
+
declare const jsonValueSymbol: unique symbol;
|
|
8
|
+
/** --- 延迟到数据库边界序列化的 JSON 参数 --- */
|
|
9
|
+
export interface IJsonValue<T> {
|
|
10
|
+
readonly [jsonValueSymbol]: true;
|
|
11
|
+
readonly 'value': T;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* --- 创建延迟序列化的 JSON 参数 ---
|
|
15
|
+
* @param value 原始 JSON 值
|
|
16
|
+
* @returns JSON 包装值
|
|
17
|
+
*/
|
|
18
|
+
export declare function json<T>(value: T): IJsonValue<T>;
|
|
19
|
+
/**
|
|
20
|
+
* --- 判断是否为 JSON 包装值 ---
|
|
21
|
+
* @param value 待判断的值
|
|
22
|
+
* @returns 是否为 JSON 包装值
|
|
23
|
+
*/
|
|
24
|
+
export declare function isJson(value: unknown): value is IJsonValue<unknown>;
|
|
25
|
+
/**
|
|
26
|
+
* --- 获取 JSON 包装值内的原始值;普通值保持不变 ---
|
|
27
|
+
* @param value 待解包的值
|
|
28
|
+
* @returns 原始值
|
|
29
|
+
*/
|
|
30
|
+
export declare function unwrapJson<T>(value: T): T;
|
|
31
|
+
/**
|
|
32
|
+
* --- 将单个 SQL 参数转换为数据库驱动可识别的值 ---
|
|
33
|
+
* @param value SQL 参数
|
|
34
|
+
* @returns 序列化后的数据库参数
|
|
35
|
+
*/
|
|
36
|
+
export declare function serialize(value: kebab.Json): kebab.Json;
|
|
37
|
+
/**
|
|
38
|
+
* --- 在进入数据库驱动前序列化特殊参数,不修改调用方数组 ---
|
|
39
|
+
* @param values SQL 参数列表
|
|
40
|
+
* @returns 可直接交给数据库驱动的参数列表
|
|
41
|
+
*/
|
|
42
|
+
export declare function serializeList(values?: kebab.DbValue[]): kebab.DbValue[] | undefined;
|
|
43
|
+
export {};
|
package/lib/sql/value.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as lText from '#kebab/lib/text.js';
|
|
2
|
+
/** --- JSON 参数的内部标记,不污染原始对象,也不会参与 JSON 序列化 --- */
|
|
3
|
+
const jsonValueSymbol = Symbol('kebab.sql.json');
|
|
4
|
+
/**
|
|
5
|
+
* --- 创建延迟序列化的 JSON 参数 ---
|
|
6
|
+
* @param value 原始 JSON 值
|
|
7
|
+
* @returns JSON 包装值
|
|
8
|
+
*/
|
|
9
|
+
export function json(value) {
|
|
10
|
+
return {
|
|
11
|
+
[jsonValueSymbol]: true,
|
|
12
|
+
'value': value,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* --- 判断是否为 JSON 包装值 ---
|
|
17
|
+
* @param value 待判断的值
|
|
18
|
+
* @returns 是否为 JSON 包装值
|
|
19
|
+
*/
|
|
20
|
+
export function isJson(value) {
|
|
21
|
+
return value !== null && typeof value === 'object' &&
|
|
22
|
+
!!value[jsonValueSymbol];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* --- 获取 JSON 包装值内的原始值;普通值保持不变 ---
|
|
26
|
+
* @param value 待解包的值
|
|
27
|
+
* @returns 原始值
|
|
28
|
+
*/
|
|
29
|
+
export function unwrapJson(value) {
|
|
30
|
+
return (isJson(value) ? value.value : value);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* --- 将单个 SQL 参数转换为数据库驱动可识别的值 ---
|
|
34
|
+
* @param value SQL 参数
|
|
35
|
+
* @returns 序列化后的数据库参数
|
|
36
|
+
*/
|
|
37
|
+
export function serialize(value) {
|
|
38
|
+
return isJson(value) ? lText.stringifyJson(value.value) : value;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* --- 在进入数据库驱动前序列化特殊参数,不修改调用方数组 ---
|
|
42
|
+
* @param values SQL 参数列表
|
|
43
|
+
* @returns 可直接交给数据库驱动的参数列表
|
|
44
|
+
*/
|
|
45
|
+
export function serializeList(values) {
|
|
46
|
+
if (!values) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
let serialized;
|
|
50
|
+
for (let i = 0; i < values.length; ++i) {
|
|
51
|
+
const value = values[i];
|
|
52
|
+
if (!isJson(value)) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
serialized ??= [...values];
|
|
56
|
+
serialized[i] = lText.stringifyJson(value.value);
|
|
57
|
+
}
|
|
58
|
+
return serialized ?? values;
|
|
59
|
+
}
|
package/lib/sql.d.ts
CHANGED
|
@@ -98,7 +98,7 @@ export declare class Sql {
|
|
|
98
98
|
/**
|
|
99
99
|
* --- 批量 UPDATE,以子查询作为数据源,纯更新语义(不会插入新行)---
|
|
100
100
|
* --- MySQL: UPDATE t INNER JOIN (SELECT col AS alias ... UNION ALL SELECT ...) AS tmp ON t.key=tmp.key SET t.c=tmp.c ---
|
|
101
|
-
* --- PostgreSQL: UPDATE t SET c=tmp.c FROM (VALUES ($1,...)) AS tmp(cols) WHERE t.key=tmp.key ---
|
|
101
|
+
* --- PostgreSQL: UPDATE t SET c=tmp.c FROM (VALUES (typed nulls), ($1,...)) AS tmp(cols) WHERE t.key=tmp.key ---
|
|
102
102
|
* @param table 表名
|
|
103
103
|
* @param key 用于定位待更新记录的字段名,通常为主键或唯一键,至少必须建立索引;
|
|
104
104
|
* 该参数是字段名而不是索引名,仅参与 ON / WHERE 匹配,不会被更新
|
|
@@ -192,14 +192,13 @@ export declare class Sql {
|
|
|
192
192
|
private _whereDataPosition;
|
|
193
193
|
/**
|
|
194
194
|
* --- 筛选器 ---
|
|
195
|
-
* ---
|
|
196
|
-
* ---
|
|
197
|
-
* ---
|
|
198
|
-
* ---
|
|
199
|
-
* ---
|
|
200
|
-
* ---
|
|
201
|
-
* ---
|
|
202
|
-
* --- 8. ['info', 'json', {'a': 1}] ---
|
|
195
|
+
* --- 标量相等:'city': 'bj', 'type': '2' ---
|
|
196
|
+
* --- 运算符条件:['type', '>', '1'] ---
|
|
197
|
+
* --- 集合条件:['type', 'in', ['1', '2']] 或 'type': ['1', '2'] ---
|
|
198
|
+
* --- 逻辑分组:'$or': [{'city': 'bj'}, {'city': 'sh'}, [['age', '>', '10']]] ---
|
|
199
|
+
* --- 字段比较:'city_in': column('city_out') ---
|
|
200
|
+
* --- 原始条件:['JSON_CONTAINS(`uid`, ?)', ['hello']] ---
|
|
201
|
+
* --- JSON 条件:['info', 'json', {'a': 1}] ---
|
|
203
202
|
* @param s 筛选数据
|
|
204
203
|
*/
|
|
205
204
|
where(s: string | kebab.Json): this;
|
|
@@ -274,11 +273,6 @@ export declare class Sql {
|
|
|
274
273
|
private _isValue;
|
|
275
274
|
/** --- 获取占位符 --- */
|
|
276
275
|
private _placeholder;
|
|
277
|
-
/**
|
|
278
|
-
* --- 返回 PostgreSQL VALUES 第一行的显式类型转换后缀,用于帮助 PostgreSQL 推断 VALUES 派生表列类型 ---
|
|
279
|
-
* @param v 要处理的值
|
|
280
|
-
*/
|
|
281
|
-
private _pgCastSuffix;
|
|
282
276
|
/**
|
|
283
277
|
* --- 处理单个值,检测数据类型并返回 SQL 和 data ---
|
|
284
278
|
* @param v 要处理的值
|
|
@@ -326,7 +320,8 @@ export declare function value(val: kebab.DbValue): {
|
|
|
326
320
|
'value': kebab.DbValue;
|
|
327
321
|
};
|
|
328
322
|
/**
|
|
329
|
-
* ---
|
|
330
|
-
* @param obj
|
|
323
|
+
* --- 标记需要写入 JSON/jsonb 字段的值;实际序列化延迟到数据库边界 ---
|
|
324
|
+
* @param obj 原始 JSON 值
|
|
325
|
+
* @returns 类型保持不变的 JSON 包装值
|
|
331
326
|
*/
|
|
332
327
|
export declare function json<T>(obj: T): T;
|