@anjianshi/utils 2.3.5 → 2.3.6
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/env-node/prisma/extensions/exist.d.ts +10 -0
- package/env-node/prisma/extensions/exist.js +16 -0
- package/env-node/prisma/extensions/find-and-count.d.ts +7 -0
- package/env-node/prisma/extensions/find-and-count.js +19 -0
- package/env-node/prisma/extensions/soft-delete.d.ts +52 -0
- package/env-node/prisma/extensions/soft-delete.js +121 -0
- package/env-node/prisma/extensions/with-transaction.d.ts +9 -0
- package/env-node/prisma/extensions/with-transaction.js +52 -0
- package/env-node/prisma/index.d.ts +5 -0
- package/env-node/prisma/index.js +5 -0
- package/env-node/prisma/transaction-contexted.d.ts +11 -0
- package/env-node/prisma/transaction-contexted.js +52 -0
- package/package.json +13 -11
- package/env-node/typeorm/adapt-logging.d.ts +0 -11
- package/env-node/typeorm/adapt-logging.js +0 -42
- package/env-node/typeorm/index.d.ts +0 -31
- package/env-node/typeorm/index.js +0 -39
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Prisma } from '@prisma/client';
|
|
2
|
+
/**
|
|
3
|
+
* 快速检查指定条件的数据是否存在
|
|
4
|
+
* const exists = await prisma.xxx.exists({ id: '1' })
|
|
5
|
+
*/
|
|
6
|
+
export declare const exists: (client: any) => import("@prisma/client").PrismaClientExtends<import("@prisma/client/runtime/library").InternalArgs<{}, {
|
|
7
|
+
$allModels: {
|
|
8
|
+
exists<T>(this: T, where: Prisma.Args<T, "count">["where"], withDeleted?: boolean): Promise<boolean>;
|
|
9
|
+
};
|
|
10
|
+
}, {}, {}>>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Prisma } from '@prisma/client';
|
|
2
|
+
/**
|
|
3
|
+
* 快速检查指定条件的数据是否存在
|
|
4
|
+
* const exists = await prisma.xxx.exists({ id: '1' })
|
|
5
|
+
*/
|
|
6
|
+
export const exists = Prisma.defineExtension({
|
|
7
|
+
name: 'exists',
|
|
8
|
+
model: {
|
|
9
|
+
$allModels: {
|
|
10
|
+
async exists(where, withDeleted = false) {
|
|
11
|
+
const context = Prisma.getExtensionContext(this);
|
|
12
|
+
return !!(await context.count({ where, withDeleted }));
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Prisma } from '@prisma/client';
|
|
2
|
+
import { type SoftDeleteQueryArgs } from './soft-delete.js';
|
|
3
|
+
export declare const findAndCount: (client: any) => import("@prisma/client").PrismaClientExtends<import("@prisma/client/runtime/library").InternalArgs<{}, {
|
|
4
|
+
$allModels: {
|
|
5
|
+
findAndCount<T, A>(this: T, rawArgs: Prisma.Exact<A, Prisma.Args<T, "findMany"> & SoftDeleteQueryArgs>): Promise<[Awaited<Prisma.Result<T, A, "findMany">>, Awaited<Prisma.Result<T, A, "count">>]>;
|
|
6
|
+
};
|
|
7
|
+
}, {}, {}>>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Prisma } from '@prisma/client';
|
|
2
|
+
export const findAndCount = Prisma.defineExtension({
|
|
3
|
+
name: 'findAndCount',
|
|
4
|
+
model: {
|
|
5
|
+
$allModels: {
|
|
6
|
+
findAndCount(rawArgs) {
|
|
7
|
+
const context = Prisma.getExtensionContext(this);
|
|
8
|
+
const args = rawArgs;
|
|
9
|
+
return Promise.all([
|
|
10
|
+
context.findMany(args),
|
|
11
|
+
context.count({
|
|
12
|
+
where: args.where,
|
|
13
|
+
withDeleted: args.withDeleted,
|
|
14
|
+
}),
|
|
15
|
+
]);
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 扩展 Prisma 实现软删除
|
|
3
|
+
*
|
|
4
|
+
* 1. 有 deleteTime 字段的 model 支持软删除。
|
|
5
|
+
* 2. 执行 delete() 和 deleteMany() 时默认是进行软删除;可指定 soft 为 false 来彻底删除;执行软删除时可指定要额外更新的 data。
|
|
6
|
+
* 2. 查询时会忽略被软删除的记录;可指定 withDeleted 为 true 来包含它们。
|
|
7
|
+
* 4. 可通过 restore() 和 restoreMany() 恢复软删除的记录。
|
|
8
|
+
*
|
|
9
|
+
* 扩展实现方式参考:
|
|
10
|
+
* https://www.prisma.io/docs/orm/prisma-client/client-extensions/type-utilities#add-a-custom-property-to-a-method
|
|
11
|
+
* https://www.npmjs.com/package/@prisma/extension-accelerate?activeTab=code => @prisma/extension-accelerate/dist/esm/extension.js
|
|
12
|
+
*
|
|
13
|
+
* 此扩展修改了 Prisma 的原生方法。
|
|
14
|
+
* 为保证其他扩展也应用到修改过的这些方法,此扩展应尽可能放在最前面。
|
|
15
|
+
*/
|
|
16
|
+
import { Prisma } from '@prisma/client';
|
|
17
|
+
import type { Operation } from '@prisma/client/runtime/library.js';
|
|
18
|
+
import { type OptionalFields } from '../../../index.js';
|
|
19
|
+
type DeleteArgs<T> = Prisma.Args<T, 'delete'> & {
|
|
20
|
+
soft?: boolean;
|
|
21
|
+
data?: Prisma.Args<T, 'update'>['data'];
|
|
22
|
+
};
|
|
23
|
+
type DeleteReturn<T, A> = Promise<Prisma.Result<T, A, 'delete'>>;
|
|
24
|
+
type DeleteManyArgs<T> = Prisma.Args<T, 'deleteMany'> & {
|
|
25
|
+
soft?: boolean;
|
|
26
|
+
data?: Prisma.Args<T, 'updateMany'>['data'];
|
|
27
|
+
};
|
|
28
|
+
type DeleteManyReturn<T, A> = Promise<Prisma.Result<T, A, 'deleteMany'>>;
|
|
29
|
+
type RestoreArgs<T> = OptionalFields<Prisma.Args<T, 'update'>, 'data'>;
|
|
30
|
+
type RestoreManyArgs<T> = OptionalFields<Prisma.Args<T, 'updateMany'>, 'data'>;
|
|
31
|
+
interface QueryExtraArgs {
|
|
32
|
+
withDeleted?: boolean;
|
|
33
|
+
}
|
|
34
|
+
export type { QueryExtraArgs as SoftDeleteQueryArgs };
|
|
35
|
+
type QueryInputArgs<T, A, K extends Operation> = Prisma.Exact<A, Prisma.Args<T, K> & QueryExtraArgs>;
|
|
36
|
+
export declare const softDelete: (client: any) => import("@prisma/client").PrismaClientExtends<import("@prisma/client/runtime/library").InternalArgs<{}, {
|
|
37
|
+
$allModels: {
|
|
38
|
+
withSoftDeleteExtension: boolean;
|
|
39
|
+
delete<T, A>(this: T, rawArgs: Prisma.Exact<A, DeleteArgs<T>>): DeleteReturn<T, A>;
|
|
40
|
+
deleteMany<T, A>(this: T, rawArgs: Prisma.Exact<A, DeleteManyArgs<T>>): DeleteManyReturn<T, A>;
|
|
41
|
+
restore<T, A>(this: T, rawArgs: Prisma.Exact<A, RestoreArgs<T>>): Promise<Prisma.Result<T, A, "update">>;
|
|
42
|
+
restoreMany<T, A>(this: T, rawArgs: Prisma.Exact<A, RestoreManyArgs<T>>): Promise<Prisma.Result<T, A, "updateMany">>;
|
|
43
|
+
aggregate<T, A>(this: T, inputArgs: QueryInputArgs<T, A, "aggregate">): Promise<Prisma.Result<T, A, "aggregate">>;
|
|
44
|
+
count<T, A>(this: T, inputArgs: QueryInputArgs<T, A, "count">): Promise<Prisma.Result<T, A, "count">>;
|
|
45
|
+
findFirst<T, A>(this: T, inputArgs: QueryInputArgs<T, A, "findFirst">): Promise<Prisma.Result<T, A, "findFirst">>;
|
|
46
|
+
findFirstOrThrow<T, A>(this: T, inputArgs: QueryInputArgs<T, A, "findFirstOrThrow">): Promise<Prisma.Result<T, A, "findFirstOrThrow">>;
|
|
47
|
+
findMany<T, A>(this: T, inputArgs: QueryInputArgs<T, A, "findMany">): Promise<Prisma.Result<T, A, "findMany">>;
|
|
48
|
+
findUnique<T, A>(this: T, inputArgs: QueryInputArgs<T, A, "findUnique">): Promise<Prisma.Result<T, A, "findUnique">>;
|
|
49
|
+
findUniqueOrThrow<T, A>(this: T, inputArgs: QueryInputArgs<T, A, "findUniqueOrThrow">): Promise<Prisma.Result<T, A, "findUniqueOrThrow">>;
|
|
50
|
+
groupBy<T, A>(this: T, inputArgs: QueryInputArgs<T, A, "groupBy">): Promise<Prisma.Result<T, A, "groupBy">>;
|
|
51
|
+
};
|
|
52
|
+
}, {}, {}>>;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 扩展 Prisma 实现软删除
|
|
3
|
+
*
|
|
4
|
+
* 1. 有 deleteTime 字段的 model 支持软删除。
|
|
5
|
+
* 2. 执行 delete() 和 deleteMany() 时默认是进行软删除;可指定 soft 为 false 来彻底删除;执行软删除时可指定要额外更新的 data。
|
|
6
|
+
* 2. 查询时会忽略被软删除的记录;可指定 withDeleted 为 true 来包含它们。
|
|
7
|
+
* 4. 可通过 restore() 和 restoreMany() 恢复软删除的记录。
|
|
8
|
+
*
|
|
9
|
+
* 扩展实现方式参考:
|
|
10
|
+
* https://www.prisma.io/docs/orm/prisma-client/client-extensions/type-utilities#add-a-custom-property-to-a-method
|
|
11
|
+
* https://www.npmjs.com/package/@prisma/extension-accelerate?activeTab=code => @prisma/extension-accelerate/dist/esm/extension.js
|
|
12
|
+
*
|
|
13
|
+
* 此扩展修改了 Prisma 的原生方法。
|
|
14
|
+
* 为保证其他扩展也应用到修改过的这些方法,此扩展应尽可能放在最前面。
|
|
15
|
+
*/
|
|
16
|
+
import { Prisma } from '@prisma/client';
|
|
17
|
+
function getModel(that) {
|
|
18
|
+
const context = Prisma.getExtensionContext(that);
|
|
19
|
+
// 1. 此扩展修改了 Prisma 原生的方法,所以要通过 context.$parent[context.$name] 获取上一层的 model,不然会自己调用自己导致死循环。
|
|
20
|
+
// 2. 如果此扩展后面还应用了其他扩展,那么仅仅一层 $parent 取得的 model 还是这个扩展修改过的版本而不是原生的。
|
|
21
|
+
// 此时需要递归向上,直到取得未经此扩展修改过的 model。不然此扩展的业务逻辑会被重复执行,
|
|
22
|
+
// 而因为第一次执行时已经把定制参数消解掉了,第二次执行时会误以为没有传入定制参数,最终导致定制参数失效。
|
|
23
|
+
let model = context;
|
|
24
|
+
do {
|
|
25
|
+
model = model.$parent[context.$name];
|
|
26
|
+
} while ('withSoftDeleteExtension' in model);
|
|
27
|
+
const supportSoftDelete = 'deleteTime' in model.fields;
|
|
28
|
+
return { model, supportSoftDelete };
|
|
29
|
+
}
|
|
30
|
+
function query(that, inputArgs, method) {
|
|
31
|
+
const { model, supportSoftDelete } = getModel(that);
|
|
32
|
+
const { withDeleted = false, ...args } = inputArgs;
|
|
33
|
+
return model[method]({
|
|
34
|
+
...args,
|
|
35
|
+
where: !supportSoftDelete || withDeleted ? args.where : { ...args.where, deleteTime: null },
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
export const softDelete = Prisma.defineExtension({
|
|
39
|
+
name: 'softDeleted',
|
|
40
|
+
model: {
|
|
41
|
+
$allModels: {
|
|
42
|
+
withSoftDeleteExtension: true,
|
|
43
|
+
// -----------------------------
|
|
44
|
+
// 操作
|
|
45
|
+
// -----------------------------
|
|
46
|
+
delete(rawArgs) {
|
|
47
|
+
const { model, supportSoftDelete } = getModel(this);
|
|
48
|
+
const { soft = true, data, ...args } = rawArgs;
|
|
49
|
+
if (supportSoftDelete && soft) {
|
|
50
|
+
return model.update({
|
|
51
|
+
...args, // .delete() 的参数 .update() 也都支持
|
|
52
|
+
data: { ...(data ?? {}), deleteTime: new Date() },
|
|
53
|
+
}); // .update() 的返回值和 .delete() 一样
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
return model.delete(args);
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
deleteMany(rawArgs) {
|
|
60
|
+
const { model, supportSoftDelete } = getModel(this);
|
|
61
|
+
const { soft = true, data, ...args } = rawArgs;
|
|
62
|
+
if (supportSoftDelete && soft) {
|
|
63
|
+
return model.updateMany({
|
|
64
|
+
...args, // .deleteMany() 的参数 .updateMany() 也都支持
|
|
65
|
+
data: { ...(data ?? {}), deleteTime: new Date() },
|
|
66
|
+
}); // .updateMany() 的返回值和 .deleteMany() 一样
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
return model.deleteMany(args);
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
restore(rawArgs) {
|
|
73
|
+
const { data, ...args } = rawArgs;
|
|
74
|
+
const { model, supportSoftDelete } = getModel(this);
|
|
75
|
+
if (!supportSoftDelete)
|
|
76
|
+
throw new Error('当前模型不支持软删除,不能执行恢复');
|
|
77
|
+
return model.update({
|
|
78
|
+
...args,
|
|
79
|
+
data: { ...(data ?? {}), deleteTime: null },
|
|
80
|
+
});
|
|
81
|
+
},
|
|
82
|
+
restoreMany(rawArgs) {
|
|
83
|
+
const { data, ...args } = rawArgs;
|
|
84
|
+
const { model, supportSoftDelete } = getModel(this);
|
|
85
|
+
if (!supportSoftDelete)
|
|
86
|
+
throw new Error('当前模型不支持软删除,不能执行恢复');
|
|
87
|
+
return model.updateMany({
|
|
88
|
+
...args,
|
|
89
|
+
data: { ...(data ?? {}), deleteTime: new Date() },
|
|
90
|
+
});
|
|
91
|
+
},
|
|
92
|
+
// -----------------------------
|
|
93
|
+
// 查询
|
|
94
|
+
// -----------------------------
|
|
95
|
+
aggregate(inputArgs) {
|
|
96
|
+
return query(this, inputArgs, 'aggregate');
|
|
97
|
+
},
|
|
98
|
+
count(inputArgs) {
|
|
99
|
+
return query(this, inputArgs, 'count');
|
|
100
|
+
},
|
|
101
|
+
findFirst(inputArgs) {
|
|
102
|
+
return query(this, inputArgs, 'findFirst');
|
|
103
|
+
},
|
|
104
|
+
findFirstOrThrow(inputArgs) {
|
|
105
|
+
return query(this, inputArgs, 'findFirstOrThrow');
|
|
106
|
+
},
|
|
107
|
+
findMany(inputArgs) {
|
|
108
|
+
return query(this, inputArgs, 'findMany');
|
|
109
|
+
},
|
|
110
|
+
findUnique(inputArgs) {
|
|
111
|
+
return query(this, inputArgs, 'findUnique');
|
|
112
|
+
},
|
|
113
|
+
findUniqueOrThrow(inputArgs) {
|
|
114
|
+
return query(this, inputArgs, 'findUniqueOrThrow');
|
|
115
|
+
},
|
|
116
|
+
groupBy(inputArgs) {
|
|
117
|
+
return query(this, inputArgs, 'groupBy');
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ITXClientDenyList } from '@prisma/client/runtime/library.js';
|
|
2
|
+
import type { MaySuccess } from '../../../index.js';
|
|
3
|
+
export declare const withTransaction: (client: any) => import("@prisma/client").PrismaClientExtends<import("@prisma/client/runtime/library").InternalArgs<{}, {}, {}, {
|
|
4
|
+
$withTransaction: typeof $withTransaction;
|
|
5
|
+
}>>;
|
|
6
|
+
export type GetPrismaClientInTransaction<PrismaClient> = Omit<PrismaClient, ITXClientDenyList>;
|
|
7
|
+
export type WithTransactionMethod = typeof $withTransaction;
|
|
8
|
+
declare function $withTransaction<That extends object, R extends MaySuccess<unknown, unknown>>(this: That, callback: (dbInTransaction: GetPrismaClientInTransaction<That>) => Promise<R>): Promise<R>;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 在事务中执行回调。与 $transaction 有几点不同:
|
|
3
|
+
* 1. 回调必须返回 MaySuccess 值
|
|
4
|
+
* 2. 回调返回 Failed 值或抛出异常都会触发回滚。
|
|
5
|
+
* 如果是返回 Failed,会作为此方法的返回值;如果是抛出异常,则异常会继续向上传递,直到被捕获或触发请求失败。
|
|
6
|
+
* 3. 如果已经处于事务中,会沿用上层事务,且回调返回 Failed 或抛出异常会触发上层事务的回滚。
|
|
7
|
+
*
|
|
8
|
+
* const result: MaySuccess = await db.$withTransaction(
|
|
9
|
+
* async (dbInTransaction) => {
|
|
10
|
+
* // do something
|
|
11
|
+
* return success()
|
|
12
|
+
* }
|
|
13
|
+
* )
|
|
14
|
+
*/
|
|
15
|
+
import { Prisma } from '@prisma/client';
|
|
16
|
+
export const withTransaction = Prisma.defineExtension({
|
|
17
|
+
name: 'withTransaction',
|
|
18
|
+
client: {
|
|
19
|
+
$withTransaction,
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
class FailedInTransaction extends Error {
|
|
23
|
+
failed;
|
|
24
|
+
constructor(failed) {
|
|
25
|
+
super(failed.message);
|
|
26
|
+
this.failed = failed;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async function $withTransaction(callback) {
|
|
30
|
+
const executeCallback = async (dbInTransaction) => {
|
|
31
|
+
const result = await callback(dbInTransaction);
|
|
32
|
+
if (result.success)
|
|
33
|
+
return result;
|
|
34
|
+
else
|
|
35
|
+
throw new FailedInTransaction(result);
|
|
36
|
+
};
|
|
37
|
+
if ('$transaction' in this && this.$transaction) {
|
|
38
|
+
// 如果当前不在事务中,开启新事务并执行回调
|
|
39
|
+
try {
|
|
40
|
+
return await this.$transaction(async (dbInTransaction) => executeCallback(dbInTransaction));
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
if (e instanceof FailedInTransaction)
|
|
44
|
+
return e.failed;
|
|
45
|
+
throw e;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// 已经在事务中,直接执行回调(如果有异常,上层开启事务的代码会捕获)
|
|
50
|
+
return executeCallback(this);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { WithTransactionMethod } from './extensions/with-transaction.js';
|
|
2
|
+
/**
|
|
3
|
+
* 返回一个可以在事务内和事务外通用的 PrismaClient 代理对象。
|
|
4
|
+
* 当前在事务内时,调用它是调用事务内的 client;当前不在事务内时,调用它是调用全局 client。
|
|
5
|
+
* 这样当一个事务涉及多个函数调用时,就不用把事务内 client 传递来传递去了。
|
|
6
|
+
* 注意:应给每个线性流程(例如一个请求)单独生成一个此对象,不能作为全局对象使用,不然可能出现事务冲突。
|
|
7
|
+
*/
|
|
8
|
+
export declare function getTransactionContextedPrismaClient<AppPrismaClient extends {
|
|
9
|
+
$transaction: (...args: unknown[]) => Promise<unknown>;
|
|
10
|
+
$withTransaction: WithTransactionMethod;
|
|
11
|
+
}>(prisma: AppPrismaClient): AppPrismaClient;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 返回一个可以在事务内和事务外通用的 PrismaClient 代理对象。
|
|
3
|
+
* 当前在事务内时,调用它是调用事务内的 client;当前不在事务内时,调用它是调用全局 client。
|
|
4
|
+
* 这样当一个事务涉及多个函数调用时,就不用把事务内 client 传递来传递去了。
|
|
5
|
+
* 注意:应给每个线性流程(例如一个请求)单独生成一个此对象,不能作为全局对象使用,不然可能出现事务冲突。
|
|
6
|
+
*/
|
|
7
|
+
export function getTransactionContextedPrismaClient(prisma) {
|
|
8
|
+
let client = prisma;
|
|
9
|
+
async function callCallbackInTransaction(callback, clientInTransaction) {
|
|
10
|
+
const prevClient = client;
|
|
11
|
+
const currentClient = clientInTransaction;
|
|
12
|
+
client = currentClient;
|
|
13
|
+
function restoreClient() {
|
|
14
|
+
if (client !== currentClient)
|
|
15
|
+
throw new Error('事务冲突,必须等一个事务结束后再开启另一个事务');
|
|
16
|
+
client = prevClient;
|
|
17
|
+
}
|
|
18
|
+
try {
|
|
19
|
+
const res = await callback(client);
|
|
20
|
+
restoreClient();
|
|
21
|
+
return res;
|
|
22
|
+
}
|
|
23
|
+
catch (e) {
|
|
24
|
+
restoreClient();
|
|
25
|
+
throw e;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function $transaction(arg, ...restArgs) {
|
|
29
|
+
if (typeof arg === 'function') {
|
|
30
|
+
const wrappedCallback = callCallbackInTransaction.bind(null, arg);
|
|
31
|
+
return client.$transaction(wrappedCallback, ...restArgs);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
return client.$transaction(arg, ...restArgs);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async function $withTransaction(callback) {
|
|
38
|
+
return client.$withTransaction(async (clientInTransaction) => callCallbackInTransaction(callback, clientInTransaction));
|
|
39
|
+
}
|
|
40
|
+
return new Proxy({}, {
|
|
41
|
+
has(_, prop) {
|
|
42
|
+
return prop in client;
|
|
43
|
+
},
|
|
44
|
+
get(_, prop) {
|
|
45
|
+
if (prop === '$transaction')
|
|
46
|
+
return $transaction;
|
|
47
|
+
if (prop === '$withTransaction')
|
|
48
|
+
return $withTransaction;
|
|
49
|
+
return client[prop];
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anjianshi/utils",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.6",
|
|
4
4
|
"description": "Common JavaScript Utils",
|
|
5
5
|
"homepage": "https://github.com/anjianshi/js-packages/utils",
|
|
6
6
|
"bugs": {
|
|
@@ -24,43 +24,45 @@
|
|
|
24
24
|
"@types/node": "^20.16.2",
|
|
25
25
|
"@types/react": "^18.3.5",
|
|
26
26
|
"dotenv": "^16.4.5",
|
|
27
|
-
"typeorm": "^0.3.20",
|
|
28
27
|
"typescript": "^5.5.4",
|
|
29
28
|
"vconsole": "^3.15.1",
|
|
30
|
-
"@anjianshi/presets-
|
|
29
|
+
"@anjianshi/presets-prettier": "3.0.1",
|
|
31
30
|
"@anjianshi/presets-eslint-typescript": "5.0.5",
|
|
32
|
-
"@anjianshi/presets-eslint-
|
|
31
|
+
"@anjianshi/presets-eslint-node": "4.0.8",
|
|
33
32
|
"@anjianshi/presets-typescript": "3.2.2",
|
|
34
|
-
"@anjianshi/presets-
|
|
33
|
+
"@anjianshi/presets-eslint-react": "4.0.7"
|
|
35
34
|
},
|
|
36
35
|
"peerDependencies": {
|
|
37
36
|
"@emotion/react": "^11.13.3",
|
|
38
37
|
"@emotion/serialize": "^1.3.1",
|
|
39
38
|
"@emotion/utils": "^1.4.0",
|
|
39
|
+
"@prisma/client": "^5.20.0",
|
|
40
40
|
"chalk": "^5.3.0",
|
|
41
41
|
"dayjs": "^1.11.10",
|
|
42
42
|
"react": "^18.3.1"
|
|
43
43
|
},
|
|
44
44
|
"peerDependenciesMeta": {
|
|
45
|
-
"
|
|
45
|
+
"@emotion/react": {
|
|
46
46
|
"optional": true
|
|
47
47
|
},
|
|
48
|
-
"
|
|
48
|
+
"@emotion/serialize": {
|
|
49
49
|
"optional": true
|
|
50
50
|
},
|
|
51
|
-
"@emotion/
|
|
51
|
+
"@emotion/utils": {
|
|
52
52
|
"optional": true
|
|
53
53
|
},
|
|
54
|
-
"@
|
|
54
|
+
"@prisma/client": {
|
|
55
55
|
"optional": true
|
|
56
56
|
},
|
|
57
|
-
"
|
|
57
|
+
"chalk": {
|
|
58
|
+
"optional": true
|
|
59
|
+
},
|
|
60
|
+
"dayjs": {
|
|
58
61
|
"optional": true
|
|
59
62
|
},
|
|
60
63
|
"react": {
|
|
61
64
|
"optional": true
|
|
62
65
|
}
|
|
63
66
|
},
|
|
64
|
-
"eslintIgnore": [],
|
|
65
67
|
"prettier": "@anjianshi/presets-prettier/prettierrc"
|
|
66
68
|
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { AbstractLogger, type LogLevel as TypeORMLogLevel, type LogMessage, type LoggerOptions } from 'typeorm';
|
|
2
|
-
import { type Logger as UtilsLogger } from '../logging/index.js';
|
|
3
|
-
/**
|
|
4
|
-
* 把 TypeORM 的日志导入到 js-utils 的 logger 中
|
|
5
|
-
* 用法参考 https://typeorm.io/logging
|
|
6
|
-
*/
|
|
7
|
-
export declare class AdaptedTypeORMLogger extends AbstractLogger {
|
|
8
|
-
readonly utilsLogger: UtilsLogger;
|
|
9
|
-
constructor(utilsLogger: UtilsLogger, options?: LoggerOptions);
|
|
10
|
-
protected writeLog(typeORMLevel: TypeORMLogLevel, logMessage: LogMessage | LogMessage[]): void;
|
|
11
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { AbstractLogger, } from 'typeorm';
|
|
2
|
-
/**
|
|
3
|
-
* 把 TypeORM 的日志导入到 js-utils 的 logger 中
|
|
4
|
-
* 用法参考 https://typeorm.io/logging
|
|
5
|
-
*/
|
|
6
|
-
export class AdaptedTypeORMLogger extends AbstractLogger {
|
|
7
|
-
utilsLogger;
|
|
8
|
-
constructor(utilsLogger, options) {
|
|
9
|
-
super(options);
|
|
10
|
-
this.utilsLogger = utilsLogger;
|
|
11
|
-
}
|
|
12
|
-
writeLog(typeORMLevel, logMessage) {
|
|
13
|
-
const messages = this.prepareLogMessages(logMessage, {
|
|
14
|
-
highlightSql: true,
|
|
15
|
-
});
|
|
16
|
-
for (const message of messages) {
|
|
17
|
-
const args = message.prefix ?? '' ? [message.prefix, message.message] : [message.message];
|
|
18
|
-
switch (message.type ?? typeORMLevel) {
|
|
19
|
-
case 'log':
|
|
20
|
-
case 'schema':
|
|
21
|
-
case 'schema-build':
|
|
22
|
-
case 'migration':
|
|
23
|
-
this.utilsLogger.debug(...args);
|
|
24
|
-
break;
|
|
25
|
-
case 'info':
|
|
26
|
-
case 'query':
|
|
27
|
-
this.utilsLogger.info(...args);
|
|
28
|
-
break;
|
|
29
|
-
case 'warn':
|
|
30
|
-
case 'query-slow':
|
|
31
|
-
this.utilsLogger.warn(...args);
|
|
32
|
-
break;
|
|
33
|
-
case 'error':
|
|
34
|
-
case 'query-error':
|
|
35
|
-
this.utilsLogger.error(...args);
|
|
36
|
-
break;
|
|
37
|
-
default:
|
|
38
|
-
this.utilsLogger.debug(...args);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TypeORM 相关工具函数
|
|
3
|
-
*/
|
|
4
|
-
import { type FindOptionsWhere, type BaseEntity } from 'typeorm';
|
|
5
|
-
import { type ExcluceMethods } from '../../lang/index.js';
|
|
6
|
-
export * from './adapt-logging.js';
|
|
7
|
-
/**
|
|
8
|
-
* 返回 Entity 对应的纯数据类型
|
|
9
|
-
*/
|
|
10
|
-
export type DataOnly<T extends BaseEntity> = Omit<ExcluceMethods<T>, 'hasId'>;
|
|
11
|
-
/**
|
|
12
|
-
* 转义字符串以安全地进行 SQL LIKE 匹配
|
|
13
|
-
*/
|
|
14
|
-
export declare function escapeLikeString(raw: string, escapeChar?: string): string;
|
|
15
|
-
/**
|
|
16
|
-
* 返回 instances 里没有出现的 id
|
|
17
|
-
*/
|
|
18
|
-
export declare function getNotExistIds<T extends {
|
|
19
|
-
id: string;
|
|
20
|
-
}>(instances: T[], ids: string[]): string[];
|
|
21
|
-
/**
|
|
22
|
-
* TypeORM 的 find({ where: {} }) 里不支持 AND 和 OR 并列使用
|
|
23
|
-
* 例如:is_disabled IS NULL AND (name LIKE '%ab%' OR nickname LIKE '%ab%')
|
|
24
|
-
* 只能蹩脚地写成 `where: [{ name: LIKE('xx'), is_disabled: xx }, { nickname: LIKE('xx'), is_disabled: xx }]`
|
|
25
|
-
*
|
|
26
|
-
* 此函数简化了这一转换步骤,使得可以逻辑直观地并列书写 AND 和 OR。
|
|
27
|
-
* 在 `where: {}` 里,`or_` 开头且值是数组的项被组织为一个 OR,其 key 会被忽略,内容转换为上面的形式。
|
|
28
|
-
*/
|
|
29
|
-
declare function smartWhere<Entity>(where: FindOptionsWhere<Entity>): FindOptionsWhere<Entity>;
|
|
30
|
-
declare function smartWhere<Entity>(where: FindOptionsWhere<Entity>[]): FindOptionsWhere<Entity>[];
|
|
31
|
-
export { smartWhere };
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
export * from './adapt-logging.js';
|
|
2
|
-
/**
|
|
3
|
-
* 转义字符串以安全地进行 SQL LIKE 匹配
|
|
4
|
-
*/
|
|
5
|
-
export function escapeLikeString(raw, escapeChar = '\\') {
|
|
6
|
-
return raw.replace(/[\\%_]/g, match => escapeChar + match);
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* 返回 instances 里没有出现的 id
|
|
10
|
-
*/
|
|
11
|
-
export function getNotExistIds(instances, ids) {
|
|
12
|
-
return ids.filter(id => !instances.find(inst => inst.id === id));
|
|
13
|
-
}
|
|
14
|
-
function smartWhere(where) {
|
|
15
|
-
if (Array.isArray(where))
|
|
16
|
-
return where.map(item => smartWhere(item));
|
|
17
|
-
const orPrefix = 'or_';
|
|
18
|
-
const orContent = {};
|
|
19
|
-
const andContent = {};
|
|
20
|
-
for (const [key, value] of Object.entries(where)) {
|
|
21
|
-
if (value === undefined)
|
|
22
|
-
continue;
|
|
23
|
-
if (key.startsWith(orPrefix) && Array.isArray(value)) {
|
|
24
|
-
orContent[key] = value;
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
;
|
|
28
|
-
andContent[key] = value;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
const nextWhere = { ...where };
|
|
32
|
-
const currentOr = Object.entries(nextWhere).find(([key, value]) => key.startsWith(orPrefix) && Array.isArray(value));
|
|
33
|
-
if (currentOr === undefined)
|
|
34
|
-
return nextWhere;
|
|
35
|
-
delete nextWhere[currentOr[0]];
|
|
36
|
-
const result = currentOr[1].map(subWhere => ({ ...subWhere, ...smartWhere(nextWhere) }));
|
|
37
|
-
return result;
|
|
38
|
-
}
|
|
39
|
-
export { smartWhere };
|