@cloudcome/utils-uni 1.11.0 → 1.12.0
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/database/db.d.ts +12 -7
- package/dist/database/fns.d.ts +2 -2
- package/dist/database/types.d.ts +25 -19
- package/dist/database.cjs.map +1 -1
- package/dist/database.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +3 -3
package/dist/database/db.d.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
import { AnyObject, HasProperty, IsEmptyObject, IsOnlyProperty, MergeIntersection } from '@cloudcome/utils-core/types';
|
|
2
|
-
import { UniClientDatabaseOutput, UniCloudDatabaseOutput, UniDatabaseCommand } from './types';
|
|
1
|
+
import { AnyObject, Exact, HasProperty, IsEmptyObject, IsOnlyProperty, MergeIntersection } from '@cloudcome/utils-core/types';
|
|
2
|
+
import { UniClientDatabaseOutput, UniCloudDatabaseOutput, UniDatabaseCommand, UniDatabaseMutateCommand, UniDatabaseQueryCommand } from './types';
|
|
3
3
|
export type DbWhere<T> = {
|
|
4
|
-
[K in keyof T]?:
|
|
4
|
+
[K in keyof T]?: T[K] | UniDatabaseQueryCommand;
|
|
5
5
|
};
|
|
6
6
|
export type DbSelect<T> = {
|
|
7
|
-
[K in keyof T]?: K extends '_id' ?
|
|
7
|
+
[K in keyof T]?: K extends '_id' ? boolean : true;
|
|
8
8
|
};
|
|
9
9
|
export type DbFieldsDefault<T> = {
|
|
10
10
|
[K in keyof T]: true;
|
|
11
11
|
};
|
|
12
|
-
type
|
|
12
|
+
type _OnlyFieldId<T, V> = IsOnlyProperty<T, '_id'> extends true ? '_id' extends keyof T ? T['_id'] extends V ? true : false : false : false;
|
|
13
|
+
type _DbFields<T, S extends DbSelect<T>> = IsEmptyObject<S> extends true ? DbFieldsDefault<T> : _OnlyFieldId<S, false> extends true ? Omit<DbFieldsDefault<T>, '_id'> : _OnlyFieldId<S, true> extends true ? {
|
|
14
|
+
_id: true;
|
|
15
|
+
} : HasProperty<S, '_id'> extends true ? S : // 没有的话补上 {_id, ...}
|
|
13
16
|
S & {
|
|
14
17
|
_id: true;
|
|
15
18
|
};
|
|
@@ -19,7 +22,9 @@ type _DbQuery<T, S extends Record<keyof T, boolean>> = {
|
|
|
19
22
|
export type DbQuery<T, S extends DbSelect<T>, R> = _DbQuery<T, _DbFields<T, S>> & R;
|
|
20
23
|
export type DbForeign<T, S extends DbSelect<T>, R, J extends DbJoinType, A> = Record<A & string, J extends '1:1' ? DbQuery<T, S, R> : DbQuery<T, S, R>[]>;
|
|
21
24
|
export type DbCreate<T> = Partial<T>;
|
|
22
|
-
export type DbUpdate<T> =
|
|
25
|
+
export type DbUpdate<T> = {
|
|
26
|
+
[K in keyof T]?: T[K] | UniDatabaseMutateCommand;
|
|
27
|
+
};
|
|
23
28
|
export type DbOrder<T> = Record<keyof T, 'asc' | 'desc'>;
|
|
24
29
|
/**
|
|
25
30
|
* 数据库操作符命令
|
|
@@ -129,7 +134,7 @@ export declare class Db<T, S extends DbSelect<T> = {}, R extends AnyObject = {}>
|
|
|
129
134
|
* @param fields 要返回的字段对象,true表示返回,false表示不返回
|
|
130
135
|
* @returns 当前Db实例,支持链式调用
|
|
131
136
|
*/
|
|
132
|
-
select<U extends DbSelect<T>>(fields: U): Db<T, S & U, R>;
|
|
137
|
+
select<U extends DbSelect<T>>(fields: Exact<U, DbSelect<T>>): Db<T, S & U, R>;
|
|
133
138
|
/**
|
|
134
139
|
* 设置排序规则
|
|
135
140
|
* @param order 排序规则对象,key为字段名,value为"asc"或"desc"
|
package/dist/database/fns.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { AnyObject } from '@cloudcome/utils-core/types';
|
|
1
|
+
import { AnyObject, Exact } from '@cloudcome/utils-core/types';
|
|
2
2
|
import { Db, DbCreate, DbProxy, DbQuery, DbSelect, DbUpdate, DbWhere } from './db';
|
|
3
3
|
export type DbUpsertOptions<T, S extends DbSelect<T>, C extends DbCreate<T>, U extends DbUpdate<T>> = {
|
|
4
4
|
/** 查询条件 */
|
|
5
5
|
where: DbWhere<T>;
|
|
6
6
|
/** 查询返回字段 */
|
|
7
|
-
select?: S
|
|
7
|
+
select?: Exact<S, DbSelect<T>>;
|
|
8
8
|
/** 创建数据 */
|
|
9
9
|
create: C;
|
|
10
10
|
/**
|
package/dist/database/types.d.ts
CHANGED
|
@@ -7,6 +7,12 @@ export type UniClientDatabaseOutput<T> = {
|
|
|
7
7
|
};
|
|
8
8
|
};
|
|
9
9
|
export type UniCloudDatabaseOutput<T> = T;
|
|
10
|
+
export type UniDatabaseQueryCommand = {
|
|
11
|
+
_: never;
|
|
12
|
+
};
|
|
13
|
+
export type UniDatabaseMutateCommand = {
|
|
14
|
+
_: never;
|
|
15
|
+
};
|
|
10
16
|
/**
|
|
11
17
|
* UniDatabaseCommand 数据库操作命令类型定义
|
|
12
18
|
*/
|
|
@@ -17,128 +23,128 @@ export type UniDatabaseCommand = {
|
|
|
17
23
|
* @returns 返回聚合表达式结果
|
|
18
24
|
* @see {@link https://doc.dcloud.net.cn/uniCloud/cf-database.html#dbcmd-expr expr 文档}
|
|
19
25
|
*/
|
|
20
|
-
expr: (expr: unknown) =>
|
|
26
|
+
expr: (expr: unknown) => UniDatabaseQueryCommand;
|
|
21
27
|
/**
|
|
22
28
|
* 等于操作符
|
|
23
29
|
* @param value 比较值
|
|
24
30
|
* @returns 返回查询条件
|
|
25
31
|
* @see {@link https://doc.dcloud.net.cn/uniCloud/cf-database.html#dbcmd-eq eq 文档}
|
|
26
32
|
*/
|
|
27
|
-
eq: (value: unknown) =>
|
|
33
|
+
eq: (value: unknown) => UniDatabaseQueryCommand;
|
|
28
34
|
/**
|
|
29
35
|
* 不等于操作符
|
|
30
36
|
* @param value 比较值
|
|
31
37
|
* @returns 返回查询条件
|
|
32
38
|
* @see {@link https://doc.dcloud.net.cn/uniCloud/cf-database.html#dbcmd-neq neq 文档}
|
|
33
39
|
*/
|
|
34
|
-
neq: (value: unknown) =>
|
|
40
|
+
neq: (value: unknown) => UniDatabaseQueryCommand;
|
|
35
41
|
/**
|
|
36
42
|
* 大于操作符
|
|
37
43
|
* @param value 比较值
|
|
38
44
|
* @returns 返回查询条件
|
|
39
45
|
* @see {@link https://doc.dcloud.net.cn/uniCloud/cf-database.html#dbcmd-gt gt 文档}
|
|
40
46
|
*/
|
|
41
|
-
gt: (value: unknown) =>
|
|
47
|
+
gt: (value: unknown) => UniDatabaseQueryCommand;
|
|
42
48
|
/**
|
|
43
49
|
* 大于等于操作符
|
|
44
50
|
* @param value 比较值
|
|
45
51
|
* @returns 返回查询条件
|
|
46
52
|
* @see {@link https://doc.dcloud.net.cn/uniCloud/cf-database.html#dbcmd-gte gte 文档}
|
|
47
53
|
*/
|
|
48
|
-
gte: (value: unknown) =>
|
|
54
|
+
gte: (value: unknown) => UniDatabaseQueryCommand;
|
|
49
55
|
/**
|
|
50
56
|
* 小于操作符
|
|
51
57
|
* @param value 比较值
|
|
52
58
|
* @returns 返回查询条件
|
|
53
59
|
* @see {@link https://doc.dcloud.net.cn/uniCloud/cf-database.html#dbcmd-lt lt 文档}
|
|
54
60
|
*/
|
|
55
|
-
lt: (value: unknown) =>
|
|
61
|
+
lt: (value: unknown) => UniDatabaseQueryCommand;
|
|
56
62
|
/**
|
|
57
63
|
* 小于等于操作符
|
|
58
64
|
* @param value 比较值
|
|
59
65
|
* @returns 返回查询条件
|
|
60
66
|
* @see {@link https://doc.dcloud.net.cn/uniCloud/cf-database.html#dbcmd-lte lte 文档}
|
|
61
67
|
*/
|
|
62
|
-
lte: (value: unknown) =>
|
|
68
|
+
lte: (value: unknown) => UniDatabaseQueryCommand;
|
|
63
69
|
/**
|
|
64
70
|
* 包含在数组内操作符
|
|
65
71
|
* @param value 包含的值数组
|
|
66
72
|
* @returns 返回查询条件
|
|
67
73
|
* @see {@link https://doc.dcloud.net.cn/uniCloud/cf-database.html#dbcmd-in in 文档}
|
|
68
74
|
*/
|
|
69
|
-
in: (value: unknown[]) =>
|
|
75
|
+
in: (value: unknown[]) => UniDatabaseQueryCommand;
|
|
70
76
|
/**
|
|
71
77
|
* 不包含在数组内操作符
|
|
72
78
|
* @param value 不包含的值数组
|
|
73
79
|
* @returns 返回查询条件
|
|
74
80
|
* @see {@link https://doc.dcloud.net.cn/uniCloud/cf-database.html#dbcmd-nin nin 文档}
|
|
75
81
|
*/
|
|
76
|
-
nin: (value: unknown[]) =>
|
|
82
|
+
nin: (value: unknown[]) => UniDatabaseQueryCommand;
|
|
77
83
|
/**
|
|
78
84
|
* 逻辑与操作符
|
|
79
85
|
* @param args 多个查询条件
|
|
80
86
|
* @returns 返回逻辑与查询条件
|
|
81
87
|
* @see {@link https://doc.dcloud.net.cn/uniCloud/cf-database.html#dbcmd-and and 文档}
|
|
82
88
|
*/
|
|
83
|
-
and: (...args: unknown[]) =>
|
|
89
|
+
and: (...args: unknown[]) => UniDatabaseQueryCommand;
|
|
84
90
|
/**
|
|
85
91
|
* 逻辑或操作符
|
|
86
92
|
* @param args 多个查询条件
|
|
87
93
|
* @returns 返回逻辑或查询条件
|
|
88
94
|
* @see {@link https://doc.dcloud.net.cn/uniCloud/cf-database.html#dbcmd-or or 文档}
|
|
89
95
|
*/
|
|
90
|
-
or: (...args: unknown[]) =>
|
|
96
|
+
or: (...args: unknown[]) => UniDatabaseQueryCommand;
|
|
91
97
|
/**
|
|
92
98
|
* 自增操作符
|
|
93
99
|
* @param value 增加的数值
|
|
94
100
|
* @returns 返回更新操作
|
|
95
101
|
* @see {@link https://doc.dcloud.net.cn/uniCloud/cf-database.html#operator-inc inc 文档}
|
|
96
102
|
*/
|
|
97
|
-
inc: (value: number) =>
|
|
103
|
+
inc: (value: number) => UniDatabaseMutateCommand;
|
|
98
104
|
/**
|
|
99
105
|
* 自乘操作符
|
|
100
106
|
* @param value 相乘的数值
|
|
101
107
|
* @returns 返回更新操作
|
|
102
108
|
* @see {@link https://doc.dcloud.net.cn/uniCloud/cf-database.html#operator-mul mul 文档}
|
|
103
109
|
*/
|
|
104
|
-
mul: (value: number) =>
|
|
110
|
+
mul: (value: number) => UniDatabaseMutateCommand;
|
|
105
111
|
/**
|
|
106
112
|
* 设置字段值操作符
|
|
107
113
|
* @param value 设置的值
|
|
108
114
|
* @returns 返回更新操作
|
|
109
115
|
* @see {@link https://doc.dcloud.net.cn/uniCloud/cf-database.html#operator-set set 文档}
|
|
110
116
|
*/
|
|
111
|
-
set: (value: unknown) =>
|
|
117
|
+
set: (value: unknown) => UniDatabaseMutateCommand;
|
|
112
118
|
/**
|
|
113
119
|
* 数组末尾添加元素操作符
|
|
114
120
|
* @param value 添加的值
|
|
115
121
|
* @returns 返回更新操作
|
|
116
122
|
* @see {@link https://doc.dcloud.net.cn/uniCloud/cf-database.html#operator-push push 文档}
|
|
117
123
|
*/
|
|
118
|
-
push: (value: unknown) =>
|
|
124
|
+
push: (value: unknown) => UniDatabaseMutateCommand;
|
|
119
125
|
/**
|
|
120
126
|
* 数组开头添加元素操作符
|
|
121
127
|
* @param value 添加的值
|
|
122
128
|
* @returns 返回更新操作
|
|
123
129
|
* @see {@link https://doc.dcloud.net.cn/uniCloud/cf-database.html#operator-unshift unshift 文档}
|
|
124
130
|
*/
|
|
125
|
-
unshift: (value: unknown) =>
|
|
131
|
+
unshift: (value: unknown) => UniDatabaseMutateCommand;
|
|
126
132
|
/**
|
|
127
133
|
* 删除数组末尾元素操作符
|
|
128
134
|
* @returns 返回更新操作
|
|
129
135
|
* @see {@link https://doc.dcloud.net.cn/uniCloud/cf-database.html#operator-pop pop 文档}
|
|
130
136
|
*/
|
|
131
|
-
pop: () =>
|
|
137
|
+
pop: () => UniDatabaseMutateCommand;
|
|
132
138
|
/**
|
|
133
139
|
* 删除数组开头元素操作符
|
|
134
140
|
* @returns 返回更新操作
|
|
135
141
|
* @see {@link https://doc.dcloud.net.cn/uniCloud/cf-database.html#operator-shift shift 文档}
|
|
136
142
|
*/
|
|
137
|
-
shift: () =>
|
|
143
|
+
shift: () => UniDatabaseMutateCommand;
|
|
138
144
|
/**
|
|
139
145
|
* 删除字段操作符
|
|
140
146
|
* @returns 返回更新操作
|
|
141
147
|
* @see {@link https://doc.dcloud.net.cn/uniCloud/cf-database.html#operator-remove remove 文档}
|
|
142
148
|
*/
|
|
143
|
-
remove: () =>
|
|
149
|
+
remove: () => UniDatabaseMutateCommand;
|
|
144
150
|
};
|
package/dist/database.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.cjs","sources":["../src/database/db.ts","../src/database/fns.ts"],"sourcesContent":["import { errorAssign } from '@cloudcome/utils-core/error';\nimport { objectEach, objectMap, objectOmit } from '@cloudcome/utils-core/object';\nimport { isArray, isFunction, isNumber, isString } from '@cloudcome/utils-core/type';\nimport type {\n AnyObject,\n HasProperty,\n IsEmptyObject,\n IsOnlyProperty,\n MergeIntersection,\n UnionToIntersection,\n} from '@cloudcome/utils-core/types';\nimport type { UniClientDatabaseOutput, UniCloudDatabaseOutput, UniDatabaseCommand } from './types';\n\nexport type DbWhere<T> = {\n [K in keyof T]?: unknown;\n};\nexport type DbSelect<T> = {\n [K in keyof T]?: K extends '_id' ? false : true;\n};\nexport type DbFieldsDefault<T> = {\n [K in keyof T]: true;\n};\ntype _DbFields<T, S extends DbSelect<T>> = IsEmptyObject<S> extends true // 判断是否为空对象\n ? // 默认全部字段\n DbFieldsDefault<T>\n : // 判断 _id 是否为唯一属性\n IsOnlyProperty<S, '_id'> extends true\n ? // 从默认字段里排除 _id\n Omit<DbFieldsDefault<T>, '_id'>\n : // 判断是否有 _id\n HasProperty<S, '_id'> extends true\n ? // 有的话保留 {_id, ...}\n S\n : // 没有的话补上 {_id, ...}\n S & { _id: true };\ntype _DbQuery<T, S extends Record<keyof T, boolean>> = {\n [K in keyof T as S[K] extends true ? K : never]: T[K];\n};\n// @ts-ignore\nexport type DbQuery<T, S extends DbSelect<T>, R> = _DbQuery<T, _DbFields<T, S>> & R;\nexport type DbForeign<T, S extends DbSelect<T>, R, J extends DbJoinType, A> = Record<\n A & string,\n J extends '1:1' ? DbQuery<T, S, R> : DbQuery<T, S, R>[]\n>;\nexport type DbCreate<T> = Partial<T>;\nexport type DbUpdate<T> = Partial<T>;\nexport type DbOrder<T> = Record<keyof T, 'asc' | 'desc'>;\n\ntype _WhereFrom = 'where' | 'whereId';\n\nconst db0 = uniCloud.database();\n/**\n * 数据库操作符命令\n */\nexport const dbCmd = db0.command as unknown as UniDatabaseCommand;\n\n/**\n * 数据库聚合操作符命令\n */\nexport const dbAgg = db0.command.aggregate as UniCloud.AggregateCommand & {\n pipeline: () => UniCloud.AggregateReference & {\n done: () => unknown;\n };\n};\n\nexport type DbOptions = {\n /**\n * 数据表名称\n */\n table: string;\n\n /**\n * 事务对象,用于事务操作\n */\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n transaction?: any;\n\n /**\n * 模拟数据库,用于单元测试\n */\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n _mockDatabase?: any;\n};\n\n/**\n * 数据库关联类型\n * - '1:1': 一对一关联,返回值 1 个\n * - '1:n': 一对多关联,返回值 n 个\n * - 'n:1': 多对一关联,返回值 n 个\n */\nexport type DbJoinType = '1:1' | '1:n' | 'n:1';\nexport type DbLookupOptions<J extends DbJoinType, L, F, A> = {\n /**\n * 关联类型\n */\n type: J;\n\n /**\n * 主表字段\n */\n localField: keyof L & string;\n\n /**\n * 关联表字段\n */\n foreignField: keyof F & string;\n\n /**\n * 关联数据在结果中的字段名\n */\n as: A;\n};\n\nexport type DbLookup = {\n /**\n * 关联表\n */\n table: Db<unknown>;\n\n /**\n * 关联类型\n */\n type: DbJoinType;\n\n /**\n * 主表字段\n */\n localField: string;\n\n /**\n * 关联表字段\n */\n foreignField: string;\n\n /**\n * 关联表名称\n */\n from: string;\n\n /**\n * 关联数据在结果中的字段名\n */\n as: string;\n};\n\nlet gid = 0;\n\n// biome-ignore lint/complexity/noBannedTypes: <explanation>\nexport class Db<T, S extends DbSelect<T> = {}, R extends AnyObject = {}> {\n #host: UniCloud.CollectionReference;\n\n /**\n * 是否为事务环境\n * - 查询条件只能是 id\n * - 不能聚合操作\n */\n #isTransaction = false;\n\n #options: DbOptions;\n\n /**\n * 构造函数,初始化数据库集合引用\n * @param collection 数据表名称\n * @param _mockDatabase 模拟数据库,用于单元测试\n */\n constructor(options: DbOptions) {\n this.#options = options;\n this.#host =\n options._mockDatabase || options.transaction?.collection(options.table) || db0.collection(options.table);\n this.#isTransaction = !!options.transaction;\n }\n\n get table() {\n return this.#options.table;\n }\n\n /**\n * 获取聚合操作实例\n * @returns 聚合操作实例\n */\n aggregate() {\n return this.#host.aggregate();\n }\n\n #hasWhere: _WhereFrom | undefined = undefined;\n #hasWhereId: _WhereFrom | undefined = undefined;\n #where = {};\n\n #doWhere(where: DbWhere<T>, from: _WhereFrom) {\n if (this.#hasWhere) throw new Error(`已调用过一次 db.${_toWhereMethod(this.#hasWhere)} 了`);\n\n const whereKeys = Object.keys(where);\n // 只有 _id 值为字符串或数字时,才能调用 doc 方法\n const isWhereId = whereKeys.length === 1 && '_id' in where && (isString(where._id) || isNumber(where._id));\n\n if (isWhereId && this.#hasLimit) {\n throw new Error(`db.${_toWhereIdMethod(from)} 方法不能与 db.limit() 方法同时调用`);\n }\n\n this.#hasWhere = from;\n this.#where = where;\n if (isWhereId) this.#hasWhereId = from;\n\n return this;\n }\n\n /**\n * 设置查询条件\n * @param where 查询条件对象\n * @returns 当前Db实例,支持链式调用\n */\n where(where: DbWhere<T>) {\n return this.#doWhere(where, 'where');\n }\n\n /**\n * 根据ID设置查询条件\n * @param id 记录ID\n * @returns 当前Db实例,支持链式调用\n */\n whereId(id: string | number) {\n // @ts-ignore\n return this.#doWhere({ _id: id }, 'whereId');\n }\n\n #hasSelect = 0;\n #select = {};\n\n /**\n * 指定要返回的字段\n * @param fields 要返回的字段对象,true表示返回,false表示不返回\n * @returns 当前Db实例,支持链式调用\n */\n select<U extends DbSelect<T>>(fields: U) {\n if (this.#hasSelect) throw new Error('db.select() 方法只能调用一次');\n\n this.#hasSelect++;\n this.#select = fields;\n\n return this as Db<T, S & U, R>;\n }\n\n #hasOrder = 0;\n #order = {};\n\n /**\n * 设置排序规则\n * @param order 排序规则对象,key为字段名,value为\"asc\"或\"desc\"\n * @returns 当前Db实例,支持链式调用\n */\n order(order: DbOrder<T>) {\n this.#hasOrder++;\n this.#order = order;\n\n return this;\n }\n\n #hasSkip = 0;\n #skip = 0;\n\n /**\n * 跳过指定数量的记录\n * @param skip 要跳过的记录数\n * @returns 当前Db实例,支持链式调用\n */\n skip(skip: number) {\n if (this.#hasSkip) throw new Error('db.skip() 方法只能调用一次');\n\n this.#hasSkip++;\n this.#skip = skip;\n\n return this;\n }\n\n #hasLimit = 0;\n #limit = 0;\n\n /**\n * 限制返回的记录数量\n * @param limit 最大返回记录数\n * @returns 当前Db实例,支持链式调用\n */\n limit(limit: number) {\n if (this.#hasLimit) throw new Error('db.limit() 方法只能调用一次');\n\n if (this.#hasWhereId) {\n throw new Error(`db.limit() 方法不能与 ${_toWhereIdMethod(this.#hasWhereId)} 方法同时调用`);\n }\n\n this.#hasLimit++;\n this.#limit = limit;\n\n return this;\n }\n\n #hasLookup = 0;\n get hasLookup() {\n return this.#hasLookup > 0;\n }\n\n #lookups: DbLookup[] = [];\n lookup<FT, FS extends DbSelect<FT>, FR extends AnyObject, J extends DbJoinType, A extends string>(\n table: Db<FT, FS, FR>,\n lookup: DbLookupOptions<J, T, FT, A>,\n ) {\n // 对方表也记为关联查询,避免做表更新操作\n table.#hasLookup++;\n this.#hasLookup++;\n this.#lookups.push({\n ...lookup,\n table,\n from: table.table,\n });\n\n // 这里必须合并联合类型,否则类型结果会丢失最后一次 lookup\n // @ts-ignore\n return this as Db<T, S, MergeIntersection<R & DbForeign<FT, FS, FR, J, A>>>;\n }\n\n #aggregated = false;\n #endAggregate(aggRef: UniCloud.AggregateReference) {\n if (this.#aggregated) throw new Error(`相同的数据表实例(${this.table})不能重复使用`);\n\n this.#aggregated = true;\n let returnAggRef = aggRef;\n const projects: Record<string, true> = {};\n\n for (const { type, as, foreignField, from, localField, table } of this.#lookups) {\n const varName = `v${gid++}`;\n let pipeline = dbAgg.pipeline();\n\n // 关联条件\n // @ts-ignore\n pipeline = pipeline.match(\n dbCmd.expr(\n type === 'n:1'\n ? // @ts-ignore\n dbAgg.in([`$${foreignField}`, `$$${varName}`])\n : dbAgg.eq([`$${foreignField}`, `$$${varName}`]),\n ),\n );\n\n // 其他查询条件\n // @ts-ignore\n pipeline = table.#endAggregate(pipeline);\n\n // @ts-ignore\n pipeline = pipeline.done();\n\n returnAggRef = returnAggRef.lookup({\n let: {\n [varName]: `$${localField}`,\n },\n as,\n from,\n pipeline,\n });\n\n // 1对1,展开数组\n if (type === '1:1') {\n // @ts-ignore\n returnAggRef = returnAggRef.unwind({\n path: `$${as}`,\n preserveNullAndEmptyArrays: true,\n });\n }\n\n projects[as] = true;\n }\n\n // 主表查询\n if (this.#hasWhere) returnAggRef = returnAggRef.match(this.#where);\n if (this.#hasSelect) returnAggRef = returnAggRef.project({ ...this.#select, ...projects });\n if (this.#hasOrder) returnAggRef = returnAggRef.sort(objectMap(this.#order, (v) => (v === 'asc' ? 1 : -1)));\n if (this.#hasSkip) returnAggRef = returnAggRef.skip(this.#skip);\n if (this.#hasLimit) returnAggRef = returnAggRef.limit(this.#limit);\n\n return returnAggRef;\n }\n\n #endHost() {\n if (this.#hasWhere) {\n // @ts-ignore\n this.#host = this.#host.where(this.#where);\n }\n\n if (this.#hasSelect) {\n // @ts-ignore\n this.#host = this.#host.field(this.#select);\n }\n\n if (this.#hasOrder) {\n objectEach(this.#order, (val, key) => {\n // @ts-ignore\n this.#host = this.#host.orderBy(key, val);\n });\n }\n\n // @ts-ignore\n if (this.#hasSkip) this.#host = this.#host.skip(this.#skip);\n\n // @ts-ignore\n if (this.#hasLimit) this.#host = this.#host.limit(this.#limit);\n // @ts-ignore\n else if (this.#hasWhereId) this.#host = this.#host.limit(1);\n }\n\n /**\n * 执行查询操作\n * @returns 查询结果\n */\n async query() {\n let res: { data: DbQuery<T, S, R>[] };\n\n // 关联查询\n if (this.#hasLookup) {\n const aggRef = this.aggregate();\n this.#endAggregate(aggRef);\n res = await aggRef.end();\n }\n // 单表查询\n else {\n this.#endHost();\n res = await this.#host.get();\n }\n\n const rows = isArray(res.data) ? res.data : [res.data];\n const { data } = parseDatabaseOutput(res);\n return data;\n }\n\n /**\n * 只查询一条,自动添加 limit(1) 条件\n * @param ignoreMiss 是否忽略没有匹配到记录\n * @returns 查询结果\n */\n async queryOne(): Promise<DbQuery<T, S, R>>;\n async queryOne(ignoreMiss: false): Promise<DbQuery<T, S, R>>;\n async queryOne(ignoreMiss: true): Promise<DbQuery<T, S, R> | undefined>;\n async queryOne(ignoreMiss = false): Promise<DbQuery<T, S, R> | undefined> {\n if (this.#hasLimit) throw new Error('db.queryOne() 方法不支持 limit 条件');\n if (!this.#hasWhereId) this.limit(1);\n\n const data = await this.query();\n const res = data.at(0);\n\n if (!ignoreMiss && !res) throw new Error('未找到匹配记录');\n return res;\n }\n\n /**\n * 获取匹配记录的数量\n * @returns 记录总数\n */\n async count() {\n if (this.#hasLookup) throw new Error('db.count() 方法不支持 lookup 聚合');\n if (this.#hasSelect) throw new Error('db.count() 方法不支持 select 条件');\n if (this.#hasOrder) throw new Error('db.count() 方法不支持 order 条件');\n if (this.#hasSkip) throw new Error('db.count() 方法不支持 skip 条件');\n if (this.#hasLimit) throw new Error('db.count() 方法不支持 limit 条件');\n\n this.#endHost();\n const res = await this.#host.count();\n const { total } = parseDatabaseOutput<{ total: number }>(res);\n return total;\n }\n\n /**\n * 创建新记录\n * @param data 要创建的数据\n * @returns 创建结果\n */\n async create(data: DbCreate<T>) {\n if (this.#hasLookup) throw new Error('db.create() 方法不支持 lookup 聚合');\n if (this.#hasWhere) throw new Error('db.create() 方法不支持 where 条件');\n if (this.#hasSelect) throw new Error('db.create() 方法不支持 select 条件');\n if (this.#hasOrder) throw new Error('db.create() 方法不支持 order 条件');\n if (this.#hasSkip) throw new Error('db.create() 方法不支持 skip 条件');\n if (this.#hasLimit) throw new Error('db.create() 方法不支持 limit 条件');\n\n this.#endHost();\n const res = await this.#host.add(data);\n const { id } = parseDatabaseOutput<{ id: string }>(res);\n return id;\n }\n\n /**\n * 更新记录\n * @param data 要更新的数据\n * @returns 更新结果\n */\n async update(data: AnyObject) {\n if (this.#hasLookup) throw new Error('db.update() 方法不支持 lookup 聚合');\n if (!this.#hasWhere) throw new Error('设置 where 条件后才能执行 db.update() 方法');\n if (this.#hasSelect) throw new Error('db.update() 方法不支持 select 条件');\n if (this.#hasOrder) throw new Error('db.update() 方法不支持 order 条件');\n if (this.#hasSkip) throw new Error('db.update() 方法不支持 skip 条件');\n if (this.#hasLimit) throw new Error('db.update() 方法不支持 limit 条件');\n\n if (this.#isTransaction && !this.#hasWhereId) throw new Error('事务模式下 db.update() 的 where 条件必须是 _id');\n\n this.#endHost();\n const res = await this.#host.update(data);\n const { updated } = parseDatabaseOutput<{ updated: number }>(res);\n return updated;\n }\n\n /**\n * 删除记录\n * @returns 删除结果\n */\n async remove() {\n if (this.#hasLookup) throw new Error('db.remove() 方法不支持 lookup 聚合');\n if (!this.#hasWhere) throw new Error('设置 where 条件后才能执行 db.remove() 方法');\n if (this.#hasSelect) throw new Error('db.remove() 方法不支持 select 条件');\n if (this.#hasOrder) throw new Error('db.remove() 方法不支持 order 条件');\n if (this.#hasSkip) throw new Error('db.remove() 方法不支持 skip 条件');\n if (this.#hasLimit) throw new Error('db.remove() 方法不支持 limit 条件');\n\n if (this.#isTransaction && !this.#hasWhereId) throw new Error('事务模式下 db.remove() 的 where 条件必须是 _id');\n\n this.#endHost();\n const res = await this.#host.remove();\n const { deleted } = parseDatabaseOutput<{ deleted: number }>(res);\n return deleted;\n }\n}\n\n// biome-ignore lint/complexity/noBannedTypes: <explanation>\nexport type DbProxy<T, S extends DbSelect<T> = {}, R extends AnyObject = {}> = Db<T, S, R> & {\n _isProxy: true;\n};\n\n/**\n * 数据库操作对象\n */\nexport const db = {\n /**\n * 获取指定名称的数据库集合实例\n * @param name 数据表名称\n * @returns Db类实例,用于执行数据库操作\n */\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n table<T, S extends DbSelect<T> = {}, R extends AnyObject = {}>(name: string) {\n return new Proxy(\n {},\n {\n get(target, prop) {\n if (prop === '_isProxy') return true;\n\n const table = new Db<T, S, R>({ table: name });\n const tableProp = prop as keyof Db<T, S, R>;\n const ref = table[tableProp];\n\n return isFunction(ref) ? ref.bind(table) : ref;\n },\n },\n ) as DbProxy<T>;\n },\n};\n\n/**\n * 解析数据库执行结果\n * @param res 客户端、云端响应结果\n * @returns 处理后的结果\n */\nexport function parseDatabaseOutput<T>(res: UniClientDatabaseOutput<T> | UniCloudDatabaseOutput<T>) {\n const keys = Object.keys(res as AnyObject);\n // 客户端 { result: {errCode: 0, errMsg: 'ok'} & 数据 }\n const isClient = keys.length === 1 && keys[0] === 'result';\n\n if (isClient) {\n const { result } = res as UniClientDatabaseOutput<T>;\n if (!result.errCode) return objectOmit(result, ['errCode', 'errMsg', 'code', 'message']);\n throw errorAssign(new Error(result.errMsg), result);\n }\n\n // 云端 数据\n return res as T;\n}\n\nfunction _toWhereMethod(whereFrom: _WhereFrom) {\n return whereFrom === 'where' ? 'where({...})' : 'whereId(id)';\n}\n\nfunction _toWhereIdMethod(whereFrom: _WhereFrom) {\n return whereFrom === 'where' ? 'where({ _id })' : 'whereId(id)';\n}\n","import { tryFlatten } from '@cloudcome/utils-core/try';\nimport { isFunction } from '@cloudcome/utils-core/type';\nimport type { AnyObject, MaybeCallable } from '@cloudcome/utils-core/types';\nimport { Db, type DbCreate, type DbProxy, type DbQuery, type DbSelect, type DbUpdate, type DbWhere, db } from './db';\n\nexport type DbUpsertOptions<T, S extends DbSelect<T>, C extends DbCreate<T>, U extends DbUpdate<T>> = {\n /** 查询条件 */\n where: DbWhere<T>;\n\n /** 查询返回字段 */\n select?: S;\n\n /** 创建数据 */\n create: C;\n\n /**\n * 更新数据,可以是对象或根据查询结果生成更新对象的函数\n * @param row 查询到的文档数据,仅在传入函数时可用\n */\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n update: U | ((exist: DbQuery<T, S, {}>) => U);\n\n /** 创建前回调函数 */\n onBeforeCreate?: () => unknown;\n\n /**\n * 创建后回调函数\n * @param id 创建的文档ID\n */\n onAfterCreate?: (id: string) => unknown;\n\n /**\n * 更新前回调函数\n * @param exist 查询到的原始文档数据\n * @returns 如果返回 false,则取消更新操作\n */\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n onBeforeUpdate?: (exist: DbQuery<T, S, {}>) => false | unknown;\n\n /**\n * 更新后回调函数\n * @param updateData 实际更新的数据\n * @param exist 查询到的原始文档数据\n */\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n onAfterUpdate?: (updateData: U, exist: DbQuery<T, S, {}>) => unknown;\n\n /** 用于测试的模拟数据库实例 */\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n _mockDbInstance?: any;\n};\n\n/**\n * 数据库 upsert 操作的返回结果类型\n */\nexport type DbUpsertOutput = {\n /** 操作的文档ID */\n id: string;\n /** 是否为创建操作 */\n created: boolean;\n /** 是否为更新操作 */\n updated: boolean;\n};\n\nexport async function dbUpsert<T, S extends DbSelect<T>, C extends DbCreate<T>, U extends DbUpdate<T>>(\n dbProxy: DbProxy<T>,\n options: DbUpsertOptions<T, S, C, U>,\n): Promise<DbUpsertOutput> {\n const {\n where,\n select = {},\n create,\n update,\n onBeforeCreate,\n onAfterCreate,\n onBeforeUpdate,\n onAfterUpdate,\n _mockDbInstance,\n } = options;\n\n // @ts-ignore\n if ('_id' in select) throw new Error('select 条件不能包含 _id 字段');\n\n const _db = (_mockDbInstance || dbProxy) as DbProxy<T, S>;\n const exist = (await _db\n .where(where)\n .select(select || {})\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n .queryOne(true)) as DbQuery<T, S, {}> | undefined;\n\n if (exist) {\n const skipUpdate = (await onBeforeUpdate?.(exist)) === false;\n\n if (skipUpdate) {\n // @ts-ignore\n return { id: exist._id as string, updated: false, created: false };\n }\n\n const updateData = isFunction(update) ? update(exist) : update;\n // @ts-ignore\n const updated = await _db.whereId(exist._id).update(updateData);\n onAfterUpdate?.(updateData, exist);\n\n // @ts-ignore\n return { id: exist._id as string, updated: true, created: false };\n }\n\n await onBeforeCreate?.();\n const createdId = await _db.create(create);\n await onAfterCreate?.(createdId);\n\n return { id: createdId, updated: false, created: true };\n}\n\ntype _TransactionDb = {\n startTransaction: () => Promise<_Transaction>;\n};\n\ntype _Transaction = {\n commit: () => Promise<unknown>;\n rollback: () => Promise<unknown>;\n};\n\ntype _WithTransaction = <T, S extends DbSelect<T>, R extends AnyObject>(table: DbProxy<T, S, R>) => Db<T, S, R>;\n\n/**\n * 在数据库事务中执行操作\n *\n * @template T - 事务操作返回值类型\n * @param transacting - 事务执行函数,接收事务数据库实例作为参数\n * @param _mockDatabase - 用于测试的模拟数据库对象\n * @param _mockDbInstance - 用于测试的模拟数据库实例\n * @returns 事务操作的返回结果\n *\n * @example\n * ```typescript\n * const result = await dbTransaction(async (withTransaction) => {\n * const userId = await withTransaction(db.table('user')).create({ name: 'John' });\n * const order = await withTransaction(db.table('orders')).create({ userId, amount: 100 });\n * return { user, order };\n * });\n * ```\n */\nexport async function dbTransaction<K>(\n transacting: (withTransaction: _WithTransaction) => Promise<K>,\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n _mockDatabase?: any,\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n _mockDbInstance?: any,\n) {\n const transactionDb = (_mockDatabase || uniCloud.database()) as _TransactionDb;\n\n const [err1, transaction] = await tryFlatten(transactionDb.startTransaction());\n if (err1) throw err1;\n\n const withTransaction = <T, S extends DbSelect<T>, R extends AnyObject>(dbProxy: DbProxy<T, S, R>) => {\n return _mockDbInstance || new Db<T, S, R>({ table: dbProxy.table, transaction });\n };\n\n const [err2, result] = await tryFlatten(async () => {\n const result = await transacting(withTransaction);\n await transaction.commit();\n return result;\n });\n\n if (err2) {\n await tryFlatten(transaction.rollback());\n throw err2;\n }\n\n return result as unknown as K;\n}\n"],"names":["isString","isNumber","type","objectMap","objectEach","isArray","isFunction","objectOmit","errorAssign","tryFlatten","result"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"database.cjs","sources":["../src/database/db.ts","../src/database/fns.ts"],"sourcesContent":["import { errorAssign } from '@cloudcome/utils-core/error';\nimport { objectEach, objectMap, objectOmit } from '@cloudcome/utils-core/object';\nimport { isArray, isFunction, isNumber, isString } from '@cloudcome/utils-core/type';\nimport type {\n AnyObject,\n Exact,\n HasProperty,\n IsEmptyObject,\n IsOnlyProperty,\n MergeIntersection,\n UnionToIntersection,\n} from '@cloudcome/utils-core/types';\nimport type {\n UniClientDatabaseOutput,\n UniCloudDatabaseOutput,\n UniDatabaseCommand,\n UniDatabaseMutateCommand,\n UniDatabaseQueryCommand,\n} from './types';\n\nexport type DbWhere<T> = {\n [K in keyof T]?: T[K] | UniDatabaseQueryCommand;\n};\nexport type DbSelect<T> = {\n [K in keyof T]?: K extends '_id' ? boolean : true;\n};\nexport type DbFieldsDefault<T> = {\n [K in keyof T]: true;\n};\ntype _OnlyFieldId<T, V> = IsOnlyProperty<T, '_id'> extends true\n ? '_id' extends keyof T\n ? T['_id'] extends V\n ? true\n : false\n : false\n : false;\ntype _DbFields<T, S extends DbSelect<T>> = IsEmptyObject<S> extends true // 判断是否为空对象\n ? // 默认全部字段\n DbFieldsDefault<T>\n : // 判断 _id 是否为唯一属性 且 为 false\n _OnlyFieldId<S, false> extends true\n ? // 从默认字段里排除 _id\n Omit<DbFieldsDefault<T>, '_id'>\n : // 判断 _id 是否为唯一属性 且 为 true\n _OnlyFieldId<S, true> extends true\n ? // 只保留 _id\n { _id: true }\n : // 判断是否有 _id\n HasProperty<S, '_id'> extends true\n ? // 有的话保留 {_id, ...}\n S\n : // 没有的话补上 {_id, ...}\n S & { _id: true };\ntype _DbQuery<T, S extends Record<keyof T, boolean>> = {\n [K in keyof T as S[K] extends true ? K : never]: T[K];\n};\n// @ts-ignore\nexport type DbQuery<T, S extends DbSelect<T>, R> = _DbQuery<T, _DbFields<T, S>> & R;\nexport type DbForeign<T, S extends DbSelect<T>, R, J extends DbJoinType, A> = Record<\n A & string,\n J extends '1:1' ? DbQuery<T, S, R> : DbQuery<T, S, R>[]\n>;\nexport type DbCreate<T> = Partial<T>;\nexport type DbUpdate<T> = {\n [K in keyof T]?: T[K] | UniDatabaseMutateCommand;\n};\nexport type DbOrder<T> = Record<keyof T, 'asc' | 'desc'>;\n\ntype _WhereFrom = 'where' | 'whereId';\n\nconst db0 = uniCloud.database();\n/**\n * 数据库操作符命令\n */\nexport const dbCmd = db0.command as unknown as UniDatabaseCommand;\n\n/**\n * 数据库聚合操作符命令\n */\nexport const dbAgg = db0.command.aggregate as UniCloud.AggregateCommand & {\n pipeline: () => UniCloud.AggregateReference & {\n done: () => unknown;\n };\n};\n\nexport type DbOptions = {\n /**\n * 数据表名称\n */\n table: string;\n\n /**\n * 事务对象,用于事务操作\n */\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n transaction?: any;\n\n /**\n * 模拟数据库,用于单元测试\n */\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n _mockDatabase?: any;\n};\n\n/**\n * 数据库关联类型\n * - '1:1': 一对一关联,返回值 1 个\n * - '1:n': 一对多关联,返回值 n 个\n * - 'n:1': 多对一关联,返回值 n 个\n */\nexport type DbJoinType = '1:1' | '1:n' | 'n:1';\nexport type DbLookupOptions<J extends DbJoinType, L, F, A> = {\n /**\n * 关联类型\n */\n type: J;\n\n /**\n * 主表字段\n */\n localField: keyof L & string;\n\n /**\n * 关联表字段\n */\n foreignField: keyof F & string;\n\n /**\n * 关联数据在结果中的字段名\n */\n as: A;\n};\n\nexport type DbLookup = {\n /**\n * 关联表\n */\n table: Db<unknown>;\n\n /**\n * 关联类型\n */\n type: DbJoinType;\n\n /**\n * 主表字段\n */\n localField: string;\n\n /**\n * 关联表字段\n */\n foreignField: string;\n\n /**\n * 关联表名称\n */\n from: string;\n\n /**\n * 关联数据在结果中的字段名\n */\n as: string;\n};\n\nlet gid = 0;\n\n// biome-ignore lint/complexity/noBannedTypes: <explanation>\nexport class Db<T, S extends DbSelect<T> = {}, R extends AnyObject = {}> {\n #host: UniCloud.CollectionReference;\n\n /**\n * 是否为事务环境\n * - 查询条件只能是 id\n * - 不能聚合操作\n */\n #isTransaction = false;\n\n #options: DbOptions;\n\n /**\n * 构造函数,初始化数据库集合引用\n * @param collection 数据表名称\n * @param _mockDatabase 模拟数据库,用于单元测试\n */\n constructor(options: DbOptions) {\n this.#options = options;\n this.#host =\n options._mockDatabase || options.transaction?.collection(options.table) || db0.collection(options.table);\n this.#isTransaction = !!options.transaction;\n }\n\n get table() {\n return this.#options.table;\n }\n\n /**\n * 获取聚合操作实例\n * @returns 聚合操作实例\n */\n aggregate() {\n return this.#host.aggregate();\n }\n\n #hasWhere: _WhereFrom | undefined = undefined;\n #hasWhereId: _WhereFrom | undefined = undefined;\n #where = {};\n\n #doWhere(where: DbWhere<T>, from: _WhereFrom) {\n if (this.#hasWhere) throw new Error(`已调用过一次 db.${_toWhereMethod(this.#hasWhere)} 了`);\n\n const whereKeys = Object.keys(where);\n // 只有 _id 值为字符串或数字时,才能调用 doc 方法\n const isWhereId = whereKeys.length === 1 && '_id' in where && (isString(where._id) || isNumber(where._id));\n\n if (isWhereId && this.#hasLimit) {\n throw new Error(`db.${_toWhereIdMethod(from)} 方法不能与 db.limit() 方法同时调用`);\n }\n\n this.#hasWhere = from;\n this.#where = where;\n if (isWhereId) this.#hasWhereId = from;\n\n return this;\n }\n\n /**\n * 设置查询条件\n * @param where 查询条件对象\n * @returns 当前Db实例,支持链式调用\n */\n where(where: DbWhere<T>) {\n return this.#doWhere(where, 'where');\n }\n\n /**\n * 根据ID设置查询条件\n * @param id 记录ID\n * @returns 当前Db实例,支持链式调用\n */\n whereId(id: string | number) {\n // @ts-ignore\n return this.#doWhere({ _id: id }, 'whereId');\n }\n\n #hasSelect = 0;\n #select = {};\n\n /**\n * 指定要返回的字段\n * @param fields 要返回的字段对象,true表示返回,false表示不返回\n * @returns 当前Db实例,支持链式调用\n */\n select<U extends DbSelect<T>>(fields: Exact<U, DbSelect<T>>) {\n if (this.#hasSelect) throw new Error('db.select() 方法只能调用一次');\n\n this.#hasSelect++;\n this.#select = fields;\n\n return this as Db<T, S & U, R>;\n }\n\n #hasOrder = 0;\n #order = {};\n\n /**\n * 设置排序规则\n * @param order 排序规则对象,key为字段名,value为\"asc\"或\"desc\"\n * @returns 当前Db实例,支持链式调用\n */\n order(order: DbOrder<T>) {\n this.#hasOrder++;\n this.#order = order;\n\n return this;\n }\n\n #hasSkip = 0;\n #skip = 0;\n\n /**\n * 跳过指定数量的记录\n * @param skip 要跳过的记录数\n * @returns 当前Db实例,支持链式调用\n */\n skip(skip: number) {\n if (this.#hasSkip) throw new Error('db.skip() 方法只能调用一次');\n\n this.#hasSkip++;\n this.#skip = skip;\n\n return this;\n }\n\n #hasLimit = 0;\n #limit = 0;\n\n /**\n * 限制返回的记录数量\n * @param limit 最大返回记录数\n * @returns 当前Db实例,支持链式调用\n */\n limit(limit: number) {\n if (this.#hasLimit) throw new Error('db.limit() 方法只能调用一次');\n\n if (this.#hasWhereId) {\n throw new Error(`db.limit() 方法不能与 ${_toWhereIdMethod(this.#hasWhereId)} 方法同时调用`);\n }\n\n this.#hasLimit++;\n this.#limit = limit;\n\n return this;\n }\n\n #hasLookup = 0;\n get hasLookup() {\n return this.#hasLookup > 0;\n }\n\n #lookups: DbLookup[] = [];\n lookup<FT, FS extends DbSelect<FT>, FR extends AnyObject, J extends DbJoinType, A extends string>(\n table: Db<FT, FS, FR>,\n lookup: DbLookupOptions<J, T, FT, A>,\n ) {\n // 对方表也记为关联查询,避免做表更新操作\n table.#hasLookup++;\n this.#hasLookup++;\n this.#lookups.push({\n ...lookup,\n table,\n from: table.table,\n });\n\n // 这里必须合并联合类型,否则类型结果会丢失最后一次 lookup\n // @ts-ignore\n return this as Db<T, S, MergeIntersection<R & DbForeign<FT, FS, FR, J, A>>>;\n }\n\n #aggregated = false;\n #endAggregate(aggRef: UniCloud.AggregateReference) {\n if (this.#aggregated) throw new Error(`相同的数据表实例(${this.table})不能重复使用`);\n\n this.#aggregated = true;\n let returnAggRef = aggRef;\n const projects: Record<string, true> = {};\n\n for (const { type, as, foreignField, from, localField, table } of this.#lookups) {\n const varName = `v${gid++}`;\n let pipeline = dbAgg.pipeline();\n\n // 关联条件\n // @ts-ignore\n pipeline = pipeline.match(\n dbCmd.expr(\n type === 'n:1'\n ? // @ts-ignore\n dbAgg.in([`$${foreignField}`, `$$${varName}`])\n : dbAgg.eq([`$${foreignField}`, `$$${varName}`]),\n ),\n );\n\n // 其他查询条件\n // @ts-ignore\n pipeline = table.#endAggregate(pipeline);\n\n // @ts-ignore\n pipeline = pipeline.done();\n\n returnAggRef = returnAggRef.lookup({\n let: {\n [varName]: `$${localField}`,\n },\n as,\n from,\n pipeline,\n });\n\n // 1对1,展开数组\n if (type === '1:1') {\n // @ts-ignore\n returnAggRef = returnAggRef.unwind({\n path: `$${as}`,\n preserveNullAndEmptyArrays: true,\n });\n }\n\n projects[as] = true;\n }\n\n // 主表查询\n if (this.#hasWhere) returnAggRef = returnAggRef.match(this.#where);\n if (this.#hasSelect) returnAggRef = returnAggRef.project({ ...this.#select, ...projects });\n if (this.#hasOrder) returnAggRef = returnAggRef.sort(objectMap(this.#order, (v) => (v === 'asc' ? 1 : -1)));\n if (this.#hasSkip) returnAggRef = returnAggRef.skip(this.#skip);\n if (this.#hasLimit) returnAggRef = returnAggRef.limit(this.#limit);\n\n return returnAggRef;\n }\n\n #endHost() {\n if (this.#hasWhere) {\n // @ts-ignore\n this.#host = this.#host.where(this.#where);\n }\n\n if (this.#hasSelect) {\n // @ts-ignore\n this.#host = this.#host.field(this.#select);\n }\n\n if (this.#hasOrder) {\n objectEach(this.#order, (val, key) => {\n // @ts-ignore\n this.#host = this.#host.orderBy(key, val);\n });\n }\n\n // @ts-ignore\n if (this.#hasSkip) this.#host = this.#host.skip(this.#skip);\n\n // @ts-ignore\n if (this.#hasLimit) this.#host = this.#host.limit(this.#limit);\n // @ts-ignore\n else if (this.#hasWhereId) this.#host = this.#host.limit(1);\n }\n\n /**\n * 执行查询操作\n * @returns 查询结果\n */\n async query() {\n let res: { data: DbQuery<T, S, R>[] };\n\n // 关联查询\n if (this.#hasLookup) {\n const aggRef = this.aggregate();\n this.#endAggregate(aggRef);\n res = await aggRef.end();\n }\n // 单表查询\n else {\n this.#endHost();\n res = await this.#host.get();\n }\n\n const rows = isArray(res.data) ? res.data : [res.data];\n const { data } = parseDatabaseOutput(res);\n return data;\n }\n\n /**\n * 只查询一条,自动添加 limit(1) 条件\n * @param ignoreMiss 是否忽略没有匹配到记录\n * @returns 查询结果\n */\n async queryOne(): Promise<DbQuery<T, S, R>>;\n async queryOne(ignoreMiss: false): Promise<DbQuery<T, S, R>>;\n async queryOne(ignoreMiss: true): Promise<DbQuery<T, S, R> | undefined>;\n async queryOne(ignoreMiss = false): Promise<DbQuery<T, S, R> | undefined> {\n if (this.#hasLimit) throw new Error('db.queryOne() 方法不支持 limit 条件');\n if (!this.#hasWhereId) this.limit(1);\n\n const data = await this.query();\n const res = data.at(0);\n\n if (!ignoreMiss && !res) throw new Error('未找到匹配记录');\n return res;\n }\n\n /**\n * 获取匹配记录的数量\n * @returns 记录总数\n */\n async count() {\n if (this.#hasLookup) throw new Error('db.count() 方法不支持 lookup 聚合');\n if (this.#hasSelect) throw new Error('db.count() 方法不支持 select 条件');\n if (this.#hasOrder) throw new Error('db.count() 方法不支持 order 条件');\n if (this.#hasSkip) throw new Error('db.count() 方法不支持 skip 条件');\n if (this.#hasLimit) throw new Error('db.count() 方法不支持 limit 条件');\n\n this.#endHost();\n const res = await this.#host.count();\n const { total } = parseDatabaseOutput<{ total: number }>(res);\n return total;\n }\n\n /**\n * 创建新记录\n * @param data 要创建的数据\n * @returns 创建结果\n */\n async create(data: DbCreate<T>) {\n if (this.#hasLookup) throw new Error('db.create() 方法不支持 lookup 聚合');\n if (this.#hasWhere) throw new Error('db.create() 方法不支持 where 条件');\n if (this.#hasSelect) throw new Error('db.create() 方法不支持 select 条件');\n if (this.#hasOrder) throw new Error('db.create() 方法不支持 order 条件');\n if (this.#hasSkip) throw new Error('db.create() 方法不支持 skip 条件');\n if (this.#hasLimit) throw new Error('db.create() 方法不支持 limit 条件');\n\n this.#endHost();\n const res = await this.#host.add(data);\n const { id } = parseDatabaseOutput<{ id: string }>(res);\n return id;\n }\n\n /**\n * 更新记录\n * @param data 要更新的数据\n * @returns 更新结果\n */\n async update(data: AnyObject) {\n if (this.#hasLookup) throw new Error('db.update() 方法不支持 lookup 聚合');\n if (!this.#hasWhere) throw new Error('设置 where 条件后才能执行 db.update() 方法');\n if (this.#hasSelect) throw new Error('db.update() 方法不支持 select 条件');\n if (this.#hasOrder) throw new Error('db.update() 方法不支持 order 条件');\n if (this.#hasSkip) throw new Error('db.update() 方法不支持 skip 条件');\n if (this.#hasLimit) throw new Error('db.update() 方法不支持 limit 条件');\n\n if (this.#isTransaction && !this.#hasWhereId) throw new Error('事务模式下 db.update() 的 where 条件必须是 _id');\n\n this.#endHost();\n const res = await this.#host.update(data);\n const { updated } = parseDatabaseOutput<{ updated: number }>(res);\n return updated;\n }\n\n /**\n * 删除记录\n * @returns 删除结果\n */\n async remove() {\n if (this.#hasLookup) throw new Error('db.remove() 方法不支持 lookup 聚合');\n if (!this.#hasWhere) throw new Error('设置 where 条件后才能执行 db.remove() 方法');\n if (this.#hasSelect) throw new Error('db.remove() 方法不支持 select 条件');\n if (this.#hasOrder) throw new Error('db.remove() 方法不支持 order 条件');\n if (this.#hasSkip) throw new Error('db.remove() 方法不支持 skip 条件');\n if (this.#hasLimit) throw new Error('db.remove() 方法不支持 limit 条件');\n\n if (this.#isTransaction && !this.#hasWhereId) throw new Error('事务模式下 db.remove() 的 where 条件必须是 _id');\n\n this.#endHost();\n const res = await this.#host.remove();\n const { deleted } = parseDatabaseOutput<{ deleted: number }>(res);\n return deleted;\n }\n}\n\n// biome-ignore lint/complexity/noBannedTypes: <explanation>\nexport type DbProxy<T, S extends DbSelect<T> = {}, R extends AnyObject = {}> = Db<T, S, R> & {\n _isProxy: true;\n};\n\n/**\n * 数据库操作对象\n */\nexport const db = {\n /**\n * 获取指定名称的数据库集合实例\n * @param name 数据表名称\n * @returns Db类实例,用于执行数据库操作\n */\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n table<T, S extends DbSelect<T> = {}, R extends AnyObject = {}>(name: string) {\n return new Proxy(\n {},\n {\n get(target, prop) {\n if (prop === '_isProxy') return true;\n\n const table = new Db<T, S, R>({ table: name });\n const tableProp = prop as keyof Db<T, S, R>;\n const ref = table[tableProp];\n\n return isFunction(ref) ? ref.bind(table) : ref;\n },\n },\n ) as DbProxy<T>;\n },\n};\n\n/**\n * 解析数据库执行结果\n * @param res 客户端、云端响应结果\n * @returns 处理后的结果\n */\nexport function parseDatabaseOutput<T>(res: UniClientDatabaseOutput<T> | UniCloudDatabaseOutput<T>) {\n const keys = Object.keys(res as AnyObject);\n // 客户端 { result: {errCode: 0, errMsg: 'ok'} & 数据 }\n const isClient = keys.length === 1 && keys[0] === 'result';\n\n if (isClient) {\n const { result } = res as UniClientDatabaseOutput<T>;\n if (!result.errCode) return objectOmit(result, ['errCode', 'errMsg', 'code', 'message']);\n throw errorAssign(new Error(result.errMsg), result);\n }\n\n // 云端 数据\n return res as T;\n}\n\nfunction _toWhereMethod(whereFrom: _WhereFrom) {\n return whereFrom === 'where' ? 'where({...})' : 'whereId(id)';\n}\n\nfunction _toWhereIdMethod(whereFrom: _WhereFrom) {\n return whereFrom === 'where' ? 'where({ _id })' : 'whereId(id)';\n}\n","import { tryFlatten } from '@cloudcome/utils-core/try';\nimport { isFunction } from '@cloudcome/utils-core/type';\nimport type { AnyObject, Exact, MaybeCallable } from '@cloudcome/utils-core/types';\nimport { Db, type DbCreate, type DbProxy, type DbQuery, type DbSelect, type DbUpdate, type DbWhere, db } from './db';\n\nexport type DbUpsertOptions<T, S extends DbSelect<T>, C extends DbCreate<T>, U extends DbUpdate<T>> = {\n /** 查询条件 */\n where: DbWhere<T>;\n\n /** 查询返回字段 */\n select?: Exact<S, DbSelect<T>>;\n\n /** 创建数据 */\n create: C;\n\n /**\n * 更新数据,可以是对象或根据查询结果生成更新对象的函数\n * @param row 查询到的文档数据,仅在传入函数时可用\n */\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n update: U | ((exist: DbQuery<T, S, {}>) => U);\n\n /** 创建前回调函数 */\n onBeforeCreate?: () => unknown;\n\n /**\n * 创建后回调函数\n * @param id 创建的文档ID\n */\n onAfterCreate?: (id: string) => unknown;\n\n /**\n * 更新前回调函数\n * @param exist 查询到的原始文档数据\n * @returns 如果返回 false,则取消更新操作\n */\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n onBeforeUpdate?: (exist: DbQuery<T, S, {}>) => false | unknown;\n\n /**\n * 更新后回调函数\n * @param updateData 实际更新的数据\n * @param exist 查询到的原始文档数据\n */\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n onAfterUpdate?: (updateData: U, exist: DbQuery<T, S, {}>) => unknown;\n\n /** 用于测试的模拟数据库实例 */\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n _mockDbInstance?: any;\n};\n\n/**\n * 数据库 upsert 操作的返回结果类型\n */\nexport type DbUpsertOutput = {\n /** 操作的文档ID */\n id: string;\n /** 是否为创建操作 */\n created: boolean;\n /** 是否为更新操作 */\n updated: boolean;\n};\n\nexport async function dbUpsert<T, S extends DbSelect<T>, C extends DbCreate<T>, U extends DbUpdate<T>>(\n dbProxy: DbProxy<T>,\n options: DbUpsertOptions<T, S, C, U>,\n): Promise<DbUpsertOutput> {\n const {\n where,\n select = {},\n create,\n update,\n onBeforeCreate,\n onAfterCreate,\n onBeforeUpdate,\n onAfterUpdate,\n _mockDbInstance,\n } = options;\n\n // @ts-ignore\n if ('_id' in select) throw new Error('select 条件不能包含 _id 字段');\n\n const _db = (_mockDbInstance || dbProxy) as DbProxy<T, S>;\n const exist = (await _db\n .where(where)\n .select(select || {})\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n .queryOne(true)) as DbQuery<T, S, {}> | undefined;\n\n if (exist) {\n const skipUpdate = (await onBeforeUpdate?.(exist)) === false;\n\n if (skipUpdate) {\n // @ts-ignore\n return { id: exist._id as string, updated: false, created: false };\n }\n\n const updateData = isFunction(update) ? update(exist) : update;\n // @ts-ignore\n const updated = await _db.whereId(exist._id).update(updateData);\n onAfterUpdate?.(updateData, exist);\n\n // @ts-ignore\n return { id: exist._id as string, updated: true, created: false };\n }\n\n await onBeforeCreate?.();\n const createdId = await _db.create(create);\n await onAfterCreate?.(createdId);\n\n return { id: createdId, updated: false, created: true };\n}\n\ntype _TransactionDb = {\n startTransaction: () => Promise<_Transaction>;\n};\n\ntype _Transaction = {\n commit: () => Promise<unknown>;\n rollback: () => Promise<unknown>;\n};\n\ntype _WithTransaction = <T, S extends DbSelect<T>, R extends AnyObject>(table: DbProxy<T, S, R>) => Db<T, S, R>;\n\n/**\n * 在数据库事务中执行操作\n *\n * @template T - 事务操作返回值类型\n * @param transacting - 事务执行函数,接收事务数据库实例作为参数\n * @param _mockDatabase - 用于测试的模拟数据库对象\n * @param _mockDbInstance - 用于测试的模拟数据库实例\n * @returns 事务操作的返回结果\n *\n * @example\n * ```typescript\n * const result = await dbTransaction(async (withTransaction) => {\n * const userId = await withTransaction(db.table('user')).create({ name: 'John' });\n * const order = await withTransaction(db.table('orders')).create({ userId, amount: 100 });\n * return { user, order };\n * });\n * ```\n */\nexport async function dbTransaction<K>(\n transacting: (withTransaction: _WithTransaction) => Promise<K>,\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n _mockDatabase?: any,\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n _mockDbInstance?: any,\n) {\n const transactionDb = (_mockDatabase || uniCloud.database()) as _TransactionDb;\n\n const [err1, transaction] = await tryFlatten(transactionDb.startTransaction());\n if (err1) throw err1;\n\n const withTransaction = <T, S extends DbSelect<T>, R extends AnyObject>(dbProxy: DbProxy<T, S, R>) => {\n return _mockDbInstance || new Db<T, S, R>({ table: dbProxy.table, transaction });\n };\n\n const [err2, result] = await tryFlatten(async () => {\n const result = await transacting(withTransaction);\n await transaction.commit();\n return result;\n });\n\n if (err2) {\n await tryFlatten(transaction.rollback());\n throw err2;\n }\n\n return result as unknown as K;\n}\n"],"names":["isString","isNumber","type","objectMap","objectEach","isArray","isFunction","objectOmit","errorAssign","tryFlatten","result"],"mappings":"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"}
|
package/dist/database.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.mjs","sources":["../src/database/db.ts","../src/database/fns.ts"],"sourcesContent":["import { errorAssign } from '@cloudcome/utils-core/error';\nimport { objectEach, objectMap, objectOmit } from '@cloudcome/utils-core/object';\nimport { isArray, isFunction, isNumber, isString } from '@cloudcome/utils-core/type';\nimport type {\n AnyObject,\n HasProperty,\n IsEmptyObject,\n IsOnlyProperty,\n MergeIntersection,\n UnionToIntersection,\n} from '@cloudcome/utils-core/types';\nimport type { UniClientDatabaseOutput, UniCloudDatabaseOutput, UniDatabaseCommand } from './types';\n\nexport type DbWhere<T> = {\n [K in keyof T]?: unknown;\n};\nexport type DbSelect<T> = {\n [K in keyof T]?: K extends '_id' ? false : true;\n};\nexport type DbFieldsDefault<T> = {\n [K in keyof T]: true;\n};\ntype _DbFields<T, S extends DbSelect<T>> = IsEmptyObject<S> extends true // 判断是否为空对象\n ? // 默认全部字段\n DbFieldsDefault<T>\n : // 判断 _id 是否为唯一属性\n IsOnlyProperty<S, '_id'> extends true\n ? // 从默认字段里排除 _id\n Omit<DbFieldsDefault<T>, '_id'>\n : // 判断是否有 _id\n HasProperty<S, '_id'> extends true\n ? // 有的话保留 {_id, ...}\n S\n : // 没有的话补上 {_id, ...}\n S & { _id: true };\ntype _DbQuery<T, S extends Record<keyof T, boolean>> = {\n [K in keyof T as S[K] extends true ? K : never]: T[K];\n};\n// @ts-ignore\nexport type DbQuery<T, S extends DbSelect<T>, R> = _DbQuery<T, _DbFields<T, S>> & R;\nexport type DbForeign<T, S extends DbSelect<T>, R, J extends DbJoinType, A> = Record<\n A & string,\n J extends '1:1' ? DbQuery<T, S, R> : DbQuery<T, S, R>[]\n>;\nexport type DbCreate<T> = Partial<T>;\nexport type DbUpdate<T> = Partial<T>;\nexport type DbOrder<T> = Record<keyof T, 'asc' | 'desc'>;\n\ntype _WhereFrom = 'where' | 'whereId';\n\nconst db0 = uniCloud.database();\n/**\n * 数据库操作符命令\n */\nexport const dbCmd = db0.command as unknown as UniDatabaseCommand;\n\n/**\n * 数据库聚合操作符命令\n */\nexport const dbAgg = db0.command.aggregate as UniCloud.AggregateCommand & {\n pipeline: () => UniCloud.AggregateReference & {\n done: () => unknown;\n };\n};\n\nexport type DbOptions = {\n /**\n * 数据表名称\n */\n table: string;\n\n /**\n * 事务对象,用于事务操作\n */\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n transaction?: any;\n\n /**\n * 模拟数据库,用于单元测试\n */\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n _mockDatabase?: any;\n};\n\n/**\n * 数据库关联类型\n * - '1:1': 一对一关联,返回值 1 个\n * - '1:n': 一对多关联,返回值 n 个\n * - 'n:1': 多对一关联,返回值 n 个\n */\nexport type DbJoinType = '1:1' | '1:n' | 'n:1';\nexport type DbLookupOptions<J extends DbJoinType, L, F, A> = {\n /**\n * 关联类型\n */\n type: J;\n\n /**\n * 主表字段\n */\n localField: keyof L & string;\n\n /**\n * 关联表字段\n */\n foreignField: keyof F & string;\n\n /**\n * 关联数据在结果中的字段名\n */\n as: A;\n};\n\nexport type DbLookup = {\n /**\n * 关联表\n */\n table: Db<unknown>;\n\n /**\n * 关联类型\n */\n type: DbJoinType;\n\n /**\n * 主表字段\n */\n localField: string;\n\n /**\n * 关联表字段\n */\n foreignField: string;\n\n /**\n * 关联表名称\n */\n from: string;\n\n /**\n * 关联数据在结果中的字段名\n */\n as: string;\n};\n\nlet gid = 0;\n\n// biome-ignore lint/complexity/noBannedTypes: <explanation>\nexport class Db<T, S extends DbSelect<T> = {}, R extends AnyObject = {}> {\n #host: UniCloud.CollectionReference;\n\n /**\n * 是否为事务环境\n * - 查询条件只能是 id\n * - 不能聚合操作\n */\n #isTransaction = false;\n\n #options: DbOptions;\n\n /**\n * 构造函数,初始化数据库集合引用\n * @param collection 数据表名称\n * @param _mockDatabase 模拟数据库,用于单元测试\n */\n constructor(options: DbOptions) {\n this.#options = options;\n this.#host =\n options._mockDatabase || options.transaction?.collection(options.table) || db0.collection(options.table);\n this.#isTransaction = !!options.transaction;\n }\n\n get table() {\n return this.#options.table;\n }\n\n /**\n * 获取聚合操作实例\n * @returns 聚合操作实例\n */\n aggregate() {\n return this.#host.aggregate();\n }\n\n #hasWhere: _WhereFrom | undefined = undefined;\n #hasWhereId: _WhereFrom | undefined = undefined;\n #where = {};\n\n #doWhere(where: DbWhere<T>, from: _WhereFrom) {\n if (this.#hasWhere) throw new Error(`已调用过一次 db.${_toWhereMethod(this.#hasWhere)} 了`);\n\n const whereKeys = Object.keys(where);\n // 只有 _id 值为字符串或数字时,才能调用 doc 方法\n const isWhereId = whereKeys.length === 1 && '_id' in where && (isString(where._id) || isNumber(where._id));\n\n if (isWhereId && this.#hasLimit) {\n throw new Error(`db.${_toWhereIdMethod(from)} 方法不能与 db.limit() 方法同时调用`);\n }\n\n this.#hasWhere = from;\n this.#where = where;\n if (isWhereId) this.#hasWhereId = from;\n\n return this;\n }\n\n /**\n * 设置查询条件\n * @param where 查询条件对象\n * @returns 当前Db实例,支持链式调用\n */\n where(where: DbWhere<T>) {\n return this.#doWhere(where, 'where');\n }\n\n /**\n * 根据ID设置查询条件\n * @param id 记录ID\n * @returns 当前Db实例,支持链式调用\n */\n whereId(id: string | number) {\n // @ts-ignore\n return this.#doWhere({ _id: id }, 'whereId');\n }\n\n #hasSelect = 0;\n #select = {};\n\n /**\n * 指定要返回的字段\n * @param fields 要返回的字段对象,true表示返回,false表示不返回\n * @returns 当前Db实例,支持链式调用\n */\n select<U extends DbSelect<T>>(fields: U) {\n if (this.#hasSelect) throw new Error('db.select() 方法只能调用一次');\n\n this.#hasSelect++;\n this.#select = fields;\n\n return this as Db<T, S & U, R>;\n }\n\n #hasOrder = 0;\n #order = {};\n\n /**\n * 设置排序规则\n * @param order 排序规则对象,key为字段名,value为\"asc\"或\"desc\"\n * @returns 当前Db实例,支持链式调用\n */\n order(order: DbOrder<T>) {\n this.#hasOrder++;\n this.#order = order;\n\n return this;\n }\n\n #hasSkip = 0;\n #skip = 0;\n\n /**\n * 跳过指定数量的记录\n * @param skip 要跳过的记录数\n * @returns 当前Db实例,支持链式调用\n */\n skip(skip: number) {\n if (this.#hasSkip) throw new Error('db.skip() 方法只能调用一次');\n\n this.#hasSkip++;\n this.#skip = skip;\n\n return this;\n }\n\n #hasLimit = 0;\n #limit = 0;\n\n /**\n * 限制返回的记录数量\n * @param limit 最大返回记录数\n * @returns 当前Db实例,支持链式调用\n */\n limit(limit: number) {\n if (this.#hasLimit) throw new Error('db.limit() 方法只能调用一次');\n\n if (this.#hasWhereId) {\n throw new Error(`db.limit() 方法不能与 ${_toWhereIdMethod(this.#hasWhereId)} 方法同时调用`);\n }\n\n this.#hasLimit++;\n this.#limit = limit;\n\n return this;\n }\n\n #hasLookup = 0;\n get hasLookup() {\n return this.#hasLookup > 0;\n }\n\n #lookups: DbLookup[] = [];\n lookup<FT, FS extends DbSelect<FT>, FR extends AnyObject, J extends DbJoinType, A extends string>(\n table: Db<FT, FS, FR>,\n lookup: DbLookupOptions<J, T, FT, A>,\n ) {\n // 对方表也记为关联查询,避免做表更新操作\n table.#hasLookup++;\n this.#hasLookup++;\n this.#lookups.push({\n ...lookup,\n table,\n from: table.table,\n });\n\n // 这里必须合并联合类型,否则类型结果会丢失最后一次 lookup\n // @ts-ignore\n return this as Db<T, S, MergeIntersection<R & DbForeign<FT, FS, FR, J, A>>>;\n }\n\n #aggregated = false;\n #endAggregate(aggRef: UniCloud.AggregateReference) {\n if (this.#aggregated) throw new Error(`相同的数据表实例(${this.table})不能重复使用`);\n\n this.#aggregated = true;\n let returnAggRef = aggRef;\n const projects: Record<string, true> = {};\n\n for (const { type, as, foreignField, from, localField, table } of this.#lookups) {\n const varName = `v${gid++}`;\n let pipeline = dbAgg.pipeline();\n\n // 关联条件\n // @ts-ignore\n pipeline = pipeline.match(\n dbCmd.expr(\n type === 'n:1'\n ? // @ts-ignore\n dbAgg.in([`$${foreignField}`, `$$${varName}`])\n : dbAgg.eq([`$${foreignField}`, `$$${varName}`]),\n ),\n );\n\n // 其他查询条件\n // @ts-ignore\n pipeline = table.#endAggregate(pipeline);\n\n // @ts-ignore\n pipeline = pipeline.done();\n\n returnAggRef = returnAggRef.lookup({\n let: {\n [varName]: `$${localField}`,\n },\n as,\n from,\n pipeline,\n });\n\n // 1对1,展开数组\n if (type === '1:1') {\n // @ts-ignore\n returnAggRef = returnAggRef.unwind({\n path: `$${as}`,\n preserveNullAndEmptyArrays: true,\n });\n }\n\n projects[as] = true;\n }\n\n // 主表查询\n if (this.#hasWhere) returnAggRef = returnAggRef.match(this.#where);\n if (this.#hasSelect) returnAggRef = returnAggRef.project({ ...this.#select, ...projects });\n if (this.#hasOrder) returnAggRef = returnAggRef.sort(objectMap(this.#order, (v) => (v === 'asc' ? 1 : -1)));\n if (this.#hasSkip) returnAggRef = returnAggRef.skip(this.#skip);\n if (this.#hasLimit) returnAggRef = returnAggRef.limit(this.#limit);\n\n return returnAggRef;\n }\n\n #endHost() {\n if (this.#hasWhere) {\n // @ts-ignore\n this.#host = this.#host.where(this.#where);\n }\n\n if (this.#hasSelect) {\n // @ts-ignore\n this.#host = this.#host.field(this.#select);\n }\n\n if (this.#hasOrder) {\n objectEach(this.#order, (val, key) => {\n // @ts-ignore\n this.#host = this.#host.orderBy(key, val);\n });\n }\n\n // @ts-ignore\n if (this.#hasSkip) this.#host = this.#host.skip(this.#skip);\n\n // @ts-ignore\n if (this.#hasLimit) this.#host = this.#host.limit(this.#limit);\n // @ts-ignore\n else if (this.#hasWhereId) this.#host = this.#host.limit(1);\n }\n\n /**\n * 执行查询操作\n * @returns 查询结果\n */\n async query() {\n let res: { data: DbQuery<T, S, R>[] };\n\n // 关联查询\n if (this.#hasLookup) {\n const aggRef = this.aggregate();\n this.#endAggregate(aggRef);\n res = await aggRef.end();\n }\n // 单表查询\n else {\n this.#endHost();\n res = await this.#host.get();\n }\n\n const rows = isArray(res.data) ? res.data : [res.data];\n const { data } = parseDatabaseOutput(res);\n return data;\n }\n\n /**\n * 只查询一条,自动添加 limit(1) 条件\n * @param ignoreMiss 是否忽略没有匹配到记录\n * @returns 查询结果\n */\n async queryOne(): Promise<DbQuery<T, S, R>>;\n async queryOne(ignoreMiss: false): Promise<DbQuery<T, S, R>>;\n async queryOne(ignoreMiss: true): Promise<DbQuery<T, S, R> | undefined>;\n async queryOne(ignoreMiss = false): Promise<DbQuery<T, S, R> | undefined> {\n if (this.#hasLimit) throw new Error('db.queryOne() 方法不支持 limit 条件');\n if (!this.#hasWhereId) this.limit(1);\n\n const data = await this.query();\n const res = data.at(0);\n\n if (!ignoreMiss && !res) throw new Error('未找到匹配记录');\n return res;\n }\n\n /**\n * 获取匹配记录的数量\n * @returns 记录总数\n */\n async count() {\n if (this.#hasLookup) throw new Error('db.count() 方法不支持 lookup 聚合');\n if (this.#hasSelect) throw new Error('db.count() 方法不支持 select 条件');\n if (this.#hasOrder) throw new Error('db.count() 方法不支持 order 条件');\n if (this.#hasSkip) throw new Error('db.count() 方法不支持 skip 条件');\n if (this.#hasLimit) throw new Error('db.count() 方法不支持 limit 条件');\n\n this.#endHost();\n const res = await this.#host.count();\n const { total } = parseDatabaseOutput<{ total: number }>(res);\n return total;\n }\n\n /**\n * 创建新记录\n * @param data 要创建的数据\n * @returns 创建结果\n */\n async create(data: DbCreate<T>) {\n if (this.#hasLookup) throw new Error('db.create() 方法不支持 lookup 聚合');\n if (this.#hasWhere) throw new Error('db.create() 方法不支持 where 条件');\n if (this.#hasSelect) throw new Error('db.create() 方法不支持 select 条件');\n if (this.#hasOrder) throw new Error('db.create() 方法不支持 order 条件');\n if (this.#hasSkip) throw new Error('db.create() 方法不支持 skip 条件');\n if (this.#hasLimit) throw new Error('db.create() 方法不支持 limit 条件');\n\n this.#endHost();\n const res = await this.#host.add(data);\n const { id } = parseDatabaseOutput<{ id: string }>(res);\n return id;\n }\n\n /**\n * 更新记录\n * @param data 要更新的数据\n * @returns 更新结果\n */\n async update(data: AnyObject) {\n if (this.#hasLookup) throw new Error('db.update() 方法不支持 lookup 聚合');\n if (!this.#hasWhere) throw new Error('设置 where 条件后才能执行 db.update() 方法');\n if (this.#hasSelect) throw new Error('db.update() 方法不支持 select 条件');\n if (this.#hasOrder) throw new Error('db.update() 方法不支持 order 条件');\n if (this.#hasSkip) throw new Error('db.update() 方法不支持 skip 条件');\n if (this.#hasLimit) throw new Error('db.update() 方法不支持 limit 条件');\n\n if (this.#isTransaction && !this.#hasWhereId) throw new Error('事务模式下 db.update() 的 where 条件必须是 _id');\n\n this.#endHost();\n const res = await this.#host.update(data);\n const { updated } = parseDatabaseOutput<{ updated: number }>(res);\n return updated;\n }\n\n /**\n * 删除记录\n * @returns 删除结果\n */\n async remove() {\n if (this.#hasLookup) throw new Error('db.remove() 方法不支持 lookup 聚合');\n if (!this.#hasWhere) throw new Error('设置 where 条件后才能执行 db.remove() 方法');\n if (this.#hasSelect) throw new Error('db.remove() 方法不支持 select 条件');\n if (this.#hasOrder) throw new Error('db.remove() 方法不支持 order 条件');\n if (this.#hasSkip) throw new Error('db.remove() 方法不支持 skip 条件');\n if (this.#hasLimit) throw new Error('db.remove() 方法不支持 limit 条件');\n\n if (this.#isTransaction && !this.#hasWhereId) throw new Error('事务模式下 db.remove() 的 where 条件必须是 _id');\n\n this.#endHost();\n const res = await this.#host.remove();\n const { deleted } = parseDatabaseOutput<{ deleted: number }>(res);\n return deleted;\n }\n}\n\n// biome-ignore lint/complexity/noBannedTypes: <explanation>\nexport type DbProxy<T, S extends DbSelect<T> = {}, R extends AnyObject = {}> = Db<T, S, R> & {\n _isProxy: true;\n};\n\n/**\n * 数据库操作对象\n */\nexport const db = {\n /**\n * 获取指定名称的数据库集合实例\n * @param name 数据表名称\n * @returns Db类实例,用于执行数据库操作\n */\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n table<T, S extends DbSelect<T> = {}, R extends AnyObject = {}>(name: string) {\n return new Proxy(\n {},\n {\n get(target, prop) {\n if (prop === '_isProxy') return true;\n\n const table = new Db<T, S, R>({ table: name });\n const tableProp = prop as keyof Db<T, S, R>;\n const ref = table[tableProp];\n\n return isFunction(ref) ? ref.bind(table) : ref;\n },\n },\n ) as DbProxy<T>;\n },\n};\n\n/**\n * 解析数据库执行结果\n * @param res 客户端、云端响应结果\n * @returns 处理后的结果\n */\nexport function parseDatabaseOutput<T>(res: UniClientDatabaseOutput<T> | UniCloudDatabaseOutput<T>) {\n const keys = Object.keys(res as AnyObject);\n // 客户端 { result: {errCode: 0, errMsg: 'ok'} & 数据 }\n const isClient = keys.length === 1 && keys[0] === 'result';\n\n if (isClient) {\n const { result } = res as UniClientDatabaseOutput<T>;\n if (!result.errCode) return objectOmit(result, ['errCode', 'errMsg', 'code', 'message']);\n throw errorAssign(new Error(result.errMsg), result);\n }\n\n // 云端 数据\n return res as T;\n}\n\nfunction _toWhereMethod(whereFrom: _WhereFrom) {\n return whereFrom === 'where' ? 'where({...})' : 'whereId(id)';\n}\n\nfunction _toWhereIdMethod(whereFrom: _WhereFrom) {\n return whereFrom === 'where' ? 'where({ _id })' : 'whereId(id)';\n}\n","import { tryFlatten } from '@cloudcome/utils-core/try';\nimport { isFunction } from '@cloudcome/utils-core/type';\nimport type { AnyObject, MaybeCallable } from '@cloudcome/utils-core/types';\nimport { Db, type DbCreate, type DbProxy, type DbQuery, type DbSelect, type DbUpdate, type DbWhere, db } from './db';\n\nexport type DbUpsertOptions<T, S extends DbSelect<T>, C extends DbCreate<T>, U extends DbUpdate<T>> = {\n /** 查询条件 */\n where: DbWhere<T>;\n\n /** 查询返回字段 */\n select?: S;\n\n /** 创建数据 */\n create: C;\n\n /**\n * 更新数据,可以是对象或根据查询结果生成更新对象的函数\n * @param row 查询到的文档数据,仅在传入函数时可用\n */\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n update: U | ((exist: DbQuery<T, S, {}>) => U);\n\n /** 创建前回调函数 */\n onBeforeCreate?: () => unknown;\n\n /**\n * 创建后回调函数\n * @param id 创建的文档ID\n */\n onAfterCreate?: (id: string) => unknown;\n\n /**\n * 更新前回调函数\n * @param exist 查询到的原始文档数据\n * @returns 如果返回 false,则取消更新操作\n */\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n onBeforeUpdate?: (exist: DbQuery<T, S, {}>) => false | unknown;\n\n /**\n * 更新后回调函数\n * @param updateData 实际更新的数据\n * @param exist 查询到的原始文档数据\n */\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n onAfterUpdate?: (updateData: U, exist: DbQuery<T, S, {}>) => unknown;\n\n /** 用于测试的模拟数据库实例 */\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n _mockDbInstance?: any;\n};\n\n/**\n * 数据库 upsert 操作的返回结果类型\n */\nexport type DbUpsertOutput = {\n /** 操作的文档ID */\n id: string;\n /** 是否为创建操作 */\n created: boolean;\n /** 是否为更新操作 */\n updated: boolean;\n};\n\nexport async function dbUpsert<T, S extends DbSelect<T>, C extends DbCreate<T>, U extends DbUpdate<T>>(\n dbProxy: DbProxy<T>,\n options: DbUpsertOptions<T, S, C, U>,\n): Promise<DbUpsertOutput> {\n const {\n where,\n select = {},\n create,\n update,\n onBeforeCreate,\n onAfterCreate,\n onBeforeUpdate,\n onAfterUpdate,\n _mockDbInstance,\n } = options;\n\n // @ts-ignore\n if ('_id' in select) throw new Error('select 条件不能包含 _id 字段');\n\n const _db = (_mockDbInstance || dbProxy) as DbProxy<T, S>;\n const exist = (await _db\n .where(where)\n .select(select || {})\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n .queryOne(true)) as DbQuery<T, S, {}> | undefined;\n\n if (exist) {\n const skipUpdate = (await onBeforeUpdate?.(exist)) === false;\n\n if (skipUpdate) {\n // @ts-ignore\n return { id: exist._id as string, updated: false, created: false };\n }\n\n const updateData = isFunction(update) ? update(exist) : update;\n // @ts-ignore\n const updated = await _db.whereId(exist._id).update(updateData);\n onAfterUpdate?.(updateData, exist);\n\n // @ts-ignore\n return { id: exist._id as string, updated: true, created: false };\n }\n\n await onBeforeCreate?.();\n const createdId = await _db.create(create);\n await onAfterCreate?.(createdId);\n\n return { id: createdId, updated: false, created: true };\n}\n\ntype _TransactionDb = {\n startTransaction: () => Promise<_Transaction>;\n};\n\ntype _Transaction = {\n commit: () => Promise<unknown>;\n rollback: () => Promise<unknown>;\n};\n\ntype _WithTransaction = <T, S extends DbSelect<T>, R extends AnyObject>(table: DbProxy<T, S, R>) => Db<T, S, R>;\n\n/**\n * 在数据库事务中执行操作\n *\n * @template T - 事务操作返回值类型\n * @param transacting - 事务执行函数,接收事务数据库实例作为参数\n * @param _mockDatabase - 用于测试的模拟数据库对象\n * @param _mockDbInstance - 用于测试的模拟数据库实例\n * @returns 事务操作的返回结果\n *\n * @example\n * ```typescript\n * const result = await dbTransaction(async (withTransaction) => {\n * const userId = await withTransaction(db.table('user')).create({ name: 'John' });\n * const order = await withTransaction(db.table('orders')).create({ userId, amount: 100 });\n * return { user, order };\n * });\n * ```\n */\nexport async function dbTransaction<K>(\n transacting: (withTransaction: _WithTransaction) => Promise<K>,\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n _mockDatabase?: any,\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n _mockDbInstance?: any,\n) {\n const transactionDb = (_mockDatabase || uniCloud.database()) as _TransactionDb;\n\n const [err1, transaction] = await tryFlatten(transactionDb.startTransaction());\n if (err1) throw err1;\n\n const withTransaction = <T, S extends DbSelect<T>, R extends AnyObject>(dbProxy: DbProxy<T, S, R>) => {\n return _mockDbInstance || new Db<T, S, R>({ table: dbProxy.table, transaction });\n };\n\n const [err2, result] = await tryFlatten(async () => {\n const result = await transacting(withTransaction);\n await transaction.commit();\n return result;\n });\n\n if (err2) {\n await tryFlatten(transaction.rollback());\n throw err2;\n }\n\n return result as unknown as K;\n}\n"],"names":["result"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"database.mjs","sources":["../src/database/db.ts","../src/database/fns.ts"],"sourcesContent":["import { errorAssign } from '@cloudcome/utils-core/error';\nimport { objectEach, objectMap, objectOmit } from '@cloudcome/utils-core/object';\nimport { isArray, isFunction, isNumber, isString } from '@cloudcome/utils-core/type';\nimport type {\n AnyObject,\n Exact,\n HasProperty,\n IsEmptyObject,\n IsOnlyProperty,\n MergeIntersection,\n UnionToIntersection,\n} from '@cloudcome/utils-core/types';\nimport type {\n UniClientDatabaseOutput,\n UniCloudDatabaseOutput,\n UniDatabaseCommand,\n UniDatabaseMutateCommand,\n UniDatabaseQueryCommand,\n} from './types';\n\nexport type DbWhere<T> = {\n [K in keyof T]?: T[K] | UniDatabaseQueryCommand;\n};\nexport type DbSelect<T> = {\n [K in keyof T]?: K extends '_id' ? boolean : true;\n};\nexport type DbFieldsDefault<T> = {\n [K in keyof T]: true;\n};\ntype _OnlyFieldId<T, V> = IsOnlyProperty<T, '_id'> extends true\n ? '_id' extends keyof T\n ? T['_id'] extends V\n ? true\n : false\n : false\n : false;\ntype _DbFields<T, S extends DbSelect<T>> = IsEmptyObject<S> extends true // 判断是否为空对象\n ? // 默认全部字段\n DbFieldsDefault<T>\n : // 判断 _id 是否为唯一属性 且 为 false\n _OnlyFieldId<S, false> extends true\n ? // 从默认字段里排除 _id\n Omit<DbFieldsDefault<T>, '_id'>\n : // 判断 _id 是否为唯一属性 且 为 true\n _OnlyFieldId<S, true> extends true\n ? // 只保留 _id\n { _id: true }\n : // 判断是否有 _id\n HasProperty<S, '_id'> extends true\n ? // 有的话保留 {_id, ...}\n S\n : // 没有的话补上 {_id, ...}\n S & { _id: true };\ntype _DbQuery<T, S extends Record<keyof T, boolean>> = {\n [K in keyof T as S[K] extends true ? K : never]: T[K];\n};\n// @ts-ignore\nexport type DbQuery<T, S extends DbSelect<T>, R> = _DbQuery<T, _DbFields<T, S>> & R;\nexport type DbForeign<T, S extends DbSelect<T>, R, J extends DbJoinType, A> = Record<\n A & string,\n J extends '1:1' ? DbQuery<T, S, R> : DbQuery<T, S, R>[]\n>;\nexport type DbCreate<T> = Partial<T>;\nexport type DbUpdate<T> = {\n [K in keyof T]?: T[K] | UniDatabaseMutateCommand;\n};\nexport type DbOrder<T> = Record<keyof T, 'asc' | 'desc'>;\n\ntype _WhereFrom = 'where' | 'whereId';\n\nconst db0 = uniCloud.database();\n/**\n * 数据库操作符命令\n */\nexport const dbCmd = db0.command as unknown as UniDatabaseCommand;\n\n/**\n * 数据库聚合操作符命令\n */\nexport const dbAgg = db0.command.aggregate as UniCloud.AggregateCommand & {\n pipeline: () => UniCloud.AggregateReference & {\n done: () => unknown;\n };\n};\n\nexport type DbOptions = {\n /**\n * 数据表名称\n */\n table: string;\n\n /**\n * 事务对象,用于事务操作\n */\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n transaction?: any;\n\n /**\n * 模拟数据库,用于单元测试\n */\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n _mockDatabase?: any;\n};\n\n/**\n * 数据库关联类型\n * - '1:1': 一对一关联,返回值 1 个\n * - '1:n': 一对多关联,返回值 n 个\n * - 'n:1': 多对一关联,返回值 n 个\n */\nexport type DbJoinType = '1:1' | '1:n' | 'n:1';\nexport type DbLookupOptions<J extends DbJoinType, L, F, A> = {\n /**\n * 关联类型\n */\n type: J;\n\n /**\n * 主表字段\n */\n localField: keyof L & string;\n\n /**\n * 关联表字段\n */\n foreignField: keyof F & string;\n\n /**\n * 关联数据在结果中的字段名\n */\n as: A;\n};\n\nexport type DbLookup = {\n /**\n * 关联表\n */\n table: Db<unknown>;\n\n /**\n * 关联类型\n */\n type: DbJoinType;\n\n /**\n * 主表字段\n */\n localField: string;\n\n /**\n * 关联表字段\n */\n foreignField: string;\n\n /**\n * 关联表名称\n */\n from: string;\n\n /**\n * 关联数据在结果中的字段名\n */\n as: string;\n};\n\nlet gid = 0;\n\n// biome-ignore lint/complexity/noBannedTypes: <explanation>\nexport class Db<T, S extends DbSelect<T> = {}, R extends AnyObject = {}> {\n #host: UniCloud.CollectionReference;\n\n /**\n * 是否为事务环境\n * - 查询条件只能是 id\n * - 不能聚合操作\n */\n #isTransaction = false;\n\n #options: DbOptions;\n\n /**\n * 构造函数,初始化数据库集合引用\n * @param collection 数据表名称\n * @param _mockDatabase 模拟数据库,用于单元测试\n */\n constructor(options: DbOptions) {\n this.#options = options;\n this.#host =\n options._mockDatabase || options.transaction?.collection(options.table) || db0.collection(options.table);\n this.#isTransaction = !!options.transaction;\n }\n\n get table() {\n return this.#options.table;\n }\n\n /**\n * 获取聚合操作实例\n * @returns 聚合操作实例\n */\n aggregate() {\n return this.#host.aggregate();\n }\n\n #hasWhere: _WhereFrom | undefined = undefined;\n #hasWhereId: _WhereFrom | undefined = undefined;\n #where = {};\n\n #doWhere(where: DbWhere<T>, from: _WhereFrom) {\n if (this.#hasWhere) throw new Error(`已调用过一次 db.${_toWhereMethod(this.#hasWhere)} 了`);\n\n const whereKeys = Object.keys(where);\n // 只有 _id 值为字符串或数字时,才能调用 doc 方法\n const isWhereId = whereKeys.length === 1 && '_id' in where && (isString(where._id) || isNumber(where._id));\n\n if (isWhereId && this.#hasLimit) {\n throw new Error(`db.${_toWhereIdMethod(from)} 方法不能与 db.limit() 方法同时调用`);\n }\n\n this.#hasWhere = from;\n this.#where = where;\n if (isWhereId) this.#hasWhereId = from;\n\n return this;\n }\n\n /**\n * 设置查询条件\n * @param where 查询条件对象\n * @returns 当前Db实例,支持链式调用\n */\n where(where: DbWhere<T>) {\n return this.#doWhere(where, 'where');\n }\n\n /**\n * 根据ID设置查询条件\n * @param id 记录ID\n * @returns 当前Db实例,支持链式调用\n */\n whereId(id: string | number) {\n // @ts-ignore\n return this.#doWhere({ _id: id }, 'whereId');\n }\n\n #hasSelect = 0;\n #select = {};\n\n /**\n * 指定要返回的字段\n * @param fields 要返回的字段对象,true表示返回,false表示不返回\n * @returns 当前Db实例,支持链式调用\n */\n select<U extends DbSelect<T>>(fields: Exact<U, DbSelect<T>>) {\n if (this.#hasSelect) throw new Error('db.select() 方法只能调用一次');\n\n this.#hasSelect++;\n this.#select = fields;\n\n return this as Db<T, S & U, R>;\n }\n\n #hasOrder = 0;\n #order = {};\n\n /**\n * 设置排序规则\n * @param order 排序规则对象,key为字段名,value为\"asc\"或\"desc\"\n * @returns 当前Db实例,支持链式调用\n */\n order(order: DbOrder<T>) {\n this.#hasOrder++;\n this.#order = order;\n\n return this;\n }\n\n #hasSkip = 0;\n #skip = 0;\n\n /**\n * 跳过指定数量的记录\n * @param skip 要跳过的记录数\n * @returns 当前Db实例,支持链式调用\n */\n skip(skip: number) {\n if (this.#hasSkip) throw new Error('db.skip() 方法只能调用一次');\n\n this.#hasSkip++;\n this.#skip = skip;\n\n return this;\n }\n\n #hasLimit = 0;\n #limit = 0;\n\n /**\n * 限制返回的记录数量\n * @param limit 最大返回记录数\n * @returns 当前Db实例,支持链式调用\n */\n limit(limit: number) {\n if (this.#hasLimit) throw new Error('db.limit() 方法只能调用一次');\n\n if (this.#hasWhereId) {\n throw new Error(`db.limit() 方法不能与 ${_toWhereIdMethod(this.#hasWhereId)} 方法同时调用`);\n }\n\n this.#hasLimit++;\n this.#limit = limit;\n\n return this;\n }\n\n #hasLookup = 0;\n get hasLookup() {\n return this.#hasLookup > 0;\n }\n\n #lookups: DbLookup[] = [];\n lookup<FT, FS extends DbSelect<FT>, FR extends AnyObject, J extends DbJoinType, A extends string>(\n table: Db<FT, FS, FR>,\n lookup: DbLookupOptions<J, T, FT, A>,\n ) {\n // 对方表也记为关联查询,避免做表更新操作\n table.#hasLookup++;\n this.#hasLookup++;\n this.#lookups.push({\n ...lookup,\n table,\n from: table.table,\n });\n\n // 这里必须合并联合类型,否则类型结果会丢失最后一次 lookup\n // @ts-ignore\n return this as Db<T, S, MergeIntersection<R & DbForeign<FT, FS, FR, J, A>>>;\n }\n\n #aggregated = false;\n #endAggregate(aggRef: UniCloud.AggregateReference) {\n if (this.#aggregated) throw new Error(`相同的数据表实例(${this.table})不能重复使用`);\n\n this.#aggregated = true;\n let returnAggRef = aggRef;\n const projects: Record<string, true> = {};\n\n for (const { type, as, foreignField, from, localField, table } of this.#lookups) {\n const varName = `v${gid++}`;\n let pipeline = dbAgg.pipeline();\n\n // 关联条件\n // @ts-ignore\n pipeline = pipeline.match(\n dbCmd.expr(\n type === 'n:1'\n ? // @ts-ignore\n dbAgg.in([`$${foreignField}`, `$$${varName}`])\n : dbAgg.eq([`$${foreignField}`, `$$${varName}`]),\n ),\n );\n\n // 其他查询条件\n // @ts-ignore\n pipeline = table.#endAggregate(pipeline);\n\n // @ts-ignore\n pipeline = pipeline.done();\n\n returnAggRef = returnAggRef.lookup({\n let: {\n [varName]: `$${localField}`,\n },\n as,\n from,\n pipeline,\n });\n\n // 1对1,展开数组\n if (type === '1:1') {\n // @ts-ignore\n returnAggRef = returnAggRef.unwind({\n path: `$${as}`,\n preserveNullAndEmptyArrays: true,\n });\n }\n\n projects[as] = true;\n }\n\n // 主表查询\n if (this.#hasWhere) returnAggRef = returnAggRef.match(this.#where);\n if (this.#hasSelect) returnAggRef = returnAggRef.project({ ...this.#select, ...projects });\n if (this.#hasOrder) returnAggRef = returnAggRef.sort(objectMap(this.#order, (v) => (v === 'asc' ? 1 : -1)));\n if (this.#hasSkip) returnAggRef = returnAggRef.skip(this.#skip);\n if (this.#hasLimit) returnAggRef = returnAggRef.limit(this.#limit);\n\n return returnAggRef;\n }\n\n #endHost() {\n if (this.#hasWhere) {\n // @ts-ignore\n this.#host = this.#host.where(this.#where);\n }\n\n if (this.#hasSelect) {\n // @ts-ignore\n this.#host = this.#host.field(this.#select);\n }\n\n if (this.#hasOrder) {\n objectEach(this.#order, (val, key) => {\n // @ts-ignore\n this.#host = this.#host.orderBy(key, val);\n });\n }\n\n // @ts-ignore\n if (this.#hasSkip) this.#host = this.#host.skip(this.#skip);\n\n // @ts-ignore\n if (this.#hasLimit) this.#host = this.#host.limit(this.#limit);\n // @ts-ignore\n else if (this.#hasWhereId) this.#host = this.#host.limit(1);\n }\n\n /**\n * 执行查询操作\n * @returns 查询结果\n */\n async query() {\n let res: { data: DbQuery<T, S, R>[] };\n\n // 关联查询\n if (this.#hasLookup) {\n const aggRef = this.aggregate();\n this.#endAggregate(aggRef);\n res = await aggRef.end();\n }\n // 单表查询\n else {\n this.#endHost();\n res = await this.#host.get();\n }\n\n const rows = isArray(res.data) ? res.data : [res.data];\n const { data } = parseDatabaseOutput(res);\n return data;\n }\n\n /**\n * 只查询一条,自动添加 limit(1) 条件\n * @param ignoreMiss 是否忽略没有匹配到记录\n * @returns 查询结果\n */\n async queryOne(): Promise<DbQuery<T, S, R>>;\n async queryOne(ignoreMiss: false): Promise<DbQuery<T, S, R>>;\n async queryOne(ignoreMiss: true): Promise<DbQuery<T, S, R> | undefined>;\n async queryOne(ignoreMiss = false): Promise<DbQuery<T, S, R> | undefined> {\n if (this.#hasLimit) throw new Error('db.queryOne() 方法不支持 limit 条件');\n if (!this.#hasWhereId) this.limit(1);\n\n const data = await this.query();\n const res = data.at(0);\n\n if (!ignoreMiss && !res) throw new Error('未找到匹配记录');\n return res;\n }\n\n /**\n * 获取匹配记录的数量\n * @returns 记录总数\n */\n async count() {\n if (this.#hasLookup) throw new Error('db.count() 方法不支持 lookup 聚合');\n if (this.#hasSelect) throw new Error('db.count() 方法不支持 select 条件');\n if (this.#hasOrder) throw new Error('db.count() 方法不支持 order 条件');\n if (this.#hasSkip) throw new Error('db.count() 方法不支持 skip 条件');\n if (this.#hasLimit) throw new Error('db.count() 方法不支持 limit 条件');\n\n this.#endHost();\n const res = await this.#host.count();\n const { total } = parseDatabaseOutput<{ total: number }>(res);\n return total;\n }\n\n /**\n * 创建新记录\n * @param data 要创建的数据\n * @returns 创建结果\n */\n async create(data: DbCreate<T>) {\n if (this.#hasLookup) throw new Error('db.create() 方法不支持 lookup 聚合');\n if (this.#hasWhere) throw new Error('db.create() 方法不支持 where 条件');\n if (this.#hasSelect) throw new Error('db.create() 方法不支持 select 条件');\n if (this.#hasOrder) throw new Error('db.create() 方法不支持 order 条件');\n if (this.#hasSkip) throw new Error('db.create() 方法不支持 skip 条件');\n if (this.#hasLimit) throw new Error('db.create() 方法不支持 limit 条件');\n\n this.#endHost();\n const res = await this.#host.add(data);\n const { id } = parseDatabaseOutput<{ id: string }>(res);\n return id;\n }\n\n /**\n * 更新记录\n * @param data 要更新的数据\n * @returns 更新结果\n */\n async update(data: AnyObject) {\n if (this.#hasLookup) throw new Error('db.update() 方法不支持 lookup 聚合');\n if (!this.#hasWhere) throw new Error('设置 where 条件后才能执行 db.update() 方法');\n if (this.#hasSelect) throw new Error('db.update() 方法不支持 select 条件');\n if (this.#hasOrder) throw new Error('db.update() 方法不支持 order 条件');\n if (this.#hasSkip) throw new Error('db.update() 方法不支持 skip 条件');\n if (this.#hasLimit) throw new Error('db.update() 方法不支持 limit 条件');\n\n if (this.#isTransaction && !this.#hasWhereId) throw new Error('事务模式下 db.update() 的 where 条件必须是 _id');\n\n this.#endHost();\n const res = await this.#host.update(data);\n const { updated } = parseDatabaseOutput<{ updated: number }>(res);\n return updated;\n }\n\n /**\n * 删除记录\n * @returns 删除结果\n */\n async remove() {\n if (this.#hasLookup) throw new Error('db.remove() 方法不支持 lookup 聚合');\n if (!this.#hasWhere) throw new Error('设置 where 条件后才能执行 db.remove() 方法');\n if (this.#hasSelect) throw new Error('db.remove() 方法不支持 select 条件');\n if (this.#hasOrder) throw new Error('db.remove() 方法不支持 order 条件');\n if (this.#hasSkip) throw new Error('db.remove() 方法不支持 skip 条件');\n if (this.#hasLimit) throw new Error('db.remove() 方法不支持 limit 条件');\n\n if (this.#isTransaction && !this.#hasWhereId) throw new Error('事务模式下 db.remove() 的 where 条件必须是 _id');\n\n this.#endHost();\n const res = await this.#host.remove();\n const { deleted } = parseDatabaseOutput<{ deleted: number }>(res);\n return deleted;\n }\n}\n\n// biome-ignore lint/complexity/noBannedTypes: <explanation>\nexport type DbProxy<T, S extends DbSelect<T> = {}, R extends AnyObject = {}> = Db<T, S, R> & {\n _isProxy: true;\n};\n\n/**\n * 数据库操作对象\n */\nexport const db = {\n /**\n * 获取指定名称的数据库集合实例\n * @param name 数据表名称\n * @returns Db类实例,用于执行数据库操作\n */\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n table<T, S extends DbSelect<T> = {}, R extends AnyObject = {}>(name: string) {\n return new Proxy(\n {},\n {\n get(target, prop) {\n if (prop === '_isProxy') return true;\n\n const table = new Db<T, S, R>({ table: name });\n const tableProp = prop as keyof Db<T, S, R>;\n const ref = table[tableProp];\n\n return isFunction(ref) ? ref.bind(table) : ref;\n },\n },\n ) as DbProxy<T>;\n },\n};\n\n/**\n * 解析数据库执行结果\n * @param res 客户端、云端响应结果\n * @returns 处理后的结果\n */\nexport function parseDatabaseOutput<T>(res: UniClientDatabaseOutput<T> | UniCloudDatabaseOutput<T>) {\n const keys = Object.keys(res as AnyObject);\n // 客户端 { result: {errCode: 0, errMsg: 'ok'} & 数据 }\n const isClient = keys.length === 1 && keys[0] === 'result';\n\n if (isClient) {\n const { result } = res as UniClientDatabaseOutput<T>;\n if (!result.errCode) return objectOmit(result, ['errCode', 'errMsg', 'code', 'message']);\n throw errorAssign(new Error(result.errMsg), result);\n }\n\n // 云端 数据\n return res as T;\n}\n\nfunction _toWhereMethod(whereFrom: _WhereFrom) {\n return whereFrom === 'where' ? 'where({...})' : 'whereId(id)';\n}\n\nfunction _toWhereIdMethod(whereFrom: _WhereFrom) {\n return whereFrom === 'where' ? 'where({ _id })' : 'whereId(id)';\n}\n","import { tryFlatten } from '@cloudcome/utils-core/try';\nimport { isFunction } from '@cloudcome/utils-core/type';\nimport type { AnyObject, Exact, MaybeCallable } from '@cloudcome/utils-core/types';\nimport { Db, type DbCreate, type DbProxy, type DbQuery, type DbSelect, type DbUpdate, type DbWhere, db } from './db';\n\nexport type DbUpsertOptions<T, S extends DbSelect<T>, C extends DbCreate<T>, U extends DbUpdate<T>> = {\n /** 查询条件 */\n where: DbWhere<T>;\n\n /** 查询返回字段 */\n select?: Exact<S, DbSelect<T>>;\n\n /** 创建数据 */\n create: C;\n\n /**\n * 更新数据,可以是对象或根据查询结果生成更新对象的函数\n * @param row 查询到的文档数据,仅在传入函数时可用\n */\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n update: U | ((exist: DbQuery<T, S, {}>) => U);\n\n /** 创建前回调函数 */\n onBeforeCreate?: () => unknown;\n\n /**\n * 创建后回调函数\n * @param id 创建的文档ID\n */\n onAfterCreate?: (id: string) => unknown;\n\n /**\n * 更新前回调函数\n * @param exist 查询到的原始文档数据\n * @returns 如果返回 false,则取消更新操作\n */\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n onBeforeUpdate?: (exist: DbQuery<T, S, {}>) => false | unknown;\n\n /**\n * 更新后回调函数\n * @param updateData 实际更新的数据\n * @param exist 查询到的原始文档数据\n */\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n onAfterUpdate?: (updateData: U, exist: DbQuery<T, S, {}>) => unknown;\n\n /** 用于测试的模拟数据库实例 */\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n _mockDbInstance?: any;\n};\n\n/**\n * 数据库 upsert 操作的返回结果类型\n */\nexport type DbUpsertOutput = {\n /** 操作的文档ID */\n id: string;\n /** 是否为创建操作 */\n created: boolean;\n /** 是否为更新操作 */\n updated: boolean;\n};\n\nexport async function dbUpsert<T, S extends DbSelect<T>, C extends DbCreate<T>, U extends DbUpdate<T>>(\n dbProxy: DbProxy<T>,\n options: DbUpsertOptions<T, S, C, U>,\n): Promise<DbUpsertOutput> {\n const {\n where,\n select = {},\n create,\n update,\n onBeforeCreate,\n onAfterCreate,\n onBeforeUpdate,\n onAfterUpdate,\n _mockDbInstance,\n } = options;\n\n // @ts-ignore\n if ('_id' in select) throw new Error('select 条件不能包含 _id 字段');\n\n const _db = (_mockDbInstance || dbProxy) as DbProxy<T, S>;\n const exist = (await _db\n .where(where)\n .select(select || {})\n // biome-ignore lint/complexity/noBannedTypes: <explanation>\n .queryOne(true)) as DbQuery<T, S, {}> | undefined;\n\n if (exist) {\n const skipUpdate = (await onBeforeUpdate?.(exist)) === false;\n\n if (skipUpdate) {\n // @ts-ignore\n return { id: exist._id as string, updated: false, created: false };\n }\n\n const updateData = isFunction(update) ? update(exist) : update;\n // @ts-ignore\n const updated = await _db.whereId(exist._id).update(updateData);\n onAfterUpdate?.(updateData, exist);\n\n // @ts-ignore\n return { id: exist._id as string, updated: true, created: false };\n }\n\n await onBeforeCreate?.();\n const createdId = await _db.create(create);\n await onAfterCreate?.(createdId);\n\n return { id: createdId, updated: false, created: true };\n}\n\ntype _TransactionDb = {\n startTransaction: () => Promise<_Transaction>;\n};\n\ntype _Transaction = {\n commit: () => Promise<unknown>;\n rollback: () => Promise<unknown>;\n};\n\ntype _WithTransaction = <T, S extends DbSelect<T>, R extends AnyObject>(table: DbProxy<T, S, R>) => Db<T, S, R>;\n\n/**\n * 在数据库事务中执行操作\n *\n * @template T - 事务操作返回值类型\n * @param transacting - 事务执行函数,接收事务数据库实例作为参数\n * @param _mockDatabase - 用于测试的模拟数据库对象\n * @param _mockDbInstance - 用于测试的模拟数据库实例\n * @returns 事务操作的返回结果\n *\n * @example\n * ```typescript\n * const result = await dbTransaction(async (withTransaction) => {\n * const userId = await withTransaction(db.table('user')).create({ name: 'John' });\n * const order = await withTransaction(db.table('orders')).create({ userId, amount: 100 });\n * return { user, order };\n * });\n * ```\n */\nexport async function dbTransaction<K>(\n transacting: (withTransaction: _WithTransaction) => Promise<K>,\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n _mockDatabase?: any,\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n _mockDbInstance?: any,\n) {\n const transactionDb = (_mockDatabase || uniCloud.database()) as _TransactionDb;\n\n const [err1, transaction] = await tryFlatten(transactionDb.startTransaction());\n if (err1) throw err1;\n\n const withTransaction = <T, S extends DbSelect<T>, R extends AnyObject>(dbProxy: DbProxy<T, S, R>) => {\n return _mockDbInstance || new Db<T, S, R>({ table: dbProxy.table, transaction });\n };\n\n const [err2, result] = await tryFlatten(async () => {\n const result = await transacting(withTransaction);\n await transaction.commit();\n return result;\n });\n\n if (err2) {\n await tryFlatten(transaction.rollback());\n throw err2;\n }\n\n return result as unknown as K;\n}\n"],"names":["result"],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudcome/utils-uni",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.12.0",
|
|
4
4
|
"description": "cloudcome utils for uni-app",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22"
|
|
@@ -58,8 +58,8 @@
|
|
|
58
58
|
"dist"
|
|
59
59
|
],
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@cloudcome/utils-core": "~1.
|
|
62
|
-
"@cloudcome/utils-vue": "~1.9.
|
|
61
|
+
"@cloudcome/utils-core": "~1.11.0",
|
|
62
|
+
"@cloudcome/utils-vue": "~1.9.9",
|
|
63
63
|
"@dcloudio/types": "^3.4.21",
|
|
64
64
|
"@dcloudio/uni-app": "vue3",
|
|
65
65
|
"vue": "^3.5.13",
|