UNPKG

autosnippet

Version:

Extract code patterns into a knowledge base for AI coding assistants

125 lines (124 loc) 4.82 kB
/** * SearchRepoAdapter — SearchEngine 用的轻量级仓储适配器 * * 当完整的 KnowledgeRepositoryImpl / RecipeSourceRefRepositoryImpl 不可用时 * (例如单元测试中只传入 raw db),SearchEngine 自动使用这些适配器。 * 放在 lib/repository/ 下,允许使用 raw SQL(lint 白名单目录)。 */ /** 解包 DatabaseConnection → raw SearchDb(若已是 raw db 则直接返回) */ export function unwrapSearchDb(db) { return typeof db.getDb === 'function' ? db.getDb() : db; } /** * 通用 db 解包:接受 raw db 或 { getDb() } wrapper,返回 raw db。 * 可用于 SearchDb、DatabaseLike 等不同 db 类型的构造函数。 */ export function unwrapRawDb(db) { if (db !== null && db !== undefined && typeof db === 'object' && 'getDb' in db && typeof db.getDb === 'function') { return db.getDb(); } return db; } /** * Raw-db 适配器:实现 SearchKnowledgeRepo 接口 * 仅在 KnowledgeRepositoryImpl 不可用时降级使用。 */ export class RawDbKnowledgeAdapter { #db; constructor(db) { this.#db = db; } findNonDeprecatedSync() { return this.#db .prepare(`SELECT id, title, description, language, category, knowledgeType, kind, content, lifecycle, tags, trigger, difficulty, quality, stats, updatedAt, createdAt FROM knowledge_entries WHERE lifecycle != 'deprecated'`) .all(); } keywordSearchSync(pattern, limit) { return this.#db .prepare(`SELECT id, title, description, language, category, knowledgeType, kind, lifecycle as status, content, trigger, headers, moduleName, 'knowledge' as type FROM knowledge_entries WHERE lifecycle != 'deprecated' AND (title LIKE ? ESCAPE '\\' OR description LIKE ? ESCAPE '\\' OR trigger LIKE ? ESCAPE '\\' OR content LIKE ? ESCAPE '\\') LIMIT ?`) .all(pattern, pattern, pattern, pattern, limit); } findByIdsDetailSync(ids) { if (ids.length === 0) { return []; } const placeholders = ids.map(() => '?').join(','); return this.#db .prepare(`SELECT id, content, description, trigger, headers, moduleName, tags, language, category, updatedAt, createdAt, quality, stats, difficulty, whenClause, doClause FROM knowledge_entries WHERE id IN (${placeholders})`) .all(...ids); } findUpdatedSinceSync(sinceIso) { return this.#db .prepare(`SELECT id, title, description, language, category, knowledgeType, kind, content, lifecycle, tags, trigger, difficulty, quality, stats, updatedAt, createdAt FROM knowledge_entries WHERE updatedAt > ?`) .all(sinceIso); } } /** * Raw-db 适配器:实现 SearchSourceRefRepo 接口 * 仅在 RecipeSourceRefRepositoryImpl 不可用时降级使用。 */ export class RawDbSourceRefAdapter { #db; constructor(db) { this.#db = db; } findActiveByRecipeIds(ids) { if (ids.length === 0) { return []; } const placeholders = ids.map(() => '?').join(','); return this.#db .prepare(`SELECT recipe_id, source_path, status, new_path FROM recipe_source_refs WHERE recipe_id IN (${placeholders}) AND status != 'stale'`) .all(...ids); } } /** * Raw-db 适配器:实现 GuardKnowledgeRepo 接口 * 仅在 KnowledgeRepositoryImpl 不可用时降级使用。 */ export class RawDbGuardAdapter { #db; constructor(db) { this.#db = db; } findGuardRulesSync(lifecycles) { const placeholders = lifecycles.map(() => '?').join(','); return this.#db .prepare(`SELECT id, title, description, language, scope, constraints, lifecycle FROM knowledge_entries WHERE kind = 'rule' AND lifecycle IN (${placeholders})`) .all(...lifecycles); } incrementGuardHitsSync(id, hits) { this.#db .prepare(`UPDATE knowledge_entries SET stats = json_set(COALESCE(stats, '{}'), '$.guardHits', COALESCE(json_extract(stats, '$.guardHits'), 0) + ?), updatedAt = strftime('%s', 'now') WHERE id = ?`) .run(hits, id); } } /* ═══ Vector Sync 适配器 ═══════════════════════════════════ */ /** 从 raw db 查询非 deprecated 的基本条目信息(SyncCoordinator 对账用) */ export function queryNonDeprecatedEntries(db) { return db .prepare(`SELECT id, title, content, kind FROM knowledge_entries WHERE lifecycle != 'deprecated'`) .all(); }