import type { ShrimpCrud } from './Shrimp/ShrimpCrud' import { IShrimpQuery, IShrimpCondition, IShrimpPopulate, IPageResult, isShrimpCondition } from './IShrimpType' export class MemoryShrimpCrud implements ShrimpCrud { private data: Map = new Map() private autoId: number = 1 private isCondition = isShrimpCondition private matchCondition(item: any, key: string, cond: IShrimpCondition | any): boolean { const v = item[key] if (this.isCondition(cond)) { if (cond.eq !== undefined && v !== cond.eq) return false if (cond.in !== undefined && !cond.in.includes(v)) return false if (cond.like !== undefined && !String(v ?? '').toLowerCase().includes(String(cond.like).toLowerCase())) return false if (cond.gte !== undefined && v < cond.gte) return false if (cond.lte !== undefined && v > cond.lte) return false return true } return v === cond } async findOne(query?: any): Promise { if (!query) return null for (const item of this.data.values()) { if (Object.keys(query).every(key => (item as any)[key] === query[key])) { return item } } return null } async list(query?: IShrimpQuery): Promise> { let items = Array.from(this.data.values()) // where 条件 (AND) if (query?.where) { for (const [key, cond] of Object.entries(query.where)) { items = items.filter(item => this.matchCondition(item, key, cond)) } } // orWhere 条件 (OR 组之间) if (query?.orWhere && query.orWhere.length > 0) { items = items.filter(item => query.orWhere!.some(group => Object.entries(group).every(([key, cond]) => this.matchCondition(item, key, cond)) ) ) } const total = items.length // 排序 if (query?.order) { for (const [key, dir] of query.order) { const d = dir === 'desc' ? -1 : 1 items.sort((a, b) => { const va = (a as any)[key], vb = (b as any)[key] if (va == null && vb == null) return 0 if (va == null) return 1 if (vb == null) return -1 if (va < vb) return -d if (va > vb) return d return 0 }) } } // 分页 const offset = query?.offset || 0 const limit = query?.limit ?? items.length const list = items.slice(offset, offset + limit) const page = Math.floor(offset / limit) + 1 const pageSize = limit const totalPages = Math.ceil(total / pageSize) return { list, total, page, pageSize, totalPages } } async populateItems(items: any[], populates: IShrimpPopulate[], crudRegistry?: Map>): Promise { if (!crudRegistry) return for (const pop of populates) { const relatedCrud = crudRegistry.get(pop.moduleKey) if (!relatedCrud) continue const allRelated = (await relatedCrud.list({})).list const labelMap = new Map(allRelated.map(item => [String(item._id), (item as any)[pop.labelKey]])) for (const item of items) { const val = (item as any)[pop.key] if (Array.isArray(val)) { (item as any)[`${pop.key}_label`] = val.map((id: any) => labelMap.get(String(id)) ?? null) } else if (val != null) { (item as any)[`${pop.key}_label`] = labelMap.get(String(val)) ?? null } } } } async get(id: string): Promise { return this.data.get(id) || null } async add(item: Omit): Promise { const id = (this.autoId++).toString() const newItem = { _id: id, ...item } as T this.data.set(id, newItem) return newItem } async edit(id: string, item: Partial): Promise { const old = this.data.get(id) if (!old) return null const updated = { ...old, ...item } this.data.set(id, updated) return updated } async delete(id: string): Promise { return this.data.delete(id) } async clear(): Promise { this.data.clear() return true } }