You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

168 lines
4.5 KiB

import { dbGlobal } from "drizzle-pkg/lib/db";
import { appConfigs, userConfigs } from "drizzle-pkg/lib/schema/config";
import { and, eq } from "drizzle-orm";
import {
canUserOverride,
deserializeConfigValue,
getConfigDefaultValue,
getConfigDefinition,
getConfigScope,
isKnownConfigKey,
KnownConfigKey,
KnownConfigValue,
serializeConfigValue,
validateConfigValue,
} from "./registry";
export class ConfigKeyNotFoundError extends Error {
code = "CONFIG_KEY_NOT_FOUND";
constructor(key: string) {
super(`配置项不存在: ${key}`);
this.name = "ConfigKeyNotFoundError";
}
}
export class ConfigScopeInvalidError extends Error {
code = "CONFIG_SCOPE_INVALID";
constructor(message: string) {
super(message);
this.name = "ConfigScopeInvalidError";
}
}
export class ConfigValueInvalidError extends Error {
code = "CONFIG_VALUE_INVALID";
constructor(message: string) {
super(message);
this.name = "ConfigValueInvalidError";
}
}
function assertKnownKey(key: string): asserts key is KnownConfigKey {
if (!isKnownConfigKey(key)) {
throw new ConfigKeyNotFoundError(key);
}
}
export function ensureKnownConfigKey(key: string): KnownConfigKey {
assertKnownKey(key);
return key;
}
export async function getGlobalConfigValue<K extends KnownConfigKey>(key: K): Promise<KnownConfigValue<K>> {
const [row] = await dbGlobal
.select({
value: appConfigs.value,
})
.from(appConfigs)
.where(eq(appConfigs.key, key))
.limit(1);
if (!row) {
return getConfigDefaultValue(key);
}
return deserializeConfigValue(key, row.value);
}
export async function getUserConfigValue<K extends KnownConfigKey>(
userId: number | undefined,
key: K,
): Promise<KnownConfigValue<K> | undefined> {
if (!userId) {
return undefined;
}
const [row] = await dbGlobal
.select({
value: userConfigs.value,
})
.from(userConfigs)
.where(and(eq(userConfigs.userId, userId), eq(userConfigs.key, key)))
.limit(1);
if (!row) {
return undefined;
}
return deserializeConfigValue(key, row.value);
}
export async function getMergedConfigValue<K extends KnownConfigKey>(
userId: number | undefined,
key: K,
): Promise<KnownConfigValue<K>> {
const scope = getConfigScope(key);
if (scope === "global") {
return getGlobalConfigValue(key);
}
if (scope === "user") {
return (await getUserConfigValue(userId, key)) ?? getConfigDefaultValue(key);
}
const userValue = await getUserConfigValue(userId, key);
if (userValue !== undefined) {
return userValue;
}
return getGlobalConfigValue(key);
}
export async function setGlobalConfigValue<K extends KnownConfigKey>(key: K, value: unknown) {
const scope = getConfigScope(key);
if (scope === "user") {
throw new ConfigScopeInvalidError(`配置项 ${key} 不支持全局写入`);
}
if (key === "siteName" && typeof value === "string") {
value = value.trim();
}
if (!validateConfigValue(key, value)) {
throw new ConfigValueInvalidError(`配置项 ${key} 的值不合法`);
}
await dbGlobal
.insert(appConfigs)
.values({
key,
value: serializeConfigValue(key, value),
valueType: getConfigDefinition(key).valueType,
})
.onConflictDoUpdate({
target: appConfigs.key,
set: {
value: serializeConfigValue(key, value),
valueType: getConfigDefinition(key).valueType,
},
});
}
export async function setCurrentUserConfigValue<K extends KnownConfigKey>(userId: number, key: K, value: unknown) {
const scope = getConfigScope(key);
if (scope === "global" || !canUserOverride(key)) {
throw new ConfigScopeInvalidError(`配置项 ${key} 不允许用户覆盖`);
}
if (!validateConfigValue(key, value)) {
throw new ConfigValueInvalidError(`配置项 ${key} 的值不合法`);
}
await dbGlobal
.insert(userConfigs)
.values({
userId,
key,
value: serializeConfigValue(key, value),
valueType: getConfigDefinition(key).valueType,
})
.onConflictDoUpdate({
target: [userConfigs.userId, userConfigs.key],
set: {
value: serializeConfigValue(key, value),
valueType: getConfigDefinition(key).valueType,
},
});
}
export async function resetCurrentUserConfigValue(userId: number, key: KnownConfigKey) {
const scope = getConfigScope(key);
if (scope === "global" || !canUserOverride(key)) {
throw new ConfigScopeInvalidError(`配置项 ${key} 不允许用户重置`);
}
await dbGlobal
.delete(userConfigs)
.where(and(eq(userConfigs.userId, userId), eq(userConfigs.key, key)));
}