@agentshouse/mdruntime 0.1.0-alpha.25 → 0.1.0-alpha.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/query.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["/workspace/packages/mdruntime/src/query.ts"],"sourcesContent":["import type { Definition, FieldSpec } from '@agentshouse/mdmodel';\nimport { normalize } from './paths.js';\n\nexport type Value = string | number | boolean | null;\n\nexport type Predicate =\n | Value\n | { $eq: Value }\n | { $ne: Value }\n | { $in: readonly Value[] }\n | { $nin: readonly Value[] }\n | { $gt?: Value; $gte?: Value; $lt?: Value; $lte?: Value }\n | { $all: readonly Value[] }\n | { $size: number }\n | { $exists: boolean };\n\nexport type Where = {\n $and?: readonly Where[];\n $or?: readonly Where[];\n [field: string]: Predicate | readonly Where[] | undefined;\n};\n\nexport type Related = { types?: readonly string[]; where?: Where; pathPrefix?: string };\n\nexport type Filter = {\n rooms?: readonly string[];\n types?: readonly string[];\n where?: Where;\n pathPrefix?: string;\n hop?: Related & { field: string };\n backlinks?: Related & { field?: string };\n};\n\nexport type Key = 'room' | 'path' | 'type' | { field: string };\n\nexport type Select =\n | 'all'\n | {\n fields?: 'all' | readonly string[];\n sections?: 'all' | readonly string[];\n preamble?: true;\n markdown?: true;\n backlinks?: true;\n };\n\nexport type OrderOptions = {\n nulls?: 'first' | 'last';\n stringSort?: 'lexical' | 'locale';\n locale?: string;\n localeOptions?: Readonly<Record<string, unknown>>;\n};\n\nexport type Direction = 'asc' | 'desc';\n\nexport type DocumentQuery = Filter & {\n select: Select;\n orderBy?: readonly ({ by: Key; direction?: Direction } & OrderOptions)[];\n limit?: number;\n};\n\nexport type GroupQuery = Filter & {\n groupBy: readonly Exclude<Key, 'path'>[];\n orderBy?: readonly { by: 'count' | Exclude<Key, 'path'>; direction?: Direction }[];\n limit?: number;\n};\n\nexport type LocalQuery = DocumentQuery | GroupQuery;\n\nexport type Backlink = { path: string; type: string; field: string };\n\nexport type QueryDocument = {\n room: string;\n path: string;\n type: string;\n fields?: Readonly<Record<string, unknown>>;\n sections?: Readonly<Record<string, string>>;\n preamble?: string;\n markdown?: string;\n backlinks?: readonly Backlink[];\n};\n\nexport type QueryGroup = { key: readonly unknown[]; count: number };\n\nexport type DocumentResult = { documents: readonly QueryDocument[] };\n\nexport type GroupResult = { groups: readonly QueryGroup[] };\n\nexport type QueryResult = DocumentResult | GroupResult;\n\nexport type QueryErrorCode = 'invalid-query' | 'unknown-type' | 'unknown-field' | 'wrong-kind';\n\nexport type RoomFacts = {\n locator: string;\n available: boolean;\n types: readonly Definition[];\n};\n\nexport type HeldRooms = {\n listed: boolean;\n rooms: readonly RoomFacts[];\n};\n\nexport type Test =\n | { op: 'eq'; value: Value }\n | { op: 'ne'; value: Value }\n | { op: 'in'; values: readonly Value[] }\n | { op: 'nin'; values: readonly Value[] }\n | { op: 'range'; bounds: readonly (readonly ['gt' | 'gte' | 'lt' | 'lte', Value])[] }\n | { op: 'all'; values: readonly Value[] }\n | { op: 'size'; size: number }\n | { op: 'exists'; exists: boolean };\n\nexport type Condition =\n | { every: readonly Condition[] }\n | { some: readonly Condition[] }\n | { field: string; test: Test };\n\nexport type Scope = {\n types: readonly string[] | null;\n where: Condition | null;\n pathPrefix: string | null;\n};\n\nexport type KeyPlan =\n | { of: 'room' }\n | { of: 'path' }\n | { of: 'type' }\n | { of: 'field'; field: string };\n\nexport type DocumentShape = {\n kind: 'documents';\n fields: 'all' | readonly string[] | null;\n sections: 'all' | readonly string[] | null;\n preamble: boolean;\n markdown: boolean;\n backlinks: boolean;\n orderBy: readonly { key: KeyPlan; options: OrderOptions & { direction: Direction } }[];\n};\n\nexport type GroupShape = {\n kind: 'groups';\n groupBy: readonly KeyPlan[];\n orderBy: readonly { by: 'count' | number; direction: Direction }[];\n};\n\nexport type Plan = {\n rooms: readonly string[] | null;\n root: Scope;\n hop: (Scope & { field: string }) | null;\n backlinks: (Scope & { field: string | null }) | null;\n shape: DocumentShape | GroupShape;\n limit: number | null;\n};\n\nexport class QueryError extends Error {\n constructor(code: QueryErrorCode, at: string, problem: string) {\n super(`${code} at ${at}: ${problem}`);\n }\n}\n\ntype Entries = Readonly<Record<string, unknown>>;\n\ntype Typing = { untyped: boolean; types: readonly Definition[] };\n\nconst RANGE = ['$gt', '$gte', '$lt', '$lte'] as const;\nconst SINGLE = ['$eq', '$ne', '$in', '$nin', '$all', '$size', '$exists'] as const;\nconst FILTER = ['rooms', 'types', 'where', 'pathPrefix', 'hop', 'backlinks', 'orderBy', 'limit'];\nconst RELATED = ['types', 'where', 'pathPrefix', 'field'];\nconst PARTS = ['fields', 'sections', 'preamble', 'markdown', 'backlinks'];\nconst ORDER = ['by', 'direction', 'nulls', 'stringSort', 'locale', 'localeOptions'];\nconst CALENDAR_DATE = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\nfunction invalid(at: string, problem: string): never {\n throw new QueryError('invalid-query', at, problem);\n}\n\nfunction place(at: string, name: string): string {\n return at === '' ? name : `${at}.${name}`;\n}\n\nfunction plain(value: unknown): value is Entries {\n return (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null)\n );\n}\n\nfunction known(value: Entries, allowed: readonly string[], at: string) {\n for (const name of Object.keys(value)) {\n if (!allowed.includes(name)) invalid(place(at, name), 'unknown part');\n }\n}\n\nfunction list(input: unknown, at: string): readonly unknown[] {\n if (!Array.isArray(input)) invalid(at, 'expects a list');\n return input;\n}\n\nfunction value(input: unknown, at: string): Value {\n if (Array.isArray(input)) invalid(at, 'a list is not a value');\n if (\n input !== null &&\n typeof input !== 'string' &&\n typeof input !== 'boolean' &&\n !(typeof input === 'number' && Number.isFinite(input))\n ) {\n invalid(at, 'not a value');\n }\n return input;\n}\n\nfunction values(input: unknown, at: string): readonly Value[] {\n return list(input, at).map((item, index) => value(item, `${at}[${index}]`));\n}\n\nfunction names(input: unknown, at: string): readonly string[] {\n const listed = list(input, at);\n if (listed.some((item) => typeof item !== 'string')) invalid(at, 'expects a list of names');\n return [...new Set(listed as readonly string[])].sort();\n}\n\nfunction directory(input: unknown, at: string): string {\n if (typeof input !== 'string' || normalize(input) !== input) {\n invalid(at, 'expects a normalized directory');\n }\n return input;\n}\n\nfunction calendarDate(value: string): boolean {\n const match = CALENDAR_DATE.exec(value);\n if (match === null) return false;\n const [year, month, day] = match.slice(1).map(Number);\n const date = new Date(Date.UTC(year, month - 1, day));\n return (\n date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day\n );\n}\n\nfunction fits(spec: FieldSpec, value: Value): boolean {\n const item = spec.kind === 'list' ? spec.of : spec;\n if (item.kind === 'number') return typeof value === 'number';\n if (typeof value !== 'string') return false;\n if (item.kind === 'enum') return item.values.includes(value);\n if (item.kind === 'date') return calendarDate(value);\n if (item.kind === 'reference') return value !== '' && normalize(value) === value;\n return true;\n}\n\nfunction reference(spec: FieldSpec): boolean {\n return spec.kind === 'reference' || (spec.kind === 'list' && spec.of.kind === 'reference');\n}\n\nfunction typing(\n facts: HeldRooms,\n rooms: readonly string[] | null,\n types: readonly string[] | null,\n at: string,\n): Typing {\n const read =\n rooms === null ? facts.rooms : facts.rooms.filter((room) => rooms.includes(room.locator));\n const acquiring =\n !facts.listed &&\n (rooms === null ||\n rooms.some((locator) => !facts.rooms.some((room) => room.locator === locator)));\n const available = !acquiring && read.every((room) => room.available);\n const declared = read.flatMap((room) => room.types);\n for (const name of types ?? []) {\n if (name === 'any' || !available || declared.some((type) => type.name === name)) continue;\n throw new QueryError('unknown-type', place(at, 'types'), `no model it reads declares ${name}`);\n }\n return {\n untyped: types === null || types.includes('any') || !available,\n types: types === null ? declared : declared.filter((type) => types.includes(type.name)),\n };\n}\n\nfunction specs(typed: Typing, field: string, at: string): readonly FieldSpec[] {\n const declared = typed.types.flatMap((type) =>\n Object.hasOwn(type.fields, field) ? [type.fields[field]] : [],\n );\n if (declared.length === 0 && !typed.untyped) {\n throw new QueryError('unknown-field', at, `no MD Type it reads declares ${field}`);\n }\n return declared;\n}\n\nfunction kind(declared: readonly FieldSpec[], checked: Value, at: string) {\n if (checked === null || declared.length === 0 || declared.some((spec) => fits(spec, checked))) {\n return;\n }\n throw new QueryError('wrong-kind', at, `${JSON.stringify(checked)} is not of its field's kind`);\n}\n\nfunction listed(declared: readonly FieldSpec[], list: boolean): boolean {\n return declared.length > 0 && declared.every((spec) => (spec.kind === 'list') === list);\n}\n\nfunction test(declared: readonly FieldSpec[], input: unknown, at: string): Test {\n if (!plain(input)) {\n const equal = value(input, at);\n kind(declared, equal, at);\n return { op: 'eq', value: equal };\n }\n const operators = Object.keys(input);\n if (operators.length === 0) invalid(at, 'names no operator');\n if (operators.some((operator) => (RANGE as readonly string[]).includes(operator))) {\n const stray = operators.find((operator) => !(RANGE as readonly string[]).includes(operator));\n if (stray !== undefined) invalid(place(at, stray), 'cannot join a range');\n if (listed(declared, true)) invalid(at, 'a range on a list');\n return {\n op: 'range',\n bounds: RANGE.filter((operator) => operators.includes(operator)).map((operator) => {\n const bound = value(input[operator], place(at, operator));\n if (bound === null) invalid(place(at, operator), 'a range bound is never null');\n kind(declared, bound, place(at, operator));\n return [operator.slice(1) as 'gt' | 'gte' | 'lt' | 'lte', bound] as const;\n }),\n };\n }\n if (operators.length > 1) invalid(place(at, operators[1]), 'names a second operator');\n const [operator] = operators;\n const where = place(at, operator);\n if (!(SINGLE as readonly string[]).includes(operator)) invalid(where, 'unknown operator');\n const operand = input[operator];\n if (operator === '$eq' || operator === '$ne') {\n const compared = value(operand, where);\n kind(declared, compared, where);\n return operator === '$eq' ? { op: 'eq', value: compared } : { op: 'ne', value: compared };\n }\n if (operator === '$in' || operator === '$nin' || operator === '$all') {\n const compared = values(operand, where);\n compared.forEach((item, index) => kind(declared, item, `${where}[${index}]`));\n if (operator === '$in') return { op: 'in', values: compared };\n if (operator === '$nin') return { op: 'nin', values: compared };\n if (compared.includes(null)) invalid(where, 'a list holds no null');\n if (listed(declared, false)) invalid(where, 'the field is not a list');\n return { op: 'all', values: compared };\n }\n if (operator === '$size') {\n if (!Number.isSafeInteger(operand) || (operand as number) < 0) {\n invalid(where, 'expects a nonnegative integer');\n }\n if (listed(declared, false)) invalid(where, 'the field is not a list');\n return { op: 'size', size: operand as number };\n }\n if (typeof operand !== 'boolean') invalid(where, 'expects true or false');\n return { op: 'exists', exists: operand };\n}\n\nfunction condition(typed: Typing, input: unknown, at: string): Condition {\n if (!plain(input)) invalid(at, 'expects an object of field predicates');\n const conditions: Condition[] = [];\n for (const name of Object.keys(input).sort()) {\n const where = place(at, name);\n const entry = input[name];\n if (name === '$and' || name === '$or') {\n const nested = list(entry, where).map((item, index) =>\n condition(typed, item, `${where}[${index}]`),\n );\n if (nested.length === 0) invalid(where, 'expects a nonempty list');\n conditions.push(name === '$and' ? { every: nested } : { some: nested });\n continue;\n }\n if (name.startsWith('$')) invalid(where, 'unknown operator');\n conditions.push({ field: name, test: test(specs(typed, name, where), entry, where) });\n }\n if (conditions.length === 0) invalid(at, 'names no field');\n return conditions.length === 1 ? conditions[0] : { every: conditions };\n}\n\nfunction scope(\n facts: HeldRooms,\n rooms: readonly string[] | null,\n input: Entries,\n at: string,\n): Scope & { typed: Typing } {\n const types = input.types === undefined ? null : names(input.types, place(at, 'types'));\n const typed = typing(facts, rooms, types, at);\n return {\n typed,\n types,\n where:\n input.where === undefined || (plain(input.where) && Object.keys(input.where).length === 0)\n ? null\n : condition(typed, input.where, place(at, 'where')),\n pathPrefix:\n input.pathPrefix === undefined ? null : directory(input.pathPrefix, place(at, 'pathPrefix')),\n };\n}\n\nfunction referenceField(typed: Typing, field: unknown, at: string): string {\n if (typeof field !== 'string') invalid(at, 'expects a field name');\n const declared = specs(typed, field, at);\n if (declared.length > 0 && !declared.some(reference)) invalid(at, 'not a reference field');\n return field;\n}\n\nfunction hopOf(\n facts: HeldRooms,\n rooms: readonly string[] | null,\n root: Typing,\n input: unknown,\n): Plan['hop'] {\n if (!plain(input)) invalid('hop', 'expects an object');\n known(input, RELATED, 'hop');\n const field = referenceField(root, input.field, 'hop.field');\n const { types, where, pathPrefix } = scope(facts, rooms, input, 'hop');\n return { types, where, pathPrefix, field };\n}\n\nfunction backlinksOf(\n facts: HeldRooms,\n rooms: readonly string[] | null,\n input: unknown,\n): Plan['backlinks'] {\n if (!plain(input)) invalid('backlinks', 'expects an object');\n known(input, RELATED, 'backlinks');\n const { typed, types, where, pathPrefix } = scope(facts, rooms, input, 'backlinks');\n const field =\n input.field === undefined ? null : referenceField(typed, input.field, 'backlinks.field');\n return { types, where, pathPrefix, field };\n}\n\nfunction keyPlan(typed: Typing, input: unknown, at: string, path: boolean): KeyPlan {\n if (input === 'room' || input === 'type' || (path && input === 'path')) return { of: input };\n if (plain(input) && typeof input.field === 'string' && Object.keys(input).length === 1) {\n specs(typed, input.field, place(at, 'field'));\n return { of: 'field', field: input.field };\n }\n return invalid(\n at,\n path ? 'expects room, path, type or a field' : 'expects room, type or a field',\n );\n}\n\nfunction direction(input: unknown, at: string): Direction {\n if (input === undefined) return 'asc';\n if (input !== 'asc' && input !== 'desc') invalid(at, 'expects asc or desc');\n return input;\n}\n\nfunction orderOptions(input: Entries, at: string): OrderOptions & { direction: Direction } {\n const options: OrderOptions & { direction: Direction } = {\n direction: direction(input.direction, place(at, 'direction')),\n };\n if (input.nulls !== undefined) {\n if (input.nulls !== 'first' && input.nulls !== 'last') {\n invalid(place(at, 'nulls'), 'expects first or last');\n }\n options.nulls = input.nulls;\n }\n if (input.stringSort !== undefined) {\n if (input.stringSort !== 'lexical' && input.stringSort !== 'locale') {\n invalid(place(at, 'stringSort'), 'expects lexical or locale');\n }\n options.stringSort = input.stringSort;\n }\n if (input.locale !== undefined) {\n if (typeof input.locale !== 'string' || !collates(input.locale, undefined)) {\n invalid(place(at, 'locale'), 'expects a locale name');\n }\n options.locale = input.locale;\n }\n if (input.localeOptions !== undefined) {\n if (!plain(input.localeOptions) || !collates(options.locale, input.localeOptions)) {\n invalid(place(at, 'localeOptions'), 'expects collation options');\n }\n options.localeOptions = input.localeOptions;\n }\n return options;\n}\n\nfunction collates(locale: string | undefined, options: Entries | undefined): boolean {\n try {\n ''.localeCompare('', locale, options);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction parts(typed: Typing, input: unknown, at: string, fields: boolean) {\n if (input === undefined) return null;\n if (input === 'all') return 'all';\n const named = list(input, at);\n named.forEach((name, index) => {\n if (typeof name !== 'string') invalid(`${at}[${index}]`, 'expects a name');\n if (fields) specs(typed, name, `${at}[${index}]`);\n });\n return named as readonly string[];\n}\n\nfunction flag(input: unknown, at: string): boolean {\n if (input === undefined) return false;\n if (input !== true) invalid(at, 'expects true');\n return true;\n}\n\nfunction documentShape(typed: Typing, input: Entries): DocumentShape {\n const orderBy = (input.orderBy === undefined ? [] : list(input.orderBy, 'orderBy')).map(\n (clause, index) => {\n const at = `orderBy[${index}]`;\n if (!plain(clause)) invalid(at, 'expects an order clause');\n known(clause, ORDER, at);\n return {\n key: keyPlan(typed, clause.by, place(at, 'by'), true),\n options: orderOptions(clause, at),\n };\n },\n );\n const select = input.select;\n if (select === 'all') {\n return {\n kind: 'documents',\n fields: 'all',\n sections: 'all',\n preamble: true,\n markdown: true,\n backlinks: true,\n orderBy,\n };\n }\n if (!plain(select)) invalid('select', \"expects 'all' or the parts to return\");\n known(select, PARTS, 'select');\n return {\n kind: 'documents',\n fields: parts(typed, select.fields, 'select.fields', true),\n sections: parts(typed, select.sections, 'select.sections', false),\n preamble: flag(select.preamble, 'select.preamble'),\n markdown: flag(select.markdown, 'select.markdown'),\n backlinks: flag(select.backlinks, 'select.backlinks'),\n orderBy,\n };\n}\n\nfunction groupShape(typed: Typing, input: Entries): GroupShape {\n const groupBy = list(input.groupBy, 'groupBy').map((key, index) =>\n keyPlan(typed, key, `groupBy[${index}]`, false),\n );\n if (groupBy.length === 0) invalid('groupBy', 'names no key');\n const grouped = groupBy.map((key) => JSON.stringify(key));\n const orderBy = (input.orderBy === undefined ? [] : list(input.orderBy, 'orderBy')).map(\n (clause, index) => {\n const at = `orderBy[${index}]`;\n if (!plain(clause)) invalid(at, 'expects an order clause');\n known(clause, ['by', 'direction'], at);\n const by =\n clause.by === 'count'\n ? ('count' as const)\n : grouped.indexOf(JSON.stringify(keyPlan(typed, clause.by, place(at, 'by'), false)));\n if (by === -1) invalid(place(at, 'by'), 'orders by a key the query does not group by');\n return { by, direction: direction(clause.direction, place(at, 'direction')) };\n },\n );\n return { kind: 'groups', groupBy, orderBy };\n}\n\nexport function planOf(input: unknown, facts: HeldRooms): Plan {\n if (!plain(input)) invalid('query', 'expects a query object');\n const grouped = input.groupBy !== undefined;\n if (grouped && input.select !== undefined) invalid('select', 'a grouped query selects nothing');\n if (!grouped && input.select === undefined) invalid('select', 'a Document query must select');\n known(input, [...FILTER, grouped ? 'groupBy' : 'select'], '');\n if (\n input.limit !== undefined &&\n (!Number.isSafeInteger(input.limit) || (input.limit as number) < 0)\n ) {\n invalid('limit', 'expects a nonnegative integer');\n }\n const rooms = input.rooms === undefined ? null : names(input.rooms, 'rooms');\n const { typed, ...root } = scope(facts, rooms, input, '');\n return {\n rooms,\n root,\n hop: input.hop === undefined ? null : hopOf(facts, rooms, typed, input.hop),\n backlinks: input.backlinks === undefined ? null : backlinksOf(facts, rooms, input.backlinks),\n shape: grouped ? groupShape(typed, input) : documentShape(typed, input),\n limit: (input.limit as number | undefined) ?? null,\n };\n}\n\nfunction canonical(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(canonical).join(',')}]`;\n if (typeof value === 'object' && value !== null) {\n return `{${Object.keys(value)\n .sort()\n .map((name) => `${JSON.stringify(name)}:${canonical((value as Entries)[name])}`)\n .join(',')}}`;\n }\n return JSON.stringify(value);\n}\n\nexport function identityOf(plan: Plan): string {\n return canonical(plan);\n}\n"],"names":["normalize","QueryError","Error","code","at","problem","RANGE","SINGLE","FILTER","RELATED","PARTS","ORDER","CALENDAR_DATE","invalid","place","name","plain","value","Array","isArray","Object","getPrototypeOf","prototype","known","allowed","keys","includes","list","input","Number","isFinite","values","map","item","index","names","listed","some","Set","sort","directory","calendarDate","match","exec","year","month","day","slice","date","Date","UTC","getUTCFullYear","getUTCMonth","getUTCDate","fits","spec","kind","of","reference","typing","facts","rooms","types","read","filter","room","locator","acquiring","available","every","declared","flatMap","type","untyped","specs","typed","field","hasOwn","fields","length","checked","JSON","stringify","test","equal","op","operators","operator","stray","find","undefined","bounds","bound","where","operand","compared","forEach","isSafeInteger","size","exists","condition","conditions","entry","nested","push","startsWith","scope","pathPrefix","referenceField","hopOf","root","backlinksOf","keyPlan","path","direction","orderOptions","options","nulls","stringSort","locale","collates","localeOptions","localeCompare","parts","named","flag","documentShape","orderBy","clause","key","by","select","sections","preamble","markdown","backlinks","groupShape","groupBy","grouped","indexOf","planOf","limit","hop","shape","canonical","join","identityOf","plan"],"mappings":"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"}
1
+ {"version":3,"sources":["/workspace/packages/mdruntime/src/query.ts"],"sourcesContent":["import type { Definition, FieldSpec } from '@agentshouse/mdmodel';\nimport { normalize } from './paths.js';\n\nexport type Value = string | number | boolean | null;\n\nexport type Predicate =\n | Value\n | { $eq: Value }\n | { $ne: Value }\n | { $in: readonly Value[] }\n | { $nin: readonly Value[] }\n | { $gt?: Value; $gte?: Value; $lt?: Value; $lte?: Value }\n | { $all: readonly Value[] }\n | { $size: number }\n | { $exists: boolean };\n\nexport type Where = {\n $and?: readonly Where[];\n $or?: readonly Where[];\n [field: string]: Predicate | readonly Where[] | undefined;\n};\n\nexport type Related = { types?: readonly string[]; where?: Where; pathPrefix?: string };\n\nexport type Filter = {\n rooms?: readonly string[];\n types?: readonly string[];\n where?: Where;\n pathPrefix?: string;\n hop?: Related & { field: string };\n backlinks?: Related & { field?: string };\n};\n\nexport type Key = 'room' | 'path' | 'type' | { field: string };\n\nexport type Select =\n | 'all'\n | {\n fields?: 'all' | readonly string[];\n sections?: 'all' | readonly string[];\n preamble?: true;\n markdown?: true;\n backlinks?: true;\n };\n\nexport type OrderOptions = {\n nulls?: 'first' | 'last';\n stringSort?: 'lexical' | 'locale';\n locale?: string;\n localeOptions?: Readonly<Record<string, unknown>>;\n};\n\nexport type Direction = 'asc' | 'desc';\n\nexport type DocumentQuery = Filter & {\n select: Select;\n orderBy?: readonly ({ by: Key; direction?: Direction } & OrderOptions)[];\n limit?: number;\n};\n\nexport type GroupQuery = Filter & {\n groupBy: readonly Exclude<Key, 'path'>[];\n orderBy?: readonly { by: 'count' | Exclude<Key, 'path'>; direction?: Direction }[];\n limit?: number;\n};\n\nexport type LocalQuery = DocumentQuery | GroupQuery;\n\nexport type Backlink = { path: string; type: string; field: string };\n\nexport type QueryDocument = {\n room: string;\n path: string;\n type: string;\n fields?: Readonly<Record<string, unknown>>;\n sections?: Readonly<Record<string, string>>;\n preamble?: string;\n markdown?: string;\n backlinks?: readonly Backlink[];\n};\n\nexport type QueryGroup = { key: readonly unknown[]; count: number };\n\nexport type DocumentResult = { documents: readonly QueryDocument[] };\n\nexport type GroupResult = { groups: readonly QueryGroup[] };\n\nexport type QueryResult = DocumentResult | GroupResult;\n\nexport type QueryErrorCode = 'invalid-query' | 'unknown-type' | 'unknown-field' | 'wrong-kind';\n\nexport type RoomFacts = {\n locator: string;\n available: boolean;\n types: readonly Definition[];\n};\n\nexport type HeldRooms = {\n listed: boolean;\n rooms: readonly RoomFacts[];\n};\n\nexport type Test =\n | { op: 'eq'; value: Value }\n | { op: 'ne'; value: Value }\n | { op: 'in'; values: readonly Value[] }\n | { op: 'nin'; values: readonly Value[] }\n | { op: 'range'; bounds: readonly (readonly ['gt' | 'gte' | 'lt' | 'lte', Value])[] }\n | { op: 'all'; values: readonly Value[] }\n | { op: 'size'; size: number }\n | { op: 'exists'; exists: boolean };\n\nexport type Condition =\n | { every: readonly Condition[] }\n | { some: readonly Condition[] }\n | { field: string; test: Test };\n\nexport type Scope = {\n types: readonly string[] | null;\n where: Condition | null;\n pathPrefix: string | null;\n};\n\nexport type KeyPlan =\n | { of: 'room' }\n | { of: 'path' }\n | { of: 'type' }\n | { of: 'field'; field: string };\n\nexport type DocumentShape = {\n kind: 'documents';\n fields: 'all' | readonly string[] | null;\n sections: 'all' | readonly string[] | null;\n preamble: boolean;\n markdown: boolean;\n backlinks: boolean;\n orderBy: readonly { key: KeyPlan; options: OrderOptions & { direction: Direction } }[];\n};\n\nexport type GroupShape = {\n kind: 'groups';\n groupBy: readonly KeyPlan[];\n orderBy: readonly { by: 'count' | number; direction: Direction }[];\n};\n\nexport type Plan = {\n rooms: readonly string[] | null;\n root: Scope;\n hop: (Scope & { field: string }) | null;\n backlinks: (Scope & { field: string | null }) | null;\n shape: DocumentShape | GroupShape;\n limit: number | null;\n};\n\nexport class QueryError extends Error {\n constructor(code: QueryErrorCode, at: string, problem: string) {\n super(`${code} at ${at}: ${problem}`);\n }\n}\n\ntype Entries = Readonly<Record<string, unknown>>;\n\ntype Typing = { untyped: boolean; types: readonly Definition[] };\n\nconst RANGE = ['$gt', '$gte', '$lt', '$lte'] as const;\nconst SINGLE = ['$eq', '$ne', '$in', '$nin', '$all', '$size', '$exists'] as const;\nconst FILTER = ['rooms', 'types', 'where', 'pathPrefix', 'hop', 'backlinks'];\nconst RELATED = ['types', 'where', 'pathPrefix', 'field'];\nconst PARTS = ['fields', 'sections', 'preamble', 'markdown', 'backlinks'];\nconst ORDER = ['by', 'direction', 'nulls', 'stringSort', 'locale', 'localeOptions'];\nconst CALENDAR_DATE = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\nexport function invalid(at: string, problem: string): never {\n throw new QueryError('invalid-query', at, problem);\n}\n\nfunction place(at: string, name: string): string {\n return at === '' ? name : `${at}.${name}`;\n}\n\nexport function plain(value: unknown): value is Entries {\n return (\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value) &&\n (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null)\n );\n}\n\nexport function known(value: Entries, allowed: readonly string[], at: string) {\n for (const name of Object.keys(value)) {\n if (!allowed.includes(name)) invalid(place(at, name), 'unknown part');\n }\n}\n\nfunction list(input: unknown, at: string): readonly unknown[] {\n if (!Array.isArray(input)) invalid(at, 'expects a list');\n return input;\n}\n\nfunction value(input: unknown, at: string): Value {\n if (Array.isArray(input)) invalid(at, 'a list is not a value');\n if (\n input !== null &&\n typeof input !== 'string' &&\n typeof input !== 'boolean' &&\n !(typeof input === 'number' && Number.isFinite(input))\n ) {\n invalid(at, 'not a value');\n }\n return input;\n}\n\nfunction values(input: unknown, at: string): readonly Value[] {\n return list(input, at).map((item, index) => value(item, `${at}[${index}]`));\n}\n\nfunction names(input: unknown, at: string): readonly string[] {\n const listed = list(input, at);\n if (listed.some((item) => typeof item !== 'string')) invalid(at, 'expects a list of names');\n return [...new Set(listed as readonly string[])].sort();\n}\n\nfunction directory(input: unknown, at: string): string {\n if (typeof input !== 'string' || normalize(input) !== input) {\n invalid(at, 'expects a normalized directory');\n }\n return input;\n}\n\nfunction calendarDate(value: string): boolean {\n const match = CALENDAR_DATE.exec(value);\n if (match === null) return false;\n const [year, month, day] = match.slice(1).map(Number);\n const date = new Date(Date.UTC(year, month - 1, day));\n return (\n date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day\n );\n}\n\nfunction fits(spec: FieldSpec, value: Value): boolean {\n const item = spec.kind === 'list' ? spec.of : spec;\n if (item.kind === 'number') return typeof value === 'number';\n if (typeof value !== 'string') return false;\n if (item.kind === 'enum') return item.values.includes(value);\n if (item.kind === 'date') return calendarDate(value);\n if (item.kind === 'reference') return value !== '' && normalize(value) === value;\n return true;\n}\n\nfunction reference(spec: FieldSpec): boolean {\n return spec.kind === 'reference' || (spec.kind === 'list' && spec.of.kind === 'reference');\n}\n\nfunction typing(\n facts: HeldRooms,\n rooms: readonly string[] | null,\n types: readonly string[] | null,\n at: string,\n): Typing {\n const read =\n rooms === null ? facts.rooms : facts.rooms.filter((room) => rooms.includes(room.locator));\n const acquiring =\n !facts.listed &&\n (rooms === null ||\n rooms.some((locator) => !facts.rooms.some((room) => room.locator === locator)));\n const available = !acquiring && read.every((room) => room.available);\n const declared = read.flatMap((room) => room.types);\n for (const name of types ?? []) {\n if (name === 'any' || !available || declared.some((type) => type.name === name)) continue;\n throw new QueryError('unknown-type', place(at, 'types'), `no model it reads declares ${name}`);\n }\n return {\n untyped: types === null || types.includes('any') || !available,\n types: types === null ? declared : declared.filter((type) => types.includes(type.name)),\n };\n}\n\nfunction specs(typed: Typing, field: string, at: string): readonly FieldSpec[] {\n const declared = typed.types.flatMap((type) =>\n Object.hasOwn(type.fields, field) ? [type.fields[field]] : [],\n );\n if (declared.length === 0 && !typed.untyped) {\n throw new QueryError('unknown-field', at, `no MD Type it reads declares ${field}`);\n }\n return declared;\n}\n\nfunction kind(declared: readonly FieldSpec[], checked: Value, at: string) {\n if (checked === null || declared.length === 0 || declared.some((spec) => fits(spec, checked))) {\n return;\n }\n throw new QueryError('wrong-kind', at, `${JSON.stringify(checked)} is not of its field's kind`);\n}\n\nfunction listed(declared: readonly FieldSpec[], list: boolean): boolean {\n return declared.length > 0 && declared.every((spec) => (spec.kind === 'list') === list);\n}\n\nfunction test(declared: readonly FieldSpec[], input: unknown, at: string): Test {\n if (!plain(input)) {\n const equal = value(input, at);\n kind(declared, equal, at);\n return { op: 'eq', value: equal };\n }\n const operators = Object.keys(input);\n if (operators.length === 0) invalid(at, 'names no operator');\n if (operators.some((operator) => (RANGE as readonly string[]).includes(operator))) {\n const stray = operators.find((operator) => !(RANGE as readonly string[]).includes(operator));\n if (stray !== undefined) invalid(place(at, stray), 'cannot join a range');\n if (listed(declared, true)) invalid(at, 'a range on a list');\n return {\n op: 'range',\n bounds: RANGE.filter((operator) => operators.includes(operator)).map((operator) => {\n const bound = value(input[operator], place(at, operator));\n if (bound === null) invalid(place(at, operator), 'a range bound is never null');\n kind(declared, bound, place(at, operator));\n return [operator.slice(1) as 'gt' | 'gte' | 'lt' | 'lte', bound] as const;\n }),\n };\n }\n if (operators.length > 1) invalid(place(at, operators[1]), 'names a second operator');\n const [operator] = operators;\n const where = place(at, operator);\n if (!(SINGLE as readonly string[]).includes(operator)) invalid(where, 'unknown operator');\n const operand = input[operator];\n if (operator === '$eq' || operator === '$ne') {\n const compared = value(operand, where);\n kind(declared, compared, where);\n return operator === '$eq' ? { op: 'eq', value: compared } : { op: 'ne', value: compared };\n }\n if (operator === '$in' || operator === '$nin' || operator === '$all') {\n const compared = values(operand, where);\n compared.forEach((item, index) => kind(declared, item, `${where}[${index}]`));\n if (operator === '$in') return { op: 'in', values: compared };\n if (operator === '$nin') return { op: 'nin', values: compared };\n if (compared.includes(null)) invalid(where, 'a list holds no null');\n if (listed(declared, false)) invalid(where, 'the field is not a list');\n return { op: 'all', values: compared };\n }\n if (operator === '$size') {\n if (!Number.isSafeInteger(operand) || (operand as number) < 0) {\n invalid(where, 'expects a nonnegative integer');\n }\n if (listed(declared, false)) invalid(where, 'the field is not a list');\n return { op: 'size', size: operand as number };\n }\n if (typeof operand !== 'boolean') invalid(where, 'expects true or false');\n return { op: 'exists', exists: operand };\n}\n\nfunction condition(typed: Typing, input: unknown, at: string): Condition {\n if (!plain(input)) invalid(at, 'expects an object of field predicates');\n const conditions: Condition[] = [];\n for (const name of Object.keys(input).sort()) {\n const where = place(at, name);\n const entry = input[name];\n if (name === '$and' || name === '$or') {\n const nested = list(entry, where).map((item, index) =>\n condition(typed, item, `${where}[${index}]`),\n );\n if (nested.length === 0) invalid(where, 'expects a nonempty list');\n conditions.push(name === '$and' ? { every: nested } : { some: nested });\n continue;\n }\n if (name.startsWith('$')) invalid(where, 'unknown operator');\n conditions.push({ field: name, test: test(specs(typed, name, where), entry, where) });\n }\n if (conditions.length === 0) invalid(at, 'names no field');\n return conditions.length === 1 ? conditions[0] : { every: conditions };\n}\n\nfunction scope(\n facts: HeldRooms,\n rooms: readonly string[] | null,\n input: Entries,\n at: string,\n): Scope & { typed: Typing } {\n const types = input.types === undefined ? null : names(input.types, place(at, 'types'));\n const typed = typing(facts, rooms, types, at);\n return {\n typed,\n types,\n where:\n input.where === undefined || (plain(input.where) && Object.keys(input.where).length === 0)\n ? null\n : condition(typed, input.where, place(at, 'where')),\n pathPrefix:\n input.pathPrefix === undefined ? null : directory(input.pathPrefix, place(at, 'pathPrefix')),\n };\n}\n\nfunction referenceField(typed: Typing, field: unknown, at: string): string {\n if (typeof field !== 'string') invalid(at, 'expects a field name');\n const declared = specs(typed, field, at);\n if (declared.length > 0 && !declared.some(reference)) invalid(at, 'not a reference field');\n return field;\n}\n\nfunction hopOf(\n facts: HeldRooms,\n rooms: readonly string[] | null,\n root: Typing,\n input: unknown,\n): Plan['hop'] {\n if (!plain(input)) invalid('hop', 'expects an object');\n known(input, RELATED, 'hop');\n const field = referenceField(root, input.field, 'hop.field');\n const { types, where, pathPrefix } = scope(facts, rooms, input, 'hop');\n return { types, where, pathPrefix, field };\n}\n\nfunction backlinksOf(\n facts: HeldRooms,\n rooms: readonly string[] | null,\n input: unknown,\n): Plan['backlinks'] {\n if (!plain(input)) invalid('backlinks', 'expects an object');\n known(input, RELATED, 'backlinks');\n const { typed, types, where, pathPrefix } = scope(facts, rooms, input, 'backlinks');\n const field =\n input.field === undefined ? null : referenceField(typed, input.field, 'backlinks.field');\n return { types, where, pathPrefix, field };\n}\n\nfunction keyPlan(typed: Typing, input: unknown, at: string, path: boolean): KeyPlan {\n if (input === 'room' || input === 'type' || (path && input === 'path')) return { of: input };\n if (plain(input) && typeof input.field === 'string' && Object.keys(input).length === 1) {\n specs(typed, input.field, place(at, 'field'));\n return { of: 'field', field: input.field };\n }\n return invalid(\n at,\n path ? 'expects room, path, type or a field' : 'expects room, type or a field',\n );\n}\n\nfunction direction(input: unknown, at: string): Direction {\n if (input === undefined) return 'asc';\n if (input !== 'asc' && input !== 'desc') invalid(at, 'expects asc or desc');\n return input;\n}\n\nfunction orderOptions(input: Entries, at: string): OrderOptions & { direction: Direction } {\n const options: OrderOptions & { direction: Direction } = {\n direction: direction(input.direction, place(at, 'direction')),\n };\n if (input.nulls !== undefined) {\n if (input.nulls !== 'first' && input.nulls !== 'last') {\n invalid(place(at, 'nulls'), 'expects first or last');\n }\n options.nulls = input.nulls;\n }\n if (input.stringSort !== undefined) {\n if (input.stringSort !== 'lexical' && input.stringSort !== 'locale') {\n invalid(place(at, 'stringSort'), 'expects lexical or locale');\n }\n options.stringSort = input.stringSort;\n }\n if (input.locale !== undefined) {\n if (typeof input.locale !== 'string' || !collates(input.locale, undefined)) {\n invalid(place(at, 'locale'), 'expects a locale name');\n }\n options.locale = input.locale;\n }\n if (input.localeOptions !== undefined) {\n if (!plain(input.localeOptions) || !collates(options.locale, input.localeOptions)) {\n invalid(place(at, 'localeOptions'), 'expects collation options');\n }\n options.localeOptions = input.localeOptions;\n }\n return options;\n}\n\nfunction collates(locale: string | undefined, options: Entries | undefined): boolean {\n try {\n ''.localeCompare('', locale, options);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction parts(typed: Typing, input: unknown, at: string, fields: boolean) {\n if (input === undefined) return null;\n if (input === 'all') return 'all';\n const named = list(input, at);\n named.forEach((name, index) => {\n if (typeof name !== 'string') invalid(`${at}[${index}]`, 'expects a name');\n if (fields) specs(typed, name, `${at}[${index}]`);\n });\n return named as readonly string[];\n}\n\nfunction flag(input: unknown, at: string): boolean {\n if (input === undefined) return false;\n if (input !== true) invalid(at, 'expects true');\n return true;\n}\n\nfunction documentShape(typed: Typing, input: Entries): DocumentShape {\n const orderBy = (input.orderBy === undefined ? [] : list(input.orderBy, 'orderBy')).map(\n (clause, index) => {\n const at = `orderBy[${index}]`;\n if (!plain(clause)) invalid(at, 'expects an order clause');\n known(clause, ORDER, at);\n return {\n key: keyPlan(typed, clause.by, place(at, 'by'), true),\n options: orderOptions(clause, at),\n };\n },\n );\n const select = input.select;\n if (select === 'all') {\n return {\n kind: 'documents',\n fields: 'all',\n sections: 'all',\n preamble: true,\n markdown: true,\n backlinks: true,\n orderBy,\n };\n }\n if (!plain(select)) invalid('select', \"expects 'all' or the parts to return\");\n known(select, PARTS, 'select');\n return {\n kind: 'documents',\n fields: parts(typed, select.fields, 'select.fields', true),\n sections: parts(typed, select.sections, 'select.sections', false),\n preamble: flag(select.preamble, 'select.preamble'),\n markdown: flag(select.markdown, 'select.markdown'),\n backlinks: flag(select.backlinks, 'select.backlinks'),\n orderBy,\n };\n}\n\nfunction groupShape(typed: Typing, input: Entries): GroupShape {\n const groupBy = list(input.groupBy, 'groupBy').map((key, index) =>\n keyPlan(typed, key, `groupBy[${index}]`, false),\n );\n if (groupBy.length === 0) invalid('groupBy', 'names no key');\n const grouped = groupBy.map((key) => JSON.stringify(key));\n const orderBy = (input.orderBy === undefined ? [] : list(input.orderBy, 'orderBy')).map(\n (clause, index) => {\n const at = `orderBy[${index}]`;\n if (!plain(clause)) invalid(at, 'expects an order clause');\n known(clause, ['by', 'direction'], at);\n const by =\n clause.by === 'count'\n ? ('count' as const)\n : grouped.indexOf(JSON.stringify(keyPlan(typed, clause.by, place(at, 'by'), false)));\n if (by === -1) invalid(place(at, 'by'), 'orders by a key the query does not group by');\n return { by, direction: direction(clause.direction, place(at, 'direction')) };\n },\n );\n return { kind: 'groups', groupBy, orderBy };\n}\n\nexport function planOf(input: unknown, facts: HeldRooms): Plan {\n if (!plain(input)) invalid('query', 'expects a query object');\n const grouped = input.groupBy !== undefined;\n if (grouped && input.select !== undefined) invalid('select', 'a grouped query selects nothing');\n if (!grouped && input.select === undefined) invalid('select', 'a Document query must select');\n known(input, [...FILTER, 'orderBy', 'limit', grouped ? 'groupBy' : 'select'], '');\n const limit = limitOf(input.limit);\n const rooms = input.rooms === undefined ? null : names(input.rooms, 'rooms');\n const { typed, ...root } = scope(facts, rooms, input, '');\n return {\n rooms,\n root,\n hop: input.hop === undefined ? null : hopOf(facts, rooms, typed, input.hop),\n backlinks: input.backlinks === undefined ? null : backlinksOf(facts, rooms, input.backlinks),\n shape: grouped ? groupShape(typed, input) : documentShape(typed, input),\n limit,\n };\n}\n\nexport function limitOf(input: unknown): number | null {\n if (input === undefined) return null;\n if (!Number.isSafeInteger(input) || (input as number) < 0) {\n invalid('limit', 'expects a nonnegative integer');\n }\n return input as number;\n}\n\nexport function filterOf(input: unknown, facts: HeldRooms): Plan {\n if (!plain(input)) invalid('documents', 'expects a filter object');\n known(input, FILTER, '');\n return planOf({ ...input, select: {} }, facts);\n}\n\nfunction canonical(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(canonical).join(',')}]`;\n if (typeof value === 'object' && value !== null) {\n return `{${Object.keys(value)\n .sort()\n .map((name) => `${JSON.stringify(name)}:${canonical((value as Entries)[name])}`)\n .join(',')}}`;\n }\n return JSON.stringify(value);\n}\n\nexport function identityOf(plan: Plan): string {\n return canonical(plan);\n}\n"],"names":["normalize","QueryError","Error","code","at","problem","RANGE","SINGLE","FILTER","RELATED","PARTS","ORDER","CALENDAR_DATE","invalid","place","name","plain","value","Array","isArray","Object","getPrototypeOf","prototype","known","allowed","keys","includes","list","input","Number","isFinite","values","map","item","index","names","listed","some","Set","sort","directory","calendarDate","match","exec","year","month","day","slice","date","Date","UTC","getUTCFullYear","getUTCMonth","getUTCDate","fits","spec","kind","of","reference","typing","facts","rooms","types","read","filter","room","locator","acquiring","available","every","declared","flatMap","type","untyped","specs","typed","field","hasOwn","fields","length","checked","JSON","stringify","test","equal","op","operators","operator","stray","find","undefined","bounds","bound","where","operand","compared","forEach","isSafeInteger","size","exists","condition","conditions","entry","nested","push","startsWith","scope","pathPrefix","referenceField","hopOf","root","backlinksOf","keyPlan","path","direction","orderOptions","options","nulls","stringSort","locale","collates","localeOptions","localeCompare","parts","named","flag","documentShape","orderBy","clause","key","by","select","sections","preamble","markdown","backlinks","groupShape","groupBy","grouped","indexOf","planOf","limit","limitOf","hop","shape","filterOf","canonical","join","identityOf","plan"],"mappings":"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"}
@@ -1,9 +1,12 @@
1
1
  import type { ChangeSet } from './change-set.js';
2
2
  import type { Plan, QueryResult } from './query.js';
3
+ import type { SearchedDocument } from './search.js';
3
4
  export type ReadSide = {
4
5
  apply(set: ChangeSet): void;
5
6
  query(plan: Plan): Promise<QueryResult>;
6
7
  observe(plan: Plan, identity: string, listener: (result: QueryResult) => void): () => void;
8
+ documents(): readonly SearchedDocument[];
9
+ document(room: string, path: string): SearchedDocument | null;
7
10
  close(): void;
8
11
  };
9
12
  export declare function createReadSide(): ReadSide;
@@ -1 +1 @@
1
- {"version":3,"file":"read-side.d.ts","sourceRoot":"","sources":["../src/read-side.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAOV,IAAI,EAEJ,WAAW,EAIZ,MAAM,YAAY,CAAC;AAqDpB,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACxC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC3F,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AAqPF,wBAAgB,cAAc,IAAI,QAAQ,CAgGzC"}
1
+ {"version":3,"file":"read-side.d.ts","sourceRoot":"","sources":["../src/read-side.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAOV,IAAI,EAEJ,WAAW,EAIZ,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAoDpD,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACxC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC3F,SAAS,IAAI,SAAS,gBAAgB,EAAE,CAAC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAC9D,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AAqPF,wBAAgB,cAAc,IAAI,QAAQ,CAmHzC"}
package/dist/read-side.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { and, BasicIndex, configureIndexDevMode, count, createCollection, createLiveQueryCollection, deepEquals, eq, gt, gte, inArray, isNull, isUndefined, lt, lte, not, or, toArray } from '@tanstack/db';
2
+ import { documentKey } from './rows.js';
2
3
  function every(expressions) {
3
4
  const [first, second, ...rest] = expressions;
4
5
  return second === undefined ? first : and(first, second, ...rest);
@@ -287,6 +288,17 @@ export function createReadSide() {
287
288
  }
288
289
  });
289
290
  const shared = new Map();
291
+ function searched(row) {
292
+ const body = rows.get(row.body);
293
+ return {
294
+ room: row.room,
295
+ path: row.path,
296
+ type: row.type,
297
+ fields: row.fields,
298
+ preamble: body.preamble,
299
+ sections: body.sections
300
+ };
301
+ }
290
302
  function publish(entry) {
291
303
  const next = resultOf(entry.plan, entry.built.live.toArray);
292
304
  if (deepEquals(entry.result, next)) return;
@@ -359,6 +371,13 @@ export function createReadSide() {
359
371
  observed.subscription = null;
360
372
  };
361
373
  },
374
+ documents () {
375
+ return rows.toArray.filter((row)=>row.kind === 'document').map(searched);
376
+ },
377
+ document (room, path) {
378
+ const row = rows.get(documentKey(room, path));
379
+ return row === undefined ? null : searched(row);
380
+ },
362
381
  close () {
363
382
  for (const entry of shared.values()){
364
383
  entry.listeners.clear();
@@ -1 +1 @@
1
- {"version":3,"sources":["/workspace/packages/mdruntime/src/read-side.ts"],"sourcesContent":["import {\n and,\n BasicIndex,\n configureIndexDevMode,\n count,\n createCollection,\n createLiveQueryCollection,\n deepEquals,\n eq,\n gt,\n gte,\n inArray,\n isNull,\n isUndefined,\n lt,\n lte,\n not,\n or,\n toArray,\n type Collection,\n type Context,\n type InitialQueryBuilder,\n type QueryBuilder,\n type Ref,\n type SyncConfig,\n} from '@tanstack/db';\nimport type { ChangeSet } from './change-set.js';\nimport type {\n Condition,\n Direction,\n DocumentShape,\n GroupShape,\n KeyPlan,\n OrderOptions,\n Plan,\n QueryDocument,\n QueryResult,\n Scope,\n Test,\n Value,\n} from './query.js';\nimport type { Row } from './rows.js';\n\ntype Stored = {\n key: string;\n kind: string;\n room: string;\n path: string;\n type: string;\n body: string;\n source: string;\n target: string;\n field: string;\n fields: Readonly<Record<string, unknown>>;\n values: Readonly<Record<string, unknown>>;\n sizes: Readonly<Record<string, number>>;\n directories: readonly string[];\n preamble: string;\n sections: Readonly<Record<string, string>>;\n markdown: string;\n} & Readonly<Record<string, unknown>>;\n\ntype Reference = Ref<Stored>;\n\ntype Field = Reference['values'][string];\n\ntype Size = Reference['sizes'][string];\n\ntype Refs = Readonly<Record<string, Reference>>;\n\ntype Expression = ReturnType<typeof eq>;\n\ntype Builder = {\n where(callback: (refs: Refs) => Expression): Builder;\n innerJoin(source: Readonly<Record<string, unknown>>, on: (refs: Refs) => Expression): Builder;\n groupBy(callback: (refs: Refs) => unknown): Builder;\n orderBy(callback: (refs: Refs) => unknown, options: Direction | OrderOptions): Builder;\n limit(count: number): Builder;\n select(callback: (refs: Refs) => object): object;\n};\n\ntype Live = Collection<Stored, string | number>;\n\ntype Built = { live: Live; dispose(): void };\n\ntype Shared = {\n plan: Plan;\n built: Built;\n result: QueryResult | undefined;\n listeners: Set<(result: QueryResult) => void>;\n subscription: { unsubscribe(): void } | null;\n};\n\nexport type ReadSide = {\n apply(set: ChangeSet): void;\n query(plan: Plan): Promise<QueryResult>;\n observe(plan: Plan, identity: string, listener: (result: QueryResult) => void): () => void;\n close(): void;\n};\n\nfunction every(expressions: readonly Expression[]): Expression {\n const [first, second, ...rest] = expressions;\n return second === undefined ? first : and(first, second, ...rest);\n}\n\nfunction some(expressions: readonly Expression[]): Expression {\n const [first, second, ...rest] = expressions;\n return second === undefined ? first : or(first, second, ...rest);\n}\n\nfunction equal(field: Field, value: Exclude<Value, null>): Expression {\n return or(eq(field, value), inArray(value, field));\n}\n\nfunction tested(test: Test, field: Field, size: Size, written: Field): Expression {\n if (test.op === 'eq') return test.value === null ? isNull(field) : equal(field, test.value);\n if (test.op === 'ne') {\n return test.value === null\n ? not(isNull(field))\n : or(isUndefined(field), isNull(field), not(equal(field, test.value)));\n }\n if (test.op === 'in' || test.op === 'nin') {\n const matches =\n test.values.length === 0\n ? inArray(field, [])\n : some(test.values.map((value) => (value === null ? isNull(field) : equal(field, value))));\n if (test.op === 'in') return matches;\n return some([\n isUndefined(field),\n ...(test.values.includes(null) ? [] : [isNull(field)]),\n not(matches),\n ]);\n }\n if (test.op === 'range') {\n const compare = { gt, gte, lt, lte };\n return every(test.bounds.map(([operator, bound]) => compare[operator](field, bound)));\n }\n if (test.op === 'all') {\n return every([not(isUndefined(size)), ...test.values.map((value) => inArray(value, field))]);\n }\n if (test.op === 'size') return eq(size, test.size);\n return test.exists ? not(isUndefined(written)) : isUndefined(written);\n}\n\nfunction conditioned(condition: Condition, row: Reference): Expression {\n if ('every' in condition) return every(condition.every.map((item) => conditioned(item, row)));\n if ('some' in condition) return some(condition.some.map((item) => conditioned(item, row)));\n return tested(\n condition.test,\n row.values[condition.field],\n row.sizes[condition.field],\n row.fields[condition.field],\n );\n}\n\nfunction scoped(scope: Scope, row: Reference, rooms: readonly string[] | null): Expression {\n return every([\n eq(row.kind, 'document'),\n ...(rooms === null ? [] : [inArray(row.room, [...rooms])]),\n ...(scope.types === null ? [] : [inArray(row.type, [...scope.types])]),\n ...(scope.pathPrefix === null ? [] : [inArray(scope.pathPrefix, row.directories)]),\n ...(scope.where === null ? [] : [conditioned(scope.where, row)]),\n ]);\n}\n\nfunction keyed(key: KeyPlan, row: Reference): Field | Reference['room'] {\n return key.of === 'field' ? row.values[key.field] : row[key.of];\n}\n\nfunction live(query: (q: InitialQueryBuilder) => object): Live {\n return createLiveQueryCollection({\n query: query as (q: InitialQueryBuilder) => QueryBuilder<Context>,\n startSync: true,\n }) as unknown as Live;\n}\n\nfunction related(\n q: InitialQueryBuilder,\n rows: Collection<Stored, string>,\n scope: Scope,\n field: string | null,\n kept: 'source' | 'target',\n): object {\n const matched = kept === 'source' ? 'target' : 'source';\n const from: Builder = q.from({ r: rows });\n return from\n .where(({ r }) =>\n every([eq(r.kind, 'reference'), ...(field === null ? [] : [eq(r.field, field)])]),\n )\n .innerJoin({ m: rows }, ({ r, m }) => eq(r[matched], m.key))\n .where(({ m }) => scoped(scope, m, null))\n .groupBy(({ r }) => r[kept])\n .select(({ r }) => ({ key: r[kept] }));\n}\n\nfunction filtered(q: InitialQueryBuilder, rows: Collection<Stored, string>, plan: Plan): Builder {\n const from: Builder = q.from({ d: rows });\n let query = from.where(({ d }) => scoped(plan.root, d, plan.rooms));\n if (plan.hop !== null) {\n const hop = related(q, rows, plan.hop, plan.hop.field, 'source');\n query = query.innerJoin({ h: hop }, ({ d, h }) => eq(d.key, h.key));\n }\n if (plan.backlinks !== null) {\n const backlinks = related(q, rows, plan.backlinks, plan.backlinks.field, 'target');\n query = query.innerJoin({ k: backlinks }, ({ d, k }) => eq(d.key, k.key));\n }\n return query;\n}\n\nfunction named<T>(prefix: string, names: readonly string[], source: Readonly<Record<string, T>>) {\n return Object.fromEntries(names.map((name, index) => [`${prefix}${index}`, source[name]]));\n}\n\nfunction documents(\n q: InitialQueryBuilder,\n rows: Collection<Stored, string>,\n plan: Plan,\n shape: DocumentShape,\n): object {\n let query = filtered(q, rows, plan);\n if (shape.sections !== null || shape.preamble || shape.markdown) {\n query = query.innerJoin({ b: rows }, ({ d, b }) => eq(d.body, b.key));\n }\n for (const { key, options } of shape.orderBy) {\n query = query.orderBy(({ d }) => keyed(key, d), options);\n }\n if (shape.orderBy.length === 0 && plan.limit !== null) {\n query = query.orderBy(({ d }) => d.key, { stringSort: 'lexical' });\n }\n if (plan.limit !== null) query = query.limit(plan.limit);\n return query.select(({ d, b }) => ({\n room: d.room,\n path: d.path,\n type: d.type,\n ...(shape.fields === 'all' ? { fields: d.fields } : {}),\n ...(Array.isArray(shape.fields) ? named('field', shape.fields, d.fields) : {}),\n ...(shape.sections === 'all' ? { sections: b.sections } : {}),\n ...(Array.isArray(shape.sections) ? named('section', shape.sections, b.sections) : {}),\n ...(shape.preamble ? { preamble: b.preamble } : {}),\n ...(shape.markdown ? { markdown: b.markdown } : {}),\n ...(shape.backlinks ? { backlinks: toArray(backlinked(q, rows, d)) } : {}),\n }));\n}\n\nfunction backlinked(q: InitialQueryBuilder, rows: Collection<Stored, string>, document: Reference) {\n const from: Builder = q.from({ r: rows });\n return from\n .where(({ r }) => eq(r.target, document.key))\n .orderBy(({ r }) => r.path, { stringSort: 'lexical' })\n .orderBy(({ r }) => r.field, { stringSort: 'lexical' })\n .select(({ r }) => ({ path: r.path, type: r.type, field: r.field })) as QueryBuilder<Context>;\n}\n\nfunction groups(q: InitialQueryBuilder, stage: Live, shape: GroupShape, limit: number | null) {\n const keys = shape.groupBy.map((_, index) => `key${index}`);\n const from: Builder = q.from({ m: stage });\n let query = from.groupBy(({ m }) => keys.map((key) => m[key]));\n for (const { by, direction } of shape.orderBy) {\n query = query.orderBy(({ m }) => (by === 'count' ? count(m.key) : m[keys[by]]), direction);\n }\n if (limit !== null && shape.orderBy.length > 0) query = query.limit(limit);\n return query.select(({ m }) => ({\n ...Object.fromEntries(keys.map((key) => [key, m[key]])),\n count: count(m.key),\n }));\n}\n\nfunction built(rows: Collection<Stored, string>, plan: Plan): Built {\n const shape = plan.shape;\n if (shape.kind === 'documents') {\n const collection = live((q) => documents(q, rows, plan, shape));\n return { live: collection, dispose: () => void collection.cleanup() };\n }\n const stage = live((q) =>\n filtered(q, rows, plan).select(({ d }) => ({\n key: d.key,\n ...Object.fromEntries(shape.groupBy.map((key, index) => [`key${index}`, keyed(key, d)])),\n })),\n );\n const collection = live((q) => groups(q, stage, shape, plan.limit));\n return {\n live: collection,\n dispose: () => {\n void collection.cleanup();\n void stage.cleanup();\n },\n };\n}\n\nfunction present(entries: readonly (readonly [string, unknown])[]) {\n return Object.fromEntries(entries.filter(([, value]) => value !== undefined));\n}\n\nfunction part(\n row: Readonly<Record<string, unknown>>,\n prefix: string,\n names: 'all' | readonly string[],\n whole: unknown,\n) {\n if (names === 'all') return whole;\n return present(names.map((name, index) => [name, row[`${prefix}${index}`]] as const));\n}\n\nfunction documentOf(row: Readonly<Record<string, unknown>>, shape: DocumentShape): QueryDocument {\n return {\n room: row.room as string,\n path: row.path as string,\n type: row.type as string,\n ...(shape.fields === null\n ? {}\n : { fields: part(row, 'field', shape.fields, row.fields) as QueryDocument['fields'] }),\n ...(shape.sections === null\n ? {}\n : {\n sections: part(row, 'section', shape.sections, row.sections) as QueryDocument['sections'],\n }),\n ...(shape.preamble ? { preamble: row.preamble as string } : {}),\n ...(shape.markdown ? { markdown: row.markdown as string } : {}),\n ...(shape.backlinks\n ? {\n backlinks: (row.backlinks as readonly Readonly<Record<string, string>>[]).map(\n ({ path, type, field }) => ({ path, type, field }),\n ),\n }\n : {}),\n };\n}\n\nfunction resultOf(plan: Plan, rows: readonly Readonly<Record<string, unknown>>[]): QueryResult {\n const shape = plan.shape;\n if (shape.kind === 'documents') {\n return structuredClone({ documents: rows.map((row) => documentOf(row, shape)) });\n }\n const bounded =\n shape.orderBy.length === 0 && plan.limit !== null ? rows.slice(0, plan.limit) : rows;\n return structuredClone({\n groups: bounded.map((row) => ({\n key: shape.groupBy.map((_, index) => row[`key${index}`]),\n count: row.count as number,\n })),\n });\n}\n\nexport function createReadSide(): ReadSide {\n configureIndexDevMode({ enabled: false });\n let sync!: Parameters<SyncConfig<Stored, string>['sync']>[0];\n const rows = createCollection<Stored, string>({\n getKey: (row) => row.key,\n gcTime: 0,\n startSync: true,\n autoIndex: 'eager',\n defaultIndexType: BasicIndex,\n sync: {\n rowUpdateMode: 'full',\n sync: (params) => {\n sync = params;\n params.markReady();\n },\n },\n });\n const shared = new Map<string, Shared>();\n\n function publish(entry: Shared) {\n const next = resultOf(entry.plan, entry.built.live.toArray);\n if (deepEquals(entry.result, next)) return;\n entry.result = next;\n for (const listener of entry.listeners) listener(next);\n }\n\n return {\n apply(set) {\n const next = new Map<string, Row | null>();\n for (const change of set.documents) {\n for (const row of change.before) next.set(row.key, null);\n for (const row of change.after) next.set(row.key, row);\n }\n if (next.size === 0) return;\n sync.begin();\n for (const [key, row] of next) {\n if (row === null) {\n if (rows.has(key)) sync.write({ type: 'delete', key });\n continue;\n }\n sync.write({ type: rows.has(key) ? 'update' : 'insert', value: row as Stored });\n }\n sync.commit();\n },\n async query(plan) {\n const { live: collection, dispose } = built(rows, plan);\n try {\n return resultOf(plan, await collection.toArrayWhenReady());\n } finally {\n dispose();\n }\n },\n observe(plan, identity, listener) {\n let entry = shared.get(identity);\n if (entry === undefined) {\n const created: Shared = {\n plan,\n built: built(rows, plan),\n result: undefined,\n listeners: new Set(),\n subscription: null,\n };\n created.built.live.on('status:change', ({ status }) => {\n if (status === 'cleaned-up' && created.listeners.size === 0) shared.delete(identity);\n });\n shared.set(identity, created);\n entry = created;\n }\n const observed = entry;\n observed.listeners.add(listener);\n observed.built.live.onFirstReady(() => {\n if (!observed.listeners.has(listener)) return;\n if (observed.subscription === null) {\n observed.result = resultOf(observed.plan, observed.built.live.toArray);\n observed.subscription = observed.built.live.subscribeChanges(() => {\n publish(observed);\n });\n }\n listener(observed.result as QueryResult);\n });\n return () => {\n if (!observed.listeners.delete(listener) || observed.listeners.size > 0) return;\n observed.subscription?.unsubscribe();\n observed.subscription = null;\n };\n },\n close() {\n for (const entry of shared.values()) {\n entry.listeners.clear();\n entry.subscription?.unsubscribe();\n entry.built.dispose();\n }\n shared.clear();\n void rows.cleanup();\n },\n };\n}\n"],"names":["and","BasicIndex","configureIndexDevMode","count","createCollection","createLiveQueryCollection","deepEquals","eq","gt","gte","inArray","isNull","isUndefined","lt","lte","not","or","toArray","every","expressions","first","second","rest","undefined","some","equal","field","value","tested","test","size","written","op","matches","values","length","map","includes","compare","bounds","operator","bound","exists","conditioned","condition","row","item","sizes","fields","scoped","scope","rooms","kind","room","types","type","pathPrefix","directories","where","keyed","key","of","live","query","startSync","related","q","rows","kept","matched","from","r","innerJoin","m","groupBy","select","filtered","plan","d","root","hop","h","backlinks","k","named","prefix","names","source","Object","fromEntries","name","index","documents","shape","sections","preamble","markdown","b","body","options","orderBy","limit","stringSort","path","Array","isArray","backlinked","document","target","groups","stage","keys","_","by","direction","built","collection","dispose","cleanup","present","entries","filter","part","whole","documentOf","resultOf","structuredClone","bounded","slice","createReadSide","enabled","sync","getKey","gcTime","autoIndex","defaultIndexType","rowUpdateMode","params","markReady","shared","Map","publish","entry","next","result","listener","listeners","apply","set","change","before","after","begin","has","write","commit","toArrayWhenReady","observe","identity","get","created","Set","subscription","on","status","delete","observed","add","onFirstReady","subscribeChanges","unsubscribe","close","clear"],"mappings":"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"}
1
+ {"version":3,"sources":["/workspace/packages/mdruntime/src/read-side.ts"],"sourcesContent":["import {\n and,\n BasicIndex,\n configureIndexDevMode,\n count,\n createCollection,\n createLiveQueryCollection,\n deepEquals,\n eq,\n gt,\n gte,\n inArray,\n isNull,\n isUndefined,\n lt,\n lte,\n not,\n or,\n toArray,\n type Collection,\n type Context,\n type InitialQueryBuilder,\n type QueryBuilder,\n type Ref,\n type SyncConfig,\n} from '@tanstack/db';\nimport type { ChangeSet } from './change-set.js';\nimport type {\n Condition,\n Direction,\n DocumentShape,\n GroupShape,\n KeyPlan,\n OrderOptions,\n Plan,\n QueryDocument,\n QueryResult,\n Scope,\n Test,\n Value,\n} from './query.js';\nimport { documentKey, type Row } from './rows.js';\nimport type { SearchedDocument } from './search.js';\n\ntype Stored = {\n key: string;\n kind: string;\n room: string;\n path: string;\n type: string;\n body: string;\n source: string;\n target: string;\n field: string;\n fields: Readonly<Record<string, unknown>>;\n values: Readonly<Record<string, unknown>>;\n sizes: Readonly<Record<string, number>>;\n directories: readonly string[];\n preamble: string;\n sections: Readonly<Record<string, string>>;\n markdown: string;\n} & Readonly<Record<string, unknown>>;\n\ntype Reference = Ref<Stored>;\n\ntype Field = Reference['values'][string];\n\ntype Size = Reference['sizes'][string];\n\ntype Refs = Readonly<Record<string, Reference>>;\n\ntype Expression = ReturnType<typeof eq>;\n\ntype Builder = {\n where(callback: (refs: Refs) => Expression): Builder;\n innerJoin(source: Readonly<Record<string, unknown>>, on: (refs: Refs) => Expression): Builder;\n groupBy(callback: (refs: Refs) => unknown): Builder;\n orderBy(callback: (refs: Refs) => unknown, options: Direction | OrderOptions): Builder;\n limit(count: number): Builder;\n select(callback: (refs: Refs) => object): object;\n};\n\ntype Live = Collection<Stored, string | number>;\n\ntype Built = { live: Live; dispose(): void };\n\ntype Shared = {\n plan: Plan;\n built: Built;\n result: QueryResult | undefined;\n listeners: Set<(result: QueryResult) => void>;\n subscription: { unsubscribe(): void } | null;\n};\n\nexport type ReadSide = {\n apply(set: ChangeSet): void;\n query(plan: Plan): Promise<QueryResult>;\n observe(plan: Plan, identity: string, listener: (result: QueryResult) => void): () => void;\n documents(): readonly SearchedDocument[];\n document(room: string, path: string): SearchedDocument | null;\n close(): void;\n};\n\nfunction every(expressions: readonly Expression[]): Expression {\n const [first, second, ...rest] = expressions;\n return second === undefined ? first : and(first, second, ...rest);\n}\n\nfunction some(expressions: readonly Expression[]): Expression {\n const [first, second, ...rest] = expressions;\n return second === undefined ? first : or(first, second, ...rest);\n}\n\nfunction equal(field: Field, value: Exclude<Value, null>): Expression {\n return or(eq(field, value), inArray(value, field));\n}\n\nfunction tested(test: Test, field: Field, size: Size, written: Field): Expression {\n if (test.op === 'eq') return test.value === null ? isNull(field) : equal(field, test.value);\n if (test.op === 'ne') {\n return test.value === null\n ? not(isNull(field))\n : or(isUndefined(field), isNull(field), not(equal(field, test.value)));\n }\n if (test.op === 'in' || test.op === 'nin') {\n const matches =\n test.values.length === 0\n ? inArray(field, [])\n : some(test.values.map((value) => (value === null ? isNull(field) : equal(field, value))));\n if (test.op === 'in') return matches;\n return some([\n isUndefined(field),\n ...(test.values.includes(null) ? [] : [isNull(field)]),\n not(matches),\n ]);\n }\n if (test.op === 'range') {\n const compare = { gt, gte, lt, lte };\n return every(test.bounds.map(([operator, bound]) => compare[operator](field, bound)));\n }\n if (test.op === 'all') {\n return every([not(isUndefined(size)), ...test.values.map((value) => inArray(value, field))]);\n }\n if (test.op === 'size') return eq(size, test.size);\n return test.exists ? not(isUndefined(written)) : isUndefined(written);\n}\n\nfunction conditioned(condition: Condition, row: Reference): Expression {\n if ('every' in condition) return every(condition.every.map((item) => conditioned(item, row)));\n if ('some' in condition) return some(condition.some.map((item) => conditioned(item, row)));\n return tested(\n condition.test,\n row.values[condition.field],\n row.sizes[condition.field],\n row.fields[condition.field],\n );\n}\n\nfunction scoped(scope: Scope, row: Reference, rooms: readonly string[] | null): Expression {\n return every([\n eq(row.kind, 'document'),\n ...(rooms === null ? [] : [inArray(row.room, [...rooms])]),\n ...(scope.types === null ? [] : [inArray(row.type, [...scope.types])]),\n ...(scope.pathPrefix === null ? [] : [inArray(scope.pathPrefix, row.directories)]),\n ...(scope.where === null ? [] : [conditioned(scope.where, row)]),\n ]);\n}\n\nfunction keyed(key: KeyPlan, row: Reference): Field | Reference['room'] {\n return key.of === 'field' ? row.values[key.field] : row[key.of];\n}\n\nfunction live(query: (q: InitialQueryBuilder) => object): Live {\n return createLiveQueryCollection({\n query: query as (q: InitialQueryBuilder) => QueryBuilder<Context>,\n startSync: true,\n }) as unknown as Live;\n}\n\nfunction related(\n q: InitialQueryBuilder,\n rows: Collection<Stored, string>,\n scope: Scope,\n field: string | null,\n kept: 'source' | 'target',\n): object {\n const matched = kept === 'source' ? 'target' : 'source';\n const from: Builder = q.from({ r: rows });\n return from\n .where(({ r }) =>\n every([eq(r.kind, 'reference'), ...(field === null ? [] : [eq(r.field, field)])]),\n )\n .innerJoin({ m: rows }, ({ r, m }) => eq(r[matched], m.key))\n .where(({ m }) => scoped(scope, m, null))\n .groupBy(({ r }) => r[kept])\n .select(({ r }) => ({ key: r[kept] }));\n}\n\nfunction filtered(q: InitialQueryBuilder, rows: Collection<Stored, string>, plan: Plan): Builder {\n const from: Builder = q.from({ d: rows });\n let query = from.where(({ d }) => scoped(plan.root, d, plan.rooms));\n if (plan.hop !== null) {\n const hop = related(q, rows, plan.hop, plan.hop.field, 'source');\n query = query.innerJoin({ h: hop }, ({ d, h }) => eq(d.key, h.key));\n }\n if (plan.backlinks !== null) {\n const backlinks = related(q, rows, plan.backlinks, plan.backlinks.field, 'target');\n query = query.innerJoin({ k: backlinks }, ({ d, k }) => eq(d.key, k.key));\n }\n return query;\n}\n\nfunction named<T>(prefix: string, names: readonly string[], source: Readonly<Record<string, T>>) {\n return Object.fromEntries(names.map((name, index) => [`${prefix}${index}`, source[name]]));\n}\n\nfunction documents(\n q: InitialQueryBuilder,\n rows: Collection<Stored, string>,\n plan: Plan,\n shape: DocumentShape,\n): object {\n let query = filtered(q, rows, plan);\n if (shape.sections !== null || shape.preamble || shape.markdown) {\n query = query.innerJoin({ b: rows }, ({ d, b }) => eq(d.body, b.key));\n }\n for (const { key, options } of shape.orderBy) {\n query = query.orderBy(({ d }) => keyed(key, d), options);\n }\n if (shape.orderBy.length === 0 && plan.limit !== null) {\n query = query.orderBy(({ d }) => d.key, { stringSort: 'lexical' });\n }\n if (plan.limit !== null) query = query.limit(plan.limit);\n return query.select(({ d, b }) => ({\n room: d.room,\n path: d.path,\n type: d.type,\n ...(shape.fields === 'all' ? { fields: d.fields } : {}),\n ...(Array.isArray(shape.fields) ? named('field', shape.fields, d.fields) : {}),\n ...(shape.sections === 'all' ? { sections: b.sections } : {}),\n ...(Array.isArray(shape.sections) ? named('section', shape.sections, b.sections) : {}),\n ...(shape.preamble ? { preamble: b.preamble } : {}),\n ...(shape.markdown ? { markdown: b.markdown } : {}),\n ...(shape.backlinks ? { backlinks: toArray(backlinked(q, rows, d)) } : {}),\n }));\n}\n\nfunction backlinked(q: InitialQueryBuilder, rows: Collection<Stored, string>, document: Reference) {\n const from: Builder = q.from({ r: rows });\n return from\n .where(({ r }) => eq(r.target, document.key))\n .orderBy(({ r }) => r.path, { stringSort: 'lexical' })\n .orderBy(({ r }) => r.field, { stringSort: 'lexical' })\n .select(({ r }) => ({ path: r.path, type: r.type, field: r.field })) as QueryBuilder<Context>;\n}\n\nfunction groups(q: InitialQueryBuilder, stage: Live, shape: GroupShape, limit: number | null) {\n const keys = shape.groupBy.map((_, index) => `key${index}`);\n const from: Builder = q.from({ m: stage });\n let query = from.groupBy(({ m }) => keys.map((key) => m[key]));\n for (const { by, direction } of shape.orderBy) {\n query = query.orderBy(({ m }) => (by === 'count' ? count(m.key) : m[keys[by]]), direction);\n }\n if (limit !== null && shape.orderBy.length > 0) query = query.limit(limit);\n return query.select(({ m }) => ({\n ...Object.fromEntries(keys.map((key) => [key, m[key]])),\n count: count(m.key),\n }));\n}\n\nfunction built(rows: Collection<Stored, string>, plan: Plan): Built {\n const shape = plan.shape;\n if (shape.kind === 'documents') {\n const collection = live((q) => documents(q, rows, plan, shape));\n return { live: collection, dispose: () => void collection.cleanup() };\n }\n const stage = live((q) =>\n filtered(q, rows, plan).select(({ d }) => ({\n key: d.key,\n ...Object.fromEntries(shape.groupBy.map((key, index) => [`key${index}`, keyed(key, d)])),\n })),\n );\n const collection = live((q) => groups(q, stage, shape, plan.limit));\n return {\n live: collection,\n dispose: () => {\n void collection.cleanup();\n void stage.cleanup();\n },\n };\n}\n\nfunction present(entries: readonly (readonly [string, unknown])[]) {\n return Object.fromEntries(entries.filter(([, value]) => value !== undefined));\n}\n\nfunction part(\n row: Readonly<Record<string, unknown>>,\n prefix: string,\n names: 'all' | readonly string[],\n whole: unknown,\n) {\n if (names === 'all') return whole;\n return present(names.map((name, index) => [name, row[`${prefix}${index}`]] as const));\n}\n\nfunction documentOf(row: Readonly<Record<string, unknown>>, shape: DocumentShape): QueryDocument {\n return {\n room: row.room as string,\n path: row.path as string,\n type: row.type as string,\n ...(shape.fields === null\n ? {}\n : { fields: part(row, 'field', shape.fields, row.fields) as QueryDocument['fields'] }),\n ...(shape.sections === null\n ? {}\n : {\n sections: part(row, 'section', shape.sections, row.sections) as QueryDocument['sections'],\n }),\n ...(shape.preamble ? { preamble: row.preamble as string } : {}),\n ...(shape.markdown ? { markdown: row.markdown as string } : {}),\n ...(shape.backlinks\n ? {\n backlinks: (row.backlinks as readonly Readonly<Record<string, string>>[]).map(\n ({ path, type, field }) => ({ path, type, field }),\n ),\n }\n : {}),\n };\n}\n\nfunction resultOf(plan: Plan, rows: readonly Readonly<Record<string, unknown>>[]): QueryResult {\n const shape = plan.shape;\n if (shape.kind === 'documents') {\n return structuredClone({ documents: rows.map((row) => documentOf(row, shape)) });\n }\n const bounded =\n shape.orderBy.length === 0 && plan.limit !== null ? rows.slice(0, plan.limit) : rows;\n return structuredClone({\n groups: bounded.map((row) => ({\n key: shape.groupBy.map((_, index) => row[`key${index}`]),\n count: row.count as number,\n })),\n });\n}\n\nexport function createReadSide(): ReadSide {\n configureIndexDevMode({ enabled: false });\n let sync!: Parameters<SyncConfig<Stored, string>['sync']>[0];\n const rows = createCollection<Stored, string>({\n getKey: (row) => row.key,\n gcTime: 0,\n startSync: true,\n autoIndex: 'eager',\n defaultIndexType: BasicIndex,\n sync: {\n rowUpdateMode: 'full',\n sync: (params) => {\n sync = params;\n params.markReady();\n },\n },\n });\n const shared = new Map<string, Shared>();\n\n function searched(row: Stored): SearchedDocument {\n const body = rows.get(row.body) as Stored;\n return {\n room: row.room,\n path: row.path,\n type: row.type,\n fields: row.fields,\n preamble: body.preamble,\n sections: body.sections,\n };\n }\n\n function publish(entry: Shared) {\n const next = resultOf(entry.plan, entry.built.live.toArray);\n if (deepEquals(entry.result, next)) return;\n entry.result = next;\n for (const listener of entry.listeners) listener(next);\n }\n\n return {\n apply(set) {\n const next = new Map<string, Row | null>();\n for (const change of set.documents) {\n for (const row of change.before) next.set(row.key, null);\n for (const row of change.after) next.set(row.key, row);\n }\n if (next.size === 0) return;\n sync.begin();\n for (const [key, row] of next) {\n if (row === null) {\n if (rows.has(key)) sync.write({ type: 'delete', key });\n continue;\n }\n sync.write({ type: rows.has(key) ? 'update' : 'insert', value: row as Stored });\n }\n sync.commit();\n },\n async query(plan) {\n const { live: collection, dispose } = built(rows, plan);\n try {\n return resultOf(plan, await collection.toArrayWhenReady());\n } finally {\n dispose();\n }\n },\n observe(plan, identity, listener) {\n let entry = shared.get(identity);\n if (entry === undefined) {\n const created: Shared = {\n plan,\n built: built(rows, plan),\n result: undefined,\n listeners: new Set(),\n subscription: null,\n };\n created.built.live.on('status:change', ({ status }) => {\n if (status === 'cleaned-up' && created.listeners.size === 0) shared.delete(identity);\n });\n shared.set(identity, created);\n entry = created;\n }\n const observed = entry;\n observed.listeners.add(listener);\n observed.built.live.onFirstReady(() => {\n if (!observed.listeners.has(listener)) return;\n if (observed.subscription === null) {\n observed.result = resultOf(observed.plan, observed.built.live.toArray);\n observed.subscription = observed.built.live.subscribeChanges(() => {\n publish(observed);\n });\n }\n listener(observed.result as QueryResult);\n });\n return () => {\n if (!observed.listeners.delete(listener) || observed.listeners.size > 0) return;\n observed.subscription?.unsubscribe();\n observed.subscription = null;\n };\n },\n documents() {\n return rows.toArray.filter((row) => row.kind === 'document').map(searched);\n },\n document(room, path) {\n const row = rows.get(documentKey(room, path));\n return row === undefined ? null : searched(row);\n },\n close() {\n for (const entry of shared.values()) {\n entry.listeners.clear();\n entry.subscription?.unsubscribe();\n entry.built.dispose();\n }\n shared.clear();\n void rows.cleanup();\n },\n };\n}\n"],"names":["and","BasicIndex","configureIndexDevMode","count","createCollection","createLiveQueryCollection","deepEquals","eq","gt","gte","inArray","isNull","isUndefined","lt","lte","not","or","toArray","documentKey","every","expressions","first","second","rest","undefined","some","equal","field","value","tested","test","size","written","op","matches","values","length","map","includes","compare","bounds","operator","bound","exists","conditioned","condition","row","item","sizes","fields","scoped","scope","rooms","kind","room","types","type","pathPrefix","directories","where","keyed","key","of","live","query","startSync","related","q","rows","kept","matched","from","r","innerJoin","m","groupBy","select","filtered","plan","d","root","hop","h","backlinks","k","named","prefix","names","source","Object","fromEntries","name","index","documents","shape","sections","preamble","markdown","b","body","options","orderBy","limit","stringSort","path","Array","isArray","backlinked","document","target","groups","stage","keys","_","by","direction","built","collection","dispose","cleanup","present","entries","filter","part","whole","documentOf","resultOf","structuredClone","bounded","slice","createReadSide","enabled","sync","getKey","gcTime","autoIndex","defaultIndexType","rowUpdateMode","params","markReady","shared","Map","searched","get","publish","entry","next","result","listener","listeners","apply","set","change","before","after","begin","has","write","commit","toArrayWhenReady","observe","identity","created","Set","subscription","on","status","delete","observed","add","onFirstReady","subscribeChanges","unsubscribe","close","clear"],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import type { ChangeSet } from './change-set.js';
2
+ import { type Filter } from './query.js';
3
+ export type DocumentPart = 'fields' | 'sections' | 'preamble' | 'path';
4
+ export type SearchRequest = {
5
+ text: string;
6
+ documents?: Filter;
7
+ conversations?: readonly string[];
8
+ limit?: number;
9
+ };
10
+ export type DocumentHit = {
11
+ room: string;
12
+ path: string;
13
+ type: string;
14
+ score: number;
15
+ matches: Readonly<Record<string, readonly DocumentPart[]>>;
16
+ };
17
+ export type MessageHit = {
18
+ conversation: string;
19
+ identity: string;
20
+ score: number;
21
+ matches: Readonly<Record<string, readonly 'text'[]>>;
22
+ };
23
+ export type SearchResult = {
24
+ documents: readonly DocumentHit[];
25
+ messages: readonly MessageHit[];
26
+ };
27
+ export type SearchedDocument = {
28
+ room: string;
29
+ path: string;
30
+ type: string;
31
+ fields: Readonly<Record<string, unknown>>;
32
+ preamble: string;
33
+ sections: Readonly<Record<string, string>>;
34
+ };
35
+ export type SearchedMessage = {
36
+ conversation: string;
37
+ identity: string;
38
+ text: string;
39
+ };
40
+ export type SearchSource = {
41
+ documents(): readonly SearchedDocument[];
42
+ document(room: string, path: string): SearchedDocument | null;
43
+ messages(): readonly SearchedMessage[];
44
+ message(conversation: string, identity: string): SearchedMessage | null;
45
+ };
46
+ export type SearchPlan = {
47
+ text: string;
48
+ documents: unknown;
49
+ conversations: readonly string[] | null;
50
+ limit: number | null;
51
+ };
52
+ export type SearchIndex = {
53
+ changed(set: ChangeSet): void;
54
+ search(plan: SearchPlan, documents: readonly {
55
+ room: string;
56
+ path: string;
57
+ }[] | null): SearchResult;
58
+ };
59
+ export declare function searchPlanOf(input: unknown): SearchPlan;
60
+ export declare function createSearchIndex(source: SearchSource): SearchIndex;
61
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAkC,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzE,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC;AAEvE,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC,CAAC,CAAC;CAC5D,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;CACtD,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,EAAE,SAAS,WAAW,EAAE,CAAC;IAClC,QAAQ,EAAE,SAAS,UAAU,EAAE,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvF,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,IAAI,SAAS,gBAAgB,EAAE,CAAC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAC9D,QAAQ,IAAI,SAAS,eAAe,EAAE,CAAC;IACvC,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAAC;CACzE,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;IACxC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,CAAC;IAC9B,MAAM,CACJ,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,SAAS;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,GAAG,IAAI,GAC1D,YAAY,CAAC;CACjB,CAAC;AA4BF,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU,CAiBvD;AAMD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW,CAyGnE"}
package/dist/search.js ADDED
@@ -0,0 +1,155 @@
1
+ import MiniSearch from 'minisearch';
2
+ import { invalid, known, limitOf, plain } from './query.js';
3
+ const FIELDS = [
4
+ 'fields',
5
+ 'sections',
6
+ 'preamble',
7
+ 'path',
8
+ 'text'
9
+ ];
10
+ function documentId(room, path) {
11
+ return JSON.stringify([
12
+ 'document',
13
+ room,
14
+ path
15
+ ]);
16
+ }
17
+ function messageId(conversation, identity) {
18
+ return JSON.stringify([
19
+ 'message',
20
+ conversation,
21
+ identity
22
+ ]);
23
+ }
24
+ function scalars(value) {
25
+ if (value === null || value === undefined) return [];
26
+ if (Array.isArray(value)) return value.flatMap(scalars);
27
+ if (typeof value === 'object') return Object.values(value).flatMap(scalars);
28
+ return [
29
+ String(value)
30
+ ];
31
+ }
32
+ export function searchPlanOf(input) {
33
+ if (!plain(input)) invalid('search', 'expects a search object');
34
+ known(input, [
35
+ 'text',
36
+ 'documents',
37
+ 'conversations',
38
+ 'limit'
39
+ ], '');
40
+ if (typeof input.text !== 'string') invalid('text', 'expects text');
41
+ const conversations = input.conversations;
42
+ if (conversations !== undefined && (!Array.isArray(conversations) || conversations.some((named)=>typeof named !== 'string'))) {
43
+ invalid('conversations', 'expects a list of conversations');
44
+ }
45
+ return {
46
+ text: input.text,
47
+ documents: input.documents,
48
+ conversations: conversations ?? null,
49
+ limit: limitOf(input.limit)
50
+ };
51
+ }
52
+ export function createSearchIndex(source) {
53
+ let index = null;
54
+ const documents = new Map();
55
+ const messages = new Map();
56
+ const changedDocuments = new Map();
57
+ const changedMessages = new Map();
58
+ function addDocument(built, document) {
59
+ const id = documentId(document.room, document.path);
60
+ documents.set(id, {
61
+ room: document.room,
62
+ path: document.path,
63
+ type: document.type
64
+ });
65
+ built.add({
66
+ id,
67
+ fields: scalars(document.fields).join('\n'),
68
+ sections: Object.entries(document.sections).map(([heading, text])=>`${heading}\n${text}`).join('\n'),
69
+ preamble: document.preamble,
70
+ path: document.path
71
+ });
72
+ }
73
+ function addMessage(built, message) {
74
+ const id = messageId(message.conversation, message.identity);
75
+ messages.set(id, {
76
+ conversation: message.conversation,
77
+ identity: message.identity
78
+ });
79
+ built.add({
80
+ id,
81
+ text: message.text
82
+ });
83
+ }
84
+ function current() {
85
+ if (index === null) {
86
+ const built = new MiniSearch({
87
+ fields: FIELDS
88
+ });
89
+ for (const document of source.documents())addDocument(built, document);
90
+ for (const message of source.messages())addMessage(built, message);
91
+ index = built;
92
+ return built;
93
+ }
94
+ const built = index;
95
+ for (const [id, { room, path }] of changedDocuments){
96
+ if (documents.delete(id)) built.discard(id);
97
+ const document = source.document(room, path);
98
+ if (document !== null) addDocument(built, document);
99
+ }
100
+ changedDocuments.clear();
101
+ for (const [id, { conversation, identity }] of changedMessages){
102
+ if (messages.delete(id)) built.discard(id);
103
+ const message = source.message(conversation, identity);
104
+ if (message !== null) addMessage(built, message);
105
+ }
106
+ changedMessages.clear();
107
+ return built;
108
+ }
109
+ function ranked(built, text, entries, keep, limit) {
110
+ const found = built.search(text, {
111
+ filter: ({ id })=>{
112
+ const entry = entries.get(id);
113
+ return entry !== undefined && keep(entry, id);
114
+ }
115
+ });
116
+ return (limit === null ? found : found.slice(0, limit)).map(({ id, score, match })=>({
117
+ ...entries.get(id),
118
+ score,
119
+ match
120
+ }));
121
+ }
122
+ return {
123
+ changed (set) {
124
+ if (index === null) return;
125
+ for (const { locator, path } of set.documents){
126
+ changedDocuments.set(documentId(locator, path), {
127
+ room: locator,
128
+ path
129
+ });
130
+ }
131
+ for (const { conversation, identity } of set.messages){
132
+ changedMessages.set(messageId(conversation, identity), {
133
+ conversation,
134
+ identity
135
+ });
136
+ }
137
+ },
138
+ search ({ text, conversations, limit }, selected) {
139
+ const built = current();
140
+ const chosen = selected === null ? null : new Set(selected.map(({ room, path })=>documentId(room, path)));
141
+ return {
142
+ documents: ranked(built, text, documents, (_entry, id)=>chosen === null || chosen.has(id), limit).map(({ match, ...hit })=>({
143
+ ...hit,
144
+ matches: match
145
+ })),
146
+ messages: ranked(built, text, messages, ({ conversation })=>conversations === null || conversations.includes(conversation), limit).map(({ match, ...hit })=>({
147
+ ...hit,
148
+ matches: match
149
+ }))
150
+ };
151
+ }
152
+ };
153
+ }
154
+
155
+ //# sourceMappingURL=search.js.map