cvx-kit 0.1.20 → 0.1.21

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.
Files changed (79) hide show
  1. package/README.md +40 -2
  2. package/dist/errors.d.mts +3 -2
  3. package/dist/errors.mjs +1 -1
  4. package/dist/errors.mjs.map +1 -1
  5. package/dist/filters.d.mts +4 -0
  6. package/dist/filters.mjs +1 -0
  7. package/dist/index.d.mts +3 -3
  8. package/dist/modules/contracts/errors.d.mts +218 -0
  9. package/dist/modules/contracts/errors.mjs +1 -1
  10. package/dist/modules/contracts/errors.mjs.map +1 -1
  11. package/dist/modules/effect/crud.d.mts +28 -0
  12. package/dist/querying/cursors.d.mts +30 -4
  13. package/dist/querying/cursors.mjs +1 -1
  14. package/dist/querying/cursors.mjs.map +1 -1
  15. package/dist/querying/execution.d.mts +14 -3
  16. package/dist/querying/execution.mjs +1 -1
  17. package/dist/querying/execution.mjs.map +1 -1
  18. package/dist/querying/failures.d.mts +13 -0
  19. package/dist/querying/failures.mjs +2 -0
  20. package/dist/querying/failures.mjs.map +1 -0
  21. package/dist/querying/filters.d.mts +39 -45
  22. package/dist/querying/filters.mjs +1 -1
  23. package/dist/querying/filters.mjs.map +1 -1
  24. package/dist/querying/planner.d.mts +11 -5
  25. package/dist/querying/planner.mjs +1 -1
  26. package/dist/querying/planner.mjs.map +1 -1
  27. package/dist/querying/relationships.d.mts +21 -4
  28. package/dist/querying/relationships.mjs +1 -1
  29. package/dist/querying/relationships.mjs.map +1 -1
  30. package/dist/querying/schema-snapshot.mjs +1 -1
  31. package/dist/querying/schema-snapshot.mjs.map +1 -1
  32. package/dist/querying/search.d.mts +69 -0
  33. package/dist/querying/search.mjs +2 -0
  34. package/dist/querying/search.mjs.map +1 -0
  35. package/dist/querying/security.d.mts +19 -2
  36. package/dist/querying/security.mjs +1 -1
  37. package/dist/querying/security.mjs.map +1 -1
  38. package/dist/querying/shared/ast.d.mts +28 -0
  39. package/dist/querying/shared/ast.mjs +2 -0
  40. package/dist/querying/shared/ast.mjs.map +1 -0
  41. package/dist/querying/shared/contract.d.mts +104 -0
  42. package/dist/querying/shared/contract.mjs +2 -0
  43. package/dist/querying/shared/contract.mjs.map +1 -0
  44. package/dist/querying/shared/evaluate.d.mts +7 -0
  45. package/dist/querying/shared/evaluate.mjs +2 -0
  46. package/dist/querying/shared/evaluate.mjs.map +1 -0
  47. package/dist/querying/shared/filters.d.mts +31 -0
  48. package/dist/querying/shared/filters.mjs +2 -0
  49. package/dist/querying/shared/filters.mjs.map +1 -0
  50. package/dist/querying.d.mts +47 -16
  51. package/dist/querying.mjs +1 -1
  52. package/dist/querying.mjs.map +1 -1
  53. package/dist/react/failures.d.mts +23 -0
  54. package/dist/react/failures.mjs +2 -0
  55. package/dist/react/failures.mjs.map +1 -0
  56. package/dist/react/optimistic.d.mts +47 -0
  57. package/dist/react/optimistic.mjs +2 -0
  58. package/dist/react/optimistic.mjs.map +1 -0
  59. package/dist/react/pagination-state.d.mts +40 -0
  60. package/dist/react/pagination-state.mjs +2 -0
  61. package/dist/react/pagination-state.mjs.map +1 -0
  62. package/dist/react/use-command.d.mts +23 -0
  63. package/dist/react/use-command.mjs +2 -0
  64. package/dist/react/use-command.mjs.map +1 -0
  65. package/dist/react/use-paginated-list.d.mts +32 -0
  66. package/dist/react/use-paginated-list.mjs +2 -0
  67. package/dist/react/use-paginated-list.mjs.map +1 -0
  68. package/dist/react.d.mts +6 -0
  69. package/dist/react.mjs +1 -0
  70. package/dist/relations-public.d.mts +2 -2
  71. package/dist/relations.d.mts +62 -7
  72. package/dist/relations.mjs +1 -1
  73. package/dist/relations.mjs.map +1 -1
  74. package/dist/zod-convex.mjs +1 -1
  75. package/dist/zod-convex.mjs.map +1 -1
  76. package/dist/zod-table.d.mts +15 -1
  77. package/dist/zod-table.mjs +1 -1
  78. package/dist/zod-table.mjs.map +1 -1
  79. package/package.json +21 -4
@@ -1 +1 @@
1
- {"version":3,"file":"filters.mjs","names":["MAX_PAGE_SIZE","MAX_FILTER_DEPTH","MAX_FILTER_NODES","MAX_FILTER_IN_VALUES","nativeOptions","convexToZod","paginationOptsValidator","nativePagination","scalarPaginationSchema","predicates","key","selected","selection","validators","scalarPredicateSchema","filters","boundedFilterSchema","z","assertSupportedScalar","validator","scalar","equality","ranged","supportsRange","explicit","value","entry","relationPredicates","variantPredicates","filterGrammars","BoundedFilterObject","inst","def","parse","namespace","namespaceObject","selectedKeys","grammar","schema","relation","withinFilterBudget","payload","ctx","relationFilterSchema","filterNodeSchema","cache","compileFilters","parseFilterPlan","input","indexes","conditions","where","args","parsed","server","paginationGrammar","residual","normalizeFilters","guaranteed","guaranteedBindings","sorted","a","b","condition","index","prefixBindings","length","candidate","usable","root","cached","name","predicate","children","expression","child","scoped","field","normalizeScalar","target","operator","valueEqual","compareValues","left","right","values","ast","choices","branches","viable","branch","impossible","prefix","bindings","member","depth","direct","relations","options","tag","node","result","depths","pending","nodes","object","array","prototype","keys","consumed","descriptor","context"],"sources":["../../src/querying/filters.ts"],"sourcesContent":["import { convexToZod, type ConvexValidatorFromZod } from 'convex-helpers/server/zod4'\nimport { paginationOptsValidator } from 'convex/server'\nimport { compareValues, type GenericId, type GenericValidator } from 'convex/values'\nimport { z } from 'zod'\n\n/** Shared hard ceilings; the execution engine may impose lower budgets. */\nexport const MAX_PAGE_SIZE = 100\nexport const MAX_FILTER_DEPTH = 4\nexport const MAX_FILTER_NODES = 256\nexport const MAX_FILTER_IN_VALUES = 100\n\nexport type FieldSchemas = Record<string, z.ZodType>\ntype NativeField<Schema extends z.ZodType> = ConvexValidatorFromZod<Schema, 'required'>\ntype ScalarKind = 'id' | 'string' | 'float64' | 'int64' | 'boolean' | 'null' | 'literal'\ntype SupportedNative<Validator extends GenericValidator> = Validator extends { kind: ScalarKind }\n\t? true\n\t: Validator extends { kind: 'union'; members: infer Members extends GenericValidator[] }\n\t\t? false extends SupportedNative<Members[number]>\n\t\t\t? false\n\t\t\t: true\n\t\t: false\n\nexport type ScalarSelection<Fields extends FieldSchemas> = {\n\t[\n\t\tKey in keyof Fields as false extends SupportedNative<NativeField<Fields[Key]>> ? never : Key\n\t]?: true\n}\nexport type ExactScalarSelection<Fields extends FieldSchemas, Selection> = Selection & {\n\t[Key in keyof Selection]: Key extends keyof ScalarSelection<Fields>\n\t\t? Selection[Key] extends true\n\t\t\t? true\n\t\t\t: never\n\t\t: never\n}\n\ntype NativeValue<Schema extends z.ZodType> = Exclude<NativeField<Schema>['type'], undefined>\ntype FilterInputValue<Value> = Value extends GenericId<string> ? string : Value\ntype FilterValue<Schema extends z.ZodType, Side extends 'input' | 'output'> = Side extends 'input'\n\t? FilterInputValue<NativeValue<Schema>>\n\t: NativeValue<Schema>\ntype RangeKind = 'string' | 'float64' | 'int64' | 'literal'\ntype OrderedNative<Validator extends GenericValidator> = Validator extends { kind: RangeKind }\n\t? Validator['type'] extends string | number | bigint | undefined\n\t\t? true\n\t\t: false\n\t: Validator extends { kind: 'union'; members: infer Members extends GenericValidator[] }\n\t\t? false extends OrderedNative<Members[number]>\n\t\t\t? false\n\t\t\t: true\n\t\t: false\ntype OrderedValue<Schema extends z.ZodType> =\n\tOrderedNative<NativeField<Schema>> extends true ? NativeValue<Schema> : never\n\nexport type ScalarPredicate<Schema extends z.ZodType, Side extends 'input' | 'output'> =\n\t| FilterValue<Schema, Side>\n\t| ({ eq?: FilterValue<Schema, Side>; in?: FilterValue<Schema, Side>[] } & ([\n\t\t\tOrderedValue<Schema>,\n\t ] extends [never]\n\t\t\t? {}\n\t\t\t: {\n\t\t\t\t\tgt?: OrderedValue<Schema>\n\t\t\t\t\tgte?: OrderedValue<Schema>\n\t\t\t\t\tlt?: OrderedValue<Schema>\n\t\t\t\t\tlte?: OrderedValue<Schema>\n\t\t\t\t}) &\n\t\t\t('optional' extends NativeField<Schema>['isOptional'] ? { exists?: boolean } : {}))\n\ntype SelectedFieldFilters<\n\tFields extends FieldSchemas,\n\tSelection,\n\tSide extends 'input' | 'output',\n> = {\n\t[Key in Extract<keyof Selection, keyof Fields>]?: ScalarPredicate<Fields[Key], Side>\n}\n\n/** Direct shorthand and explicit fields combine with AND. The fields namespace\n * accepts every selected scalar name, including boolean-control/namespace names.\n */\ntype FilterDepth = readonly [1, 1, 1, 1]\ntype Tail<Depth extends readonly 1[]> = Depth extends readonly [1, ...infer Rest extends 1[]]\n\t? Rest\n\t: []\n\nexport type ScalarFilters<\n\tFields extends FieldSchemas,\n\tSelection,\n\tSide extends 'input' | 'output' = 'output',\n\tDepth extends readonly 1[] = FilterDepth,\n> = Omit<SelectedFieldFilters<Fields, Selection, Side>, 'and' | 'or' | 'not' | 'fields'> & {\n\tfields?: SelectedFieldFilters<Fields, Selection, Side>\n} & (Depth extends readonly []\n\t\t? {}\n\t\t: {\n\t\t\t\tand?: ScalarFilters<Fields, Selection, Side, Tail<Depth>>[]\n\t\t\t\tor?: ScalarFilters<Fields, Selection, Side, Tail<Depth>>[]\n\t\t\t\tnot?: ScalarFilters<Fields, Selection, Side, Tail<Depth>>\n\t\t\t})\n\nconst nativeOptions = convexToZod(paginationOptsValidator)\nexport const nativePagination = nativeOptions.strict().extend({\n\tnumItems: nativeOptions.shape.numItems.int().positive().max(MAX_PAGE_SIZE),\n\tmaximumRowsRead: nativeOptions.shape.maximumRowsRead.unwrap().int().positive().optional(),\n\tmaximumBytesRead: nativeOptions.shape.maximumBytesRead.unwrap().int().positive().optional(),\n})\nexport type NativePagination = z.output<typeof nativePagination>\n/** Preserve the object boundary so pagination options can be registered directly as query args. */\nexport type PaginationOptionsSchema<Filters, InputFilters = Filters> = z.ZodObject<\n\t(typeof nativePagination)['shape'] & {\n\t\tfilters: z.ZodOptional<z.ZodType<Filters, InputFilters>>\n\t\torder: z.ZodOptional<z.ZodEnum<{ asc: 'asc'; desc: 'desc' }>>\n\t},\n\tz.core.$strict\n>\nexport type ScalarPaginationSchema<\n\tFields extends FieldSchemas,\n\tSelection,\n> = PaginationOptionsSchema<\n\tScalarFilters<Fields, Selection>,\n\tScalarFilters<Fields, Selection, 'input'>\n>\n\n/** Scalar-only schema constructor shared by table and future registry boundaries.\n * Convex metadata describes stored INPUT, so storage refinements/transforms never run here.\n */\nexport function scalarPaginationSchema<\n\tFields extends FieldSchemas,\n\tconst Selection extends ScalarSelection<Fields>,\n>(\n\tvalidators: Record<string, GenericValidator>,\n\tselection: ExactScalarSelection<Fields, Selection>,\n): ScalarPaginationSchema<Fields, Selection> {\n\tconst predicates: FieldSchemas = {}\n\tfor (const [key, selected] of Object.entries(selection)) {\n\t\tif (selected !== true || !Object.hasOwn(validators, key)) {\n\t\t\tthrow new Error(`Invalid scalar filter selection \"${key}\"`)\n\t\t}\n\t\tpredicates[key] = scalarPredicateSchema(validators[key]).optional()\n\t}\n\tconst filters = boundedFilterSchema(predicates)\n\tconst result = nativePagination.extend({\n\t\tfilters: filters.optional(),\n\t\torder: z.enum(['asc', 'desc']).optional(),\n\t})\n\t// SAFETY: selected validators generate the same native scalar input/output relationships\n\t// described by ScalarFilters, including converter-registered ID brands.\n\treturn result as ScalarPaginationSchema<Fields, Selection>\n}\n\nexport function scalarPredicateSchema(validator: GenericValidator): z.ZodType {\n\tassertSupportedScalar(validator)\n\tconst scalar = convexToZod(validator).nonoptional()\n\tconst equality = z.object({\n\t\teq: scalar.optional(),\n\t\tin: z.array(scalar).min(1).max(MAX_FILTER_IN_VALUES).optional(),\n\t})\n\tconst ranged = supportsRange(validator)\n\t\t? equality.extend({\n\t\t\t\tgt: scalar.optional(),\n\t\t\t\tgte: scalar.optional(),\n\t\t\t\tlt: scalar.optional(),\n\t\t\t\tlte: scalar.optional(),\n\t\t\t})\n\t\t: equality\n\tconst existence =\n\t\tvalidator.isOptional === 'optional' ? ranged.extend({ exists: z.boolean().optional() }) : ranged\n\tconst explicit = existence\n\t\t.strict()\n\t\t.refine(\n\t\t\t(value) => Object.values(value).some((entry) => entry !== undefined),\n\t\t\t'At least one operator is required',\n\t\t)\n\treturn z.union([scalar, explicit])\n}\n\ntype FilterTree =\n\t| string\n\t| number\n\t| bigint\n\t| boolean\n\t| null\n\t| undefined\n\t| FilterTree[]\n\t| { [key: string]: FilterTree }\n\n// Compose Zod's exported core constructor with its ordinary object initializer.\n// Clones use this constructor again, preserving preflight without replacing the\n// converter-recognized object definition or any native scalar/ID validators.\nconst relationPredicates = new WeakMap<\n\tz.core.$ZodType,\n\t{ cardinality: 'one' | 'many'; target: FilterGrammar }\n>()\nconst variantPredicates = new WeakMap<z.core.$ZodType, NonNullable<FilterGrammar['variants']>>()\nconst filterGrammars = new WeakMap<z.core.$ZodType, FilterGrammar>()\n\nconst BoundedFilterObject = z.core.$constructor<z.ZodObject>('BoundedFilterObject', (inst, def) => {\n\tz.ZodObject.init(inst, def)\n\tconst parse = inst._zod.parse\n\tconst namespace = def.shape.fields\n\tconst namespaceObject = namespace instanceof z.ZodOptional ? namespace.unwrap() : undefined\n\tconst selectedKeys =\n\t\tnamespaceObject instanceof z.ZodObject\n\t\t\t? Object.keys(namespaceObject.shape)\n\t\t\t: Object.keys(def.shape)\n\tconst grammar: FilterGrammar = {\n\t\tvariants: variantPredicates.get(def.shape.variant),\n\t\tfields: Object.fromEntries(selectedKeys.map((key) => [key, def.shape[key]])),\n\t\trelations: Object.fromEntries(\n\t\t\tObject.entries(def.shape).flatMap(([key, schema]) => {\n\t\t\t\tconst relation = relationPredicates.get(schema)\n\t\t\t\treturn relation ? [[key, relation]] : []\n\t\t\t}),\n\t\t),\n\t}\n\t// Zod refinements run after parsing. Guard parse itself so both the deferred\n\t// no-check run and the refinement run retain the same pre-child boundary.\n\tinst._zod.parse = (payload, ctx) => {\n\t\t// SAFETY: preflight examines layout and budgets only; Zod still validates values.\n\t\tif (!withinFilterBudget(payload.value as FilterTree, grammar)) {\n\t\t\tpayload.issues.push({\n\t\t\t\tcode: 'custom',\n\t\t\t\tinput: payload.value,\n\t\t\t\tmessage: 'Unsupported filter layout or depth/node budget exceeded',\n\t\t\t})\n\t\t\treturn payload\n\t\t}\n\t\treturn parse(payload, ctx)\n\t}\n})\n\n/** Each boolean child and relation target expression consumes one of four edges.\n * some/none wrappers and fields namespaces consume nodes, but no extra depth.\n */\nexport interface FilterGrammar {\n\tfields: FieldSchemas\n\tvariants?: { discriminator: string; options: Record<string, FilterGrammar> }\n\trelations: Record<string, { cardinality: 'one' | 'many'; target: FilterGrammar }>\n}\n\nexport function relationFilterSchema(\n\tgrammar: FilterGrammar,\n\tcache = new WeakMap<FilterGrammar, Map<number, z.ZodObject>>(),\n): z.ZodType {\n\tconst schema = new BoundedFilterObject(filterNodeSchema(grammar, 0, cache)._zod.def)\n\tfilterGrammars.set(schema, grammar)\n\treturn schema\n}\n\nexport type FilterScalar = string | number | bigint | boolean | null\nexport type FilterOperator = 'eq' | 'in' | 'gt' | 'gte' | 'lt' | 'lte' | 'exists'\nexport type FilterAst =\n\t| { kind: 'and' | 'or'; children: FilterAst[] }\n\t| { kind: 'not'; child: FilterAst }\n\t| { kind: 'variant'; discriminator: string; tag: string; child: FilterAst }\n\t| {\n\t\t\tkind: 'scalar'\n\t\t\tfield: string\n\t\t\toperator: FilterOperator\n\t\t\tvalue: FilterScalar | FilterScalar[]\n\t }\n\t| { kind: 'relation'; name: string; mode: 'one' | 'some' | 'none'; predicate: FilterAst | null }\nexport interface QueryIndex {\n\tname: string\n\tfields: readonly string[]\n}\nexport interface IndexCondition {\n\tvalue: FilterScalar | undefined\n\tindex: string\n}\nexport interface CompiledFilters {\n\tresidual: FilterAst\n\tbindings: ReadonlyMap<string, FilterScalar>\n\tunsatisfiable: boolean\n\tindex: QueryIndex | null\n\tprefix: readonly { field: string; value: FilterScalar }[]\n}\ntype FilterSpec<Schema extends z.ZodType> =\n\tz.input<Schema> extends { filters?: infer Spec } ? Spec : never\nexport type ServerFilter<Fields extends FieldSchemas> = ScalarFilters<\n\tFields,\n\tScalarSelection<Fields>\n>\n\ninterface BindingResult {\n\tvalues: Map<string, FilterScalar>\n\timpossible: boolean\n}\n\n/** Validate first; where is independently validated and ANDed with client predicates.\n * OR remains a residual expression over one traversal, never multiple streams.\n */\nexport function compileFilters<Schema extends z.ZodType>(\n\tschema: Schema,\n\tinput: z.input<Schema>,\n\tindexes: readonly QueryIndex[],\n\tconditions: readonly IndexCondition[] = [],\n\twhere?: FilterSpec<Schema>,\n): CompiledFilters {\n\treturn parseFilterPlan(schema, input, indexes, conditions, where).compiled\n}\n\n/** Internal planner boundary: retain the parsed arguments without parsing them again. */\nexport function parseFilterPlan<Schema extends z.ZodType>(\n\tschema: Schema,\n\tinput: z.input<Schema>,\n\tindexes: readonly QueryIndex[],\n\tconditions: readonly IndexCondition[] = [],\n\twhere?: FilterSpec<Schema>,\n) {\n\tconst args = schema.parse(input)\n\t// SAFETY: pagination schemas validate filters before this internal AST adapter reads them.\n\tconst parsed = args as { filters?: FilterTree }\n\t// SAFETY: server filters use the same validation boundary as client filters.\n\tconst server =\n\t\twhere === undefined\n\t\t\t? undefined\n\t\t\t: (schema.parse({ ...parsed, filters: where }) as { filters?: FilterTree })\n\tconst grammar = paginationGrammar(schema)\n\tconst residual: FilterAst = {\n\t\tkind: 'and',\n\t\tchildren: [\n\t\t\tnormalizeFilters(parsed.filters, grammar),\n\t\t\tnormalizeFilters(server?.filters, grammar),\n\t\t],\n\t}\n\tconst guaranteed = guaranteedBindings(residual)\n\tconst sorted = [...indexes].sort(\n\t\t(a, b) =>\n\t\t\ta.name.localeCompare(b.name) || a.fields.join('\\0').localeCompare(b.fields.join('\\0')),\n\t)\n\tconst condition = conditions.find((entry) => entry.value !== null && entry.value !== undefined)\n\tlet index: QueryIndex | null = null\n\tif (condition) {\n\t\tindex = sorted.find((entry) => entry.name === condition.index) ?? null\n\t\tif (!index || prefixBindings(index, guaranteed.values).length === 0)\n\t\t\tthrow new Error(`Explicit index \"${condition.index}\" is incompatible with guaranteed filters`)\n\t} else {\n\t\tlet length = 0\n\t\tfor (const candidate of sorted) {\n\t\t\tconst usable = prefixBindings(candidate, guaranteed.values).length\n\t\t\tif (usable > length) {\n\t\t\t\tindex = candidate\n\t\t\t\tlength = usable\n\t\t\t}\n\t\t}\n\t}\n\tconst compiled: CompiledFilters = {\n\t\tresidual,\n\t\tbindings: guaranteed.values,\n\t\tunsatisfiable: guaranteed.impossible,\n\t\tindex,\n\t\tprefix: index ? prefixBindings(index, guaranteed.values) : [],\n\t}\n\treturn { args, compiled }\n}\nfunction paginationGrammar(schema: z.ZodType): FilterGrammar | undefined {\n\tif (!(schema instanceof z.ZodObject)) return undefined\n\tconst filters = schema.shape.filters\n\tif (!(filters instanceof z.ZodOptional)) return undefined\n\tconst root = filters.unwrap()\n\tconst cached = filterGrammars.get(root)\n\tif (cached) return cached\n\tif (!(root instanceof z.ZodObject)) return undefined\n\treturn {\n\t\tfields: root.shape,\n\t\tvariants: variantPredicates.get(root.shape.variant),\n\t\trelations: Object.fromEntries(\n\t\t\tObject.entries(root.shape).flatMap(([name, predicate]) => {\n\t\t\t\t// SAFETY: object shapes contain Zod schemas; metadata only recognizes predicates created by our grammar.\n\t\t\t\tconst relation = relationPredicates.get(predicate as z.core.$ZodType)\n\t\t\t\treturn relation ? [[name, relation]] : []\n\t\t\t}),\n\t\t),\n\t}\n}\nfunction normalizeFilters(value: FilterTree, grammar?: FilterGrammar): FilterAst {\n\tconst children: FilterAst[] = []\n\tif (!value) return { kind: 'and', children }\n\t// SAFETY: the caller parsed a strict filter object; its grammar has no array/primitive expression.\n\tconst expression = value as Record<string, FilterTree>\n\tfor (const [name, predicate] of Object.entries(expression)) {\n\t\tif (predicate === undefined) continue\n\t\tif (name === 'and' || name === 'or') {\n\t\t\t// SAFETY: boolean composition is validated as an array of expressions.\n\t\t\tchildren.push({\n\t\t\t\tkind: name,\n\t\t\t\tchildren: (predicate as FilterTree[]).map((child) => normalizeFilters(child, grammar)),\n\t\t\t})\n\t\t} else if (name === 'variant' && grammar?.variants) {\n\t\t\t// SAFETY: strict branch grammar validates the literal tag and its selected target filters.\n\t\t\tconst scoped = predicate as { tag: string; filters: FilterTree }\n\t\t\tchildren.push({\n\t\t\t\tkind: 'variant',\n\t\t\t\tdiscriminator: grammar.variants.discriminator,\n\t\t\t\ttag: scoped.tag,\n\t\t\t\tchild: normalizeFilters(scoped.filters, grammar.variants.options[scoped.tag]),\n\t\t\t})\n\t\t} else if (name === 'not')\n\t\t\tchildren.push({ kind: 'not', child: normalizeFilters(predicate, grammar) })\n\t\telse if (name === 'fields') {\n\t\t\t// SAFETY: fields is a strict selected scalar namespace.\n\t\t\tfor (const [field, scalar] of Object.entries(predicate as Record<string, FilterTree>))\n\t\t\t\tchildren.push(...normalizeScalar(field, scalar))\n\t\t} else if (grammar?.relations[name]) {\n\t\t\tconst relation = grammar.relations[name]\n\t\t\tif (relation.cardinality === 'one')\n\t\t\t\tchildren.push({\n\t\t\t\t\tkind: 'relation',\n\t\t\t\t\tname,\n\t\t\t\t\tmode: 'one',\n\t\t\t\t\tpredicate: predicate === null ? null : normalizeFilters(predicate, relation.target),\n\t\t\t\t})\n\t\t\telse {\n\t\t\t\t// SAFETY: many predicates validate as exactly one some/none target expression.\n\t\t\t\tconst target = predicate as { some?: FilterTree; none?: FilterTree }\n\t\t\t\tchildren.push({\n\t\t\t\t\tkind: 'relation',\n\t\t\t\t\tname,\n\t\t\t\t\tmode: target.some === undefined ? 'none' : 'some',\n\t\t\t\t\tpredicate: normalizeFilters(target.some ?? target.none, relation.target),\n\t\t\t\t})\n\t\t\t}\n\t\t} else children.push(...normalizeScalar(name, predicate))\n\t}\n\treturn { kind: 'and', children }\n}\nfunction normalizeScalar(field: string, predicate: FilterTree): FilterAst[] {\n\tif (predicate === undefined) return []\n\tif (Object(predicate) !== predicate) {\n\t\t// SAFETY: native scalar grammar excludes object/array values and preserves branded ID strings.\n\t\treturn [{ kind: 'scalar', field, operator: 'eq', value: predicate as FilterScalar }]\n\t}\n\t// SAFETY: only selected supported scalar operator objects survive validation.\n\treturn Object.entries(predicate as Record<FilterOperator, FilterScalar | FilterScalar[]>)\n\t\t.filter(([, value]) => value !== undefined)\n\t\t.map(([operator, value]) => ({\n\t\t\tkind: 'scalar',\n\t\t\tfield,\n\t\t\toperator: operator as FilterOperator,\n\t\t\tvalue,\n\t\t}))\n}\nfunction valueEqual(left: FilterScalar, right: FilterScalar): boolean {\n\treturn compareValues(left, right) === 0\n}\nfunction guaranteedBindings(ast: FilterAst): BindingResult {\n\tconst values = new Map<string, FilterScalar>()\n\tif (ast.kind === 'variant')\n\t\treturn guaranteedBindings({\n\t\t\tkind: 'and',\n\t\t\tchildren: [\n\t\t\t\t{ kind: 'scalar', field: ast.discriminator, operator: 'eq', value: ast.tag },\n\t\t\t\tast.child,\n\t\t\t],\n\t\t})\n\tif (ast.kind === 'scalar') {\n\t\tif (ast.operator === 'eq' && !Array.isArray(ast.value)) values.set(ast.field, ast.value)\n\t\tconst choices = Array.isArray(ast.value) ? ast.value : undefined\n\t\tif (ast.operator === 'in' && choices && choices.every((value) => valueEqual(value, choices[0])))\n\t\t\tvalues.set(ast.field, choices[0])\n\t\treturn { values, impossible: false }\n\t}\n\tif (ast.kind === 'not' || ast.kind === 'relation') return { values, impossible: false }\n\tconst branches = ast.children.map(guaranteedBindings)\n\tif (ast.kind === 'or') {\n\t\tconst viable = branches.filter((branch) => !branch.impossible)\n\t\tfor (const [field, value] of viable[0]?.values ?? [])\n\t\t\tif (\n\t\t\t\tviable.every(\n\t\t\t\t\t(branch) => branch.values.has(field) && valueEqual(branch.values.get(field)!, value),\n\t\t\t\t)\n\t\t\t)\n\t\t\t\tvalues.set(field, value)\n\t\treturn { values, impossible: viable.every((branch) => branch.impossible) }\n\t}\n\tlet impossible = branches.some((branch) => branch.impossible)\n\tfor (const branch of branches)\n\t\tfor (const [field, value] of branch.values) {\n\t\t\tif (values.has(field) && !valueEqual(values.get(field)!, value)) impossible = true\n\t\t\tvalues.set(field, value)\n\t\t}\n\treturn { values, impossible }\n}\nfunction prefixBindings(\n\tindex: QueryIndex,\n\tbindings: ReadonlyMap<string, FilterScalar>,\n): { field: string; value: FilterScalar }[] {\n\tconst prefix: { field: string; value: FilterScalar }[] = []\n\tfor (const field of index.fields) {\n\t\tif (!bindings.has(field)) break\n\t\tprefix.push({ field, value: bindings.get(field)! })\n\t}\n\treturn prefix\n}\n\nfunction assertSupportedScalar(validator: GenericValidator): void {\n\tswitch (validator.kind) {\n\t\tcase 'id':\n\t\tcase 'string':\n\t\tcase 'float64':\n\t\tcase 'int64':\n\t\tcase 'boolean':\n\t\tcase 'null':\n\t\tcase 'literal':\n\t\t\treturn\n\t\tcase 'union':\n\t\t\tfor (const member of validator.members) {\n\t\t\t\tassertSupportedScalar(member)\n\t\t\t}\n\t\t\treturn\n\t\tdefault:\n\t\t\tthrow new Error(`Unsupported scalar filter kind \"${validator.kind}\"`)\n\t}\n}\n\nfunction supportsRange(validator: GenericValidator): boolean {\n\tswitch (validator.kind) {\n\t\tcase 'string':\n\t\tcase 'float64':\n\t\tcase 'int64':\n\t\t\treturn true\n\t\tcase 'literal':\n\t\t\treturn z.union([z.string(), z.number(), z.bigint()]).safeParse(validator.value).success\n\t\tcase 'union':\n\t\t\treturn validator.members.every(supportsRange)\n\t\tdefault:\n\t\t\treturn false\n\t}\n}\n\nfunction boundedFilterSchema(predicates: FieldSchemas): z.ZodType {\n\treturn relationFilterSchema({ fields: predicates, relations: {} })\n}\n\nfunction filterNodeSchema(\n\tgrammar: FilterGrammar,\n\tdepth: number,\n\tcache = new WeakMap<FilterGrammar, Map<number, z.ZodObject>>(),\n): z.ZodObject {\n\tconst cached = cache.get(grammar)?.get(depth)\n\tif (cached) return cached\n\tconst predicates = grammar.fields\n\tconst direct = Object.fromEntries(\n\t\tObject.entries(predicates).filter(\n\t\t\t([key]) =>\n\t\t\t\t!['and', 'or', 'not', 'fields', ...(grammar.variants ? ['variant'] : [])].includes(key),\n\t\t),\n\t)\n\tconst relations: FieldSchemas = {}\n\tfor (const [name, relation] of Object.entries(grammar.relations)) {\n\t\tif (depth === MAX_FILTER_DEPTH) continue\n\t\tconst target = filterNodeSchema(relation.target, depth + 1, cache)\n\t\trelations[name] = (\n\t\t\trelation.cardinality === 'one'\n\t\t\t\t? target.nullable()\n\t\t\t\t: z.union([z.object({ some: target }).strict(), z.object({ none: target }).strict()])\n\t\t).optional()\n\t\trelationPredicates.set(relations[name], relation)\n\t}\n\tif (grammar.variants && depth < MAX_FILTER_DEPTH) {\n\t\tconst options = Object.entries(grammar.variants.options).map(([tag, branch]) =>\n\t\t\tz.strictObject({ tag: z.literal(tag), filters: filterNodeSchema(branch, depth + 1, cache) }),\n\t\t)\n\t\tif (options.length) {\n\t\t\trelations.variant = z.union(options).optional()\n\t\t\tvariantPredicates.set(relations.variant, grammar.variants)\n\t\t}\n\t}\n\tconst node = z\n\t\t.object({ ...direct, ...relations, fields: z.object(predicates).strict().optional() })\n\t\t.strict()\n\tconst child = depth === MAX_FILTER_DEPTH ? undefined : filterNodeSchema(grammar, depth + 1, cache)\n\tconst result = child\n\t\t? node.extend({\n\t\t\t\tand: z.array(child).min(1).max(MAX_FILTER_NODES).optional(),\n\t\t\t\tor: z.array(child).min(1).max(MAX_FILTER_NODES).optional(),\n\t\t\t\tnot: child.optional(),\n\t\t\t})\n\t\t: node\n\tlet depths = cache.get(grammar)\n\tif (!depths) {\n\t\tdepths = new Map()\n\t\tcache.set(grammar, depths)\n\t}\n\tdepths.set(depth, result)\n\treturn result\n}\n\nfunction withinFilterBudget(value: FilterTree, grammar: FilterGrammar): boolean {\n\ttype Context =\n\t\t| 'expression'\n\t\t| 'fields'\n\t\t| 'predicate'\n\t\t| 'composition'\n\t\t| 'many'\n\t\t| 'variant'\n\t\t| 'value'\n\tinterface Entry {\n\t\tvalue: FilterTree\n\t\tdepth: number\n\t\tcontext: Context\n\t\tgrammar: FilterGrammar\n\t}\n\tconst pending: Entry[] = [{ value, depth: 0, context: 'expression', grammar }]\n\tlet nodes = 0\n\twhile (pending.length) {\n\t\tconst entry = pending.pop()!\n\t\tif (++nodes > MAX_FILTER_NODES || entry.depth > MAX_FILTER_DEPTH) return false\n\t\tif (Object(entry.value) !== entry.value) continue\n\t\t// SAFETY: boxing excludes null and primitives; descriptors below avoid invoking getters.\n\t\tconst object = entry.value as FilterTree[] | Record<string, FilterTree>\n\t\tconst array = Array.isArray(object) ? object : undefined\n\t\tconst prototype = Object.getPrototypeOf(object)\n\t\tif (\n\t\t\tarray ? prototype !== Array.prototype : prototype !== Object.prototype && prototype !== null\n\t\t)\n\t\t\treturn false\n\t\tif (array && array.length + nodes + pending.length > MAX_FILTER_NODES) return false\n\t\tconst keys = Reflect.ownKeys(object)\n\t\tif (\n\t\t\tkeys.length - (array ? 1 : 0) + nodes + pending.length > MAX_FILTER_NODES ||\n\t\t\t(array && keys.length !== array.length + 1)\n\t\t)\n\t\t\treturn false\n\t\tlet consumed: string[]\n\t\tswitch (entry.context) {\n\t\t\tcase 'expression':\n\t\t\t\tconsumed = [\n\t\t\t\t\t...Object.keys(entry.grammar.fields),\n\t\t\t\t\t...Object.keys(entry.grammar.relations),\n\t\t\t\t\t'and',\n\t\t\t\t\t'or',\n\t\t\t\t\t'not',\n\t\t\t\t\t'fields',\n\t\t\t\t\t...(entry.grammar.variants ? ['variant'] : []),\n\t\t\t\t]\n\t\t\t\tbreak\n\t\t\tcase 'variant':\n\t\t\t\tconsumed = ['tag', 'filters']\n\t\t\t\tbreak\n\t\t\tcase 'fields':\n\t\t\t\tconsumed = Object.keys(entry.grammar.fields)\n\t\t\t\tbreak\n\t\t\tcase 'predicate':\n\t\t\t\tconsumed = ['eq', 'in', 'gt', 'gte', 'lt', 'lte', 'exists']\n\t\t\t\tbreak\n\t\t\tcase 'many':\n\t\t\t\tconsumed = ['some', 'none']\n\t\t\t\tbreak\n\t\t\tdefault:\n\t\t\t\tconsumed = []\n\t\t}\n\t\tfor (const key of consumed) if (!Object.hasOwn(object, key) && key in object) return false\n\t\tfor (const key of keys) {\n\t\t\tif (array && key === 'length') continue\n\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(object, key)!\n\t\t\tconst name = String(key)\n\t\t\tif (!descriptor.enumerable || !('value' in descriptor) || name !== key) return false\n\t\t\tif (array && (!/^(0|[1-9]\\d*)$/.test(name) || Number(name) >= array.length)) return false\n\t\t\tlet context: Context = 'value'\n\t\t\tlet depth = entry.depth\n\t\t\tlet target = entry.grammar\n\t\t\tif (entry.context === 'expression') {\n\t\t\t\tcontext = 'predicate'\n\t\t\t\tif (name === 'variant' && entry.grammar.variants) {\n\t\t\t\t\tcontext = 'variant'\n\t\t\t\t\tdepth++\n\t\t\t\t} else if (name === 'fields') context = 'fields'\n\t\t\t\telse if (name === 'and' || name === 'or') {\n\t\t\t\t\tcontext = 'composition'\n\t\t\t\t\tdepth++\n\t\t\t\t} else if (name === 'not') {\n\t\t\t\t\tcontext = 'expression'\n\t\t\t\t\tdepth++\n\t\t\t\t} else if (entry.grammar.relations[name]) {\n\t\t\t\t\tconst relation = entry.grammar.relations[name]\n\t\t\t\t\tcontext = relation.cardinality === 'one' ? 'expression' : 'many'\n\t\t\t\t\ttarget = relation.target\n\t\t\t\t\tdepth++\n\t\t\t\t}\n\t\t\t} else if (entry.context === 'variant' && name === 'filters') {\n\t\t\t\tconst tag = Object.getOwnPropertyDescriptor(object, 'tag')\n\t\t\t\tif (\n\t\t\t\t\t!tag ||\n\t\t\t\t\t!('value' in tag) ||\n\t\t\t\t\t!z.string().safeParse(tag.value).success ||\n\t\t\t\t\t!Object.hasOwn(entry.grammar.variants?.options ?? {}, tag.value)\n\t\t\t\t)\n\t\t\t\t\treturn false\n\t\t\t\tcontext = 'expression'\n\t\t\t\ttarget = entry.grammar.variants!.options[String(tag.value)]\n\t\t\t} else if (entry.context === 'fields') context = 'predicate'\n\t\t\telse if (entry.context === 'composition' || entry.context === 'many') context = 'expression'\n\t\t\tpending.push({ value: descriptor.value, depth, context, grammar: target })\n\t\t}\n\t}\n\treturn true\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"filters.mjs","names":["MAX_PAGE_SIZE","nativeOptions","convexToZod","paginationOptsValidator","nativePagination","z","scalarPaginationSchema","predicates","key","selected","selection","validators","scalarPredicateSchema","filters","boundedFilterSchema","assertSupportedScalar","validator","scalar","scalarPredicateFromSchema","supportsRange","MAX_INDEX_EXPANSION","compileFilters","parseFilterPlan","schema","input","indexes","conditions","where","args","parsed","server","grammar","paginationGrammar","residual","canonicalSets","normalizeFilters","guaranteed","guaranteedBindings","ranges","guaranteedRanges","sets","guaranteedSets","field","values","eligible","valueEqual","value","withinRange","range","compared","compareValues","sorted","a","b","condition","entry","index","ordering","prefixBindings","length","ranged","candidate","prefix","expanded","usable","hasRange","expansionForIndex","rangeForIndex","lower","upper","explicit","error","queryFanoutErrors","isQueryFanoutError","ast","uniqueValues","children","node","branches","first","branch","i","child","previous","other","choices","viable","impossible","side","next","bindings","member","MAX_FILTER_DEPTH","MAX_FILTER_IN_VALUES","MAX_FILTER_NODES","relationFilterSchema"],"sources":["../../src/querying/filters.ts"],"sourcesContent":["import {\n\tboundedFilterSchema,\n\tpaginationGrammar,\n\tnormalizeFilters,\n\tscalarPredicateFromSchema,\n\ttype FilterTree,\n\ttype FieldSchemas,\n} from './shared/filters'\n// oxlint-disable-next-line cvx/no-internal-reexports -- Preserve existing internal imports while the neutral grammar owns implementation.\nexport {\n\trelationFilterSchema,\n\tMAX_FILTER_DEPTH,\n\tMAX_FILTER_NODES,\n\tMAX_FILTER_IN_VALUES,\n\ttype FilterGrammar,\n\ttype FieldSchemas,\n} from './shared/filters'\nimport { valueEqual, type FilterAst, type FilterScalar } from './shared/ast'\n// oxlint-disable-next-line cvx/no-internal-reexports -- Existing executor consumers retain their type import boundary.\nexport type { FilterAst, FilterScalar, FilterOperator } from './shared/ast'\nimport { convexToZod, type ConvexValidatorFromZod } from 'convex-helpers/server/zod4'\nimport { paginationOptsValidator } from 'convex/server'\nimport { compareValues, type GenericId, type GenericValidator } from 'convex/values'\nimport { z } from 'zod'\n\n/** Shared hard ceilings; the execution engine may impose lower budgets. */\nexport const MAX_PAGE_SIZE = 100\n\ntype NativeField<Schema extends z.ZodType> = ConvexValidatorFromZod<Schema, 'required'>\ntype ScalarKind = 'id' | 'string' | 'float64' | 'int64' | 'boolean' | 'null' | 'literal'\ntype SupportedNative<Validator extends GenericValidator> = Validator extends { kind: ScalarKind }\n\t? true\n\t: Validator extends { kind: 'union'; members: infer Members extends GenericValidator[] }\n\t\t? false extends SupportedNative<Members[number]>\n\t\t\t? false\n\t\t\t: true\n\t\t: false\n\nexport type ScalarSelection<Fields extends FieldSchemas> = {\n\t[\n\t\tKey in keyof Fields as false extends SupportedNative<NativeField<Fields[Key]>> ? never : Key\n\t]?: true\n}\nexport type ExactScalarSelection<Fields extends FieldSchemas, Selection> = Selection & {\n\t[Key in keyof Selection]: Key extends keyof ScalarSelection<Fields>\n\t\t? Selection[Key] extends true\n\t\t\t? true\n\t\t\t: never\n\t\t: never\n}\n\ntype NativeValue<Schema extends z.ZodType> = Exclude<NativeField<Schema>['type'], undefined>\ntype FilterInputValue<Value> = Value extends GenericId<string> ? string : Value\ntype FilterValue<Schema extends z.ZodType, Side extends 'input' | 'output'> = Side extends 'input'\n\t? FilterInputValue<NativeValue<Schema>>\n\t: NativeValue<Schema>\ntype RangeKind = 'string' | 'float64' | 'int64' | 'literal'\ntype OrderedNative<Validator extends GenericValidator> = Validator extends { kind: RangeKind }\n\t? Validator['type'] extends string | number | bigint | undefined\n\t\t? true\n\t\t: false\n\t: Validator extends { kind: 'union'; members: infer Members extends GenericValidator[] }\n\t\t? false extends OrderedNative<Members[number]>\n\t\t\t? false\n\t\t\t: true\n\t\t: false\ntype OrderedValue<Schema extends z.ZodType> =\n\tOrderedNative<NativeField<Schema>> extends true ? NativeValue<Schema> : never\n\nexport type ScalarPredicate<Schema extends z.ZodType, Side extends 'input' | 'output'> =\n\t| FilterValue<Schema, Side>\n\t| ({ eq?: FilterValue<Schema, Side>; in?: FilterValue<Schema, Side>[] } & ([\n\t\t\tOrderedValue<Schema>,\n\t ] extends [never]\n\t\t\t? {}\n\t\t\t: {\n\t\t\t\t\tgt?: OrderedValue<Schema>\n\t\t\t\t\tgte?: OrderedValue<Schema>\n\t\t\t\t\tlt?: OrderedValue<Schema>\n\t\t\t\t\tlte?: OrderedValue<Schema>\n\t\t\t\t}) &\n\t\t\t('optional' extends NativeField<Schema>['isOptional'] ? { exists?: boolean } : {}))\n\ntype SelectedFieldFilters<\n\tFields extends FieldSchemas,\n\tSelection,\n\tSide extends 'input' | 'output',\n> = {\n\t[Key in Extract<keyof Selection, keyof Fields>]?: ScalarPredicate<Fields[Key], Side>\n}\n\n/** Direct shorthand and explicit fields combine with AND. The fields namespace\n * accepts every selected scalar name, including boolean-control/namespace names.\n */\ntype FilterDepth = readonly [1, 1, 1, 1]\ntype Tail<Depth extends readonly 1[]> = Depth extends readonly [1, ...infer Rest extends 1[]]\n\t? Rest\n\t: []\n\nexport type ScalarFilters<\n\tFields extends FieldSchemas,\n\tSelection,\n\tSide extends 'input' | 'output' = 'output',\n\tDepth extends readonly 1[] = FilterDepth,\n> = Omit<SelectedFieldFilters<Fields, Selection, Side>, 'and' | 'or' | 'not' | 'fields'> & {\n\tfields?: SelectedFieldFilters<Fields, Selection, Side>\n} & (Depth extends readonly []\n\t\t? {}\n\t\t: {\n\t\t\t\tand?: ScalarFilters<Fields, Selection, Side, Tail<Depth>>[]\n\t\t\t\tor?: ScalarFilters<Fields, Selection, Side, Tail<Depth>>[]\n\t\t\t\tnot?: ScalarFilters<Fields, Selection, Side, Tail<Depth>>\n\t\t\t})\n\nconst nativeOptions = convexToZod(paginationOptsValidator)\nexport const nativePagination = nativeOptions.strict().extend({\n\t/** Explicitly accept safe progressing empty splits; legacy safe splits remain supported. */\n\tonEmptyBudget: z.literal('split').optional(),\n\tnumItems: nativeOptions.shape.numItems.int().positive().max(MAX_PAGE_SIZE),\n\tmaximumRowsRead: nativeOptions.shape.maximumRowsRead.unwrap().int().positive().optional(),\n\tmaximumBytesRead: nativeOptions.shape.maximumBytesRead.unwrap().int().positive().optional(),\n})\nexport type NativePagination = z.output<typeof nativePagination>\n/** Preserve the object boundary so pagination options can be registered directly as query args. */\nexport type PaginationOptionsSchema<Filters, InputFilters = Filters> = z.ZodObject<\n\t(typeof nativePagination)['shape'] & {\n\t\tfilters: z.ZodOptional<z.ZodType<Filters, InputFilters>>\n\t\torder: z.ZodOptional<z.ZodEnum<{ asc: 'asc'; desc: 'desc' }>>\n\t},\n\tz.core.$strict\n>\nexport type ScalarPaginationSchema<\n\tFields extends FieldSchemas,\n\tSelection,\n> = PaginationOptionsSchema<\n\tScalarFilters<Fields, Selection>,\n\tScalarFilters<Fields, Selection, 'input'>\n>\n\n/** Scalar-only schema constructor shared by table and future registry boundaries.\n * Convex metadata describes stored INPUT, so storage refinements/transforms never run here.\n */\nexport function scalarPaginationSchema<\n\tFields extends FieldSchemas,\n\tconst Selection extends ScalarSelection<Fields>,\n>(\n\tvalidators: Record<string, GenericValidator>,\n\tselection: ExactScalarSelection<Fields, Selection>,\n): ScalarPaginationSchema<Fields, Selection> {\n\tconst predicates: FieldSchemas = {}\n\tfor (const [key, selected] of Object.entries(selection)) {\n\t\tif (selected !== true || !Object.hasOwn(validators, key)) {\n\t\t\tthrow new Error(`Invalid scalar filter selection \"${key}\"`)\n\t\t}\n\t\tpredicates[key] = scalarPredicateSchema(validators[key]).optional()\n\t}\n\tconst filters = boundedFilterSchema(predicates)\n\tconst result = nativePagination.extend({\n\t\tfilters: filters.optional(),\n\t\torder: z.enum(['asc', 'desc']).optional(),\n\t})\n\t// SAFETY: selected validators generate the same native scalar input/output relationships\n\t// described by ScalarFilters, including converter-registered ID brands.\n\treturn result as ScalarPaginationSchema<Fields, Selection>\n}\n\nexport function scalarPredicateSchema(validator: GenericValidator): z.ZodType {\n\tassertSupportedScalar(validator)\n\tconst scalar = convexToZod(validator).nonoptional()\n\treturn scalarPredicateFromSchema(\n\t\tscalar,\n\t\tsupportsRange(validator),\n\t\tvalidator.isOptional === 'optional',\n\t)\n}\n\nexport interface QueryIndex {\n\tname: string\n\tfields: readonly string[]\n}\nexport interface IndexCondition {\n\tvalue: FilterScalar | undefined\n\tindex: string\n}\nexport interface RangeBound {\n\tvalue: FilterScalar\n\tinclusive: boolean\n}\nexport interface FieldRange {\n\tlower?: RangeBound\n\tupper?: RangeBound\n}\nexport interface NativeRange extends FieldRange {\n\tfield: string\n}\nexport const MAX_INDEX_EXPANSION = 8\nexport interface IndexExpansion {\n\tfield: string\n\tvalues: FilterScalar[]\n\tcomparator: 'tail' | 'full-index'\n}\nexport interface CompiledFilters {\n\texpansion: IndexExpansion | null\n\tsets: ReadonlyMap<string, FilterScalar[]>\n\n\tresidual: FilterAst\n\tbindings: ReadonlyMap<string, FilterScalar>\n\tranges: ReadonlyMap<string, FieldRange>\n\trange: NativeRange | null\n\tunsatisfiable: boolean\n\tindex: QueryIndex | null\n\tprefix: readonly { field: string; value: FilterScalar }[]\n}\ntype FilterSpec<Schema extends z.ZodType> =\n\tz.input<Schema> extends { filters?: infer Spec } ? Spec : never\nexport type ServerFilter<Fields extends FieldSchemas> = ScalarFilters<\n\tFields,\n\tScalarSelection<Fields>\n>\n\ninterface BindingResult {\n\tvalues: Map<string, FilterScalar>\n\timpossible: boolean\n}\n\n/** Validate first; where is independently validated and ANDed with client predicates.\n * Only guaranteed sets at one consecutive index position may expand.\n */\nexport function compileFilters<Schema extends z.ZodType>(\n\tschema: Schema,\n\tinput: z.input<Schema>,\n\tindexes: readonly QueryIndex[],\n\tconditions: readonly IndexCondition[] = [],\n\twhere?: FilterSpec<Schema>,\n): CompiledFilters {\n\treturn parseFilterPlan(schema, input, indexes, conditions, where).compiled\n}\n\n/** Internal planner boundary: retain the parsed arguments without parsing them again. */\nexport function parseFilterPlan<Schema extends z.ZodType>(\n\tschema: Schema,\n\tinput: z.input<Schema>,\n\tindexes: readonly QueryIndex[],\n\tconditions: readonly IndexCondition[] = [],\n\twhere?: FilterSpec<Schema>,\n\tordering?: string,\n) {\n\tconst args = schema.parse(input)\n\t// SAFETY: pagination schemas validate filters before this internal AST adapter reads them.\n\tconst parsed = args as { filters?: FilterTree }\n\t// SAFETY: server filters use the same validation boundary as client filters.\n\tconst server =\n\t\twhere === undefined\n\t\t\t? undefined\n\t\t\t: (schema.parse({ ...parsed, filters: where }) as { filters?: FilterTree })\n\tconst grammar = paginationGrammar(schema)\n\tconst residual: FilterAst = {\n\t\tkind: 'and',\n\t\tchildren: [\n\t\t\tcanonicalSets(normalizeFilters(parsed.filters, grammar)),\n\t\t\tcanonicalSets(normalizeFilters(server?.filters, grammar)),\n\t\t],\n\t}\n\tconst guaranteed = guaranteedBindings(residual)\n\tconst ranges = guaranteedRanges(residual)\n\tconst sets = guaranteedSets(residual)\n\tfor (const [field, values] of sets) {\n\t\tconst eligible = values.filter(\n\t\t\t(value) =>\n\t\t\t\t(!guaranteed.values.has(field) || valueEqual(value, guaranteed.values.get(field)!)) &&\n\t\t\t\t(!ranges.has(field) || withinRange(value, ranges.get(field)!)),\n\t\t)\n\t\tsets.set(field, eligible)\n\t\tif (!eligible.length) guaranteed.impossible = true\n\t}\n\tfor (const [field, range] of ranges) {\n\t\tif (range.lower && range.upper) {\n\t\t\tconst compared = compareValues(range.lower.value, range.upper.value)\n\t\t\tif (compared > 0 || (compared === 0 && (!range.lower.inclusive || !range.upper.inclusive)))\n\t\t\t\tguaranteed.impossible = true\n\t\t}\n\t\tif (guaranteed.values.has(field) && !withinRange(guaranteed.values.get(field)!, range))\n\t\t\tguaranteed.impossible = true\n\t}\n\tconst sorted = [...indexes].sort(\n\t\t(a, b) =>\n\t\t\ta.name.localeCompare(b.name) || a.fields.join('\\0').localeCompare(b.fields.join('\\0')),\n\t)\n\tconst condition = conditions.find((entry) => entry.value !== null && entry.value !== undefined)\n\tlet index: QueryIndex | null = null\n\tif (ordering !== undefined) {\n\t\tif (condition) throw new Error('orderBy cannot be combined with an active when selector')\n\t\tindex = sorted.find((entry) => entry.name === ordering) ?? null\n\t\tif (!index) throw new Error(`Unknown ordering index \"${ordering}\"`)\n\t} else if (condition) {\n\t\tindex = sorted.find((entry) => entry.name === condition.index) ?? null\n\t\tif (!index || prefixBindings(index, guaranteed.values).length === 0)\n\t\t\tthrow new Error(`Explicit index \"${condition.index}\" is incompatible with guaranteed filters`)\n\t} else {\n\t\tlet length = 0\n\t\tlet ranged = false\n\t\tfor (const candidate of sorted) {\n\t\t\tconst prefix = prefixBindings(candidate, guaranteed.values)\n\t\t\tconst expanded = sets.has(candidate.fields[prefix.length])\n\t\t\tconst usable = prefix.length + Number(expanded)\n\t\t\tconst hasRange = ranges.has(candidate.fields[usable])\n\t\t\tif (usable > length || (usable === length && hasRange && !ranged)) {\n\t\t\t\tindex = candidate\n\t\t\t\tlength = usable\n\t\t\t\tranged = hasRange\n\t\t\t}\n\t\t}\n\t}\n\tconst prefix = index ? prefixBindings(index, guaranteed.values) : []\n\tconst expansion =\n\t\tindex && !guaranteed.impossible\n\t\t\t? expansionForIndex(index, prefix, sets, ordering !== undefined || !!condition)\n\t\t\t: null\n\tconst compiled: CompiledFilters = {\n\t\tsets,\n\t\texpansion,\n\t\tresidual,\n\t\tbindings: guaranteed.values,\n\t\tranges,\n\t\trange: index ? rangeForIndex(index, prefixBindings(index, guaranteed.values), ranges) : null,\n\t\tunsatisfiable: guaranteed.impossible,\n\t\tindex,\n\t\tprefix: index ? prefixBindings(index, guaranteed.values) : [],\n\t}\n\treturn { args, compiled }\n}\nexport function withinRange(value: FilterScalar, range: FieldRange): boolean {\n\tconst lower = range.lower && compareValues(value, range.lower.value)\n\tconst upper = range.upper && compareValues(value, range.upper.value)\n\treturn (\n\t\t(lower === undefined || lower > 0 || (lower === 0 && range.lower!.inclusive)) &&\n\t\t(upper === undefined || upper < 0 || (upper === 0 && range.upper!.inclusive))\n\t)\n}\n/** Recompute against the actual stream prefix, including relationship lookup bindings. */\nexport function rangeForIndex(\n\tindex: QueryIndex,\n\tprefix: readonly { field: string; value: FilterScalar }[],\n\tranges: ReadonlyMap<string, FieldRange>,\n): NativeRange | null {\n\tconst field = index.fields[prefix.length]\n\tconst range = ranges.get(field)\n\treturn range ? { field, ...range } : null\n}\n/** Recompute for the actual lookup prefix on direct relationships, too. */\nexport function expansionForIndex(\n\tindex: QueryIndex,\n\tprefix: readonly { field: string; value: FilterScalar }[],\n\tsets: ReadonlyMap<string, FilterScalar[]>,\n\texplicit: boolean,\n): IndexExpansion | null {\n\tconst field = index.fields[prefix.length]\n\tconst values = sets.get(field)\n\tif (!values?.length) return null\n\tif (values.length > MAX_INDEX_EXPANSION) {\n\t\tif (explicit) return null\n\t\tconst error = new Error('QUERY_FANOUT')\n\t\tqueryFanoutErrors.add(error)\n\t\tthrow error\n\t}\n\treturn { field, values, comparator: explicit ? 'full-index' : 'tail' }\n}\n\n// Preserve the existing Error/message for direct callers; only engine-created identities are transportable.\nconst queryFanoutErrors = new WeakSet<Error>()\n// oxlint-disable-next-line anti-slop/no-unknown-parameters -- Endpoint projection must accept arbitrary thrown values.\nexport function isQueryFanoutError(error: unknown): boolean {\n\treturn error instanceof Error && queryFanoutErrors.has(error)\n}\n\n/** Normalize only membership sets; unrelated boolean expressions retain their identity. */\nfunction canonicalSets(ast: FilterAst): FilterAst {\n\tif (ast.kind === 'scalar' && ast.operator === 'in' && Array.isArray(ast.value))\n\t\treturn { ...ast, value: uniqueValues(ast.value) }\n\tif (ast.kind === 'and' || ast.kind === 'or') {\n\t\tconst children = ast.children.map(canonicalSets)\n\t\tconst scalar = (node: FilterAst): { field: string; value: FilterScalar } | undefined => {\n\t\t\tif (node.kind === 'scalar' && node.operator === 'eq' && !Array.isArray(node.value))\n\t\t\t\treturn { field: node.field, value: node.value }\n\t\t\tif (node.kind === 'and' && node.children.length === 1) return scalar(node.children[0])\n\t\t\treturn undefined\n\t\t}\n\t\tconst branches = children.map(scalar)\n\t\tconst first = branches[0]\n\t\tif (ast.kind === 'or' && first && branches.every((branch) => branch?.field === first.field))\n\t\t\treturn {\n\t\t\t\tkind: 'scalar',\n\t\t\t\tfield: first.field,\n\t\t\t\toperator: 'in',\n\t\t\t\tvalue: uniqueValues(branches.map((branch) => branch!.value)),\n\t\t\t}\n\t\treturn { ...ast, children }\n\t}\n\tif (ast.kind === 'not') return { ...ast, child: canonicalSets(ast.child) }\n\tif (ast.kind === 'variant') return { ...ast, child: canonicalSets(ast.child) }\n\tif (ast.kind === 'relation' && ast.predicate)\n\t\treturn { ...ast, predicate: canonicalSets(ast.predicate) }\n\treturn ast\n}\nfunction uniqueValues(values: FilterScalar[]): FilterScalar[] {\n\treturn [...values]\n\t\t.sort(compareValues)\n\t\t.filter((value, i, sorted) => i === 0 || !valueEqual(value, sorted[i - 1]))\n}\nfunction guaranteedSets(ast: FilterAst, sets = new Map<string, FilterScalar[]>()) {\n\tif (ast.kind === 'and') for (const child of ast.children) guaranteedSets(child, sets)\n\telse if (ast.kind === 'variant') guaranteedSets(ast.child, sets)\n\telse if (ast.kind === 'scalar' && ast.operator === 'in' && Array.isArray(ast.value)) {\n\t\tconst previous = sets.get(ast.field)\n\t\tsets.set(\n\t\t\tast.field,\n\t\t\tprevious\n\t\t\t\t? ast.value.filter((value) => previous.some((other) => valueEqual(value, other)))\n\t\t\t\t: ast.value,\n\t\t)\n\t}\n\treturn sets\n}\nfunction guaranteedBindings(ast: FilterAst): BindingResult {\n\tconst values = new Map<string, FilterScalar>()\n\tif (ast.kind === 'variant')\n\t\treturn guaranteedBindings({\n\t\t\tkind: 'and',\n\t\t\tchildren: [\n\t\t\t\t{ kind: 'scalar', field: ast.discriminator, operator: 'eq', value: ast.tag },\n\t\t\t\tast.child,\n\t\t\t],\n\t\t})\n\tif (ast.kind === 'scalar') {\n\t\tif (ast.operator === 'eq' && !Array.isArray(ast.value)) values.set(ast.field, ast.value)\n\t\tconst choices = Array.isArray(ast.value) ? ast.value : undefined\n\t\tif (\n\t\t\tast.operator === 'in' &&\n\t\t\tchoices?.length &&\n\t\t\tchoices.every((value) => valueEqual(value, choices[0]))\n\t\t)\n\t\t\tvalues.set(ast.field, choices[0])\n\t\treturn { values, impossible: ast.operator === 'in' && choices?.length === 0 }\n\t}\n\tif (ast.kind === 'not' || ast.kind === 'relation') return { values, impossible: false }\n\tconst branches = ast.children.map(guaranteedBindings)\n\tif (ast.kind === 'or') {\n\t\tconst viable = branches.filter((branch) => !branch.impossible)\n\t\tfor (const [field, value] of viable[0]?.values ?? [])\n\t\t\tif (\n\t\t\t\tviable.every(\n\t\t\t\t\t(branch) => branch.values.has(field) && valueEqual(branch.values.get(field)!, value),\n\t\t\t\t)\n\t\t\t)\n\t\t\t\tvalues.set(field, value)\n\t\treturn { values, impossible: viable.every((branch) => branch.impossible) }\n\t}\n\tlet impossible = branches.some((branch) => branch.impossible)\n\tfor (const branch of branches)\n\t\tfor (const [field, value] of branch.values) {\n\t\t\tif (values.has(field) && !valueEqual(values.get(field)!, value)) impossible = true\n\t\t\tvalues.set(field, value)\n\t\t}\n\treturn { values, impossible }\n}\n/** Bounds under OR/NOT are deliberately residual, even when branches coincide. */\nfunction guaranteedRanges(ast: FilterAst, ranges = new Map<string, FieldRange>()) {\n\tif (ast.kind === 'and') for (const child of ast.children) guaranteedRanges(child, ranges)\n\telse if (ast.kind === 'variant') guaranteedRanges(ast.child, ranges)\n\telse if (ast.kind === 'scalar' && !Array.isArray(ast.value)) {\n\t\tconst lower = ast.operator === 'gt' || ast.operator === 'gte'\n\t\tconst upper = ast.operator === 'lt' || ast.operator === 'lte'\n\t\tif (lower || upper) {\n\t\t\tconst range = ranges.get(ast.field) ?? {}\n\t\t\tconst side = lower ? 'lower' : 'upper'\n\t\t\tconst next = { value: ast.value, inclusive: ast.operator === 'gte' || ast.operator === 'lte' }\n\t\t\tconst previous = range[side]\n\t\t\tconst compared = previous ? compareValues(next.value, previous.value) : 0\n\t\t\tif (!previous || (lower ? compared > 0 : compared < 0) || (compared === 0 && !next.inclusive))\n\t\t\t\trange[side] = next\n\t\t\tranges.set(ast.field, range)\n\t\t}\n\t}\n\treturn ranges\n}\nfunction prefixBindings(\n\tindex: QueryIndex,\n\tbindings: ReadonlyMap<string, FilterScalar>,\n): { field: string; value: FilterScalar }[] {\n\tconst prefix: { field: string; value: FilterScalar }[] = []\n\tfor (const field of index.fields) {\n\t\tif (!bindings.has(field)) break\n\t\tprefix.push({ field, value: bindings.get(field)! })\n\t}\n\treturn prefix\n}\n\nfunction assertSupportedScalar(validator: GenericValidator): void {\n\tswitch (validator.kind) {\n\t\tcase 'id':\n\t\tcase 'string':\n\t\tcase 'float64':\n\t\tcase 'int64':\n\t\tcase 'boolean':\n\t\tcase 'null':\n\t\tcase 'literal':\n\t\t\treturn\n\t\tcase 'union':\n\t\t\tfor (const member of validator.members) {\n\t\t\t\tassertSupportedScalar(member)\n\t\t\t}\n\t\t\treturn\n\t\tdefault:\n\t\t\tthrow new Error(`Unsupported scalar filter kind \"${validator.kind}\"`)\n\t}\n}\n\nfunction supportsRange(validator: GenericValidator): boolean {\n\tswitch (validator.kind) {\n\t\tcase 'string':\n\t\tcase 'float64':\n\t\tcase 'int64':\n\t\t\treturn true\n\t\tcase 'literal':\n\t\t\treturn z.union([z.string(), z.number(), z.bigint()]).safeParse(validator.value).success\n\t\tcase 'union':\n\t\t\treturn validator.members.every(supportsRange)\n\t\tdefault:\n\t\t\treturn false\n\t}\n}\n"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
- import { FilterAst, FilterScalar, IndexCondition, QueryIndex } from "./filters.mjs";
2
- import { RelationMetadata, RelationRegistryIdentity, SelectionMask, getRelationExecutor } from "../relations.mjs";
1
+ import { FilterAst, FilterScalar } from "./shared/ast.mjs";
2
+ import { FieldRange, IndexCondition, IndexExpansion, NativeRange, QueryIndex } from "./filters.mjs";
3
+ import { GroupSelection, RelationMetadata, RelationRegistryIdentity, SelectionMask, getRelationExecutor } from "../relations.mjs";
3
4
  import { GenericSchema, SchemaDefinition } from "convex/server";
4
5
  import { z } from "zod";
5
6
  import { Value } from "convex/values";
@@ -9,13 +10,18 @@ export type StoredConstraint = NonNullable<QueryInput['filters']>;
9
10
  export declare function createPlanner(schema: SchemaDefinition<GenericSchema, boolean>, relations: RelationRegistryIdentity): {
10
11
  metadata: RelationMetadata;
11
12
  select: (table: string, selection: SelectionMask) => void;
13
+ groups: (table: string, groups: GroupSelection) => GroupSelection;
12
14
  validateDocument: (table: string, row: Record<string, import('convex/values').Value>) => void;
13
15
  streamSchema: SchemaDefinition<GenericSchema, boolean>;
14
16
  beforeLeaf(table: string): void;
15
- complete(table: string, document: Record<string, Value>, permitted: boolean, residual: FilterAst): Record<string, unknown> | null;
16
- plan(table: string, input: QueryInput, conditions: readonly IndexCondition[], constraints: readonly StoredConstraint[]): {
17
+ complete(table: string, document: Record<string, Value>, permitted: boolean, residual: FilterAst, groups?: readonly string[]): Record<string, unknown> | null;
18
+ plan(table: string, input: QueryInput, conditions: readonly IndexCondition[], constraints: readonly StoredConstraint[], ordering?: string, traversal?: 'root' | 'relation'): {
19
+ expansion: IndexExpansion | null;
20
+ sets: ReadonlyMap<string, FilterScalar[]>;
17
21
  residual: FilterAst;
18
22
  bindings: ReadonlyMap<string, FilterScalar>;
23
+ ranges: ReadonlyMap<string, FieldRange>;
24
+ range: NativeRange | null;
19
25
  unsatisfiable: boolean;
20
26
  index: QueryIndex | null;
21
27
  prefix: readonly {
@@ -26,6 +32,7 @@ export declare function createPlanner(schema: SchemaDefinition<GenericSchema, bo
26
32
  cursor: string | null;
27
33
  endCursor?: string | null | undefined;
28
34
  id?: number | undefined;
35
+ onEmptyBudget?: "split" | undefined;
29
36
  numItems: number;
30
37
  maximumRowsRead?: number | undefined;
31
38
  maximumBytesRead?: number | undefined;
@@ -36,7 +43,6 @@ export declare function createPlanner(schema: SchemaDefinition<GenericSchema, bo
36
43
  serverIdentity: Value;
37
44
  };
38
45
  };
39
- /** Native scalar ordering/equality, including missing vs null, without coercion. */
40
46
  export declare function scalarMatches(ast: FilterAst, document: Record<string, Value | undefined>): boolean;
41
47
  //#endregion
42
48
  //# sourceMappingURL=planner.d.mts.map
@@ -1,2 +1,2 @@
1
- import{parseFilterPlan as e}from"./filters.mjs";import{getRelationExecutor as t,getRelationMetadata as n}from"../relations.mjs";import{compareValues as r}from"convex/values";function i(r,i){let o=t(i);o.assertSchema(r.tables);let s=n(i),c=/* @__PURE__ */ new Map;return{metadata:s,select:o.select,validateDocument:o.validateDocument,streamSchema:o.streamSchema,beforeLeaf(e){if(!Object.hasOwn(s.tables,e))throw Error(`Unknown query table`)},complete(e,t,n,r){return o.project(e,t,()=>n&&a(r,t))},plan(t,n,r,i){if(!Object.hasOwn(s.tables,t))throw Error(`Unknown query table`);let a=c.get(t);a||(a=o.pagination(t),c.set(t,a));let l=i.length===1?i[0]:i.length?{and:i}:void 0,{args:u,compiled:d}=e(a,n,s.tables[t].indexes,r,l);if(d.residual.kind!==`and`)throw Error(`Invalid compiled filter root`);let[f,p]=d.residual.children,m={kind:`and`,children:[]},h={kind:`and`,children:[f,m]},g={kind:`and`,children:[p,m]};return{...d,args:u,clientIdentity:h,serverIdentity:g}}}}function a(e,t){switch(e.kind){case`and`:return e.children.every(e=>a(e,t));case`or`:return e.children.some(e=>a(e,t));case`variant`:return t[e.discriminator]===e.tag&&a(e.child,t);case`not`:return!a(e.child,t);case`relation`:throw Error(`Relation execution requires U6`);case`scalar`:{let n=t[e.field];if(e.operator===`exists`)return n!==void 0===e.value;if(e.operator===`in`)return Array.isArray(e.value)&&e.value.some(e=>r(n,e)===0);if(Array.isArray(e.value))throw Error(`Invalid scalar predicate`);let i=r(n,e.value);switch(e.operator){case`eq`:return i===0;case`gt`:return i>0;case`gte`:return i>=0;case`lt`:return i<0;case`lte`:return i<=0}}}}export{i as createPlanner,a as scalarMatches};
1
+ import{evaluateFilter as e}from"./shared/evaluate.mjs";import{parseFilterPlan as t}from"./filters.mjs";import{getRelationExecutor as n,getRelationMetadata as r}from"../relations.mjs";import"convex/values";function i(e,i){let o=n(i);o.assertSchema(e.tables);let s=r(i),c=/* @__PURE__ */ new Map;return{metadata:s,select:o.select,groups:o.groups,validateDocument:o.validateDocument,streamSchema:o.streamSchema,beforeLeaf(e){if(!Object.hasOwn(s.tables,e))throw Error(`Unknown query table`)},complete(e,t,n,r,i=[]){return o.project(e,t,()=>n&&a(r,t),i)},plan(e,n,r,i,a,l=`root`){if(!Object.hasOwn(s.tables,e))throw Error(`Unknown query table`);let u=c.get(e);u||(u=o.pagination(e),c.set(e,u));let d=i.length===1?i[0]:i.length?{and:i}:void 0,{args:f,compiled:p}=t(u,n,l===`relation`&&a===void 0?[]:s.tables[e].indexes,r,d,a);if(p.residual.kind!==`and`)throw Error(`Invalid compiled filter root`);let[m,h]=p.residual.children,g={kind:`and`,children:[]},_={kind:`and`,children:[m,g]},v=p.sets.size?{kind:`and`,children:[h,g],traversal:{version:2,expansion:p.expansion}}:{kind:`and`,children:[h,g]};return{...p,args:f,clientIdentity:_,serverIdentity:v}}}}function a(t,n){return e(t,n)===!0}export{i as createPlanner,a as scalarMatches};
2
2
  //# sourceMappingURL=planner.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"planner.mjs","names":["createPlanner","owned","getRelationExecutor","relations","schema","metadata","getRelationMetadata","inputs","table","document","permitted","scalarMatches","residual","validator","where","constraints","parseFilterPlan","input","conditions","compiled","client","server","empty","clientIdentity","serverIdentity","ast","child","actual","compareValues","value","compared"],"sources":["../../src/querying/planner.ts"],"sourcesContent":["import type { z } from 'zod'\nimport type { SchemaDefinition, GenericSchema } from 'convex/server'\nimport { compareValues, type Value } from 'convex/values'\nimport {\n\tgetRelationExecutor,\n\tgetRelationMetadata,\n\ttype RelationRegistryIdentity,\n} from '../relations'\nimport { parseFilterPlan, type FilterAst, type IndexCondition } from './filters'\n\nexport type QueryInput = z.input<ReturnType<ReturnType<typeof getRelationExecutor>['pagination']>>\nexport type StoredConstraint = NonNullable<QueryInput['filters']>\n\nexport function createPlanner(\n\tschema: SchemaDefinition<GenericSchema, boolean>,\n\trelations: RelationRegistryIdentity,\n) {\n\tconst owned = getRelationExecutor(relations)\n\towned.assertSchema(schema.tables)\n\tconst metadata = getRelationMetadata(relations)\n\t// Build each immutable filter grammar only when that table is queried. Engine\n\t// declarations also load in mutations, which never need pagination validators.\n\tconst inputs = new Map<string, ReturnType<typeof owned.pagination>>()\n\treturn {\n\t\tmetadata,\n\t\tselect: owned.select,\n\t\tvalidateDocument: owned.validateDocument,\n\t\tstreamSchema: owned.streamSchema,\n\t\tbeforeLeaf(table: string) {\n\t\t\tif (!Object.hasOwn(metadata.tables, table)) throw new Error('Unknown query table')\n\t\t},\n\t\tcomplete(\n\t\t\ttable: string,\n\t\t\tdocument: Record<string, Value>,\n\t\t\tpermitted: boolean,\n\t\t\tresidual: FilterAst,\n\t\t) {\n\t\t\treturn owned.project(table, document, () => permitted && scalarMatches(residual, document))\n\t\t},\n\t\tplan(\n\t\t\ttable: string,\n\t\t\tinput: QueryInput,\n\t\t\tconditions: readonly IndexCondition[],\n\t\t\tconstraints: readonly StoredConstraint[],\n\t\t) {\n\t\t\tif (!Object.hasOwn(metadata.tables, table)) throw new Error('Unknown query table')\n\t\t\tlet validator = inputs.get(table)\n\t\t\tif (!validator) {\n\t\t\t\tvalidator = owned.pagination(table)\n\t\t\t\tinputs.set(table, validator)\n\t\t\t}\n\t\t\t// Server constraints are independently validated against stored fields,\n\t\t\t// not the endpoint's public input/filter mask. Client values cannot replace them.\n\t\t\tconst where =\n\t\t\t\tconstraints.length === 1\n\t\t\t\t\t? constraints[0]\n\t\t\t\t\t: constraints.length\n\t\t\t\t\t\t? { and: constraints }\n\t\t\t\t\t\t: undefined\n\t\t\tconst { args, compiled } = parseFilterPlan(\n\t\t\t\tvalidator,\n\t\t\t\tinput,\n\t\t\t\tmetadata.tables[table].indexes,\n\t\t\t\tconditions,\n\t\t\t\twhere,\n\t\t\t)\n\t\t\tif (compiled.residual.kind !== 'and') throw new Error('Invalid compiled filter root')\n\t\t\tconst [client, server] = compiled.residual.children\n\t\t\tconst empty: FilterAst = { kind: 'and', children: [] }\n\t\t\tconst clientIdentity = { kind: 'and', children: [client, empty] }\n\t\t\tconst serverIdentity = { kind: 'and', children: [server, empty] }\n\t\t\t// SAFETY: normalized AST nodes contain only validated native scalar Values.\n\t\t\treturn {\n\t\t\t\t...compiled,\n\t\t\t\targs,\n\t\t\t\tclientIdentity: clientIdentity as Value,\n\t\t\t\tserverIdentity: serverIdentity as Value,\n\t\t\t}\n\t\t},\n\t}\n}\n\n/** Native scalar ordering/equality, including missing vs null, without coercion. */\nexport function scalarMatches(\n\tast: FilterAst,\n\tdocument: Record<string, Value | undefined>,\n): boolean {\n\tswitch (ast.kind) {\n\t\tcase 'and':\n\t\t\treturn ast.children.every((child) => scalarMatches(child, document))\n\t\tcase 'or':\n\t\t\treturn ast.children.some((child) => scalarMatches(child, document))\n\t\tcase 'variant':\n\t\t\treturn document[ast.discriminator] === ast.tag && scalarMatches(ast.child, document)\n\t\tcase 'not':\n\t\t\treturn !scalarMatches(ast.child, document)\n\t\tcase 'relation':\n\t\t\tthrow new Error('Relation execution requires U6')\n\t\tcase 'scalar': {\n\t\t\tconst actual = document[ast.field]\n\t\t\tif (ast.operator === 'exists') return (actual !== undefined) === ast.value\n\t\t\tif (ast.operator === 'in')\n\t\t\t\treturn (\n\t\t\t\t\tArray.isArray(ast.value) && ast.value.some((value) => compareValues(actual, value) === 0)\n\t\t\t\t)\n\t\t\tif (Array.isArray(ast.value)) throw new Error('Invalid scalar predicate')\n\t\t\tconst compared = compareValues(actual, ast.value)\n\t\t\tswitch (ast.operator) {\n\t\t\t\tcase 'eq':\n\t\t\t\t\treturn compared === 0\n\t\t\t\tcase 'gt':\n\t\t\t\t\treturn compared > 0\n\t\t\t\tcase 'gte':\n\t\t\t\t\treturn compared >= 0\n\t\t\t\tcase 'lt':\n\t\t\t\t\treturn compared < 0\n\t\t\t\tcase 'lte':\n\t\t\t\t\treturn compared <= 0\n\t\t\t}\n\t\t}\n\t}\n}\n"],"mappings":"8KAaA,SAAgBA,EACf,EACA,EACC,CACD,IAAMC,EAAQC,EAAoBC,CAAS,EAC3CF,EAAM,aAAaG,EAAO,MAAM,EAChC,IAAMC,EAAWC,EAAoBH,CAAS,EAGxCI,kBAAS,IAAI,IACnB,MAAO,CACN,WACA,OAAQN,EAAM,OACd,iBAAkBA,EAAM,iBACxB,aAAcA,EAAM,aACpB,WAAW,EAAe,CACzB,GAAI,CAAC,OAAO,OAAOI,EAAS,OAAQG,CAAK,EAAG,MAAU,MAAM,qBAAqB,CAClF,EACA,SACC,EACA,EACA,EACA,EACC,CACD,OAAOP,EAAM,QAAQO,EAAOC,MAAgBC,GAAaC,EAAcC,EAAUH,CAAQ,CAAC,CAC3F,EACA,KACC,EACA,EACA,EACA,EACC,CACD,GAAI,CAAC,OAAO,OAAOJ,EAAS,OAAQG,CAAK,EAAG,MAAU,MAAM,qBAAqB,EACjF,IAAIK,EAAYN,EAAO,IAAIC,CAAK,EAC3BK,IACJ,EAAYZ,EAAM,WAAWO,CAAK,EAClCD,EAAO,IAAIC,EAAOK,CAAS,GAI5B,IAAMC,EACLC,EAAY,SAAW,EACpBA,EAAY,GACZA,EAAY,OACX,CAAE,IAAKA,CAAY,EACnB,IAAA,GACC,CAAE,OAAM,YAAaC,EAC1BH,EACAI,EACAZ,EAAS,OAAOG,EAAM,CAAC,QACvBU,EACAJ,CACD,EACA,GAAIK,EAAS,SAAS,OAAS,MAAO,MAAU,MAAM,8BAA8B,EACpF,GAAM,CAACC,EAAQC,GAAUF,EAAS,SAAS,SACrCG,EAAmB,CAAE,KAAM,MAAO,SAAU,CAAC,CAAE,EAC/CC,EAAiB,CAAE,KAAM,MAAO,SAAU,CAACH,EAAQE,CAAK,CAAE,EAC1DE,EAAiB,CAAE,KAAM,MAAO,SAAU,CAACH,EAAQC,CAAK,CAAE,EAEhE,MAAO,CACN,GAAGH,EACH,OACgB,iBACA,gBACjB,CACD,CACD,CACD,CAGA,SAAgBR,EACf,EACA,EACU,CACV,OAAQc,EAAI,KAAZ,CACC,IAAK,MACJ,OAAOA,EAAI,SAAS,MAAO,GAAUd,EAAce,EAAOjB,CAAQ,CAAC,EACpE,IAAK,KACJ,OAAOgB,EAAI,SAAS,KAAM,GAAUd,EAAce,EAAOjB,CAAQ,CAAC,EACnE,IAAK,UACJ,OAAOA,EAASgB,EAAI,iBAAmBA,EAAI,KAAOd,EAAcc,EAAI,MAAOhB,CAAQ,EACpF,IAAK,MACJ,MAAO,CAACE,EAAcc,EAAI,MAAOhB,CAAQ,EAC1C,IAAK,WACJ,MAAU,MAAM,gCAAgC,EACjD,IAAK,SAAU,CACd,IAAMkB,EAASlB,EAASgB,EAAI,OAC5B,GAAIA,EAAI,WAAa,SAAU,OAAQE,IAAW,IAAA,KAAeF,EAAI,MACrE,GAAIA,EAAI,WAAa,KACpB,OACC,MAAM,QAAQA,EAAI,KAAK,GAAKA,EAAI,MAAM,KAAM,GAAUG,EAAcD,EAAQE,CAAK,IAAM,CAAC,EAE1F,GAAI,MAAM,QAAQJ,EAAI,KAAK,EAAG,MAAU,MAAM,0BAA0B,EACxE,IAAMK,EAAWF,EAAcD,EAAQF,EAAI,KAAK,EAChD,OAAQA,EAAI,SAAZ,CACC,IAAK,KACJ,OAAOK,IAAa,EACrB,IAAK,KACJ,OAAOA,EAAW,EACnB,IAAK,MACJ,OAAOA,GAAY,EACpB,IAAK,KACJ,OAAOA,EAAW,EACnB,IAAK,MACJ,OAAOA,GAAY,CACrB,CACD,CACD,CACD"}
1
+ {"version":3,"file":"planner.mjs","names":["createPlanner","owned","getRelationExecutor","relations","schema","metadata","getRelationMetadata","inputs","table","document","permitted","scalarMatches","residual","groups","validator","where","constraints","parseFilterPlan","input","traversal","ordering","conditions","compiled","client","server","empty","clientIdentity","serverIdentity","evaluateFilter","ast"],"sources":["../../src/querying/planner.ts"],"sourcesContent":["import { evaluateFilter } from './shared/evaluate'\nimport type { z } from 'zod'\nimport type { SchemaDefinition, GenericSchema } from 'convex/server'\nimport { type Value } from 'convex/values'\nimport {\n\tgetRelationExecutor,\n\tgetRelationMetadata,\n\ttype RelationRegistryIdentity,\n} from '../relations'\nimport { parseFilterPlan, type FilterAst, type IndexCondition } from './filters'\n\nexport type QueryInput = z.input<ReturnType<ReturnType<typeof getRelationExecutor>['pagination']>>\nexport type StoredConstraint = NonNullable<QueryInput['filters']>\n\nexport function createPlanner(\n\tschema: SchemaDefinition<GenericSchema, boolean>,\n\trelations: RelationRegistryIdentity,\n) {\n\tconst owned = getRelationExecutor(relations)\n\towned.assertSchema(schema.tables)\n\tconst metadata = getRelationMetadata(relations)\n\t// Build each immutable filter grammar only when that table is queried. Engine\n\t// declarations also load in mutations, which never need pagination validators.\n\tconst inputs = new Map<string, ReturnType<typeof owned.pagination>>()\n\treturn {\n\t\tmetadata,\n\t\tselect: owned.select,\n\t\tgroups: owned.groups,\n\t\tvalidateDocument: owned.validateDocument,\n\t\tstreamSchema: owned.streamSchema,\n\t\tbeforeLeaf(table: string) {\n\t\t\tif (!Object.hasOwn(metadata.tables, table)) throw new Error('Unknown query table')\n\t\t},\n\t\tcomplete(\n\t\t\ttable: string,\n\t\t\tdocument: Record<string, Value>,\n\t\t\tpermitted: boolean,\n\t\t\tresidual: FilterAst,\n\t\t\tgroups: readonly string[] = [],\n\t\t) {\n\t\t\treturn owned.project(\n\t\t\t\ttable,\n\t\t\t\tdocument,\n\t\t\t\t() => permitted && scalarMatches(residual, document),\n\t\t\t\tgroups,\n\t\t\t)\n\t\t},\n\t\tplan(\n\t\t\ttable: string,\n\t\t\tinput: QueryInput,\n\t\t\tconditions: readonly IndexCondition[],\n\t\t\tconstraints: readonly StoredConstraint[],\n\t\t\tordering?: string,\n\t\t\ttraversal: 'root' | 'relation' = 'root',\n\t\t) {\n\t\t\tif (!Object.hasOwn(metadata.tables, table)) throw new Error('Unknown query table')\n\t\t\tlet validator = inputs.get(table)\n\t\t\tif (!validator) {\n\t\t\t\tvalidator = owned.pagination(table)\n\t\t\t\tinputs.set(table, validator)\n\t\t\t}\n\t\t\t// Server constraints are independently validated against stored fields,\n\t\t\t// not the endpoint's public input/filter mask. Client values cannot replace them.\n\t\t\tconst where =\n\t\t\t\tconstraints.length === 1\n\t\t\t\t\t? constraints[0]\n\t\t\t\t\t: constraints.length\n\t\t\t\t\t\t? { and: constraints }\n\t\t\t\t\t\t: undefined\n\t\t\tconst { args, compiled } = parseFilterPlan(\n\t\t\t\tvalidator,\n\t\t\t\tinput,\n\t\t\t\ttraversal === 'relation' && ordering === undefined ? [] : metadata.tables[table].indexes,\n\t\t\t\tconditions,\n\t\t\t\twhere,\n\t\t\t\tordering,\n\t\t\t)\n\t\t\tif (compiled.residual.kind !== 'and') throw new Error('Invalid compiled filter root')\n\t\t\tconst [client, server] = compiled.residual.children\n\t\t\tconst empty: FilterAst = { kind: 'and', children: [] }\n\t\t\tconst clientIdentity = { kind: 'and', children: [client, empty] }\n\t\t\tconst serverIdentity = compiled.sets.size\n\t\t\t\t? {\n\t\t\t\t\t\tkind: 'and',\n\t\t\t\t\t\tchildren: [server, empty],\n\t\t\t\t\t\ttraversal: { version: 2, expansion: compiled.expansion },\n\t\t\t\t\t}\n\t\t\t\t: { kind: 'and', children: [server, empty] }\n\t\t\t// SAFETY: normalized AST nodes contain only validated native scalar Values.\n\t\t\treturn {\n\t\t\t\t...compiled,\n\t\t\t\targs,\n\t\t\t\tclientIdentity: clientIdentity as Value,\n\t\t\t\tserverIdentity: serverIdentity as Value,\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport function scalarMatches(\n\tast: FilterAst,\n\tdocument: Record<string, Value | undefined>,\n): boolean {\n\treturn evaluateFilter(ast, document) === true\n}\n"],"mappings":"6MAcA,SAAgBA,EACf,EACA,EACC,CACD,IAAMC,EAAQC,EAAoBC,CAAS,EAC3CF,EAAM,aAAaG,EAAO,MAAM,EAChC,IAAMC,EAAWC,EAAoBH,CAAS,EAGxCI,kBAAS,IAAI,IACnB,MAAO,CACN,WACA,OAAQN,EAAM,OACd,OAAQA,EAAM,OACd,iBAAkBA,EAAM,iBACxB,aAAcA,EAAM,aACpB,WAAW,EAAe,CACzB,GAAI,CAAC,OAAO,OAAOI,EAAS,OAAQG,CAAK,EAAG,MAAU,MAAM,qBAAqB,CAClF,EACA,SACC,EACA,EACA,EACA,EACA,EAA4B,CAAC,EAC5B,CACD,OAAOP,EAAM,QACZO,EACAC,MACMC,GAAaC,EAAcC,EAAUH,CAAQ,EACnDI,CACD,CACD,EACA,KACC,EACA,EACA,EACA,EACA,EACA,EAAiC,OAChC,CACD,GAAI,CAAC,OAAO,OAAOR,EAAS,OAAQG,CAAK,EAAG,MAAU,MAAM,qBAAqB,EACjF,IAAIM,EAAYP,EAAO,IAAIC,CAAK,EAC3BM,IACJ,EAAYb,EAAM,WAAWO,CAAK,EAClCD,EAAO,IAAIC,EAAOM,CAAS,GAI5B,IAAMC,EACLC,EAAY,SAAW,EACpBA,EAAY,GACZA,EAAY,OACX,CAAE,IAAKA,CAAY,EACnB,IAAA,GACC,CAAE,OAAM,YAAaC,EAC1BH,EACAI,EACAC,IAAc,YAAcC,IAAa,IAAA,GAAY,CAAC,EAAIf,EAAS,OAAOG,EAAM,CAAC,QACjFa,EACAN,EACAK,CACD,EACA,GAAIE,EAAS,SAAS,OAAS,MAAO,MAAU,MAAM,8BAA8B,EACpF,GAAM,CAACC,EAAQC,GAAUF,EAAS,SAAS,SACrCG,EAAmB,CAAE,KAAM,MAAO,SAAU,CAAC,CAAE,EAC/CC,EAAiB,CAAE,KAAM,MAAO,SAAU,CAACH,EAAQE,CAAK,CAAE,EAC1DE,EAAiBL,EAAS,KAAK,KAClC,CACA,KAAM,MACN,SAAU,CAACE,EAAQC,CAAK,EACxB,UAAW,CAAE,QAAS,EAAG,UAAWH,EAAS,SAAU,CACxD,EACC,CAAE,KAAM,MAAO,SAAU,CAACE,EAAQC,CAAK,CAAE,EAE5C,MAAO,CACN,GAAGH,EACH,OACgB,iBACA,gBACjB,CACD,CACD,CACD,CAEA,SAAgBX,EACf,EACA,EACU,CACV,OAAOiB,EAAeC,EAAKpB,CAAQ,IAAM,EAC1C"}
@@ -1,7 +1,9 @@
1
- import { FilterAst, IndexCondition, NativePagination } from "./filters.mjs";
1
+ import { FilterAst } from "./shared/ast.mjs";
2
+ import { IndexCondition, NativePagination } from "./filters.mjs";
3
+ import { PageCompleteness } from "../zod-table.mjs";
2
4
  import { RelationEdge } from "../relations.mjs";
3
- import { CursorBinding, createCursorCodec } from "./cursors.mjs";
4
5
  import { QueryInput, StoredConstraint, createPlanner } from "./planner.mjs";
6
+ import { CursorBinding, createCursorCodec } from "./cursors.mjs";
5
7
  import { ExecutionRequest } from "./execution.mjs";
6
8
  import { GenericSchema, SchemaDefinition } from "convex/server";
7
9
  import { GenericId, Value } from "convex/values";
@@ -9,6 +11,18 @@ import { GenericId, Value } from "convex/values";
9
11
  export interface OutputSelection {
10
12
  [name: string]: true | OutputSelection;
11
13
  }
14
+ export type ResolvedGroups = {
15
+ fieldGroups: Record<string, {
16
+ mode: 'required' | 'if-permitted';
17
+ allowed: boolean;
18
+ }>;
19
+ relations: Record<string, ResolvedGroups>;
20
+ };
21
+ export interface GroupAccess {
22
+ at(path: readonly string[]): ResolvedGroups;
23
+ allowed(path: readonly string[]): readonly string[];
24
+ checkOrder(table: string, fields: readonly string[], path?: readonly string[]): void;
25
+ }
12
26
  type Edge = RelationEdge<string, string, 'one' | 'many', any, any>;
13
27
  export type RelationDocument = Record<string, Value> & {
14
28
  _id: GenericId<string>;
@@ -23,19 +37,22 @@ export declare class RelationshipError extends Error {
23
37
  /** The selection has already passed the registry validator; count leaf edges too. */
24
38
  export declare function assertRelationshipDepth(selection: OutputSelection, depth: number): void;
25
39
  /** One request owns all traversal and authorized ID memoization. No raw reader escapes. */
26
- export declare function relationshipExecutor(schema: SchemaDefinition<GenericSchema, boolean>, request: ExecutionRequest, planner: Planner, codec: ReturnType<typeof createCursorCodec>, rootBinding: CursorBinding): {
40
+ export declare function relationshipExecutor(schema: SchemaDefinition<GenericSchema, boolean>, request: ExecutionRequest, planner: Planner, codec: ReturnType<typeof createCursorCodec>, rootBinding: CursorBinding, groups?: GroupAccess): {
27
41
  matches: (table: string, parent: Document, ast: FilterAst, depth?: number) => Promise<boolean>;
28
42
  output: (table: string, parent: Document, selection: OutputSelection, args: NativePagination & {
29
43
  order?: 'asc' | 'desc';
30
44
  }, path?: readonly string[], depth?: number, parents?: readonly string[]) => Promise<Record<string, Value>>;
31
- continuation: (rootTable: string, rootId: string, path: readonly string[], selection: OutputSelection, input: QueryInput, conditions: readonly IndexCondition[], constraints: readonly StoredConstraint[]) => Promise<{
45
+ continuation: (rootTable: string, rootId: string, path: readonly string[], selection: OutputSelection, input: QueryInput, conditions: readonly IndexCondition[], constraints: readonly StoredConstraint[], ordering?: string) => Promise<{
32
46
  page: Record<string, Value>[];
33
47
  isDone: boolean;
34
48
  splitCursor?: import("convex/server").Cursor | null;
35
49
  pageStatus?: "SplitRecommended" | "SplitRequired" | null;
50
+ paginationMode?: 'native-search';
51
+ completeness: PageCompleteness;
36
52
  continueCursor: string;
37
53
  }>;
38
54
  edge: (table: string, name: string) => Edge;
55
+ preflight: (table: string, selection: OutputSelection, input: QueryInput, path?: readonly string[]) => void;
39
56
  };
40
57
  //#endregion
41
58
  //# sourceMappingURL=relationships.d.mts.map
@@ -1,2 +1,2 @@
1
- import{scalarMatches as e}from"./planner.mjs";import{CursorError as t}from"./cursors.mjs";import{executeStream as n,rethrowQueryError as r}from"./execution.mjs";import{z as i}from"zod";import{EmptyStream as a,getIndexFields as o,stream as s}from"convex-helpers/server/stream";const c=i.object({cursor:i.string(),ancestors:i.array(i.string()).max(3)}).strict();var l=class extends Error{code;constructor(e){super(e),this.code=e,this.name=`RelationshipError`}};function u(e,t){for(let n of Object.values(e)){if(t>=4)throw new l(`INVALID_RELATION`);n!==!0&&u(n,t+1)}}function d(d,p,m,h,g){let _=m.metadata,v=e=>`base`in e?e.base:e;function y(e,t){let n=_.declarations[e]?.[t];if(!n)throw new l(`INVALID_RELATION`);return n}let b=(e,t)=>!t||e[t.discriminator]===t.tag,x=i.string();function S(e,t){if(!t)return!0;let n=x.safeParse(e);return n.success&&p.db.normalizeId(t.table,n.data)!==null}function C(e,t){if(!t||!b(t,e.sourceGuard))return;let n=t[v(e.from).field];return S(n,e.sourceMember)&&S(n,e.targetMember)?n:void 0}function w(e,t,n){let r=t===`_id`?{name:`by_id`,fields:[`_id`]}:_.tables[e].indexes.find(e=>{let r=e.fields.indexOf(t);return r>=0&&e.fields.slice(0,r).every(e=>e===n?.discriminator)});if(!r)throw new l(`INVALID_RELATION`);return r}function T(e,t,n,r,i){let a=t===`_id`?[{name:`by_id`,fields:[`_id`]}]:_.tables[e].indexes,o=e=>e===t||e===i?.discriminator||n.bindings.has(e),s=e=>e.fields.includes(t)&&e.fields.slice(0,e.fields.indexOf(t)).every(o),c=e=>{let t=0;for(let n of e.fields){if(!o(n))break;t++}return t},u=r.find(e=>e.value!==null&&e.value!==void 0);if(u){let e=a.find(e=>e.name===u.index&&s(e));if(!e)throw Error(`Explicit index "${u.index}" is incompatible with declared relationship lookup`);return e}let d=a.filter(s).sort((e,t)=>c(t)-c(e)||e.name.localeCompare(t.name)||e.fields.join(`\0`).localeCompare(t.fields.join(`\0`)));if(!d.length)throw new l(`INVALID_RELATION`);return d[0]}function E(e,t,n,r,i){let a=[];for(let o of e.fields)if(o===t)a.push({field:o,value:n});else if(o===i?.discriminator)a.push({field:o,value:i.tag});else if(r?.bindings.has(o))a.push({field:o,value:r.bindings.get(o)});else break;return a}async function D(e,t){if(m.beforeLeaf(e),t==null||!p.db.normalizeId(e,t))return null;let n=await p.db.get(e,t);return n&&m.validateDocument(e,n),n}async function*O(e,t,n,r,i,a){if(p.expand(r,0),n==null||!S(n,a))return;if(t===`_id`){let o=await D(e,n);o&&b(o,i)&&S(o[t],a)&&(p.expand(r),yield o);return}m.beforeLeaf(e);let o=w(e,t,i),s=p.leafQuery(e).withIndex(o.name,e=>{let r=e;for(let e of E(o,t,n,void 0,i))r=r.eq(e.field,e.value);return r})[Symbol.asyncIterator]();try{for(;;){m.beforeLeaf(e);let n=await s.next();if(n.done)return;await p.authorize(e,n.value)&&(m.validateDocument(e,n.value),b(n.value,i)&&S(n.value[t],a)&&(p.expand(r),yield n.value))}}finally{await s.return?.()}}async function*k(e,t,n){p.expand(n,0);let r=C(e,t);if(r!=null){if(`base`in e.from&&`base`in e.to)for await(let t of O(e.from.junction.table,e.from.junction.field,r,n,e.junctionGuard))yield*O(e.target,e.to.base.field,t[e.to.junction.field],n,e.targetGuard);else yield*O(e.target,v(e.to).field,r,n,e.targetGuard,e.targetMember)}}async function A(e,t,n){let r=null;for await(let i of k(e,t,n)){if(r)throw new l(`AMBIGUOUS_RELATION`);r=i}return r}async function j(t,n,r,i=0){if(p.expand(i,0),_.tables[t].variant&&m.validateDocument(t,n),f(r))return e(r,n);if(r.kind===`variant`)return n[r.discriminator]===r.tag&&j(t,n,r.child,i);if(r.kind===`scalar`)return e(r,n);if(r.kind===`not`)return!await j(t,n,r.child,i);if(r.kind===`and`||r.kind===`or`){for(let e of r.children){let a=await j(t,n,e,i);if(r.kind===`and`&&!a)return!1;if(r.kind===`or`&&a)return!0}return r.kind===`and`}if(r.kind!==`relation`)throw new l(`INVALID_RELATION`);let a=y(t,r.name);if(r.mode===`one`){let e=await A(a,n,i+1);return r.predicate===null?e===null:e!==null&&await j(a.target,e,r.predicate,i+1)}for await(let e of k(a,n,i+1))if(await j(a.target,e,r.predicate,i+1))return r.mode===`some`;return r.mode===`none`}async function M(e,t,n,r,i=[],a=0,o=[]){p.expand(a,0);let s=m.complete(e,t,!0,{kind:`and`,children:[]});for(let[c,l]of Object.entries(n)){let n=y(e,c),u=l===!0?{}:l;if(n.cardinality===`one`){let e=await A(n,t,a+1);s[c]=e?await M(n.target,e,u,r,[...i,c],a+1,[...o,t._id]):null}else s[c]=await P(e,t,c,u,{numItems:r.numItems,cursor:null,order:r.order},[],[],[...i,c],a+1,[...o,t._id])}return s}function N(e,n,r,i,a,o,s,d){m.select(y(e,n).target,r),u(r,s.length);let f=y(e,n);if(f.cardinality!==`many`)throw new l(`INVALID_RELATION`);let _=f.targetGuard?{fields:{[f.targetGuard.discriminator]:f.targetGuard.tag}}:void 0,b=m.plan(f.target,i,[],_?[...o,_]:o),x=f.from,S=f.to,C=`base`in x&&`base`in S?{table:x.junction.table,field:x.junction.field,targetField:S.base.field,targetReference:S.junction.field}:null,E=C?C.table:f.target,D=C?C.field:v(S).field,O=T(f.target,C?C.targetField:D,b,a,f.targetGuard),k=C?w(E,D,f.junctionGuard):O,A={...g,table:E,index:k.name,order:b.args.order??`asc`,clientFilters:b.clientIdentity,serverFilters:{predicates:b.serverIdentity,selection:r,scope:{...p.scope},rootTable:g.table,lookupIndex:O.name,guards:{source:f.sourceGuard?{...f.sourceGuard}:null,target:f.targetGuard?{...f.targetGuard}:null,junction:f.junctionGuard?{...f.junctionGuard}:null},...(f.sourceMember||f.targetMember)&&{members:{source:f.sourceMember?{...f.sourceMember}:null,target:f.targetMember?{...f.targetMember}:null}}},relationPath:s,parent:d};function j(e){try{return c.parse(JSON.parse(h.open(e,A)))}catch{throw new t}}return{declared:f,plan:b,through:C,sourceTable:E,field:D,index:k,targetIndex:O,binding:A,open:j}}async function P(e,t,r,i,c,l=[],u=[],f=[r],g=1,_=[],y=N(e,r,i,c,l,u,f,_[0]??t._id),x){p.expand(g,0);let{declared:w,plan:T,through:O,sourceTable:k,field:A,index:P,targetIndex:F,binding:I}=y,L=C(w,t),R={...T.args,...x??{cursor:null}},z={...T,index:P,prefix:L==null?[]:O?E(P,A,L,void 0,w.junctionGuard):E(P,A,L,T,w.targetGuard),unsatisfiable:L==null||T.unsatisfiable},B=O&&O.targetField!==`_id`;return await n(d,p,k,z,m,h,I,R,async(e,t)=>{if(t&&m.validateDocument(B?w.target:k,e),!t||O&&!B&&!b(e,w.junctionGuard))return null;p.expand(g);let n;return n=O&&!B?await D(w.target,e[O.targetReference]):e,!n||!b(n,w.targetGuard)||!S(n[v(w.to).field],w.targetMember)||!await j(w.target,n,T.residual,g)?null:M(w.target,n,i,T.args,f,g,_)},e=>h.seal(JSON.stringify({cursor:e,ancestors:_.slice(1)}),I),B?(e,t)=>{let n=d,r=o(w.target,F.name,n);return e.flatMap(async e=>{p.expand(g);let i=await p.authorize(k,e);i&&m.validateDocument(k,e);let o=e[O.targetReference];return!i||!b(e,w.junctionGuard)||o==null?new a(T.args.order??`asc`,r):s(t,n).query(w.target).withIndex(F.name,e=>{let t=e,n=E(F,O.targetField,o,T,w.targetGuard);for(let e of n)t=t.eq(e.field,e.value);return t}).order(T.args.order??`asc`)},r)}:void 0,B?w.target:k)}async function F(e,n,i,a,o,s,c){if(!i.length||i.length>4||!p.db.normalizeId(e,n))throw new l(`INVALID_RELATION`);let u=e,d=i.map(e=>{let t=y(u,e);return u=t.target,t}),f=d.at(-1),m=N(f.source,i.at(-1),a,o,s,c,i,n),h=o.cursor===null?null:m.open(o.cursor),g=o.endCursor==null?null:m.open(o.endCursor),_=h?.ancestors??g?.ancestors??[];if(_.length!==i.length-1||h&&g&&JSON.stringify(h.ancestors)!==JSON.stringify(g.ancestors)||_.some((e,t)=>!p.db.normalizeId(d[t].target,e)))throw new t;try{let t=await D(e,n);for(let e=0;t&&e<_.length;e++){let n=d[e],r=null;if(n.cardinality===`one`){let i=await A(n,t,e+1);i?._id===_[e]&&(r=i)}else for await(let i of k(n,t,e+1))if(i._id===_[e]){r=i;break}t=r}return await P(f.source,t,i.at(-1),a,o,s,c,i,i.length,[n,..._],m,{cursor:h?.cursor??null,endCursor:g?.cursor??o.endCursor})}catch(e){r(e)}}return{matches:j,output:M,continuation:F,edge:y}}function f(e){return e.kind===`relation`?!1:e.kind===`and`||e.kind===`or`?e.children.every(f):e.kind===`not`||e.kind===`variant`?f(e.child):!0}export{l as RelationshipError,u as assertRelationshipDepth,d as relationshipExecutor};
1
+ import{expansionForIndex as e,rangeForIndex as t,withinRange as n}from"./filters.mjs";import{scalarMatches as r}from"./planner.mjs";import{CursorError as i}from"./cursors.mjs";import{executeStream as a,nativeIndexRange as o,rethrowQueryError as s}from"./execution.mjs";import{z as c}from"zod";import{compareValues as l}from"convex/values";import{EmptyStream as u,getIndexFields as d,stream as f}from"convex-helpers/server/stream";const p=c.object({cursor:c.string(),ancestors:c.array(c.string()).max(3)}).strict();var m=class extends Error{code;constructor(e){super(e),this.code=e,this.name=`RelationshipError`}};function h(e,t){for(let n of Object.values(e)){if(t>=4)throw new m(`INVALID_RELATION`);n!==!0&&h(n,t+1)}}function g(g,v,y,b,x,S){let C=y.metadata,w=e=>`base`in e?e.base:e;function T(e,t){let n=C.declarations[e]?.[t];if(!n)throw new m(`INVALID_RELATION`);return n}let E=(e,t)=>!t||e[t.discriminator]===t.tag,D=c.string();function O(e,t){if(!t)return!0;let n=D.safeParse(e);return n.success&&v.db.normalizeId(t.table,n.data)!==null}function k(e,t){if(!t||!E(t,e.sourceGuard))return;let n=t[w(e.from).field];return O(n,e.sourceMember)&&O(n,e.targetMember)?n:void 0}function A(e,t,n){let r=t===`_id`?{name:`by_id`,fields:[`_id`]}:C.tables[e].indexes.find(e=>{let r=e.fields.indexOf(t);return r>=0&&e.fields.slice(0,r).every(e=>e===n?.discriminator)});if(!r)throw new m(`INVALID_RELATION`);return r}function j(e,t){function n(e,t,n,r){S?.checkOrder(e,A(e,t,n).fields.filter(e=>e!==t&&e!==n?.discriminator),r)}`base`in e.from&&`base`in e.to?(n(e.from.junction.table,e.from.junction.field,e.junctionGuard),n(e.target,e.to.base.field,e.targetGuard,t)):n(e.target,w(e.to).field,e.targetGuard,t)}function M(e,t,n,r,i){let a=t===`_id`?[{name:`by_id`,fields:[`_id`]}]:C.tables[e].indexes,o=e=>e===t||e===i?.discriminator||n.bindings.has(e),s=e=>e.fields.includes(t)&&e.fields.slice(0,e.fields.indexOf(t)).every(o),c=e=>{let t=0;for(let n of e.fields){if(!o(n))break;t++}return t},l=r.find(e=>e.value!==null&&e.value!==void 0);if(l){let e=a.find(e=>e.name===l.index&&s(e));if(!e)throw Error(`Explicit index "${l.index}" is incompatible with declared relationship lookup`);return e}let u=a.filter(s).sort((e,t)=>c(t)-c(e)||Number(n.sets.has(t.fields[c(t)]))-Number(n.sets.has(e.fields[c(e)]))||Number(n.ranges.has(t.fields[c(t)]))-Number(n.ranges.has(e.fields[c(e)]))||e.name.localeCompare(t.name)||e.fields.join(`\0`).localeCompare(t.fields.join(`\0`)));if(!u.length)throw new m(`INVALID_RELATION`);return u[0]}function N(e,t,n,r,i){let a=[];for(let o of e.fields)if(o===t)a.push({field:o,value:n});else if(o===i?.discriminator)a.push({field:o,value:i.tag});else if(r?.bindings.has(o))a.push({field:o,value:r.bindings.get(o)});else break;return a}async function P(e,t){if(y.beforeLeaf(e),t==null||!v.db.normalizeId(e,t))return null;let n=await v.db.get(e,t);return n&&y.validateDocument(e,n),n}async function*F(e,t,n,r,i,a){if(v.expand(r,0),n==null||!O(n,a))return;if(t===`_id`){let o=await P(e,n);o&&E(o,i)&&O(o[t],a)&&(v.expand(r),yield o);return}y.beforeLeaf(e);let o=A(e,t,i),s=v.leafQuery(e).withIndex(o.name,e=>{let r=e;for(let e of N(o,t,n,void 0,i))r=r.eq(e.field,e.value);return r})[Symbol.asyncIterator]();try{for(;;){y.beforeLeaf(e);let n=await s.next();if(n.done)return;await v.authorize(e,n.value)&&(y.validateDocument(e,n.value),E(n.value,i)&&O(n.value[t],a)&&(v.expand(r),yield n.value))}}finally{await s.return?.()}}async function*I(e,t,n){v.expand(n,0);let r=k(e,t);if(r!=null){if(`base`in e.from&&`base`in e.to)for await(let t of F(e.from.junction.table,e.from.junction.field,r,n,e.junctionGuard))yield*F(e.target,e.to.base.field,t[e.to.junction.field],n,e.targetGuard);else yield*F(e.target,w(e.to).field,r,n,e.targetGuard,e.targetMember)}}async function L(e,t,n){let r=null;for await(let i of I(e,t,n)){if(r)throw new m(`AMBIGUOUS_RELATION`);r=i}return r}async function R(e,t,n,i=0){if(v.expand(i,0),C.tables[e].variant&&y.validateDocument(e,t),_(n))return r(n,t);if(n.kind===`variant`)return t[n.discriminator]===n.tag&&R(e,t,n.child,i);if(n.kind===`scalar`)return r(n,t);if(n.kind===`not`)return!await R(e,t,n.child,i);if(n.kind===`and`||n.kind===`or`){for(let r of n.children){let a=await R(e,t,r,i);if(n.kind===`and`&&!a)return!1;if(n.kind===`or`&&a)return!0}return n.kind===`and`}if(n.kind!==`relation`)throw new m(`INVALID_RELATION`);let a=T(e,n.name);if(n.mode===`one`){let e=await L(a,t,i+1);return n.predicate===null?e===null:e!==null&&await R(a.target,e,n.predicate,i+1)}for await(let e of I(a,t,i+1))if(await R(a.target,e,n.predicate,i+1))return n.mode===`some`;return n.mode===`none`}async function z(e,t,n,r,i=[],a=0,o=[]){v.expand(a,0);let s=y.complete(e,t,!0,{kind:`and`,children:[]},S?.allowed(i));for(let[c,l]of Object.entries(n)){let n=T(e,c),u=l===!0?{}:l;if(n.cardinality===`one`){let e=await L(n,t,a+1);s[c]=e?await z(n.target,e,u,r,[...i,c],a+1,[...o,t._id]):null}else s[c]=await V(e,t,c,u,{numItems:r.numItems,cursor:null,order:r.order},[],[],[...i,c],a+1,[...o,t._id])}return s}function B(t,n,r,a,o,s,c,l,u){if(u!==void 0&&o.some(e=>e.value!==null&&e.value!==void 0))throw Error(`orderBy cannot be combined with an active when selector`);y.select(T(t,n).target,r),h(r,c.length);let d=T(t,n);if(d.cardinality!==`many`)throw new m(`INVALID_RELATION`);let f=d.targetGuard?{fields:{[d.targetGuard.discriminator]:d.targetGuard.tag}}:void 0,g=y.plan(d.target,a,[],f?[...s,f]:s,u,`relation`),_=d.from,C=d.to,E=`base`in _&&`base`in C?{table:_.junction.table,field:_.junction.field,targetField:C.base.field,targetReference:C.junction.field}:null;if(u!==void 0&&E)throw Error(`orderBy is unsupported for junction relationships`);let D=E?E.table:d.target,O=E?E.field:w(C).field,k=M(d.target,E?E.targetField:O,g,u===void 0?o:[{value:!0,index:u}],d.targetGuard);S?.checkOrder(d.target,k.fields.filter(e=>e!==(E?E.targetField:O)&&e!==d.targetGuard?.discriminator&&!g.bindings.has(e)),c);let j=E?A(D,O,d.junctionGuard):k;E&&S?.checkOrder(D,j.fields.filter(e=>e!==O&&e!==d.junctionGuard?.discriminator));let P=E||g.unsatisfiable?null:e(j,N(j,O,null,g,d.targetGuard),g.sets,u!==void 0||o.some(e=>e.value!==null&&e.value!==void 0)),F={},I=S?.at(c);I&&(Object.keys(I.fieldGroups).length||Object.keys(I.relations).length)&&(F.fieldGroups=I);let L={...x,table:D,index:j.name,order:g.args.order??`asc`,clientFilters:g.clientIdentity,serverFilters:{predicates:g.sets.size?{predicates:g.serverIdentity,traversal:{version:2,expansion:P?{...P}:null}}:g.serverIdentity,selection:r,...F,scope:{...v.scope},rootTable:x.table,lookupIndex:k.name,guards:{source:d.sourceGuard?{...d.sourceGuard}:null,target:d.targetGuard?{...d.targetGuard}:null,junction:d.junctionGuard?{...d.junctionGuard}:null},...(d.sourceMember||d.targetMember)&&{members:{source:d.sourceMember?{...d.sourceMember}:null,target:d.targetMember?{...d.targetMember}:null}}},relationPath:c,parent:l};function R(e){try{return p.parse(JSON.parse(b.open(e,L)))}catch{throw new i}}return{declared:d,plan:g,through:E,sourceTable:D,field:O,index:j,targetIndex:k,binding:L,open:R,expansion:P}}async function V(e,r,i,s,c,p=[],m=[],h=[i],_=1,x=[],S=B(e,i,s,c,p,m,h,x[0]??r._id),C){v.expand(_,0);let{declared:T,plan:D,through:A,sourceTable:j,field:M,index:F,targetIndex:I,binding:L,expansion:V}=S,H=k(T,r),U={...D.args,...C??{cursor:null}},W={...D,expansion:V,index:F,prefix:H==null?[]:A?N(F,M,H,void 0,T.junctionGuard):N(F,M,H,D,T.targetGuard),unsatisfiable:H==null||D.unsatisfiable};if(W.range=A?null:t(F,W.prefix,D.ranges),!A)for(let e of W.prefix){let t=D.ranges.get(e.field);D.bindings.has(e.field)&&l(e.value,D.bindings.get(e.field))!==0&&(W.unsatisfiable=!0),t&&!n(e.value,t)&&(W.unsatisfiable=!0)}let G=A&&A.targetField!==`_id`;return await a(g,v,j,W,y,b,L,U,async(e,t)=>{if(t&&y.validateDocument(G?T.target:j,e),!t||A&&!G&&!E(e,T.junctionGuard))return null;v.expand(_);let n;return n=A&&!G?await P(T.target,e[A.targetReference]):e,!n||!E(n,T.targetGuard)||!O(n[w(T.to).field],T.targetMember)||!await R(T.target,n,D.residual,_)?null:z(T.target,n,s,D.args,h,_,x)},e=>b.seal(JSON.stringify({cursor:e,ancestors:x.slice(1)}),L),G?(e,n)=>{let r=g,i=d(T.target,I.name,r);return e.flatMap(async e=>{v.expand(_);let a=await v.authorize(j,e);a&&y.validateDocument(j,e);let s=e[A.targetReference];return!a||!E(e,T.junctionGuard)||s==null?new u(D.args.order??`asc`,i):f(n,r).query(T.target).withIndex(I.name,e=>{let n=N(I,A.targetField,s,D,T.targetGuard);return o(e,n,t(I,n,D.ranges))}).order(D.args.order??`asc`)},i)}:void 0,G?T.target:j)}async function H(e,t,n,r,a,o,c,u){if(!n.length||n.length>4||!v.db.normalizeId(e,t))throw new m(`INVALID_RELATION`);let d=e,f=n.map(e=>{let t=T(d,e);return d=t.target,t});if(u!==void 0&&f.some(e=>`base`in e.from||`base`in e.to))throw Error(`orderBy is unsupported for junction relationships`);let p=f.at(-1);for(let e of f.slice(0,-1))(e.cardinality===`one`||`base`in e.from||`base`in e.to)&&j(e);let h=B(p.source,n.at(-1),r,a,o,c,n,t,u),g=a.cursor===null?null:h.open(a.cursor),_=a.endCursor==null?null:h.open(a.endCursor),y=g?.ancestors??_?.ancestors??[];if(y.length!==n.length-1||g&&_&&JSON.stringify(g.ancestors)!==JSON.stringify(_.ancestors)||y.some((e,t)=>!v.db.normalizeId(f[t].target,e)))throw new i;try{let i=await P(e,t);for(let e=0;i&&e<y.length;e++){let t=f[e],n=null;if(t.cardinality===`many`&&!(`base`in t.from)&&!(`base`in t.to)){v.expand(e+1,0);let r=k(t,i),a=r==null?null:await P(t.target,y[e]),o=t.to.field;r!=null&&a&&E(a,t.targetGuard)&&O(a[o],t.targetMember)&&a[o]!==void 0&&l(r,a[o])===0&&(v.expand(e+1),n=a)}else if(t.cardinality===`one`){let r=await L(t,i,e+1);r?._id===y[e]&&(n=r)}else for await(let r of I(t,i,e+1))if(r._id===y[e]){n=r;break}i=n}return await V(p.source,i,n.at(-1),r,a,o,c,n,n.length,[t,...y],h,{cursor:g?.cursor??null,endCursor:_?.cursor??a.endCursor})}catch(e){s(e)}}function U(e,t,n,r=[]){for(let[i,a]of Object.entries(t)){let t=T(e,i),o=a===!0?{}:a,s=[...r,i];t.cardinality===`many`?B(e,i,o,{numItems:n.numItems,cursor:null,order:n.order},[],[],s,``):j(t,s),U(t.target,o,n,s)}}return{matches:R,output:z,continuation:H,edge:T,preflight:U}}function _(e){return e.kind===`relation`?!1:e.kind===`and`||e.kind===`or`?e.children.every(_):e.kind===`not`||e.kind===`variant`?_(e.child):!0}export{m as RelationshipError,h as assertRelationshipDepth,g as relationshipExecutor};
2
2
  //# sourceMappingURL=relationships.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"relationships.mjs","names":["navigation","z","RelationshipError","code","assertRelationshipDepth","nested","selection","depth","relationshipExecutor","metadata","planner","base","leg","edge","declared","table","name","guarded","guard","row","memberIdSchema","memberMatches","member","id","value","request","sourceValue","parent","lookup","index","field","position","i","key","relationIndex","indexes","bound","plan","usable","length","size","condition","conditions","c","chosen","candidates","b","a","relationPrefix","prefix","get","result","targets","target","iterator","range","q","binding","next","traverse","junction","one","match","matches","scalarOnly","ast","scalarMatches","child","output","dto","selected","args","path","parents","pageRelation","prepare","guardConstraint","input","constraints","from","to","through","sourceTable","targetIndex","rootBinding","rootId","open","codec","token","CursorError","prepared","opened","lookupPlan","indexedTarget","executeStream","schema","permitted","raw","nativeSchema","fields","getIndexFields","source","reference","EmptyStream","stream","db","continuation","rootTable","declarations","declaration","final","start","end","ancestors","found","error","rethrowQueryError"],"sources":["../../src/querying/relationships.ts"],"sourcesContent":["import type { GenericSchema, SchemaDefinition, IndexRangeBuilder } from 'convex/server'\nimport type { GenericId, Value } from 'convex/values'\nimport type { RelationEdge, RelationGuard } from '../relations'\nimport type { createPlanner, QueryInput, StoredConstraint } from './planner'\nimport { scalarMatches } from './planner'\nimport type {\n\tFilterAst,\n\tFilterScalar,\n\tIndexCondition,\n\tNativePagination,\n\tQueryIndex,\n} from './filters'\nimport { executeStream, rethrowQueryError, type ExecutionRequest } from './execution'\nimport type { createCursorCodec, CursorBinding } from './cursors'\nimport { CursorError } from './cursors'\nimport { z } from 'zod'\nimport { stream, EmptyStream, getIndexFields } from 'convex-helpers/server/stream'\n\nexport interface OutputSelection {\n\t[name: string]: true | OutputSelection\n}\ntype Edge = RelationEdge<string, string, 'one' | 'many', any, any>\nexport type RelationDocument = Record<string, Value> & {\n\t_id: GenericId<string>\n\t_creationTime: number\n}\ntype Document = RelationDocument\ntype Planner = ReturnType<typeof createPlanner>\nconst navigation = z.object({ cursor: z.string(), ancestors: z.array(z.string()).max(3) }).strict()\n\nexport class RelationshipError extends Error {\n\tconstructor(readonly code: 'AMBIGUOUS_RELATION' | 'INVALID_RELATION') {\n\t\tsuper(code)\n\t\tthis.name = 'RelationshipError'\n\t}\n}\n\n/** The selection has already passed the registry validator; count leaf edges too. */\nexport function assertRelationshipDepth(selection: OutputSelection, depth: number): void {\n\tfor (const nested of Object.values(selection)) {\n\t\tif (depth >= 4) throw new RelationshipError('INVALID_RELATION')\n\t\tif (nested !== true) assertRelationshipDepth(nested, depth + 1)\n\t}\n}\n\n/** One request owns all traversal and authorized ID memoization. No raw reader escapes. */\nexport function relationshipExecutor(\n\tschema: SchemaDefinition<GenericSchema, boolean>,\n\trequest: ExecutionRequest,\n\tplanner: Planner,\n\tcodec: ReturnType<typeof createCursorCodec>,\n\trootBinding: CursorBinding,\n) {\n\tconst metadata = planner.metadata\n\tconst base = (leg: Edge['from']) => ('base' in leg ? leg.base : leg)\n\tfunction edge(table: string, name: string): Edge {\n\t\tconst declared = metadata.declarations[table]?.[name]\n\t\tif (!declared) throw new RelationshipError('INVALID_RELATION')\n\t\treturn declared\n\t}\n\tconst guarded = (row: Document | Record<string, Value>, guard?: RelationGuard) =>\n\t\t!guard || row[guard.discriminator] === guard.tag\n\tconst memberIdSchema = z.string()\n\tfunction memberMatches(value: Value | undefined, member: Edge['sourceMember']): boolean {\n\t\tif (!member) return true\n\t\tconst id = memberIdSchema.safeParse(value)\n\t\treturn id.success && request.db.normalizeId(member.table, id.data) !== null\n\t}\n\tfunction sourceValue(declared: Edge, parent: Document | null): Value | undefined {\n\t\tif (!parent || !guarded(parent, declared.sourceGuard)) return undefined\n\t\tconst value = parent[base(declared.from).field]\n\t\treturn memberMatches(value, declared.sourceMember) &&\n\t\t\tmemberMatches(value, declared.targetMember)\n\t\t\t? value\n\t\t\t: undefined\n\t}\n\tfunction lookup(table: string, field: string, guard?: RelationGuard) {\n\t\tconst index =\n\t\t\tfield === '_id'\n\t\t\t\t? { name: 'by_id', fields: ['_id'] }\n\t\t\t\t: metadata.tables[table].indexes.find((i) => {\n\t\t\t\t\t\tconst position = i.fields.indexOf(field)\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\tposition >= 0 &&\n\t\t\t\t\t\t\ti.fields.slice(0, position).every((key) => key === guard?.discriminator)\n\t\t\t\t\t\t)\n\t\t\t\t\t})\n\t\tif (!index) throw new RelationshipError('INVALID_RELATION')\n\t\treturn index\n\t}\n\tfunction relationIndex(\n\t\ttable: string,\n\t\tfield: string,\n\t\tplan: ReturnType<Planner['plan']>,\n\t\tconditions: readonly IndexCondition[],\n\t\tguard?: RelationGuard,\n\t): QueryIndex {\n\t\tconst indexes =\n\t\t\tfield === '_id' ? [{ name: 'by_id', fields: ['_id'] }] : metadata.tables[table].indexes\n\t\tconst bound = (key: string) =>\n\t\t\tkey === field || key === guard?.discriminator || plan.bindings.has(key)\n\t\tconst usable = (index: QueryIndex) =>\n\t\t\tindex.fields.includes(field) &&\n\t\t\tindex.fields.slice(0, index.fields.indexOf(field)).every(bound)\n\t\tconst length = (index: QueryIndex) => {\n\t\t\tlet size = 0\n\t\t\tfor (const key of index.fields) {\n\t\t\t\tif (!bound(key)) break\n\t\t\t\tsize++\n\t\t\t}\n\t\t\treturn size\n\t\t}\n\t\tconst condition = conditions.find((c) => c.value !== null && c.value !== undefined)\n\t\tif (condition) {\n\t\t\tconst chosen = indexes.find((i) => i.name === condition.index && usable(i))\n\t\t\tif (!chosen)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Explicit index \"${condition.index}\" is incompatible with declared relationship lookup`,\n\t\t\t\t)\n\t\t\treturn chosen\n\t\t}\n\t\tconst candidates = indexes\n\t\t\t.filter(usable)\n\t\t\t.sort(\n\t\t\t\t(a, b) =>\n\t\t\t\t\tlength(b) - length(a) ||\n\t\t\t\t\ta.name.localeCompare(b.name) ||\n\t\t\t\t\ta.fields.join('\\0').localeCompare(b.fields.join('\\0')),\n\t\t\t)\n\t\tif (!candidates.length) throw new RelationshipError('INVALID_RELATION')\n\t\treturn candidates[0]\n\t}\n\tfunction relationPrefix(\n\t\tindex: QueryIndex,\n\t\tfield: string,\n\t\tvalue: FilterScalar,\n\t\tplan?: ReturnType<Planner['plan']>,\n\t\tguard?: RelationGuard,\n\t) {\n\t\tconst prefix: { field: string; value: FilterScalar }[] = []\n\t\tfor (const key of index.fields) {\n\t\t\tif (key === field) prefix.push({ field: key, value })\n\t\t\telse if (key === guard?.discriminator) prefix.push({ field: key, value: guard.tag })\n\t\t\telse if (plan?.bindings.has(key)) prefix.push({ field: key, value: plan.bindings.get(key)! })\n\t\t\telse break\n\t\t}\n\t\treturn prefix\n\t}\n\n\tasync function get(table: string, id: Value | undefined): Promise<Document | null> {\n\t\tplanner.beforeLeaf(table)\n\t\t// SAFETY: native normalization rejects non-string/non-table IDs before any read.\n\t\tif (id == null || !request.db.normalizeId(table, id as string)) return null\n\t\t// SAFETY: normalizeId verifies the declared native table before the authorized metered get.\n\t\tconst result = await request.db.get(table, id as GenericId<string>)\n\t\tif (result) planner.validateDocument(table, result)\n\t\t// SAFETY: normalizeId checked the table; the authorized native get retains system fields.\n\t\treturn result as Document | null\n\t}\n\tasync function* targets(\n\t\ttable: string,\n\t\tfield: string,\n\t\tvalue: Value | undefined,\n\t\tdepth: number,\n\t\tguard?: RelationGuard,\n\t\tmember?: Edge['targetMember'],\n\t): AsyncGenerator<Document> {\n\t\trequest.expand(depth, 0)\n\t\tif (value == null || !memberMatches(value, member)) return\n\t\tif (field === '_id') {\n\t\t\tconst target = await get(table, value)\n\t\t\tif (target && guarded(target, guard) && memberMatches(target[field], member)) {\n\t\t\t\trequest.expand(depth)\n\t\t\t\tyield target\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tplanner.beforeLeaf(table)\n\t\tconst index = lookup(table, field, guard)\n\t\t// SAFETY: registry validates the indexed native lookup prefix and compatible values.\n\t\tconst source = request.leafQuery(table).withIndex(index.name, (q) => {\n\t\t\t// SAFETY: registration checks the mandatory join and every preceding guard equality.\n\t\t\tlet range = q as IndexRangeBuilder<any, string[], number>\n\t\t\t// SAFETY: registered relation fields are native scalars; each equality advances the consecutive checked prefix.\n\t\t\tfor (const binding of relationPrefix(index, field, value as FilterScalar, undefined, guard)) {\n\t\t\t\t// SAFETY: the prefix comes from the declared index and registry-owned guard.\n\t\t\t\trange = range.eq(binding.field, binding.value) as IndexRangeBuilder<any, string[], number>\n\t\t\t}\n\t\t\treturn range\n\t\t})\n\t\tconst iterator = source[Symbol.asyncIterator]()\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tplanner.beforeLeaf(table)\n\t\t\t\tconst next = await iterator.next()\n\t\t\t\tif (next.done) return\n\t\t\t\tconst permitted = await request.authorize(table, next.value)\n\t\t\t\t// Denials are an await boundary too; never hide them inside an authorized iterator.\n\t\t\t\tif (!permitted) continue\n\t\t\t\tplanner.validateDocument(table, next.value)\n\t\t\t\tif (!guarded(next.value, guard) || !memberMatches(next.value[field], member)) continue\n\t\t\t\trequest.expand(depth)\n\t\t\t\t// SAFETY: native rows include system fields and explicit authorization just completed.\n\t\t\t\tyield next.value as Document\n\t\t\t}\n\t\t} finally {\n\t\t\tawait iterator.return?.()\n\t\t}\n\t}\n\tasync function* traverse(\n\t\tdeclared: Edge,\n\t\tparent: Document,\n\t\tdepth: number,\n\t): AsyncGenerator<Document> {\n\t\trequest.expand(depth, 0)\n\t\tconst value = sourceValue(declared, parent)\n\t\tif (value == null) return\n\t\tif ('base' in declared.from && 'base' in declared.to) {\n\t\t\tfor await (const junction of targets(\n\t\t\t\tdeclared.from.junction.table,\n\t\t\t\tdeclared.from.junction.field,\n\t\t\t\tvalue,\n\t\t\t\tdepth,\n\t\t\t\tdeclared.junctionGuard,\n\t\t\t))\n\t\t\t\tyield* targets(\n\t\t\t\t\tdeclared.target,\n\t\t\t\t\tdeclared.to.base.field,\n\t\t\t\t\tjunction[declared.to.junction.field],\n\t\t\t\t\tdepth,\n\t\t\t\t\tdeclared.targetGuard,\n\t\t\t\t)\n\t\t} else\n\t\t\tyield* targets(\n\t\t\t\tdeclared.target,\n\t\t\t\tbase(declared.to).field,\n\t\t\t\tvalue,\n\t\t\t\tdepth,\n\t\t\t\tdeclared.targetGuard,\n\t\t\t\tdeclared.targetMember,\n\t\t\t)\n\t}\n\tasync function one(declared: Edge, parent: Document, depth: number) {\n\t\tlet match: Document | null = null\n\t\tfor await (const target of traverse(declared, parent, depth)) {\n\t\t\tif (match) throw new RelationshipError('AMBIGUOUS_RELATION')\n\t\t\tmatch = target\n\t\t}\n\t\treturn match\n\t}\n\tasync function matches(\n\t\ttable: string,\n\t\tparent: Document,\n\t\tast: FilterAst,\n\t\tdepth = 0,\n\t): Promise<boolean> {\n\t\trequest.expand(depth, 0)\n\t\t// Variant rows must satisfy the captured stored branch before predicates\n\t\t// inspect branch fields. Ordinary output rows are validated by projection.\n\t\tif (metadata.tables[table].variant) planner.validateDocument(table, parent)\n\t\tif (scalarOnly(ast)) return scalarMatches(ast, parent)\n\t\tif (ast.kind === 'variant')\n\t\t\treturn parent[ast.discriminator] === ast.tag && matches(table, parent, ast.child, depth)\n\t\tif (ast.kind === 'scalar') return scalarMatches(ast, parent)\n\t\tif (ast.kind === 'not') return !(await matches(table, parent, ast.child, depth))\n\t\tif (ast.kind === 'and' || ast.kind === 'or') {\n\t\t\tfor (const child of ast.children) {\n\t\t\t\tconst result = await matches(table, parent, child, depth)\n\t\t\t\tif (ast.kind === 'and' && !result) return false\n\t\t\t\tif (ast.kind === 'or' && result) return true\n\t\t\t}\n\t\t\treturn ast.kind === 'and'\n\t\t}\n\t\tif (ast.kind !== 'relation') throw new RelationshipError('INVALID_RELATION')\n\t\tconst declared = edge(table, ast.name)\n\t\tif (ast.mode === 'one') {\n\t\t\tconst target = await one(declared, parent, depth + 1)\n\t\t\treturn ast.predicate === null\n\t\t\t\t? target === null\n\t\t\t\t: target !== null && (await matches(declared.target, target, ast.predicate, depth + 1))\n\t\t}\n\t\tfor await (const target of traverse(declared, parent, depth + 1))\n\t\t\tif (await matches(declared.target, target, ast.predicate!, depth + 1))\n\t\t\t\treturn ast.mode === 'some'\n\t\t// Only actual authorized traversal exhaustion proves none.\n\t\treturn ast.mode === 'none'\n\t}\n\tasync function output(\n\t\ttable: string,\n\t\tparent: Document,\n\t\tselection: OutputSelection,\n\t\targs: NativePagination & { order?: 'asc' | 'desc' },\n\t\tpath: readonly string[] = [],\n\t\tdepth = 0,\n\t\tparents: readonly string[] = [],\n\t): Promise<Record<string, Value>> {\n\t\trequest.expand(depth, 0)\n\t\t// SAFETY: the registry strictly validates this public native DTO projection.\n\t\tconst dto = planner.complete(table, parent, true, { kind: 'and', children: [] }) as Record<\n\t\t\tstring,\n\t\t\tValue\n\t\t>\n\t\tfor (const [name, selected] of Object.entries(selection)) {\n\t\t\tconst declared = edge(table, name),\n\t\t\t\tnested = selected === true ? {} : selected\n\t\t\tif (declared.cardinality === 'one') {\n\t\t\t\tconst target = await one(declared, parent, depth + 1)\n\t\t\t\tdto[name] = target\n\t\t\t\t\t? await output(declared.target, target, nested, args, [...path, name], depth + 1, [\n\t\t\t\t\t\t\t...parents,\n\t\t\t\t\t\t\tparent._id,\n\t\t\t\t\t\t])\n\t\t\t\t\t: null\n\t\t\t} else {\n\t\t\t\tconst page = await pageRelation(\n\t\t\t\t\ttable,\n\t\t\t\t\tparent,\n\t\t\t\t\tname,\n\t\t\t\t\tnested,\n\t\t\t\t\t{ numItems: args.numItems, cursor: null, order: args.order },\n\t\t\t\t\t[],\n\t\t\t\t\t[],\n\t\t\t\t\t[...path, name],\n\t\t\t\t\tdepth + 1,\n\t\t\t\t\t[...parents, parent._id],\n\t\t\t\t)\n\t\t\t\t// SAFETY: pageRelation projects and validates each nested DTO row.\n\t\t\t\tdto[name] = page as Value\n\t\t\t}\n\t\t}\n\t\treturn dto\n\t}\n\tfunction prepare(\n\t\ttable: string,\n\t\tname: string,\n\t\tselection: OutputSelection,\n\t\tinput: QueryInput,\n\t\tconditions: readonly IndexCondition[],\n\t\tconstraints: readonly StoredConstraint[],\n\t\tpath: readonly string[],\n\t\trootId: string,\n\t) {\n\t\tplanner.select(edge(table, name).target, selection)\n\t\tassertRelationshipDepth(selection, path.length)\n\t\tconst declared = edge(table, name)\n\t\tif (declared.cardinality !== 'many') throw new RelationshipError('INVALID_RELATION')\n\t\tconst guardConstraint = declared.targetGuard\n\t\t\t? { fields: { [declared.targetGuard.discriminator]: declared.targetGuard.tag } }\n\t\t\t: undefined\n\t\tconst plan = planner.plan(\n\t\t\tdeclared.target,\n\t\t\tinput,\n\t\t\t[],\n\t\t\tguardConstraint ? [...constraints, guardConstraint] : constraints,\n\t\t)\n\t\tconst from = declared.from,\n\t\t\tto = declared.to\n\t\tconst through =\n\t\t\t'base' in from && 'base' in to\n\t\t\t\t? {\n\t\t\t\t\t\ttable: from.junction.table,\n\t\t\t\t\t\tfield: from.junction.field,\n\t\t\t\t\t\ttargetField: to.base.field,\n\t\t\t\t\t\ttargetReference: to.junction.field,\n\t\t\t\t\t}\n\t\t\t\t: null\n\t\tconst sourceTable = through ? through.table : declared.target\n\t\tconst field = through ? through.field : base(to).field\n\t\tconst targetIndex = relationIndex(\n\t\t\tdeclared.target,\n\t\t\tthrough ? through.targetField : field,\n\t\t\tplan,\n\t\t\tconditions,\n\t\t\tdeclared.targetGuard,\n\t\t)\n\t\tconst index = through ? lookup(sourceTable, field, declared.junctionGuard) : targetIndex\n\t\t// SAFETY: planner.page validated the complete output mask before cursor binding.\n\t\tconst binding: CursorBinding = {\n\t\t\t...rootBinding,\n\t\t\ttable: sourceTable,\n\t\t\tindex: index.name,\n\t\t\torder: plan.args.order ?? 'asc',\n\t\t\tclientFilters: plan.clientIdentity,\n\t\t\tserverFilters: {\n\t\t\t\tpredicates: plan.serverIdentity,\n\t\t\t\tselection: selection as Value,\n\t\t\t\tscope: { ...request.scope },\n\t\t\t\trootTable: rootBinding.table,\n\t\t\t\tlookupIndex: targetIndex.name,\n\t\t\t\tguards: {\n\t\t\t\t\tsource: declared.sourceGuard ? { ...declared.sourceGuard } : null,\n\t\t\t\t\ttarget: declared.targetGuard ? { ...declared.targetGuard } : null,\n\t\t\t\t\tjunction: declared.junctionGuard ? { ...declared.junctionGuard } : null,\n\t\t\t\t},\n\t\t\t\t...((declared.sourceMember || declared.targetMember) && {\n\t\t\t\t\tmembers: {\n\t\t\t\t\t\tsource: declared.sourceMember ? { ...declared.sourceMember } : null,\n\t\t\t\t\t\ttarget: declared.targetMember ? { ...declared.targetMember } : null,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t\trelationPath: path,\n\t\t\tparent: rootId,\n\t\t}\n\t\tfunction open(token: string) {\n\t\t\ttry {\n\t\t\t\treturn navigation.parse(JSON.parse(codec.open(token, binding)))\n\t\t\t} catch {\n\t\t\t\tthrow new CursorError()\n\t\t\t}\n\t\t}\n\t\treturn { declared, plan, through, sourceTable, field, index, targetIndex, binding, open }\n\t}\n\tasync function pageRelation(\n\t\ttable: string,\n\t\tparent: Document | null,\n\t\tname: string,\n\t\tselection: OutputSelection,\n\t\tinput: QueryInput,\n\t\tconditions: readonly IndexCondition[] = [],\n\t\tconstraints: readonly StoredConstraint[] = [],\n\t\tpath: readonly string[] = [name],\n\t\tdepth = 1,\n\t\tparents: readonly string[] = [],\n\t\tprepared = prepare(\n\t\t\ttable,\n\t\t\tname,\n\t\t\tselection,\n\t\t\tinput,\n\t\t\tconditions,\n\t\t\tconstraints,\n\t\t\tpath,\n\t\t\tparents[0] ?? parent!._id,\n\t\t),\n\t\topened?: { cursor: string | null; endCursor?: string | null },\n\t) {\n\t\trequest.expand(depth, 0)\n\t\tconst { declared, plan, through, sourceTable, field, index, targetIndex, binding } = prepared\n\t\tconst value = sourceValue(declared, parent)\n\t\tconst args = { ...plan.args, ...(opened ?? { cursor: null }) }\n\t\t// SAFETY: declarations accept only native scalar lookup values; nullish references are absence.\n\t\tconst lookupPlan = {\n\t\t\t...plan,\n\t\t\tindex,\n\t\t\tprefix:\n\t\t\t\tvalue == null\n\t\t\t\t\t? []\n\t\t\t\t\t: through\n\t\t\t\t\t\t? relationPrefix(index, field, value as FilterScalar, undefined, declared.junctionGuard)\n\t\t\t\t\t\t: relationPrefix(index, field, value as FilterScalar, plan, declared.targetGuard),\n\t\t\tunsatisfiable: value == null || plan.unsatisfiable,\n\t\t}\n\t\tconst indexedTarget = through && through.targetField !== '_id'\n\t\tconst result = await executeStream(\n\t\t\tschema,\n\t\t\trequest,\n\t\t\tsourceTable,\n\t\t\tlookupPlan,\n\t\t\tplanner,\n\t\t\tcodec,\n\t\t\tbinding,\n\t\t\targs,\n\t\t\tasync (row, permitted) => {\n\t\t\t\tif (permitted) planner.validateDocument(indexedTarget ? declared.target : sourceTable, row)\n\t\t\t\tif (!permitted || (through && !indexedTarget && !guarded(row, declared.junctionGuard)))\n\t\t\t\t\treturn null\n\t\t\t\trequest.expand(depth)\n\t\t\t\tlet target: Document | null\n\t\t\t\tif (through && !indexedTarget)\n\t\t\t\t\ttarget = await get(declared.target, row[through.targetReference])\n\t\t\t\telse {\n\t\t\t\t\t// SAFETY: native direct/flattened target streams retain validated system fields.\n\t\t\t\t\ttarget = row as Document\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\t!target ||\n\t\t\t\t\t!guarded(target, declared.targetGuard) ||\n\t\t\t\t\t!memberMatches(target[base(declared.to).field], declared.targetMember) ||\n\t\t\t\t\t!(await matches(declared.target, target, plan.residual, depth))\n\t\t\t\t)\n\t\t\t\t\treturn null\n\t\t\t\treturn output(declared.target, target, selection, plan.args, path, depth, parents)\n\t\t\t},\n\t\t\t(raw) => codec.seal(JSON.stringify({ cursor: raw, ancestors: parents.slice(1) }), binding),\n\t\t\tindexedTarget\n\t\t\t\t? (source, db) => {\n\t\t\t\t\t\t// SAFETY: the registry owns the native schema/index descriptors. Public\n\t\t\t\t\t\t// helper flatMap concatenates native outer/inner keys and paginates them.\n\t\t\t\t\t\tconst nativeSchema = schema as SchemaDefinition<\n\t\t\t\t\t\t\tRecord<\n\t\t\t\t\t\t\t\tstring,\n\t\t\t\t\t\t\t\timport('convex/server').TableDefinition<any, Record<string, string[]>>\n\t\t\t\t\t\t\t>,\n\t\t\t\t\t\t\tboolean\n\t\t\t\t\t\t>\n\t\t\t\t\t\tconst fields = getIndexFields(declared.target, targetIndex.name, nativeSchema)\n\t\t\t\t\t\treturn source.flatMap(async (junction) => {\n\t\t\t\t\t\t\trequest.expand(depth)\n\t\t\t\t\t\t\tconst permitted = await request.authorize(sourceTable, junction)\n\t\t\t\t\t\t\tif (permitted) planner.validateDocument(sourceTable, junction)\n\t\t\t\t\t\t\tconst reference = junction[through.targetReference]\n\t\t\t\t\t\t\tif (!permitted || !guarded(junction, declared.junctionGuard) || reference == null)\n\t\t\t\t\t\t\t\treturn new EmptyStream(plan.args.order ?? 'asc', fields)\n\t\t\t\t\t\t\treturn stream(db, nativeSchema)\n\t\t\t\t\t\t\t\t.query(declared.target)\n\t\t\t\t\t\t\t\t.withIndex(targetIndex.name, (q) => {\n\t\t\t\t\t\t\t\t\t// SAFETY: registry validates the native leading lookup; validated filters supply each consecutive trailing binding.\n\t\t\t\t\t\t\t\t\tlet range = q as IndexRangeBuilder<any, string[], number>\n\t\t\t\t\t\t\t\t\t// SAFETY: junction references are native scalar Values validated by the declared lookup.\n\t\t\t\t\t\t\t\t\tconst prefix = relationPrefix(\n\t\t\t\t\t\t\t\t\t\ttargetIndex,\n\t\t\t\t\t\t\t\t\t\tthrough.targetField,\n\t\t\t\t\t\t\t\t\t\treference as FilterScalar,\n\t\t\t\t\t\t\t\t\t\tplan,\n\t\t\t\t\t\t\t\t\t\tdeclared.targetGuard,\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\tfor (const binding of prefix) {\n\t\t\t\t\t\t\t\t\t\t// SAFETY: native eq advances the validated consecutive index prefix.\n\t\t\t\t\t\t\t\t\t\trange = range.eq(binding.field, binding.value) as IndexRangeBuilder<\n\t\t\t\t\t\t\t\t\t\t\tany,\n\t\t\t\t\t\t\t\t\t\t\tstring[],\n\t\t\t\t\t\t\t\t\t\t\tnumber\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\treturn range\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t.order(plan.args.order ?? 'asc')\n\t\t\t\t\t\t}, fields)\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t\tindexedTarget ? declared.target : sourceTable,\n\t\t)\n\t\treturn result\n\t}\n\tasync function continuation(\n\t\trootTable: string,\n\t\trootId: string,\n\t\tpath: readonly string[],\n\t\tselection: OutputSelection,\n\t\tinput: QueryInput,\n\t\tconditions: readonly IndexCondition[],\n\t\tconstraints: readonly StoredConstraint[],\n\t) {\n\t\tif (!path.length || path.length > 4 || !request.db.normalizeId(rootTable, rootId))\n\t\t\tthrow new RelationshipError('INVALID_RELATION')\n\t\tlet table = rootTable\n\t\tconst declarations = path.map((name) => {\n\t\t\tconst declaration = edge(table, name)\n\t\t\ttable = declaration.target\n\t\t\treturn declaration\n\t\t})\n\t\tconst final = declarations.at(-1)!\n\t\tconst prepared = prepare(\n\t\t\tfinal.source,\n\t\t\tpath.at(-1)!,\n\t\t\tselection,\n\t\t\tinput,\n\t\t\tconditions,\n\t\t\tconstraints,\n\t\t\tpath,\n\t\t\trootId,\n\t\t)\n\t\t// Authenticate both slots and native ancestor IDs before ANY parent/traversal read.\n\t\tconst start = input.cursor === null ? null : prepared.open(input.cursor)\n\t\tconst end = input.endCursor == null ? null : prepared.open(input.endCursor)\n\t\tconst ancestors = start?.ancestors ?? end?.ancestors ?? []\n\t\tif (\n\t\t\tancestors.length !== path.length - 1 ||\n\t\t\t(start && end && JSON.stringify(start.ancestors) !== JSON.stringify(end.ancestors)) ||\n\t\t\tancestors.some((id, i) => !request.db.normalizeId(declarations[i].target, id))\n\t\t)\n\t\t\tthrow new CursorError()\n\t\t// Declarative input/index/cursor validation above retains its pre-read errors,\n\t\t// just as on the root path. Every awaited read, ancestry proof and page is protected.\n\t\ttry {\n\t\t\tlet parent = await get(rootTable, rootId)\n\t\t\tfor (let i = 0; parent && i < ancestors.length; i++) {\n\t\t\t\tconst declared = declarations[i]\n\t\t\t\tlet found: Document | null = null\n\t\t\t\tif (declared.cardinality === 'one') {\n\t\t\t\t\tconst target = await one(declared, parent, i + 1)\n\t\t\t\t\tif (target?._id === ancestors[i]) found = target\n\t\t\t\t} else\n\t\t\t\t\tfor await (const target of traverse(declared, parent, i + 1)) {\n\t\t\t\t\t\tif (target._id === ancestors[i]) {\n\t\t\t\t\t\t\tfound = target\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tparent = found\n\t\t\t}\n\t\t\treturn await pageRelation(\n\t\t\t\tfinal.source,\n\t\t\t\tparent,\n\t\t\t\tpath.at(-1)!,\n\t\t\t\tselection,\n\t\t\t\tinput,\n\t\t\t\tconditions,\n\t\t\t\tconstraints,\n\t\t\t\tpath,\n\t\t\t\tpath.length,\n\t\t\t\t[rootId, ...ancestors],\n\t\t\t\tprepared,\n\t\t\t\t{ cursor: start?.cursor ?? null, endCursor: end?.cursor ?? input.endCursor },\n\t\t\t)\n\t\t} catch (error) {\n\t\t\trethrowQueryError(error)\n\t\t}\n\t}\n\treturn { matches, output, continuation, edge }\n}\n\nfunction scalarOnly(ast: FilterAst): boolean {\n\tif (ast.kind === 'relation') return false\n\tif (ast.kind === 'and' || ast.kind === 'or') return ast.children.every(scalarOnly)\n\tif (ast.kind === 'not' || ast.kind === 'variant') return scalarOnly(ast.child)\n\treturn true\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"relationships.mjs","names":["navigation","z","RelationshipError","code","assertRelationshipDepth","nested","selection","depth","relationshipExecutor","metadata","planner","base","leg","edge","declared","table","name","guarded","guard","row","memberIdSchema","memberMatches","member","id","value","request","sourceValue","parent","lookup","index","field","position","i","key","checkTraversal","check","groups","targetPath","path","relationIndex","indexes","bound","plan","usable","length","size","condition","conditions","c","chosen","candidates","b","a","relationPrefix","prefix","get","result","targets","target","iterator","range","q","binding","next","traverse","junction","one","match","matches","scalarOnly","ast","scalarMatches","child","output","dto","selected","args","parents","pageRelation","prepare","ordering","guardConstraint","input","constraints","from","to","through","sourceTable","targetIndex","expansion","expansionForIndex","groupBinding","resolved","rootBinding","rootId","open","codec","token","CursorError","prepared","opened","lookupPlan","rangeForIndex","compareValues","withinRange","indexedTarget","executeStream","schema","permitted","raw","nativeSchema","fields","getIndexFields","source","reference","EmptyStream","stream","db","nativeIndexRange","continuation","rootTable","declarations","declaration","d","final","start","end","ancestors","found","error","rethrowQueryError","preflight","nestedPath"],"sources":["../../src/querying/relationships.ts"],"sourcesContent":["import type { GenericSchema, SchemaDefinition, IndexRangeBuilder } from 'convex/server'\nimport { compareValues, type GenericId, type Value } from 'convex/values'\nimport type { RelationEdge, RelationGuard } from '../relations'\nimport type { createPlanner, QueryInput, StoredConstraint } from './planner'\nimport { scalarMatches } from './planner'\nimport type {\n\tFilterAst,\n\tFilterScalar,\n\tIndexCondition,\n\tNativePagination,\n\tQueryIndex,\n} from './filters'\nimport { expansionForIndex, rangeForIndex, withinRange } from './filters'\nimport {\n\texecuteStream,\n\tnativeIndexRange,\n\trethrowQueryError,\n\ttype ExecutionRequest,\n} from './execution'\nimport type { createCursorCodec, CursorBinding } from './cursors'\nimport { CursorError } from './cursors'\nimport { z } from 'zod'\nimport { stream, EmptyStream, getIndexFields } from 'convex-helpers/server/stream'\n\nexport interface OutputSelection {\n\t[name: string]: true | OutputSelection\n}\nexport type ResolvedGroups = {\n\tfieldGroups: Record<string, { mode: 'required' | 'if-permitted'; allowed: boolean }>\n\trelations: Record<string, ResolvedGroups>\n}\nexport interface GroupAccess {\n\tat(path: readonly string[]): ResolvedGroups\n\tallowed(path: readonly string[]): readonly string[]\n\tcheckOrder(table: string, fields: readonly string[], path?: readonly string[]): void\n}\ntype Edge = RelationEdge<string, string, 'one' | 'many', any, any>\nexport type RelationDocument = Record<string, Value> & {\n\t_id: GenericId<string>\n\t_creationTime: number\n}\ntype Document = RelationDocument\ntype Planner = ReturnType<typeof createPlanner>\nconst navigation = z.object({ cursor: z.string(), ancestors: z.array(z.string()).max(3) }).strict()\n\nexport class RelationshipError extends Error {\n\tconstructor(readonly code: 'AMBIGUOUS_RELATION' | 'INVALID_RELATION') {\n\t\tsuper(code)\n\t\tthis.name = 'RelationshipError'\n\t}\n}\n\n/** The selection has already passed the registry validator; count leaf edges too. */\nexport function assertRelationshipDepth(selection: OutputSelection, depth: number): void {\n\tfor (const nested of Object.values(selection)) {\n\t\tif (depth >= 4) throw new RelationshipError('INVALID_RELATION')\n\t\tif (nested !== true) assertRelationshipDepth(nested, depth + 1)\n\t}\n}\n\n/** One request owns all traversal and authorized ID memoization. No raw reader escapes. */\nexport function relationshipExecutor(\n\tschema: SchemaDefinition<GenericSchema, boolean>,\n\trequest: ExecutionRequest,\n\tplanner: Planner,\n\tcodec: ReturnType<typeof createCursorCodec>,\n\trootBinding: CursorBinding,\n\tgroups?: GroupAccess,\n) {\n\tconst metadata = planner.metadata\n\tconst base = (leg: Edge['from']) => ('base' in leg ? leg.base : leg)\n\tfunction edge(table: string, name: string): Edge {\n\t\tconst declared = metadata.declarations[table]?.[name]\n\t\tif (!declared) throw new RelationshipError('INVALID_RELATION')\n\t\treturn declared\n\t}\n\tconst guarded = (row: Document | Record<string, Value>, guard?: RelationGuard) =>\n\t\t!guard || row[guard.discriminator] === guard.tag\n\tconst memberIdSchema = z.string()\n\tfunction memberMatches(value: Value | undefined, member: Edge['sourceMember']): boolean {\n\t\tif (!member) return true\n\t\tconst id = memberIdSchema.safeParse(value)\n\t\treturn id.success && request.db.normalizeId(member.table, id.data) !== null\n\t}\n\tfunction sourceValue(declared: Edge, parent: Document | null): Value | undefined {\n\t\tif (!parent || !guarded(parent, declared.sourceGuard)) return undefined\n\t\tconst value = parent[base(declared.from).field]\n\t\treturn memberMatches(value, declared.sourceMember) &&\n\t\t\tmemberMatches(value, declared.targetMember)\n\t\t\t? value\n\t\t\t: undefined\n\t}\n\tfunction lookup(table: string, field: string, guard?: RelationGuard) {\n\t\tconst index =\n\t\t\tfield === '_id'\n\t\t\t\t? { name: 'by_id', fields: ['_id'] }\n\t\t\t\t: metadata.tables[table].indexes.find((i) => {\n\t\t\t\t\t\tconst position = i.fields.indexOf(field)\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\tposition >= 0 &&\n\t\t\t\t\t\t\ti.fields.slice(0, position).every((key) => key === guard?.discriminator)\n\t\t\t\t\t\t)\n\t\t\t\t\t})\n\t\tif (!index) throw new RelationshipError('INVALID_RELATION')\n\t\treturn index\n\t}\n\tfunction checkTraversal(declared: Edge, path?: readonly string[]) {\n\t\tfunction check(\n\t\t\ttable: string,\n\t\t\tfield: string,\n\t\t\tguard?: RelationGuard,\n\t\t\ttargetPath?: readonly string[],\n\t\t) {\n\t\t\tgroups?.checkOrder(\n\t\t\t\ttable,\n\t\t\t\tlookup(table, field, guard).fields.filter(\n\t\t\t\t\t(key) => key !== field && key !== guard?.discriminator,\n\t\t\t\t),\n\t\t\t\ttargetPath,\n\t\t\t)\n\t\t}\n\t\tif ('base' in declared.from && 'base' in declared.to) {\n\t\t\tcheck(declared.from.junction.table, declared.from.junction.field, declared.junctionGuard)\n\t\t\tcheck(declared.target, declared.to.base.field, declared.targetGuard, path)\n\t\t} else check(declared.target, base(declared.to).field, declared.targetGuard, path)\n\t}\n\tfunction relationIndex(\n\t\ttable: string,\n\t\tfield: string,\n\t\tplan: ReturnType<Planner['plan']>,\n\t\tconditions: readonly IndexCondition[],\n\t\tguard?: RelationGuard,\n\t): QueryIndex {\n\t\tconst indexes =\n\t\t\tfield === '_id' ? [{ name: 'by_id', fields: ['_id'] }] : metadata.tables[table].indexes\n\t\tconst bound = (key: string) =>\n\t\t\tkey === field || key === guard?.discriminator || plan.bindings.has(key)\n\t\tconst usable = (index: QueryIndex) =>\n\t\t\tindex.fields.includes(field) &&\n\t\t\tindex.fields.slice(0, index.fields.indexOf(field)).every(bound)\n\t\tconst length = (index: QueryIndex) => {\n\t\t\tlet size = 0\n\t\t\tfor (const key of index.fields) {\n\t\t\t\tif (!bound(key)) break\n\t\t\t\tsize++\n\t\t\t}\n\t\t\treturn size\n\t\t}\n\t\tconst condition = conditions.find((c) => c.value !== null && c.value !== undefined)\n\t\tif (condition) {\n\t\t\tconst chosen = indexes.find((i) => i.name === condition.index && usable(i))\n\t\t\tif (!chosen)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Explicit index \"${condition.index}\" is incompatible with declared relationship lookup`,\n\t\t\t\t)\n\t\t\treturn chosen\n\t\t}\n\t\tconst candidates = indexes\n\t\t\t.filter(usable)\n\t\t\t.sort(\n\t\t\t\t(a, b) =>\n\t\t\t\t\tlength(b) - length(a) ||\n\t\t\t\t\tNumber(plan.sets.has(b.fields[length(b)])) - Number(plan.sets.has(a.fields[length(a)])) ||\n\t\t\t\t\tNumber(plan.ranges.has(b.fields[length(b)])) -\n\t\t\t\t\t\tNumber(plan.ranges.has(a.fields[length(a)])) ||\n\t\t\t\t\ta.name.localeCompare(b.name) ||\n\t\t\t\t\ta.fields.join('\\0').localeCompare(b.fields.join('\\0')),\n\t\t\t)\n\t\tif (!candidates.length) throw new RelationshipError('INVALID_RELATION')\n\t\treturn candidates[0]\n\t}\n\tfunction relationPrefix(\n\t\tindex: QueryIndex,\n\t\tfield: string,\n\t\tvalue: FilterScalar,\n\t\tplan?: ReturnType<Planner['plan']>,\n\t\tguard?: RelationGuard,\n\t) {\n\t\tconst prefix: { field: string; value: FilterScalar }[] = []\n\t\tfor (const key of index.fields) {\n\t\t\tif (key === field) prefix.push({ field: key, value })\n\t\t\telse if (key === guard?.discriminator) prefix.push({ field: key, value: guard.tag })\n\t\t\telse if (plan?.bindings.has(key)) prefix.push({ field: key, value: plan.bindings.get(key)! })\n\t\t\telse break\n\t\t}\n\t\treturn prefix\n\t}\n\n\tasync function get(table: string, id: Value | undefined): Promise<Document | null> {\n\t\tplanner.beforeLeaf(table)\n\t\t// SAFETY: native normalization rejects non-string/non-table IDs before any read.\n\t\tif (id == null || !request.db.normalizeId(table, id as string)) return null\n\t\t// SAFETY: normalizeId verifies the declared native table before the authorized metered get.\n\t\tconst result = await request.db.get(table, id as GenericId<string>)\n\t\tif (result) planner.validateDocument(table, result)\n\t\t// SAFETY: normalizeId checked the table; the authorized native get retains system fields.\n\t\treturn result as Document | null\n\t}\n\tasync function* targets(\n\t\ttable: string,\n\t\tfield: string,\n\t\tvalue: Value | undefined,\n\t\tdepth: number,\n\t\tguard?: RelationGuard,\n\t\tmember?: Edge['targetMember'],\n\t): AsyncGenerator<Document> {\n\t\trequest.expand(depth, 0)\n\t\tif (value == null || !memberMatches(value, member)) return\n\t\tif (field === '_id') {\n\t\t\tconst target = await get(table, value)\n\t\t\tif (target && guarded(target, guard) && memberMatches(target[field], member)) {\n\t\t\t\trequest.expand(depth)\n\t\t\t\tyield target\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tplanner.beforeLeaf(table)\n\t\tconst index = lookup(table, field, guard)\n\t\t// SAFETY: registry validates the indexed native lookup prefix and compatible values.\n\t\tconst source = request.leafQuery(table).withIndex(index.name, (q) => {\n\t\t\t// SAFETY: registration checks the mandatory join and every preceding guard equality.\n\t\t\tlet range = q as IndexRangeBuilder<any, string[], number>\n\t\t\t// SAFETY: registered relation fields are native scalars; each equality advances the consecutive checked prefix.\n\t\t\tfor (const binding of relationPrefix(index, field, value as FilterScalar, undefined, guard)) {\n\t\t\t\t// SAFETY: the prefix comes from the declared index and registry-owned guard.\n\t\t\t\trange = range.eq(binding.field, binding.value) as IndexRangeBuilder<any, string[], number>\n\t\t\t}\n\t\t\treturn range\n\t\t})\n\t\tconst iterator = source[Symbol.asyncIterator]()\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tplanner.beforeLeaf(table)\n\t\t\t\tconst next = await iterator.next()\n\t\t\t\tif (next.done) return\n\t\t\t\tconst permitted = await request.authorize(table, next.value)\n\t\t\t\t// Denials are an await boundary too; never hide them inside an authorized iterator.\n\t\t\t\tif (!permitted) continue\n\t\t\t\tplanner.validateDocument(table, next.value)\n\t\t\t\tif (!guarded(next.value, guard) || !memberMatches(next.value[field], member)) continue\n\t\t\t\trequest.expand(depth)\n\t\t\t\t// SAFETY: native rows include system fields and explicit authorization just completed.\n\t\t\t\tyield next.value as Document\n\t\t\t}\n\t\t} finally {\n\t\t\tawait iterator.return?.()\n\t\t}\n\t}\n\tasync function* traverse(\n\t\tdeclared: Edge,\n\t\tparent: Document,\n\t\tdepth: number,\n\t): AsyncGenerator<Document> {\n\t\trequest.expand(depth, 0)\n\t\tconst value = sourceValue(declared, parent)\n\t\tif (value == null) return\n\t\tif ('base' in declared.from && 'base' in declared.to) {\n\t\t\tfor await (const junction of targets(\n\t\t\t\tdeclared.from.junction.table,\n\t\t\t\tdeclared.from.junction.field,\n\t\t\t\tvalue,\n\t\t\t\tdepth,\n\t\t\t\tdeclared.junctionGuard,\n\t\t\t))\n\t\t\t\tyield* targets(\n\t\t\t\t\tdeclared.target,\n\t\t\t\t\tdeclared.to.base.field,\n\t\t\t\t\tjunction[declared.to.junction.field],\n\t\t\t\t\tdepth,\n\t\t\t\t\tdeclared.targetGuard,\n\t\t\t\t)\n\t\t} else\n\t\t\tyield* targets(\n\t\t\t\tdeclared.target,\n\t\t\t\tbase(declared.to).field,\n\t\t\t\tvalue,\n\t\t\t\tdepth,\n\t\t\t\tdeclared.targetGuard,\n\t\t\t\tdeclared.targetMember,\n\t\t\t)\n\t}\n\tasync function one(declared: Edge, parent: Document, depth: number) {\n\t\tlet match: Document | null = null\n\t\tfor await (const target of traverse(declared, parent, depth)) {\n\t\t\tif (match) throw new RelationshipError('AMBIGUOUS_RELATION')\n\t\t\tmatch = target\n\t\t}\n\t\treturn match\n\t}\n\tasync function matches(\n\t\ttable: string,\n\t\tparent: Document,\n\t\tast: FilterAst,\n\t\tdepth = 0,\n\t): Promise<boolean> {\n\t\trequest.expand(depth, 0)\n\t\t// Variant rows must satisfy the captured stored branch before predicates\n\t\t// inspect branch fields. Ordinary output rows are validated by projection.\n\t\tif (metadata.tables[table].variant) planner.validateDocument(table, parent)\n\t\tif (scalarOnly(ast)) return scalarMatches(ast, parent)\n\t\tif (ast.kind === 'variant')\n\t\t\treturn parent[ast.discriminator] === ast.tag && matches(table, parent, ast.child, depth)\n\t\tif (ast.kind === 'scalar') return scalarMatches(ast, parent)\n\t\tif (ast.kind === 'not') return !(await matches(table, parent, ast.child, depth))\n\t\tif (ast.kind === 'and' || ast.kind === 'or') {\n\t\t\tfor (const child of ast.children) {\n\t\t\t\tconst result = await matches(table, parent, child, depth)\n\t\t\t\tif (ast.kind === 'and' && !result) return false\n\t\t\t\tif (ast.kind === 'or' && result) return true\n\t\t\t}\n\t\t\treturn ast.kind === 'and'\n\t\t}\n\t\tif (ast.kind !== 'relation') throw new RelationshipError('INVALID_RELATION')\n\t\tconst declared = edge(table, ast.name)\n\t\tif (ast.mode === 'one') {\n\t\t\tconst target = await one(declared, parent, depth + 1)\n\t\t\treturn ast.predicate === null\n\t\t\t\t? target === null\n\t\t\t\t: target !== null && (await matches(declared.target, target, ast.predicate, depth + 1))\n\t\t}\n\t\tfor await (const target of traverse(declared, parent, depth + 1))\n\t\t\tif (await matches(declared.target, target, ast.predicate!, depth + 1))\n\t\t\t\treturn ast.mode === 'some'\n\t\t// Only actual authorized traversal exhaustion proves none.\n\t\treturn ast.mode === 'none'\n\t}\n\tasync function output(\n\t\ttable: string,\n\t\tparent: Document,\n\t\tselection: OutputSelection,\n\t\targs: NativePagination & { order?: 'asc' | 'desc' },\n\t\tpath: readonly string[] = [],\n\t\tdepth = 0,\n\t\tparents: readonly string[] = [],\n\t): Promise<Record<string, Value>> {\n\t\trequest.expand(depth, 0)\n\t\t// SAFETY: the registry strictly validates this public native DTO projection.\n\t\tconst dto = planner.complete(\n\t\t\ttable,\n\t\t\tparent,\n\t\t\ttrue,\n\t\t\t{ kind: 'and', children: [] },\n\t\t\tgroups?.allowed(path),\n\t\t) as Record<string, Value>\n\t\tfor (const [name, selected] of Object.entries(selection)) {\n\t\t\tconst declared = edge(table, name),\n\t\t\t\tnested = selected === true ? {} : selected\n\t\t\tif (declared.cardinality === 'one') {\n\t\t\t\tconst target = await one(declared, parent, depth + 1)\n\t\t\t\tdto[name] = target\n\t\t\t\t\t? await output(declared.target, target, nested, args, [...path, name], depth + 1, [\n\t\t\t\t\t\t\t...parents,\n\t\t\t\t\t\t\tparent._id,\n\t\t\t\t\t\t])\n\t\t\t\t\t: null\n\t\t\t} else {\n\t\t\t\tconst page = await pageRelation(\n\t\t\t\t\ttable,\n\t\t\t\t\tparent,\n\t\t\t\t\tname,\n\t\t\t\t\tnested,\n\t\t\t\t\t{ numItems: args.numItems, cursor: null, order: args.order },\n\t\t\t\t\t[],\n\t\t\t\t\t[],\n\t\t\t\t\t[...path, name],\n\t\t\t\t\tdepth + 1,\n\t\t\t\t\t[...parents, parent._id],\n\t\t\t\t)\n\t\t\t\t// SAFETY: pageRelation projects and validates each nested DTO row.\n\t\t\t\tdto[name] = page as Value\n\t\t\t}\n\t\t}\n\t\treturn dto\n\t}\n\tfunction prepare(\n\t\ttable: string,\n\t\tname: string,\n\t\tselection: OutputSelection,\n\t\tinput: QueryInput,\n\t\tconditions: readonly IndexCondition[],\n\t\tconstraints: readonly StoredConstraint[],\n\t\tpath: readonly string[],\n\t\trootId: string,\n\t\tordering?: string,\n\t) {\n\t\tif (ordering !== undefined && conditions.some((c) => c.value !== null && c.value !== undefined))\n\t\t\tthrow new Error('orderBy cannot be combined with an active when selector')\n\t\tplanner.select(edge(table, name).target, selection)\n\t\tassertRelationshipDepth(selection, path.length)\n\t\tconst declared = edge(table, name)\n\t\tif (declared.cardinality !== 'many') throw new RelationshipError('INVALID_RELATION')\n\t\tconst guardConstraint = declared.targetGuard\n\t\t\t? { fields: { [declared.targetGuard.discriminator]: declared.targetGuard.tag } }\n\t\t\t: undefined\n\t\tconst plan = planner.plan(\n\t\t\tdeclared.target,\n\t\t\tinput,\n\t\t\t[],\n\t\t\tguardConstraint ? [...constraints, guardConstraint] : constraints,\n\t\t\tordering,\n\t\t\t'relation',\n\t\t)\n\t\tconst from = declared.from,\n\t\t\tto = declared.to\n\t\tconst through =\n\t\t\t'base' in from && 'base' in to\n\t\t\t\t? {\n\t\t\t\t\t\ttable: from.junction.table,\n\t\t\t\t\t\tfield: from.junction.field,\n\t\t\t\t\t\ttargetField: to.base.field,\n\t\t\t\t\t\ttargetReference: to.junction.field,\n\t\t\t\t\t}\n\t\t\t\t: null\n\t\tif (ordering !== undefined && through)\n\t\t\tthrow new Error('orderBy is unsupported for junction relationships')\n\t\tconst sourceTable = through ? through.table : declared.target\n\t\tconst field = through ? through.field : base(to).field\n\t\tconst targetIndex = relationIndex(\n\t\t\tdeclared.target,\n\t\t\tthrough ? through.targetField : field,\n\t\t\tplan,\n\t\t\tordering === undefined ? conditions : [{ value: true, index: ordering }],\n\t\t\tdeclared.targetGuard,\n\t\t)\n\t\tgroups?.checkOrder(\n\t\t\tdeclared.target,\n\t\t\ttargetIndex.fields.filter(\n\t\t\t\t(key) =>\n\t\t\t\t\tkey !== (through ? through.targetField : field) &&\n\t\t\t\t\tkey !== declared.targetGuard?.discriminator &&\n\t\t\t\t\t!plan.bindings.has(key),\n\t\t\t),\n\t\t\tpath,\n\t\t)\n\t\tconst index = through ? lookup(sourceTable, field, declared.junctionGuard) : targetIndex\n\t\tif (through)\n\t\t\tgroups?.checkOrder(\n\t\t\t\tsourceTable,\n\t\t\t\tindex.fields.filter(\n\t\t\t\t\t(key) => key !== field && key !== declared.junctionGuard?.discriminator,\n\t\t\t\t),\n\t\t\t)\n\t\t// The lookup value changes only values, not prefix positions or comparator.\n\t\tconst expansion =\n\t\t\tthrough || plan.unsatisfiable\n\t\t\t\t? null\n\t\t\t\t: expansionForIndex(\n\t\t\t\t\t\tindex,\n\t\t\t\t\t\trelationPrefix(index, field, null, plan, declared.targetGuard),\n\t\t\t\t\t\tplan.sets,\n\t\t\t\t\t\tordering !== undefined ||\n\t\t\t\t\t\t\tconditions.some((c) => c.value !== null && c.value !== undefined),\n\t\t\t\t\t)\n\t\tconst groupBinding: Record<string, Value> = {}\n\t\tconst resolved = groups?.at(path)\n\t\tif (\n\t\t\tresolved &&\n\t\t\t(Object.keys(resolved.fieldGroups).length || Object.keys(resolved.relations).length)\n\t\t)\n\t\t\tgroupBinding.fieldGroups = resolved\n\t\t// SAFETY: planner.page validated the complete output mask before cursor binding.\n\t\tconst binding: CursorBinding = {\n\t\t\t...rootBinding,\n\t\t\ttable: sourceTable,\n\t\t\tindex: index.name,\n\t\t\torder: plan.args.order ?? 'asc',\n\t\t\tclientFilters: plan.clientIdentity,\n\t\t\tserverFilters: {\n\t\t\t\tpredicates: plan.sets.size\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tpredicates: plan.serverIdentity,\n\t\t\t\t\t\t\ttraversal: { version: 2, expansion: expansion ? { ...expansion } : null },\n\t\t\t\t\t\t}\n\t\t\t\t\t: plan.serverIdentity,\n\t\t\t\tselection: selection as Value,\n\t\t\t\t...groupBinding,\n\t\t\t\tscope: { ...request.scope },\n\t\t\t\trootTable: rootBinding.table,\n\t\t\t\tlookupIndex: targetIndex.name,\n\t\t\t\tguards: {\n\t\t\t\t\tsource: declared.sourceGuard ? { ...declared.sourceGuard } : null,\n\t\t\t\t\ttarget: declared.targetGuard ? { ...declared.targetGuard } : null,\n\t\t\t\t\tjunction: declared.junctionGuard ? { ...declared.junctionGuard } : null,\n\t\t\t\t},\n\t\t\t\t...((declared.sourceMember || declared.targetMember) && {\n\t\t\t\t\tmembers: {\n\t\t\t\t\t\tsource: declared.sourceMember ? { ...declared.sourceMember } : null,\n\t\t\t\t\t\ttarget: declared.targetMember ? { ...declared.targetMember } : null,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t},\n\t\t\trelationPath: path,\n\t\t\tparent: rootId,\n\t\t}\n\t\tfunction open(token: string) {\n\t\t\ttry {\n\t\t\t\treturn navigation.parse(JSON.parse(codec.open(token, binding)))\n\t\t\t} catch {\n\t\t\t\tthrow new CursorError()\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\tdeclared,\n\t\t\tplan,\n\t\t\tthrough,\n\t\t\tsourceTable,\n\t\t\tfield,\n\t\t\tindex,\n\t\t\ttargetIndex,\n\t\t\tbinding,\n\t\t\topen,\n\t\t\texpansion,\n\t\t}\n\t}\n\tasync function pageRelation(\n\t\ttable: string,\n\t\tparent: Document | null,\n\t\tname: string,\n\t\tselection: OutputSelection,\n\t\tinput: QueryInput,\n\t\tconditions: readonly IndexCondition[] = [],\n\t\tconstraints: readonly StoredConstraint[] = [],\n\t\tpath: readonly string[] = [name],\n\t\tdepth = 1,\n\t\tparents: readonly string[] = [],\n\t\tprepared = prepare(\n\t\t\ttable,\n\t\t\tname,\n\t\t\tselection,\n\t\t\tinput,\n\t\t\tconditions,\n\t\t\tconstraints,\n\t\t\tpath,\n\t\t\tparents[0] ?? parent!._id,\n\t\t),\n\t\topened?: { cursor: string | null; endCursor?: string | null },\n\t) {\n\t\trequest.expand(depth, 0)\n\t\tconst { declared, plan, through, sourceTable, field, index, targetIndex, binding, expansion } =\n\t\t\tprepared\n\t\tconst value = sourceValue(declared, parent)\n\t\tconst args = { ...plan.args, ...(opened ?? { cursor: null }) }\n\t\t// SAFETY: declarations accept only native scalar lookup values; nullish references are absence.\n\t\tconst lookupPlan = {\n\t\t\t...plan,\n\t\t\texpansion,\n\t\t\tindex,\n\t\t\tprefix:\n\t\t\t\tvalue == null\n\t\t\t\t\t? []\n\t\t\t\t\t: through\n\t\t\t\t\t\t? relationPrefix(index, field, value as FilterScalar, undefined, declared.junctionGuard)\n\t\t\t\t\t\t: relationPrefix(index, field, value as FilterScalar, plan, declared.targetGuard),\n\t\t\tunsatisfiable: value == null || plan.unsatisfiable,\n\t\t}\n\t\tlookupPlan.range = through ? null : rangeForIndex(index, lookupPlan.prefix, plan.ranges)\n\t\tif (!through)\n\t\t\tfor (const binding of lookupPlan.prefix) {\n\t\t\t\tconst range = plan.ranges.get(binding.field)\n\t\t\t\tif (\n\t\t\t\t\tplan.bindings.has(binding.field) &&\n\t\t\t\t\tcompareValues(binding.value, plan.bindings.get(binding.field)!) !== 0\n\t\t\t\t)\n\t\t\t\t\tlookupPlan.unsatisfiable = true\n\t\t\t\tif (range && !withinRange(binding.value, range)) lookupPlan.unsatisfiable = true\n\t\t\t}\n\t\tconst indexedTarget = through && through.targetField !== '_id'\n\t\tconst result = await executeStream(\n\t\t\tschema,\n\t\t\trequest,\n\t\t\tsourceTable,\n\t\t\tlookupPlan,\n\t\t\tplanner,\n\t\t\tcodec,\n\t\t\tbinding,\n\t\t\targs,\n\t\t\tasync (row, permitted) => {\n\t\t\t\tif (permitted) planner.validateDocument(indexedTarget ? declared.target : sourceTable, row)\n\t\t\t\tif (!permitted || (through && !indexedTarget && !guarded(row, declared.junctionGuard)))\n\t\t\t\t\treturn null\n\t\t\t\trequest.expand(depth)\n\t\t\t\tlet target: Document | null\n\t\t\t\tif (through && !indexedTarget)\n\t\t\t\t\ttarget = await get(declared.target, row[through.targetReference])\n\t\t\t\telse {\n\t\t\t\t\t// SAFETY: native direct/flattened target streams retain validated system fields.\n\t\t\t\t\ttarget = row as Document\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\t!target ||\n\t\t\t\t\t!guarded(target, declared.targetGuard) ||\n\t\t\t\t\t!memberMatches(target[base(declared.to).field], declared.targetMember) ||\n\t\t\t\t\t!(await matches(declared.target, target, plan.residual, depth))\n\t\t\t\t)\n\t\t\t\t\treturn null\n\t\t\t\treturn output(declared.target, target, selection, plan.args, path, depth, parents)\n\t\t\t},\n\t\t\t(raw) => codec.seal(JSON.stringify({ cursor: raw, ancestors: parents.slice(1) }), binding),\n\t\t\tindexedTarget\n\t\t\t\t? (source, db) => {\n\t\t\t\t\t\t// SAFETY: the registry owns the native schema/index descriptors. Public\n\t\t\t\t\t\t// helper flatMap concatenates native outer/inner keys and paginates them.\n\t\t\t\t\t\tconst nativeSchema = schema as SchemaDefinition<\n\t\t\t\t\t\t\tRecord<\n\t\t\t\t\t\t\t\tstring,\n\t\t\t\t\t\t\t\timport('convex/server').TableDefinition<any, Record<string, string[]>>\n\t\t\t\t\t\t\t>,\n\t\t\t\t\t\t\tboolean\n\t\t\t\t\t\t>\n\t\t\t\t\t\tconst fields = getIndexFields(declared.target, targetIndex.name, nativeSchema)\n\t\t\t\t\t\treturn source.flatMap(async (junction) => {\n\t\t\t\t\t\t\trequest.expand(depth)\n\t\t\t\t\t\t\tconst permitted = await request.authorize(sourceTable, junction)\n\t\t\t\t\t\t\tif (permitted) planner.validateDocument(sourceTable, junction)\n\t\t\t\t\t\t\tconst reference = junction[through.targetReference]\n\t\t\t\t\t\t\tif (!permitted || !guarded(junction, declared.junctionGuard) || reference == null)\n\t\t\t\t\t\t\t\treturn new EmptyStream(plan.args.order ?? 'asc', fields)\n\t\t\t\t\t\t\treturn stream(db, nativeSchema)\n\t\t\t\t\t\t\t\t.query(declared.target)\n\t\t\t\t\t\t\t\t.withIndex(targetIndex.name, (q) => {\n\t\t\t\t\t\t\t\t\t// SAFETY: registry-owned lookup bindings are native scalar index values.\n\t\t\t\t\t\t\t\t\tconst prefix = relationPrefix(\n\t\t\t\t\t\t\t\t\t\ttargetIndex,\n\t\t\t\t\t\t\t\t\t\tthrough.targetField,\n\t\t\t\t\t\t\t\t\t\treference as FilterScalar,\n\t\t\t\t\t\t\t\t\t\tplan,\n\t\t\t\t\t\t\t\t\t\tdeclared.targetGuard,\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\treturn nativeIndexRange(\n\t\t\t\t\t\t\t\t\t\tq,\n\t\t\t\t\t\t\t\t\t\tprefix,\n\t\t\t\t\t\t\t\t\t\trangeForIndex(targetIndex, prefix, plan.ranges),\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t.order(plan.args.order ?? 'asc')\n\t\t\t\t\t\t}, fields)\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t\tindexedTarget ? declared.target : sourceTable,\n\t\t)\n\t\treturn result\n\t}\n\tasync function continuation(\n\t\trootTable: string,\n\t\trootId: string,\n\t\tpath: readonly string[],\n\t\tselection: OutputSelection,\n\t\tinput: QueryInput,\n\t\tconditions: readonly IndexCondition[],\n\t\tconstraints: readonly StoredConstraint[],\n\t\tordering?: string,\n\t) {\n\t\tif (!path.length || path.length > 4 || !request.db.normalizeId(rootTable, rootId))\n\t\t\tthrow new RelationshipError('INVALID_RELATION')\n\t\tlet table = rootTable\n\t\tconst declarations = path.map((name) => {\n\t\t\tconst declaration = edge(table, name)\n\t\t\ttable = declaration.target\n\t\t\treturn declaration\n\t\t})\n\t\tif (ordering !== undefined && declarations.some((d) => 'base' in d.from || 'base' in d.to))\n\t\t\tthrow new Error('orderBy is unsupported for junction relationships')\n\t\tconst final = declarations.at(-1)!\n\t\tfor (const declaration of declarations.slice(0, -1))\n\t\t\tif (\n\t\t\t\tdeclaration.cardinality === 'one' ||\n\t\t\t\t'base' in declaration.from ||\n\t\t\t\t'base' in declaration.to\n\t\t\t)\n\t\t\t\tcheckTraversal(declaration)\n\t\tconst prepared = prepare(\n\t\t\tfinal.source,\n\t\t\tpath.at(-1)!,\n\t\t\tselection,\n\t\t\tinput,\n\t\t\tconditions,\n\t\t\tconstraints,\n\t\t\tpath,\n\t\t\trootId,\n\t\t\tordering,\n\t\t)\n\t\t// Authenticate both slots and native ancestor IDs before ANY parent/traversal read.\n\t\tconst start = input.cursor === null ? null : prepared.open(input.cursor)\n\t\tconst end = input.endCursor == null ? null : prepared.open(input.endCursor)\n\t\tconst ancestors = start?.ancestors ?? end?.ancestors ?? []\n\t\tif (\n\t\t\tancestors.length !== path.length - 1 ||\n\t\t\t(start && end && JSON.stringify(start.ancestors) !== JSON.stringify(end.ancestors)) ||\n\t\t\tancestors.some((id, i) => !request.db.normalizeId(declarations[i].target, id))\n\t\t)\n\t\t\tthrow new CursorError()\n\t\t// Declarative input/index/cursor validation above retains its pre-read errors,\n\t\t// just as on the root path. Every awaited read, ancestry proof and page is protected.\n\t\ttry {\n\t\t\tlet parent = await get(rootTable, rootId)\n\t\t\tfor (let i = 0; parent && i < ancestors.length; i++) {\n\t\t\t\tconst declared = declarations[i]\n\t\t\t\tlet found: Document | null = null\n\t\t\t\tif (\n\t\t\t\t\tdeclared.cardinality === 'many' &&\n\t\t\t\t\t!('base' in declared.from) &&\n\t\t\t\t\t!('base' in declared.to)\n\t\t\t\t) {\n\t\t\t\t\t// A cursor names this ancestor. Prove its current authorized membership\n\t\t\t\t\t// by ID instead of replaying an ordering that is not part of this page.\n\t\t\t\t\trequest.expand(i + 1, 0)\n\t\t\t\t\tconst value = sourceValue(declared, parent)\n\t\t\t\t\tconst target = value == null ? null : await get(declared.target, ancestors[i])\n\t\t\t\t\tconst key = declared.to.field\n\t\t\t\t\tif (\n\t\t\t\t\t\tvalue != null &&\n\t\t\t\t\t\ttarget &&\n\t\t\t\t\t\tguarded(target, declared.targetGuard) &&\n\t\t\t\t\t\tmemberMatches(target[key], declared.targetMember) &&\n\t\t\t\t\t\ttarget[key] !== undefined &&\n\t\t\t\t\t\tcompareValues(value, target[key]) === 0\n\t\t\t\t\t) {\n\t\t\t\t\t\trequest.expand(i + 1)\n\t\t\t\t\t\tfound = target\n\t\t\t\t\t}\n\t\t\t\t} else if (declared.cardinality === 'one') {\n\t\t\t\t\tconst target = await one(declared, parent, i + 1)\n\t\t\t\t\tif (target?._id === ancestors[i]) found = target\n\t\t\t\t} else\n\t\t\t\t\tfor await (const target of traverse(declared, parent, i + 1)) {\n\t\t\t\t\t\tif (target._id === ancestors[i]) {\n\t\t\t\t\t\t\tfound = target\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\tparent = found\n\t\t\t}\n\t\t\treturn await pageRelation(\n\t\t\t\tfinal.source,\n\t\t\t\tparent,\n\t\t\t\tpath.at(-1)!,\n\t\t\t\tselection,\n\t\t\t\tinput,\n\t\t\t\tconditions,\n\t\t\t\tconstraints,\n\t\t\t\tpath,\n\t\t\t\tpath.length,\n\t\t\t\t[rootId, ...ancestors],\n\t\t\t\tprepared,\n\t\t\t\t{ cursor: start?.cursor ?? null, endCursor: end?.cursor ?? input.endCursor },\n\t\t\t)\n\t\t} catch (error) {\n\t\t\trethrowQueryError(error)\n\t\t}\n\t}\n\t/** Admit the complete output tree even when a parent query produces no rows. */\n\tfunction preflight(\n\t\ttable: string,\n\t\tselection: OutputSelection,\n\t\tinput: QueryInput,\n\t\tpath: readonly string[] = [],\n\t) {\n\t\tfor (const [name, selected] of Object.entries(selection)) {\n\t\t\tconst declared = edge(table, name)\n\t\t\tconst nested = selected === true ? {} : selected\n\t\t\tconst nestedPath = [...path, name]\n\t\t\tif (declared.cardinality === 'many')\n\t\t\t\tprepare(\n\t\t\t\t\ttable,\n\t\t\t\t\tname,\n\t\t\t\t\tnested,\n\t\t\t\t\t{ numItems: input.numItems, cursor: null, order: input.order },\n\t\t\t\t\t[],\n\t\t\t\t\t[],\n\t\t\t\t\tnestedPath,\n\t\t\t\t\t'',\n\t\t\t\t)\n\t\t\telse checkTraversal(declared, nestedPath)\n\t\t\tpreflight(declared.target, nested, input, nestedPath)\n\t\t}\n\t}\n\treturn { matches, output, continuation, edge, preflight }\n}\n\nfunction scalarOnly(ast: FilterAst): boolean {\n\tif (ast.kind === 'relation') return false\n\tif (ast.kind === 'and' || ast.kind === 'or') return ast.children.every(scalarOnly)\n\tif (ast.kind === 'not' || ast.kind === 'variant') return scalarOnly(ast.child)\n\treturn true\n}\n"],"mappings":"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"}