sa2kit 1.4.2 → 1.5.1
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/ConfigService-7MEZXKJ5.js +21 -0
- package/dist/ConfigService-7MEZXKJ5.js.map +1 -0
- package/dist/ConfigService-BV57YYFW.mjs +4 -0
- package/dist/ConfigService-BV57YYFW.mjs.map +1 -0
- package/dist/ConfigService-BxK06xP6.d.mts +262 -0
- package/dist/ConfigService-BxK06xP6.d.ts +262 -0
- package/dist/audioDetection/index.d.mts +449 -0
- package/dist/audioDetection/index.d.ts +449 -0
- package/dist/audioDetection/index.js +1244 -0
- package/dist/audioDetection/index.js.map +1 -0
- package/dist/audioDetection/index.mjs +1227 -0
- package/dist/audioDetection/index.mjs.map +1 -0
- package/dist/chunk-5XUE72Y3.mjs +1001 -0
- package/dist/chunk-5XUE72Y3.mjs.map +1 -0
- package/dist/chunk-DQVPZTVC.js +1009 -0
- package/dist/chunk-DQVPZTVC.js.map +1 -0
- package/dist/chunk-NEPD75MX.mjs +467 -0
- package/dist/chunk-NEPD75MX.mjs.map +1 -0
- package/dist/chunk-OEDY7GI4.js +473 -0
- package/dist/chunk-OEDY7GI4.js.map +1 -0
- package/dist/chunk-TFQF2HDO.mjs +354 -0
- package/dist/chunk-TFQF2HDO.mjs.map +1 -0
- package/dist/chunk-TOC5FSHP.js +358 -0
- package/dist/chunk-TOC5FSHP.js.map +1 -0
- package/dist/imageCrop/index.d.mts +165 -0
- package/dist/imageCrop/index.d.ts +165 -0
- package/dist/imageCrop/index.js +559 -0
- package/dist/imageCrop/index.js.map +1 -0
- package/dist/imageCrop/index.mjs +540 -0
- package/dist/imageCrop/index.mjs.map +1 -0
- package/dist/index.d.mts +139 -0
- package/dist/index.d.ts +139 -0
- package/dist/index.js +670 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +662 -0
- package/dist/index.mjs.map +1 -1
- package/dist/mmd/index.d.mts +113 -2
- package/dist/mmd/index.d.ts +113 -2
- package/dist/mmd/index.js +484 -2
- package/dist/mmd/index.js.map +1 -1
- package/dist/mmd/index.mjs +482 -4
- package/dist/mmd/index.mjs.map +1 -1
- package/dist/testYourself/admin/index.d.mts +58 -0
- package/dist/testYourself/admin/index.d.ts +58 -0
- package/dist/testYourself/admin/index.js +17 -0
- package/dist/testYourself/admin/index.js.map +1 -0
- package/dist/testYourself/admin/index.mjs +4 -0
- package/dist/testYourself/admin/index.mjs.map +1 -0
- package/dist/testYourself/index.d.mts +6 -98
- package/dist/testYourself/index.d.ts +6 -98
- package/dist/testYourself/index.js +90 -334
- package/dist/testYourself/index.js.map +1 -1
- package/dist/testYourself/index.mjs +47 -333
- package/dist/testYourself/index.mjs.map +1 -1
- package/dist/testYourself/server/index.d.mts +1029 -0
- package/dist/testYourself/server/index.d.ts +1029 -0
- package/dist/testYourself/server/index.js +42 -0
- package/dist/testYourself/server/index.js.map +1 -0
- package/dist/testYourself/server/index.mjs +5 -0
- package/dist/testYourself/server/index.mjs.map +1 -0
- package/dist/universalFile/server/index.js +5 -5
- package/dist/universalFile/server/index.mjs +1 -1
- package/package.json +62 -20
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
import { eq, sql, and, or, desc } from 'drizzle-orm';
|
|
2
|
+
import { pgTable, timestamp, varchar, json, uuid, integer, boolean, text, index } from 'drizzle-orm/pg-core';
|
|
3
|
+
|
|
4
|
+
// src/testYourself/server/DatabaseConfigAdapter.ts
|
|
5
|
+
var testYourselfConfigs = pgTable(
|
|
6
|
+
"test_yourself_configs",
|
|
7
|
+
{
|
|
8
|
+
// ========== 主键 ==========
|
|
9
|
+
/** 配置唯一ID */
|
|
10
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
11
|
+
// ========== 基本信息 ==========
|
|
12
|
+
/** 配置名称 */
|
|
13
|
+
name: varchar("name", { length: 255 }).notNull(),
|
|
14
|
+
/** 配置描述 */
|
|
15
|
+
description: text("description"),
|
|
16
|
+
/** 配置标签(用于分类和搜索) */
|
|
17
|
+
tags: json("tags").$type().default([]),
|
|
18
|
+
// ========== 配置数据 ==========
|
|
19
|
+
/** 测试配置内容(JSON格式) */
|
|
20
|
+
config: json("config").$type().notNull(),
|
|
21
|
+
/** 结果数量(冗余字段,便于查询) */
|
|
22
|
+
resultCount: integer("result_count").notNull().default(0),
|
|
23
|
+
// ========== 状态字段 ==========
|
|
24
|
+
/** 是否为默认配置 */
|
|
25
|
+
isDefault: boolean("is_default").notNull().default(false),
|
|
26
|
+
/** 是否已发布(草稿/发布) */
|
|
27
|
+
isPublished: boolean("is_published").notNull().default(true),
|
|
28
|
+
/** 是否已归档 */
|
|
29
|
+
isArchived: boolean("is_archived").notNull().default(false),
|
|
30
|
+
/** 是否已删除(软删除) */
|
|
31
|
+
isDeleted: boolean("is_deleted").notNull().default(false),
|
|
32
|
+
// ========== 权限和所有权 ==========
|
|
33
|
+
/** 创建者ID */
|
|
34
|
+
createdBy: varchar("created_by", { length: 255 }).notNull(),
|
|
35
|
+
/** 最后更新者ID */
|
|
36
|
+
updatedBy: varchar("updated_by", { length: 255 }),
|
|
37
|
+
/** 所属组织/租户ID(多租户支持) */
|
|
38
|
+
organizationId: varchar("organization_id", { length: 255 }),
|
|
39
|
+
// ========== 统计信息 ==========
|
|
40
|
+
/** 使用次数 */
|
|
41
|
+
usageCount: integer("usage_count").notNull().default(0),
|
|
42
|
+
/** 最后使用时间 */
|
|
43
|
+
lastUsedAt: timestamp("last_used_at"),
|
|
44
|
+
/** 浏览次数 */
|
|
45
|
+
viewCount: integer("view_count").notNull().default(0),
|
|
46
|
+
// ========== 版本控制 ==========
|
|
47
|
+
/** 配置版本号 */
|
|
48
|
+
version: integer("version").notNull().default(1),
|
|
49
|
+
/** 父配置ID(用于版本追踪) */
|
|
50
|
+
parentId: uuid("parent_id"),
|
|
51
|
+
// ========== 自定义字段 ==========
|
|
52
|
+
/** 自定义元数据(扩展字段) */
|
|
53
|
+
metadata: json("metadata").$type(),
|
|
54
|
+
/** 配置来源(web/api/import) */
|
|
55
|
+
source: varchar("source", { length: 50 }),
|
|
56
|
+
// ========== 时间戳 ==========
|
|
57
|
+
/** 创建时间 */
|
|
58
|
+
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
59
|
+
/** 更新时间 */
|
|
60
|
+
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
|
61
|
+
/** 发布时间 */
|
|
62
|
+
publishedAt: timestamp("published_at"),
|
|
63
|
+
/** 归档时间 */
|
|
64
|
+
archivedAt: timestamp("archived_at"),
|
|
65
|
+
/** 删除时间 */
|
|
66
|
+
deletedAt: timestamp("deleted_at")
|
|
67
|
+
},
|
|
68
|
+
(table) => ({
|
|
69
|
+
// ========== 索引设计 ==========
|
|
70
|
+
/** 名称搜索索引 */
|
|
71
|
+
nameIndex: index("test_configs_name_idx").on(table.name),
|
|
72
|
+
/** 创建者索引 */
|
|
73
|
+
createdByIndex: index("test_configs_created_by_idx").on(table.createdBy),
|
|
74
|
+
/** 组织索引(多租户) */
|
|
75
|
+
organizationIndex: index("test_configs_organization_idx").on(table.organizationId),
|
|
76
|
+
/** 默认配置索引 */
|
|
77
|
+
isDefaultIndex: index("test_configs_is_default_idx").on(table.isDefault),
|
|
78
|
+
/** 发布状态索引 */
|
|
79
|
+
isPublishedIndex: index("test_configs_is_published_idx").on(table.isPublished),
|
|
80
|
+
/** 删除状态索引 */
|
|
81
|
+
isDeletedIndex: index("test_configs_is_deleted_idx").on(table.isDeleted),
|
|
82
|
+
/** 创建时间索引 */
|
|
83
|
+
createdAtIndex: index("test_configs_created_at_idx").on(table.createdAt),
|
|
84
|
+
/** 最后使用时间索引 */
|
|
85
|
+
lastUsedAtIndex: index("test_configs_last_used_at_idx").on(table.lastUsedAt),
|
|
86
|
+
/** 组合索引:组织+删除状态+发布状态 */
|
|
87
|
+
orgDeletedPublishedIndex: index("test_configs_org_deleted_published_idx").on(
|
|
88
|
+
table.organizationId,
|
|
89
|
+
table.isDeleted,
|
|
90
|
+
table.isPublished
|
|
91
|
+
),
|
|
92
|
+
/** 组合索引:创建者+删除状态 */
|
|
93
|
+
createdByDeletedIndex: index("test_configs_created_by_deleted_idx").on(
|
|
94
|
+
table.createdBy,
|
|
95
|
+
table.isDeleted
|
|
96
|
+
)
|
|
97
|
+
})
|
|
98
|
+
);
|
|
99
|
+
var testYourselfConfigUsage = pgTable(
|
|
100
|
+
"test_yourself_config_usage",
|
|
101
|
+
{
|
|
102
|
+
/** 记录ID */
|
|
103
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
104
|
+
/** 配置ID */
|
|
105
|
+
configId: uuid("config_id").references(() => testYourselfConfigs.id, { onDelete: "cascade" }).notNull(),
|
|
106
|
+
/** 用户ID */
|
|
107
|
+
userId: varchar("user_id", { length: 255 }),
|
|
108
|
+
/** 设备指纹 */
|
|
109
|
+
fingerprint: text("fingerprint"),
|
|
110
|
+
/** 测试结果ID */
|
|
111
|
+
resultId: varchar("result_id", { length: 255 }),
|
|
112
|
+
/** IP地址 */
|
|
113
|
+
ipAddress: varchar("ip_address", { length: 45 }),
|
|
114
|
+
/** User Agent */
|
|
115
|
+
userAgent: text("user_agent"),
|
|
116
|
+
/** 来源页面 */
|
|
117
|
+
referer: text("referer"),
|
|
118
|
+
/** 使用时间 */
|
|
119
|
+
usedAt: timestamp("used_at").defaultNow().notNull(),
|
|
120
|
+
/** 完成时间(毫秒) */
|
|
121
|
+
completionTime: integer("completion_time"),
|
|
122
|
+
/** 额外数据 */
|
|
123
|
+
metadata: json("metadata").$type()
|
|
124
|
+
},
|
|
125
|
+
(table) => ({
|
|
126
|
+
/** 配置ID索引 */
|
|
127
|
+
configIndex: index("test_usage_config_idx").on(table.configId),
|
|
128
|
+
/** 用户ID索引 */
|
|
129
|
+
userIndex: index("test_usage_user_idx").on(table.userId),
|
|
130
|
+
/** 使用时间索引 */
|
|
131
|
+
usedAtIndex: index("test_usage_used_at_idx").on(table.usedAt),
|
|
132
|
+
/** 指纹索引 */
|
|
133
|
+
fingerprintIndex: index("test_usage_fingerprint_idx").on(table.fingerprint)
|
|
134
|
+
})
|
|
135
|
+
);
|
|
136
|
+
var testYourselfConfigShares = pgTable(
|
|
137
|
+
"test_yourself_config_shares",
|
|
138
|
+
{
|
|
139
|
+
/** 分享ID */
|
|
140
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
141
|
+
/** 分享代码(短链接标识) */
|
|
142
|
+
shareCode: varchar("share_code", { length: 20 }).notNull().unique(),
|
|
143
|
+
/** 配置ID */
|
|
144
|
+
configId: uuid("config_id").references(() => testYourselfConfigs.id, { onDelete: "cascade" }).notNull(),
|
|
145
|
+
/** 分享标题 */
|
|
146
|
+
title: varchar("title", { length: 255 }),
|
|
147
|
+
/** 分享描述 */
|
|
148
|
+
description: text("description"),
|
|
149
|
+
/** 访问密码 */
|
|
150
|
+
password: varchar("password", { length: 100 }),
|
|
151
|
+
/** 最大访问次数 */
|
|
152
|
+
maxAccess: integer("max_access"),
|
|
153
|
+
/** 当前访问次数 */
|
|
154
|
+
accessCount: integer("access_count").notNull().default(0),
|
|
155
|
+
/** 是否启用 */
|
|
156
|
+
isActive: boolean("is_active").notNull().default(true),
|
|
157
|
+
/** 过期时间 */
|
|
158
|
+
expiresAt: timestamp("expires_at"),
|
|
159
|
+
/** 创建者ID */
|
|
160
|
+
createdBy: varchar("created_by", { length: 255 }).notNull(),
|
|
161
|
+
/** 创建时间 */
|
|
162
|
+
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
163
|
+
/** 更新时间 */
|
|
164
|
+
updatedAt: timestamp("updated_at").defaultNow().notNull()
|
|
165
|
+
},
|
|
166
|
+
(table) => ({
|
|
167
|
+
/** 分享代码索引 */
|
|
168
|
+
shareCodeIndex: index("test_shares_share_code_idx").on(table.shareCode),
|
|
169
|
+
/** 配置ID索引 */
|
|
170
|
+
configIndex: index("test_shares_config_idx").on(table.configId),
|
|
171
|
+
/** 创建者索引 */
|
|
172
|
+
createdByIndex: index("test_shares_created_by_idx").on(table.createdBy),
|
|
173
|
+
/** 活跃状态索引 */
|
|
174
|
+
isActiveIndex: index("test_shares_is_active_idx").on(table.isActive)
|
|
175
|
+
})
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
// src/testYourself/server/DatabaseConfigAdapter.ts
|
|
179
|
+
var DatabaseConfigAdapter = class {
|
|
180
|
+
constructor(options) {
|
|
181
|
+
this.db = options.db;
|
|
182
|
+
this.userId = options.userId || "system";
|
|
183
|
+
this.organizationId = options.organizationId;
|
|
184
|
+
this.softDelete = options.softDelete !== false;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* 设置当前用户ID
|
|
188
|
+
*/
|
|
189
|
+
setUserId(userId) {
|
|
190
|
+
this.userId = userId;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* 设置组织ID
|
|
194
|
+
*/
|
|
195
|
+
setOrganizationId(organizationId) {
|
|
196
|
+
this.organizationId = organizationId;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* 将数据库记录转换为 SavedConfig
|
|
200
|
+
*/
|
|
201
|
+
toSavedConfig(dbConfig) {
|
|
202
|
+
return {
|
|
203
|
+
id: dbConfig.id,
|
|
204
|
+
name: dbConfig.name,
|
|
205
|
+
description: dbConfig.description || void 0,
|
|
206
|
+
config: dbConfig.config,
|
|
207
|
+
createdAt: dbConfig.createdAt.getTime(),
|
|
208
|
+
updatedAt: dbConfig.updatedAt.getTime(),
|
|
209
|
+
isDefault: dbConfig.isDefault
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* 保存配置
|
|
214
|
+
*/
|
|
215
|
+
async saveConfig(config) {
|
|
216
|
+
try {
|
|
217
|
+
const existing = await this.db.select().from(testYourselfConfigs).where(eq(testYourselfConfigs.id, config.id)).limit(1);
|
|
218
|
+
const resultCount = config.config.results?.length || 0;
|
|
219
|
+
if (existing && existing.length > 0) {
|
|
220
|
+
await this.db.update(testYourselfConfigs).set({
|
|
221
|
+
name: config.name,
|
|
222
|
+
description: config.description || null,
|
|
223
|
+
config: config.config,
|
|
224
|
+
resultCount,
|
|
225
|
+
isDefault: config.isDefault || false,
|
|
226
|
+
updatedBy: this.userId,
|
|
227
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
228
|
+
version: sql`${testYourselfConfigs.version} + 1`
|
|
229
|
+
// 版本号递增
|
|
230
|
+
}).where(eq(testYourselfConfigs.id, config.id));
|
|
231
|
+
console.log("\u2705 [DatabaseAdapter] \u914D\u7F6E\u5DF2\u66F4\u65B0:", config.id);
|
|
232
|
+
} else {
|
|
233
|
+
await this.db.insert(testYourselfConfigs).values({
|
|
234
|
+
id: config.id,
|
|
235
|
+
name: config.name,
|
|
236
|
+
description: config.description || null,
|
|
237
|
+
config: config.config,
|
|
238
|
+
resultCount,
|
|
239
|
+
isDefault: config.isDefault || false,
|
|
240
|
+
createdBy: this.userId,
|
|
241
|
+
organizationId: this.organizationId,
|
|
242
|
+
createdAt: new Date(config.createdAt),
|
|
243
|
+
updatedAt: new Date(config.updatedAt)
|
|
244
|
+
});
|
|
245
|
+
console.log("\u2705 [DatabaseAdapter] \u914D\u7F6E\u5DF2\u521B\u5EFA:", config.id);
|
|
246
|
+
}
|
|
247
|
+
} catch (error) {
|
|
248
|
+
console.error("\u274C [DatabaseAdapter] \u4FDD\u5B58\u914D\u7F6E\u5931\u8D25:", error);
|
|
249
|
+
throw error;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* 获取配置
|
|
254
|
+
*/
|
|
255
|
+
async getConfig(id) {
|
|
256
|
+
try {
|
|
257
|
+
const conditions = [eq(testYourselfConfigs.id, id)];
|
|
258
|
+
if (this.softDelete) {
|
|
259
|
+
conditions.push(eq(testYourselfConfigs.isDeleted, false));
|
|
260
|
+
}
|
|
261
|
+
const result = await this.db.select().from(testYourselfConfigs).where(and(...conditions)).limit(1);
|
|
262
|
+
if (!result || result.length === 0) {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
return this.toSavedConfig(result[0]);
|
|
266
|
+
} catch (error) {
|
|
267
|
+
console.error("\u274C [DatabaseAdapter] \u83B7\u53D6\u914D\u7F6E\u5931\u8D25:", error);
|
|
268
|
+
throw error;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* 获取所有配置列表
|
|
273
|
+
*/
|
|
274
|
+
async getAllConfigs() {
|
|
275
|
+
try {
|
|
276
|
+
const conditions = [];
|
|
277
|
+
if (this.softDelete) {
|
|
278
|
+
conditions.push(eq(testYourselfConfigs.isDeleted, false));
|
|
279
|
+
}
|
|
280
|
+
if (this.organizationId) {
|
|
281
|
+
conditions.push(
|
|
282
|
+
or(
|
|
283
|
+
eq(testYourselfConfigs.organizationId, this.organizationId),
|
|
284
|
+
sql`${testYourselfConfigs.organizationId} IS NULL`
|
|
285
|
+
// 包含全局配置
|
|
286
|
+
)
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
const result = await this.db.select().from(testYourselfConfigs).where(conditions.length > 0 ? and(...conditions) : void 0).orderBy(desc(testYourselfConfigs.createdAt));
|
|
290
|
+
return result.map((config) => this.toSavedConfig(config));
|
|
291
|
+
} catch (error) {
|
|
292
|
+
console.error("\u274C [DatabaseAdapter] \u83B7\u53D6\u914D\u7F6E\u5217\u8868\u5931\u8D25:", error);
|
|
293
|
+
throw error;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* 删除配置
|
|
298
|
+
*/
|
|
299
|
+
async deleteConfig(id) {
|
|
300
|
+
try {
|
|
301
|
+
if (this.softDelete) {
|
|
302
|
+
await this.db.update(testYourselfConfigs).set({
|
|
303
|
+
isDeleted: true,
|
|
304
|
+
deletedAt: /* @__PURE__ */ new Date(),
|
|
305
|
+
updatedBy: this.userId,
|
|
306
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
307
|
+
}).where(eq(testYourselfConfigs.id, id));
|
|
308
|
+
console.log("\u{1F5D1}\uFE0F [DatabaseAdapter] \u914D\u7F6E\u5DF2\u8F6F\u5220\u9664:", id);
|
|
309
|
+
} else {
|
|
310
|
+
await this.db.delete(testYourselfConfigs).where(eq(testYourselfConfigs.id, id));
|
|
311
|
+
console.log("\u{1F5D1}\uFE0F [DatabaseAdapter] \u914D\u7F6E\u5DF2\u786C\u5220\u9664:", id);
|
|
312
|
+
}
|
|
313
|
+
} catch (error) {
|
|
314
|
+
console.error("\u274C [DatabaseAdapter] \u5220\u9664\u914D\u7F6E\u5931\u8D25:", error);
|
|
315
|
+
throw error;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* 更新配置
|
|
320
|
+
*/
|
|
321
|
+
async updateConfig(id, config) {
|
|
322
|
+
try {
|
|
323
|
+
const resultCount = config.config.results?.length || 0;
|
|
324
|
+
await this.db.update(testYourselfConfigs).set({
|
|
325
|
+
name: config.name,
|
|
326
|
+
description: config.description || null,
|
|
327
|
+
config: config.config,
|
|
328
|
+
resultCount,
|
|
329
|
+
isDefault: config.isDefault || false,
|
|
330
|
+
updatedBy: this.userId,
|
|
331
|
+
updatedAt: new Date(config.updatedAt),
|
|
332
|
+
version: sql`${testYourselfConfigs.version} + 1`
|
|
333
|
+
}).where(eq(testYourselfConfigs.id, id));
|
|
334
|
+
console.log("\u2705 [DatabaseAdapter] \u914D\u7F6E\u5DF2\u66F4\u65B0:", id);
|
|
335
|
+
} catch (error) {
|
|
336
|
+
console.error("\u274C [DatabaseAdapter] \u66F4\u65B0\u914D\u7F6E\u5931\u8D25:", error);
|
|
337
|
+
throw error;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* 设置默认配置
|
|
342
|
+
*/
|
|
343
|
+
async setDefaultConfig(id) {
|
|
344
|
+
try {
|
|
345
|
+
await this.db.transaction(async (tx) => {
|
|
346
|
+
const conditions = [eq(testYourselfConfigs.isDefault, true)];
|
|
347
|
+
if (this.organizationId) {
|
|
348
|
+
conditions.push(
|
|
349
|
+
eq(testYourselfConfigs.organizationId, this.organizationId)
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
await tx.update(testYourselfConfigs).set({
|
|
353
|
+
isDefault: false,
|
|
354
|
+
updatedBy: this.userId,
|
|
355
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
356
|
+
}).where(and(...conditions));
|
|
357
|
+
await tx.update(testYourselfConfigs).set({
|
|
358
|
+
isDefault: true,
|
|
359
|
+
updatedBy: this.userId,
|
|
360
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
361
|
+
}).where(eq(testYourselfConfigs.id, id));
|
|
362
|
+
});
|
|
363
|
+
console.log("\u2705 [DatabaseAdapter] \u9ED8\u8BA4\u914D\u7F6E\u5DF2\u8BBE\u7F6E:", id);
|
|
364
|
+
} catch (error) {
|
|
365
|
+
console.error("\u274C [DatabaseAdapter] \u8BBE\u7F6E\u9ED8\u8BA4\u914D\u7F6E\u5931\u8D25:", error);
|
|
366
|
+
throw error;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* 获取默认配置
|
|
371
|
+
*/
|
|
372
|
+
async getDefaultConfig() {
|
|
373
|
+
try {
|
|
374
|
+
const conditions = [eq(testYourselfConfigs.isDefault, true)];
|
|
375
|
+
if (this.softDelete) {
|
|
376
|
+
conditions.push(eq(testYourselfConfigs.isDeleted, false));
|
|
377
|
+
}
|
|
378
|
+
if (this.organizationId) {
|
|
379
|
+
conditions.push(
|
|
380
|
+
eq(testYourselfConfigs.organizationId, this.organizationId)
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
const result = await this.db.select().from(testYourselfConfigs).where(and(...conditions)).limit(1);
|
|
384
|
+
if (!result || result.length === 0) {
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
return this.toSavedConfig(result[0]);
|
|
388
|
+
} catch (error) {
|
|
389
|
+
console.error("\u274C [DatabaseAdapter] \u83B7\u53D6\u9ED8\u8BA4\u914D\u7F6E\u5931\u8D25:", error);
|
|
390
|
+
throw error;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* 恢复已删除的配置(软删除时可用)
|
|
395
|
+
*/
|
|
396
|
+
async restoreConfig(id) {
|
|
397
|
+
if (!this.softDelete) {
|
|
398
|
+
throw new Error("\u6062\u590D\u529F\u80FD\u4EC5\u5728\u542F\u7528\u8F6F\u5220\u9664\u65F6\u53EF\u7528");
|
|
399
|
+
}
|
|
400
|
+
try {
|
|
401
|
+
await this.db.update(testYourselfConfigs).set({
|
|
402
|
+
isDeleted: false,
|
|
403
|
+
deletedAt: null,
|
|
404
|
+
updatedBy: this.userId,
|
|
405
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
406
|
+
}).where(eq(testYourselfConfigs.id, id));
|
|
407
|
+
console.log("\u267B\uFE0F [DatabaseAdapter] \u914D\u7F6E\u5DF2\u6062\u590D:", id);
|
|
408
|
+
} catch (error) {
|
|
409
|
+
console.error("\u274C [DatabaseAdapter] \u6062\u590D\u914D\u7F6E\u5931\u8D25:", error);
|
|
410
|
+
throw error;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* 归档配置
|
|
415
|
+
*/
|
|
416
|
+
async archiveConfig(id) {
|
|
417
|
+
try {
|
|
418
|
+
await this.db.update(testYourselfConfigs).set({
|
|
419
|
+
isArchived: true,
|
|
420
|
+
archivedAt: /* @__PURE__ */ new Date(),
|
|
421
|
+
updatedBy: this.userId,
|
|
422
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
423
|
+
}).where(eq(testYourselfConfigs.id, id));
|
|
424
|
+
console.log("\u{1F4E6} [DatabaseAdapter] \u914D\u7F6E\u5DF2\u5F52\u6863:", id);
|
|
425
|
+
} catch (error) {
|
|
426
|
+
console.error("\u274C [DatabaseAdapter] \u5F52\u6863\u914D\u7F6E\u5931\u8D25:", error);
|
|
427
|
+
throw error;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* 取消归档
|
|
432
|
+
*/
|
|
433
|
+
async unarchiveConfig(id) {
|
|
434
|
+
try {
|
|
435
|
+
await this.db.update(testYourselfConfigs).set({
|
|
436
|
+
isArchived: false,
|
|
437
|
+
archivedAt: null,
|
|
438
|
+
updatedBy: this.userId,
|
|
439
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
440
|
+
}).where(eq(testYourselfConfigs.id, id));
|
|
441
|
+
console.log("\u{1F4C2} [DatabaseAdapter] \u914D\u7F6E\u5DF2\u53D6\u6D88\u5F52\u6863:", id);
|
|
442
|
+
} catch (error) {
|
|
443
|
+
console.error("\u274C [DatabaseAdapter] \u53D6\u6D88\u5F52\u6863\u5931\u8D25:", error);
|
|
444
|
+
throw error;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* 记录使用次数
|
|
449
|
+
*/
|
|
450
|
+
async incrementUsageCount(id) {
|
|
451
|
+
try {
|
|
452
|
+
await this.db.update(testYourselfConfigs).set({
|
|
453
|
+
usageCount: sql`${testYourselfConfigs.usageCount} + 1`,
|
|
454
|
+
lastUsedAt: /* @__PURE__ */ new Date()
|
|
455
|
+
}).where(eq(testYourselfConfigs.id, id));
|
|
456
|
+
} catch (error) {
|
|
457
|
+
console.error("\u274C [DatabaseAdapter] \u66F4\u65B0\u4F7F\u7528\u6B21\u6570\u5931\u8D25:", error);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
function createDatabaseConfigAdapter(options) {
|
|
462
|
+
return new DatabaseConfigAdapter(options);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
export { DatabaseConfigAdapter, createDatabaseConfigAdapter, testYourselfConfigShares, testYourselfConfigUsage, testYourselfConfigs };
|
|
466
|
+
//# sourceMappingURL=chunk-NEPD75MX.mjs.map
|
|
467
|
+
//# sourceMappingURL=chunk-NEPD75MX.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/testYourself/server/drizzle-schema.ts","../src/testYourself/server/DatabaseConfigAdapter.ts"],"names":[],"mappings":"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","file":"chunk-NEPD75MX.mjs","sourcesContent":["/**\n * TestYourself 模块数据库表结构定义\n * Database Schema for TestYourself Module\n * \n * 使用 Drizzle ORM 定义配置表\n */\n\nimport {\n pgTable,\n uuid,\n varchar,\n text,\n timestamp,\n boolean,\n json,\n integer,\n index,\n} from 'drizzle-orm/pg-core';\nimport type { TestConfig } from '../types';\n\n/**\n * 测试配置表 (test_yourself_configs)\n * \n * 存储所有测试配置,支持多租户、版本控制等企业级功能\n */\nexport const testYourselfConfigs = pgTable(\n 'test_yourself_configs',\n {\n // ========== 主键 ==========\n /** 配置唯一ID */\n id: uuid('id').primaryKey().defaultRandom(),\n\n // ========== 基本信息 ==========\n /** 配置名称 */\n name: varchar('name', { length: 255 }).notNull(),\n \n /** 配置描述 */\n description: text('description'),\n \n /** 配置标签(用于分类和搜索) */\n tags: json('tags').$type<string[]>().default([]),\n\n // ========== 配置数据 ==========\n /** 测试配置内容(JSON格式) */\n config: json('config').$type<TestConfig>().notNull(),\n \n /** 结果数量(冗余字段,便于查询) */\n resultCount: integer('result_count').notNull().default(0),\n\n // ========== 状态字段 ==========\n /** 是否为默认配置 */\n isDefault: boolean('is_default').notNull().default(false),\n \n /** 是否已发布(草稿/发布) */\n isPublished: boolean('is_published').notNull().default(true),\n \n /** 是否已归档 */\n isArchived: boolean('is_archived').notNull().default(false),\n \n /** 是否已删除(软删除) */\n isDeleted: boolean('is_deleted').notNull().default(false),\n\n // ========== 权限和所有权 ==========\n /** 创建者ID */\n createdBy: varchar('created_by', { length: 255 }).notNull(),\n \n /** 最后更新者ID */\n updatedBy: varchar('updated_by', { length: 255 }),\n \n /** 所属组织/租户ID(多租户支持) */\n organizationId: varchar('organization_id', { length: 255 }),\n\n // ========== 统计信息 ==========\n /** 使用次数 */\n usageCount: integer('usage_count').notNull().default(0),\n \n /** 最后使用时间 */\n lastUsedAt: timestamp('last_used_at'),\n \n /** 浏览次数 */\n viewCount: integer('view_count').notNull().default(0),\n\n // ========== 版本控制 ==========\n /** 配置版本号 */\n version: integer('version').notNull().default(1),\n \n /** 父配置ID(用于版本追踪) */\n parentId: uuid('parent_id'),\n\n // ========== 自定义字段 ==========\n /** 自定义元数据(扩展字段) */\n metadata: json('metadata').$type<Record<string, any>>(),\n \n /** 配置来源(web/api/import) */\n source: varchar('source', { length: 50 }),\n\n // ========== 时间戳 ==========\n /** 创建时间 */\n createdAt: timestamp('created_at').defaultNow().notNull(),\n \n /** 更新时间 */\n updatedAt: timestamp('updated_at').defaultNow().notNull(),\n \n /** 发布时间 */\n publishedAt: timestamp('published_at'),\n \n /** 归档时间 */\n archivedAt: timestamp('archived_at'),\n \n /** 删除时间 */\n deletedAt: timestamp('deleted_at'),\n },\n (table) => ({\n // ========== 索引设计 ==========\n \n /** 名称搜索索引 */\n nameIndex: index('test_configs_name_idx').on(table.name),\n \n /** 创建者索引 */\n createdByIndex: index('test_configs_created_by_idx').on(table.createdBy),\n \n /** 组织索引(多租户) */\n organizationIndex: index('test_configs_organization_idx').on(table.organizationId),\n \n /** 默认配置索引 */\n isDefaultIndex: index('test_configs_is_default_idx').on(table.isDefault),\n \n /** 发布状态索引 */\n isPublishedIndex: index('test_configs_is_published_idx').on(table.isPublished),\n \n /** 删除状态索引 */\n isDeletedIndex: index('test_configs_is_deleted_idx').on(table.isDeleted),\n \n /** 创建时间索引 */\n createdAtIndex: index('test_configs_created_at_idx').on(table.createdAt),\n \n /** 最后使用时间索引 */\n lastUsedAtIndex: index('test_configs_last_used_at_idx').on(table.lastUsedAt),\n \n /** 组合索引:组织+删除状态+发布状态 */\n orgDeletedPublishedIndex: index('test_configs_org_deleted_published_idx').on(\n table.organizationId,\n table.isDeleted,\n table.isPublished\n ),\n \n /** 组合索引:创建者+删除状态 */\n createdByDeletedIndex: index('test_configs_created_by_deleted_idx').on(\n table.createdBy,\n table.isDeleted\n ),\n })\n);\n\n/**\n * 配置使用记录表 (test_yourself_config_usage)\n * \n * 记录配置的每次使用情况,用于统计分析\n */\nexport const testYourselfConfigUsage = pgTable(\n 'test_yourself_config_usage',\n {\n /** 记录ID */\n id: uuid('id').primaryKey().defaultRandom(),\n \n /** 配置ID */\n configId: uuid('config_id')\n .references(() => testYourselfConfigs.id, { onDelete: 'cascade' })\n .notNull(),\n \n /** 用户ID */\n userId: varchar('user_id', { length: 255 }),\n \n /** 设备指纹 */\n fingerprint: text('fingerprint'),\n \n /** 测试结果ID */\n resultId: varchar('result_id', { length: 255 }),\n \n /** IP地址 */\n ipAddress: varchar('ip_address', { length: 45 }),\n \n /** User Agent */\n userAgent: text('user_agent'),\n \n /** 来源页面 */\n referer: text('referer'),\n \n /** 使用时间 */\n usedAt: timestamp('used_at').defaultNow().notNull(),\n \n /** 完成时间(毫秒) */\n completionTime: integer('completion_time'),\n \n /** 额外数据 */\n metadata: json('metadata').$type<Record<string, any>>(),\n },\n (table) => ({\n /** 配置ID索引 */\n configIndex: index('test_usage_config_idx').on(table.configId),\n \n /** 用户ID索引 */\n userIndex: index('test_usage_user_idx').on(table.userId),\n \n /** 使用时间索引 */\n usedAtIndex: index('test_usage_used_at_idx').on(table.usedAt),\n \n /** 指纹索引 */\n fingerprintIndex: index('test_usage_fingerprint_idx').on(table.fingerprint),\n })\n);\n\n/**\n * 配置分享表 (test_yourself_config_shares)\n * \n * 管理配置的公开分享功能\n */\nexport const testYourselfConfigShares = pgTable(\n 'test_yourself_config_shares',\n {\n /** 分享ID */\n id: uuid('id').primaryKey().defaultRandom(),\n \n /** 分享代码(短链接标识) */\n shareCode: varchar('share_code', { length: 20 }).notNull().unique(),\n \n /** 配置ID */\n configId: uuid('config_id')\n .references(() => testYourselfConfigs.id, { onDelete: 'cascade' })\n .notNull(),\n \n /** 分享标题 */\n title: varchar('title', { length: 255 }),\n \n /** 分享描述 */\n description: text('description'),\n \n /** 访问密码 */\n password: varchar('password', { length: 100 }),\n \n /** 最大访问次数 */\n maxAccess: integer('max_access'),\n \n /** 当前访问次数 */\n accessCount: integer('access_count').notNull().default(0),\n \n /** 是否启用 */\n isActive: boolean('is_active').notNull().default(true),\n \n /** 过期时间 */\n expiresAt: timestamp('expires_at'),\n \n /** 创建者ID */\n createdBy: varchar('created_by', { length: 255 }).notNull(),\n \n /** 创建时间 */\n createdAt: timestamp('created_at').defaultNow().notNull(),\n \n /** 更新时间 */\n updatedAt: timestamp('updated_at').defaultNow().notNull(),\n },\n (table) => ({\n /** 分享代码索引 */\n shareCodeIndex: index('test_shares_share_code_idx').on(table.shareCode),\n \n /** 配置ID索引 */\n configIndex: index('test_shares_config_idx').on(table.configId),\n \n /** 创建者索引 */\n createdByIndex: index('test_shares_created_by_idx').on(table.createdBy),\n \n /** 活跃状态索引 */\n isActiveIndex: index('test_shares_is_active_idx').on(table.isActive),\n })\n);\n\n// ========== 类型导出 ==========\n\nexport type TestYourselfConfig = typeof testYourselfConfigs.$inferSelect;\nexport type NewTestYourselfConfig = typeof testYourselfConfigs.$inferInsert;\n\nexport type TestYourselfConfigUsage = typeof testYourselfConfigUsage.$inferSelect;\nexport type NewTestYourselfConfigUsage = typeof testYourselfConfigUsage.$inferInsert;\n\nexport type TestYourselfConfigShare = typeof testYourselfConfigShares.$inferSelect;\nexport type NewTestYourselfConfigShare = typeof testYourselfConfigShares.$inferInsert;\n","/**\n * TestYourself 数据库配置适配器\n * Database Configuration Adapter\n * \n * 实现基于数据库的配置存储\n */\n\nimport { eq, and, desc, sql, or } from 'drizzle-orm';\nimport type { IConfigStorage } from './ConfigService';\nimport type { SavedConfig } from '../types';\nimport { testYourselfConfigs } from './drizzle-schema';\nimport type { TestYourselfConfig } from './drizzle-schema';\n\n/**\n * Drizzle 数据库连接类型\n */\nexport type DrizzleDb = any;\n\n/**\n * 数据库适配器配置\n */\nexport interface DatabaseConfigAdapterOptions {\n /** Drizzle 数据库实例 */\n db: DrizzleDb;\n /** 当前用户ID(用于创建和更新) */\n userId?: string;\n /** 组织ID(多租户支持) */\n organizationId?: string;\n /** 是否启用软删除(默认 true) */\n softDelete?: boolean;\n}\n\n/**\n * 数据库配置适配器\n * \n * 实现 IConfigStorage 接口,将配置存储在数据库中\n */\nexport class DatabaseConfigAdapter implements IConfigStorage {\n private db: DrizzleDb;\n private userId: string;\n private organizationId?: string;\n private softDelete: boolean;\n\n constructor(options: DatabaseConfigAdapterOptions) {\n this.db = options.db;\n this.userId = options.userId || 'system';\n this.organizationId = options.organizationId;\n this.softDelete = options.softDelete !== false;\n }\n\n /**\n * 设置当前用户ID\n */\n setUserId(userId: string): void {\n this.userId = userId;\n }\n\n /**\n * 设置组织ID\n */\n setOrganizationId(organizationId: string): void {\n this.organizationId = organizationId;\n }\n\n /**\n * 将数据库记录转换为 SavedConfig\n */\n private toSavedConfig(dbConfig: TestYourselfConfig): SavedConfig {\n return {\n id: dbConfig.id,\n name: dbConfig.name,\n description: dbConfig.description || undefined,\n config: dbConfig.config,\n createdAt: dbConfig.createdAt.getTime(),\n updatedAt: dbConfig.updatedAt.getTime(),\n isDefault: dbConfig.isDefault,\n };\n }\n\n /**\n * 保存配置\n */\n async saveConfig(config: SavedConfig): Promise<void> {\n try {\n // 检查是否已存在\n const existing = await this.db\n .select()\n .from(testYourselfConfigs)\n .where(eq(testYourselfConfigs.id, config.id))\n .limit(1);\n\n const resultCount = config.config.results?.length || 0;\n\n if (existing && existing.length > 0) {\n // 更新现有配置\n await this.db\n .update(testYourselfConfigs)\n .set({\n name: config.name,\n description: config.description || null,\n config: config.config,\n resultCount,\n isDefault: config.isDefault || false,\n updatedBy: this.userId,\n updatedAt: new Date(),\n version: sql`${testYourselfConfigs.version} + 1`, // 版本号递增\n })\n .where(eq(testYourselfConfigs.id, config.id));\n\n console.log('✅ [DatabaseAdapter] 配置已更新:', config.id);\n } else {\n // 插入新配置\n await this.db.insert(testYourselfConfigs).values({\n id: config.id,\n name: config.name,\n description: config.description || null,\n config: config.config,\n resultCount,\n isDefault: config.isDefault || false,\n createdBy: this.userId,\n organizationId: this.organizationId,\n createdAt: new Date(config.createdAt),\n updatedAt: new Date(config.updatedAt),\n });\n\n console.log('✅ [DatabaseAdapter] 配置已创建:', config.id);\n }\n } catch (error) {\n console.error('❌ [DatabaseAdapter] 保存配置失败:', error);\n throw error;\n }\n }\n\n /**\n * 获取配置\n */\n async getConfig(id: string): Promise<SavedConfig | null> {\n try {\n const conditions = [eq(testYourselfConfigs.id, id)];\n\n // 如果启用软删除,过滤已删除的记录\n if (this.softDelete) {\n conditions.push(eq(testYourselfConfigs.isDeleted, false));\n }\n\n const result = await this.db\n .select()\n .from(testYourselfConfigs)\n .where(and(...conditions))\n .limit(1);\n\n if (!result || result.length === 0) {\n return null;\n }\n\n return this.toSavedConfig(result[0]);\n } catch (error) {\n console.error('❌ [DatabaseAdapter] 获取配置失败:', error);\n throw error;\n }\n }\n\n /**\n * 获取所有配置列表\n */\n async getAllConfigs(): Promise<SavedConfig[]> {\n try {\n const conditions = [];\n\n // 如果启用软删除,过滤已删除的记录\n if (this.softDelete) {\n conditions.push(eq(testYourselfConfigs.isDeleted, false));\n }\n\n // 如果设置了组织ID,只查询该组织的配置\n if (this.organizationId) {\n conditions.push(\n or(\n eq(testYourselfConfigs.organizationId, this.organizationId),\n sql`${testYourselfConfigs.organizationId} IS NULL` // 包含全局配置\n )\n );\n }\n\n const result = await this.db\n .select()\n .from(testYourselfConfigs)\n .where(conditions.length > 0 ? and(...conditions) : undefined)\n .orderBy(desc(testYourselfConfigs.createdAt));\n\n return result.map((config: TestYourselfConfig) => this.toSavedConfig(config));\n } catch (error) {\n console.error('❌ [DatabaseAdapter] 获取配置列表失败:', error);\n throw error;\n }\n }\n\n /**\n * 删除配置\n */\n async deleteConfig(id: string): Promise<void> {\n try {\n if (this.softDelete) {\n // 软删除\n await this.db\n .update(testYourselfConfigs)\n .set({\n isDeleted: true,\n deletedAt: new Date(),\n updatedBy: this.userId,\n updatedAt: new Date(),\n })\n .where(eq(testYourselfConfigs.id, id));\n\n console.log('🗑️ [DatabaseAdapter] 配置已软删除:', id);\n } else {\n // 硬删除\n await this.db\n .delete(testYourselfConfigs)\n .where(eq(testYourselfConfigs.id, id));\n\n console.log('🗑️ [DatabaseAdapter] 配置已硬删除:', id);\n }\n } catch (error) {\n console.error('❌ [DatabaseAdapter] 删除配置失败:', error);\n throw error;\n }\n }\n\n /**\n * 更新配置\n */\n async updateConfig(id: string, config: SavedConfig): Promise<void> {\n try {\n const resultCount = config.config.results?.length || 0;\n\n await this.db\n .update(testYourselfConfigs)\n .set({\n name: config.name,\n description: config.description || null,\n config: config.config,\n resultCount,\n isDefault: config.isDefault || false,\n updatedBy: this.userId,\n updatedAt: new Date(config.updatedAt),\n version: sql`${testYourselfConfigs.version} + 1`,\n })\n .where(eq(testYourselfConfigs.id, id));\n\n console.log('✅ [DatabaseAdapter] 配置已更新:', id);\n } catch (error) {\n console.error('❌ [DatabaseAdapter] 更新配置失败:', error);\n throw error;\n }\n }\n\n /**\n * 设置默认配置\n */\n async setDefaultConfig(id: string): Promise<void> {\n try {\n // 使用事务确保原子性\n await this.db.transaction(async (tx: any) => {\n // 1. 清除所有默认配置标记\n const conditions = [eq(testYourselfConfigs.isDefault, true)];\n \n if (this.organizationId) {\n conditions.push(\n eq(testYourselfConfigs.organizationId, this.organizationId)\n );\n }\n\n await tx\n .update(testYourselfConfigs)\n .set({\n isDefault: false,\n updatedBy: this.userId,\n updatedAt: new Date(),\n })\n .where(and(...conditions));\n\n // 2. 设置新的默认配置\n await tx\n .update(testYourselfConfigs)\n .set({\n isDefault: true,\n updatedBy: this.userId,\n updatedAt: new Date(),\n })\n .where(eq(testYourselfConfigs.id, id));\n });\n\n console.log('✅ [DatabaseAdapter] 默认配置已设置:', id);\n } catch (error) {\n console.error('❌ [DatabaseAdapter] 设置默认配置失败:', error);\n throw error;\n }\n }\n\n /**\n * 获取默认配置\n */\n async getDefaultConfig(): Promise<SavedConfig | null> {\n try {\n const conditions = [eq(testYourselfConfigs.isDefault, true)];\n\n // 如果启用软删除,过滤已删除的记录\n if (this.softDelete) {\n conditions.push(eq(testYourselfConfigs.isDeleted, false));\n }\n\n // 如果设置了组织ID,只查询该组织的配置\n if (this.organizationId) {\n conditions.push(\n eq(testYourselfConfigs.organizationId, this.organizationId)\n );\n }\n\n const result = await this.db\n .select()\n .from(testYourselfConfigs)\n .where(and(...conditions))\n .limit(1);\n\n if (!result || result.length === 0) {\n return null;\n }\n\n return this.toSavedConfig(result[0]);\n } catch (error) {\n console.error('❌ [DatabaseAdapter] 获取默认配置失败:', error);\n throw error;\n }\n }\n\n /**\n * 恢复已删除的配置(软删除时可用)\n */\n async restoreConfig(id: string): Promise<void> {\n if (!this.softDelete) {\n throw new Error('恢复功能仅在启用软删除时可用');\n }\n\n try {\n await this.db\n .update(testYourselfConfigs)\n .set({\n isDeleted: false,\n deletedAt: null,\n updatedBy: this.userId,\n updatedAt: new Date(),\n })\n .where(eq(testYourselfConfigs.id, id));\n\n console.log('♻️ [DatabaseAdapter] 配置已恢复:', id);\n } catch (error) {\n console.error('❌ [DatabaseAdapter] 恢复配置失败:', error);\n throw error;\n }\n }\n\n /**\n * 归档配置\n */\n async archiveConfig(id: string): Promise<void> {\n try {\n await this.db\n .update(testYourselfConfigs)\n .set({\n isArchived: true,\n archivedAt: new Date(),\n updatedBy: this.userId,\n updatedAt: new Date(),\n })\n .where(eq(testYourselfConfigs.id, id));\n\n console.log('📦 [DatabaseAdapter] 配置已归档:', id);\n } catch (error) {\n console.error('❌ [DatabaseAdapter] 归档配置失败:', error);\n throw error;\n }\n }\n\n /**\n * 取消归档\n */\n async unarchiveConfig(id: string): Promise<void> {\n try {\n await this.db\n .update(testYourselfConfigs)\n .set({\n isArchived: false,\n archivedAt: null,\n updatedBy: this.userId,\n updatedAt: new Date(),\n })\n .where(eq(testYourselfConfigs.id, id));\n\n console.log('📂 [DatabaseAdapter] 配置已取消归档:', id);\n } catch (error) {\n console.error('❌ [DatabaseAdapter] 取消归档失败:', error);\n throw error;\n }\n }\n\n /**\n * 记录使用次数\n */\n async incrementUsageCount(id: string): Promise<void> {\n try {\n await this.db\n .update(testYourselfConfigs)\n .set({\n usageCount: sql`${testYourselfConfigs.usageCount} + 1`,\n lastUsedAt: new Date(),\n })\n .where(eq(testYourselfConfigs.id, id));\n } catch (error) {\n console.error('❌ [DatabaseAdapter] 更新使用次数失败:', error);\n // 不抛出错误,避免影响主流程\n }\n }\n}\n\n/**\n * 创建数据库配置适配器\n * \n * @example\n * ```typescript\n * import { drizzle } from 'drizzle-orm/postgres-js';\n * import { createDatabaseConfigAdapter } from './DatabaseConfigAdapter';\n * \n * const db = drizzle(connection);\n * const adapter = createDatabaseConfigAdapter({\n * db,\n * userId: 'user-123',\n * organizationId: 'org-456',\n * });\n * \n * // 在 ConfigService 中使用\n * const configService = new ConfigService({\n * storageType: 'custom',\n * customStorage: adapter,\n * });\n * ```\n */\nexport function createDatabaseConfigAdapter(\n options: DatabaseConfigAdapterOptions\n): DatabaseConfigAdapter {\n return new DatabaseConfigAdapter(options);\n}\n"]}
|