/* eslint-disable @typescript-eslint/no-explicit-any */ import { Redis } from '@upstash/redis'; import { RedisClientType } from 'redis'; /** * 统一的 Redis 适配器接口 * 只抽象 API 命名差异,不处理序列化(由调用者负责) */ export interface RedisAdapter { // Hash 操作 hSet(key: string, field: string, value: string): Promise; hSet(key: string, data: Record): Promise; hGet(key: string, field: string): Promise; hGetAll(key: string): Promise>; hDel(key: string, ...fields: string[]): Promise; // String 操作 set(key: string, value: string): Promise; get(key: string): Promise; del(keys: string | string[]): Promise; exists(...keys: string[]): Promise; keys(pattern: string): Promise; mGet(keys: string[]): Promise<(string | null)[]>; // List 操作 lPush(key: string, ...values: string[]): Promise; lRange(key: string, start: number, stop: number): Promise; lRem(key: string, count: number, value: string): Promise; lTrim(key: string, start: number, stop: number): Promise; // Set 操作 sAdd(key: string, ...members: string[]): Promise; sMembers(key: string): Promise; sRem(key: string, ...members: string[]): Promise; // Sorted Set 操作 zAdd(key: string, member: { score: number; value: string }): Promise; zRange(key: string, start: number, stop: number): Promise; zCard(key: string): Promise; zRem(key: string, ...members: string[]): Promise; } /** * 标准 Redis 客户端适配器(用于 Redis 和 Kvrocks) * 只处理 API 命名,不处理序列化 */ export class StandardRedisAdapter implements RedisAdapter { constructor(private client: RedisClientType) {} // Hash 操作 async hSet(key: string, fieldOrData: string | Record, value?: string): Promise { if (typeof fieldOrData === 'string') { return this.client.hSet(key, fieldOrData, value!); } else { return this.client.hSet(key, fieldOrData); } } async hGet(key: string, field: string): Promise { const val = await this.client.hGet(key, field); return val ?? null; } async hGetAll(key: string): Promise> { return this.client.hGetAll(key); } async hDel(key: string, ...fields: string[]): Promise { return this.client.hDel(key, fields); } // String 操作 async set(key: string, value: string): Promise { await this.client.set(key, value); } async get(key: string): Promise { return this.client.get(key); } async del(keys: string | string[]): Promise { const keyArray = Array.isArray(keys) ? keys : [keys]; if (keyArray.length === 0) return 0; return this.client.del(keyArray); } async exists(...keys: string[]): Promise { return this.client.exists(keys); } async keys(pattern: string): Promise { return this.client.keys(pattern); } async mGet(keys: string[]): Promise<(string | null)[]> { return this.client.mGet(keys); } // List 操作 async lPush(key: string, ...values: string[]): Promise { return this.client.lPush(key, values); } async lRange(key: string, start: number, stop: number): Promise { return this.client.lRange(key, start, stop); } async lRem(key: string, count: number, value: string): Promise { return this.client.lRem(key, count, value); } async lTrim(key: string, start: number, stop: number): Promise { await this.client.lTrim(key, start, stop); } // Set 操作 async sAdd(key: string, ...members: string[]): Promise { return this.client.sAdd(key, members); } async sMembers(key: string): Promise { return Array.from(await this.client.sMembers(key)); } async sRem(key: string, ...members: string[]): Promise { return this.client.sRem(key, members); } // Sorted Set 操作 async zAdd(key: string, member: { score: number; value: string }): Promise { return this.client.zAdd(key, member); } async zRange(key: string, start: number, stop: number): Promise { return this.client.zRange(key, start, stop); } async zCard(key: string): Promise { return this.client.zCard(key); } async zRem(key: string, ...members: string[]): Promise { return this.client.zRem(key, members); } } /** * Upstash Redis 客户端适配器(用于 Upstash REST API) * 处理 API 命名差异和 Upstash 的自动序列化 */ export class UpstashRedisAdapter implements RedisAdapter { constructor(private client: Redis) {} // Hash 操作 async hSet(key: string, fieldOrData: string | Record, value?: string): Promise { if (typeof fieldOrData === 'string') { // Upstash 会自动序列化,但我们传入的已经是字符串,所以直接存储 return this.client.hset(key, { [fieldOrData]: value! }); } else { return this.client.hset(key, fieldOrData); } } async hGet(key: string, field: string): Promise { const val = await this.client.hget(key, field); if (val === null || val === undefined) return null; // Upstash 可能返回对象、字符串或其他类型 // 需要统一转换为字符串 if (typeof val === 'string') return val; if (typeof val === 'object') return JSON.stringify(val); return String(val); } async hGetAll(key: string): Promise> { const hashData = await this.client.hgetall(key); if (!hashData) return {}; // 确保所有值都是字符串 const result: Record = {}; for (const [k, v] of Object.entries(hashData)) { if (typeof v === 'string') { result[k] = v; } else if (typeof v === 'object') { result[k] = JSON.stringify(v); } else { result[k] = String(v); } } return result; } async hDel(key: string, ...fields: string[]): Promise { return this.client.hdel(key, ...fields); } // String 操作 async set(key: string, value: string): Promise { await this.client.set(key, value); } async get(key: string): Promise { const val = await this.client.get(key); if (val === null || val === undefined) return null; // Upstash 可能返回对象、字符串或其他类型 if (typeof val === 'string') return val; if (typeof val === 'object') return JSON.stringify(val); return String(val); } async del(keys: string | string[]): Promise { const keyArray = Array.isArray(keys) ? keys : [keys]; if (keyArray.length === 0) return 0; return this.client.del(...keyArray); } async exists(...keys: string[]): Promise { return this.client.exists(...keys); } async keys(pattern: string): Promise { return this.client.keys(pattern); } async mGet(keys: string[]): Promise<(string | null)[]> { const values = await this.client.mget(...keys); return values.map(v => { if (v === null || v === undefined) return null; if (typeof v === 'string') return v; if (typeof v === 'object') return JSON.stringify(v); return String(v); }); } // List 操作 async lPush(key: string, ...values: string[]): Promise { return this.client.lpush(key, ...values); } async lRange(key: string, start: number, stop: number): Promise { const values = await this.client.lrange(key, start, stop); return values.map(v => { if (typeof v === 'string') return v; if (typeof v === 'object') return JSON.stringify(v); return String(v); }); } async lRem(key: string, count: number, value: string): Promise { return this.client.lrem(key, count, value); } async lTrim(key: string, start: number, stop: number): Promise { await this.client.ltrim(key, start, stop); } // Set 操作 async sAdd(key: string, ...members: string[]): Promise { if (members.length === 0) return 0; return this.client.sadd(key, members[0], ...members.slice(1)); } async sMembers(key: string): Promise { const members = await this.client.smembers(key); return members.map(m => { if (typeof m === 'string') return m; if (typeof m === 'object') return JSON.stringify(m); return String(m); }); } async sRem(key: string, ...members: string[]): Promise { return this.client.srem(key, ...members); } // Sorted Set 操作 async zAdd(key: string, member: { score: number; value: string }): Promise { const result = await this.client.zadd(key, { score: member.score, member: member.value }); return result || 0; } async zRange(key: string, start: number, stop: number): Promise { const values = await this.client.zrange(key, start, stop); return values.map(v => { if (typeof v === 'string') return v; if (typeof v === 'object') return JSON.stringify(v); return String(v); }); } async zCard(key: string): Promise { return this.client.zcard(key); } async zRem(key: string, ...members: string[]): Promise { return this.client.zrem(key, ...members); } }