UNPKG

iagate-querykit

Version:

QueryKit: lightweight TypeScript query toolkit with models, views, triggers, events, scheduler and adapters (better-sqlite3).

68 lines (67 loc) 2.73 kB
import { QueryBuilder } from './query-builder'; export async function attachRelations(table, rows, selector) { if (!rows || rows.length === 0) return rows; let registry = {}; try { registry = (await import(process.env.QK_RELATIONS_PATH || '')).RELATIONS || {}; } catch { } const defs = registry[table] || []; if (defs.length === 0) return rows; let wanted = 'ALL'; if (selector) { const tmp = {}; selector((name, select) => { tmp[name] = select; }); wanted = tmp; } const byId = new Map(); for (const r of rows) byId.set(r.id, r); for (const def of defs) { if (wanted !== 'ALL' && !(def.name in wanted)) continue; if (def.kind === 'hasMany') { const ids = rows.map(r => r[def.localKey || 'id']); const children = await new QueryBuilder(def.table).whereIn(def.foreignKey, ids).all(); for (const c of children) { const parent = byId.get(c[def.foreignKey]); if (!parent) continue; parent[def.name] = parent[def.name] || []; parent[def.name].push(c); } } if (def.kind === 'belongsTo') { const fks = rows.map(r => r[def.foreignKey]).filter((v) => v !== undefined && v !== null); if (fks.length === 0) continue; const parents = await new QueryBuilder(def.table).whereIn(def.ownerKey || 'id', fks).all(); const parentByKey = new Map(parents.map((p) => [p[def.ownerKey || 'id'], p])); for (const r of rows) r[def.name] = parentByKey.get(r[def.foreignKey]) || null; } if (def.kind === 'manyToMany') { const ids = rows.map(r => r.id); const join = def.through.table; const leftKey = def.through.leftKey; const rightKey = def.through.rightKey; const links = await new QueryBuilder(join).whereIn(leftKey, ids).all(); const rightIds = links.map((l) => l[rightKey]); const rights = rightIds.length ? await new QueryBuilder(def.table).whereIn('id', rightIds).all() : []; const rightById = new Map(rights.map((x) => [x.id, x])); const bucket = new Map(); for (const l of links) { const arr = bucket.get(l[leftKey]) || []; const item = rightById.get(l[rightKey]); if (item) arr.push(item); bucket.set(l[leftKey], arr); } for (const r of rows) r[def.name] = bucket.get(r.id) || []; } } return rows; }