mirror of
https://github.com/ZeroCatDev/ClassworksKV.git
synced 2025-07-01 20:09:23 +00:00
179 lines
4.2 KiB
JavaScript
179 lines
4.2 KiB
JavaScript
import { PrismaClient } from "@prisma/client";
|
||
const prisma = new PrismaClient();
|
||
class KVStore {
|
||
/**
|
||
* 通过命名空间和键名获取值
|
||
* @param {string} namespace - 命名空间
|
||
* @param {string} key - 键名
|
||
* @returns {object|null} 键对应的值或null
|
||
*/
|
||
async get(namespace, key) {
|
||
const item = await prisma.kVStore.findUnique({
|
||
where: {
|
||
namespace_key: {
|
||
namespace: namespace,
|
||
key: key,
|
||
},
|
||
},
|
||
});
|
||
return item ? item.value : null;
|
||
}
|
||
|
||
/**
|
||
* 获取键的完整信息(包括元数据)
|
||
* @param {string} namespace - 命名空间
|
||
* @param {string} key - 键名
|
||
* @returns {object|null} 键的完整信息或null
|
||
*/
|
||
async getMetadata(namespace, key) {
|
||
const item = await prisma.kVStore.findUnique({
|
||
where: {
|
||
namespace_key: {
|
||
namespace: namespace,
|
||
key: key,
|
||
},
|
||
},
|
||
select: {
|
||
key: true,
|
||
namespace: true,
|
||
creatorIp: true,
|
||
createdAt: true,
|
||
updatedAt: true,
|
||
},
|
||
});
|
||
|
||
if (!item) return null;
|
||
|
||
// 转换为更友好的格式
|
||
return {
|
||
namespace: item.namespace,
|
||
key: item.key,
|
||
metadata: {
|
||
creatorIp: item.creatorIp,
|
||
createdAt: item.createdAt,
|
||
updatedAt: item.updatedAt,
|
||
},
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 在指定命名空间下创建或更新键值
|
||
* @param {string} namespace - 命名空间
|
||
* @param {string} key - 键名
|
||
* @param {object} value - 键值
|
||
* @param {string} creatorIp - 创建者IP,可选
|
||
* @returns {object} 创建或更新的记录
|
||
*/
|
||
async upsert(namespace, key, value, creatorIp = "") {
|
||
const item = await prisma.kVStore.upsert({
|
||
where: {
|
||
namespace_key: {
|
||
namespace: namespace,
|
||
key: key,
|
||
},
|
||
},
|
||
update: {
|
||
value,
|
||
...(creatorIp && { creatorIp }),
|
||
},
|
||
create: {
|
||
namespace: namespace,
|
||
key: key,
|
||
value,
|
||
creatorIp,
|
||
},
|
||
});
|
||
|
||
// 返回带有命名空间和原始键的结果
|
||
return {
|
||
id: item.id,
|
||
namespace,
|
||
key,
|
||
value: item.value,
|
||
creatorIp: item.creatorIp,
|
||
createdAt: item.createdAt,
|
||
updatedAt: item.updatedAt,
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 通过命名空间和键名删除
|
||
* @param {string} namespace - 命名空间
|
||
* @param {string} key - 键名
|
||
* @returns {object|null} 删除的记录或null
|
||
*/
|
||
async delete(namespace, key) {
|
||
try {
|
||
const item = await prisma.kVStore.delete({
|
||
where: {
|
||
namespace_key: {
|
||
namespace: namespace,
|
||
key: key,
|
||
},
|
||
},
|
||
});
|
||
return item ? { ...item, namespace, key } : null;
|
||
} catch (error) {
|
||
// 忽略记录不存在的错误
|
||
if (error.code === "P2025") return null;
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 列出指定命名空间下的所有键名及其元数据
|
||
* @param {string} namespace - 命名空间
|
||
* @param {object} options - 选项参数
|
||
* @returns {Array} 键名和元数据数组
|
||
*/
|
||
async list(namespace, options = {}) {
|
||
const { sortBy = "key", sortDir = "asc", limit = 100, skip = 0 } = options;
|
||
|
||
// 构建排序条件
|
||
const orderBy = {};
|
||
orderBy[sortBy] = sortDir.toLowerCase();
|
||
|
||
// 查询以命名空间开头的所有键
|
||
const items = await prisma.kVStore.findMany({
|
||
where: {
|
||
namespace: namespace,
|
||
},
|
||
select: {
|
||
namespace: true,
|
||
key: true,
|
||
creatorIp: true,
|
||
createdAt: true,
|
||
updatedAt: true,
|
||
value: false,
|
||
},
|
||
orderBy,
|
||
take: limit,
|
||
skip: skip,
|
||
});
|
||
|
||
// 处理结果,从键名中移除命名空间前缀
|
||
return items.map((item) => ({
|
||
namespace: item.namespace,
|
||
key: item.key,
|
||
value: item.value,
|
||
metadata: item.metadata,
|
||
}));
|
||
}
|
||
|
||
/**
|
||
* 统计指定命名空间下的键值对数量
|
||
* @param {string} namespace - 命名空间
|
||
* @returns {number} 键值对数量
|
||
*/
|
||
async count(namespace) {
|
||
const count = await prisma.kVStore.count({
|
||
where: {
|
||
namespace: namespace,
|
||
},
|
||
});
|
||
return count;
|
||
}
|
||
}
|
||
|
||
export default new KVStore();
|