@loradb/lora-graphql 0.16.2

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 (55) hide show
  1. package/LICENSE +87 -0
  2. package/README.md +994 -0
  3. package/dist/analyze/cypher-check.d.ts +8 -0
  4. package/dist/analyze/diff.d.ts +32 -0
  5. package/dist/analyze/indexes.d.ts +61 -0
  6. package/dist/analyze/lint.d.ts +6 -0
  7. package/dist/analyze/plans.d.ts +31 -0
  8. package/dist/analyze/statistics.d.ts +19 -0
  9. package/dist/cli.d.ts +6 -0
  10. package/dist/cli.js +631 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/codegen.d.ts +32 -0
  13. package/dist/compile/aggregate.d.ts +17 -0
  14. package/dist/compile/auth.d.ts +46 -0
  15. package/dist/compile/context.d.ts +43 -0
  16. package/dist/compile/cursor.d.ts +4 -0
  17. package/dist/compile/cypher.d.ts +175 -0
  18. package/dist/compile/filter.d.ts +19 -0
  19. package/dist/compile/hmac.d.ts +4 -0
  20. package/dist/compile/read.d.ts +89 -0
  21. package/dist/compile/selection.d.ts +18 -0
  22. package/dist/diff-BVP1Jzh3.js +99 -0
  23. package/dist/diff-BVP1Jzh3.js.map +1 -0
  24. package/dist/driver-C8vA5fV-.js +9127 -0
  25. package/dist/driver-C8vA5fV-.js.map +1 -0
  26. package/dist/driver.d.ts +117 -0
  27. package/dist/errors.d.ts +20 -0
  28. package/dist/execute/changes.d.ts +61 -0
  29. package/dist/execute/cypher-mutation.d.ts +4 -0
  30. package/dist/execute/feed.d.ts +10 -0
  31. package/dist/execute/mutate.d.ts +57 -0
  32. package/dist/execute/transaction.d.ts +17 -0
  33. package/dist/guards.d.ts +42 -0
  34. package/dist/index.d.ts +21 -0
  35. package/dist/index.js +24 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/lora-graphql.d.ts +291 -0
  38. package/dist/migrate.d.ts +8 -0
  39. package/dist/model/build.d.ts +25 -0
  40. package/dist/model/cypher-lexer.d.ts +10 -0
  41. package/dist/model/directives.d.ts +3 -0
  42. package/dist/model/points.d.ts +12 -0
  43. package/dist/model/relations.d.ts +7 -0
  44. package/dist/model/types.d.ts +311 -0
  45. package/dist/observe.d.ts +72 -0
  46. package/dist/schema/build.d.ts +38 -0
  47. package/dist/schema/global-id.d.ts +6 -0
  48. package/dist/schema/guard.d.ts +5 -0
  49. package/dist/schema/mutations.d.ts +44 -0
  50. package/dist/schema/names.d.ts +37 -0
  51. package/dist/schema/scalars.d.ts +9 -0
  52. package/dist/testing.d.ts +36 -0
  53. package/dist/testing.js +56 -0
  54. package/dist/testing.js.map +1 -0
  55. package/package.json +85 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sources":["../src/migrate.ts","../src/cli.ts"],"sourcesContent":["// `lora-graphql migrate neo4j`: rewrite an @neo4j/graphql SDL into this\n// package's vocabulary. What maps is rewritten; what does not is removed\n// and listed as a TODO. With the client's operations, the opt-in surface\n// (@mutation, @filterable, @sortable) follows observed usage; without\n// them, mutations stay on for every type (as in @neo4j/graphql).\n\nimport {\n Kind,\n parse,\n print,\n visit,\n type ArgumentNode,\n type ConstArgumentNode,\n type ConstDirectiveNode,\n type ConstValueNode,\n type DocumentNode,\n type FieldDefinitionNode,\n type ObjectTypeDefinitionNode,\n type SelectionSetNode,\n type ValueNode,\n} from \"graphql\";\nimport { defaultPlural } from \"./model/build.js\";\n\nexport interface MigrationResult {\n /** The rewritten SDL. */\n typeDefs: string;\n /** What has no equivalent or needs a decision, by type and field. */\n todos: string[];\n}\n\nconst ROOT = new Set([\"Query\", \"Mutation\", \"Subscription\"]);\n\n/** Removed with a TODO: no equivalent here. */\nconst UNSUPPORTED: Record<string, string> = {\n coalesce:\n \"@coalesce is not supported: it hides predicates from indexes; store a value instead\",\n subscriptionsAuthorization:\n \"@subscriptionsAuthorization is not supported: SUBSCRIBE rules go in @authorization\",\n shareable: \"federation (@shareable) is not supported\",\n external: \"federation (@external) is not supported\",\n requires: \"federation (@requires) is not supported\",\n provides: \"federation (@provides) is not supported\",\n exclude: \"@exclude: use @query / @mutation to choose operations\",\n vector:\n \"@vector on types (with a provider) is not supported: put @vector(dimensions:, similarity:) on a [Float!] field\",\n};\n\n/** neo4j 5 filter suffixes → @filterable operators. */\nconst SUFFIX_OPS: Array<[string, string]> = [\n [\"_NOT_IN\", \"IN\"],\n [\"_STARTS_WITH\", \"STARTS_WITH\"],\n [\"_ENDS_WITH\", \"ENDS_WITH\"],\n [\"_CONTAINS\", \"CONTAINS\"],\n [\"_INCLUDES\", \"INCLUDES\"],\n [\"_GTE\", \"GTE\"],\n [\"_LTE\", \"LTE\"],\n [\"_GT\", \"GT\"],\n [\"_LT\", \"LT\"],\n [\"_IN\", \"IN\"],\n [\"_EQ\", \"EQ\"],\n];\n\n/** neo4j 6 nested filter operators → @filterable operators. */\nconst NESTED_OPS: Record<string, string> = {\n eq: \"EQ\",\n in: \"IN\",\n lt: \"LT\",\n lte: \"LTE\",\n gt: \"GT\",\n gte: \"GTE\",\n contains: \"CONTAINS\",\n startsWith: \"STARTS_WITH\",\n endsWith: \"ENDS_WITH\",\n includes: \"INCLUDES\",\n caseInsensitive: \"CASE_INSENSITIVE\",\n};\n\ninterface Usage {\n filters: Map<string, Map<string, Set<string>>>;\n sorts: Map<string, Set<string>>;\n mutations: Map<string, Set<string>>;\n}\n\nexport function migrateNeo4j(\n sdl: string,\n operations: DocumentNode[] = [],\n): MigrationResult {\n const doc = parse(sdl, { noLocation: true });\n const todos: string[] = [];\n const nodeTypes = doc.definitions.filter(\n (d): d is ObjectTypeDefinitionNode =>\n d.kind === Kind.OBJECT_TYPE_DEFINITION &&\n !ROOT.has(d.name.value) &&\n !has(d.directives, \"relationshipProperties\") &&\n !has(d.directives, \"jwt\"),\n );\n const nodeNames = new Set(nodeTypes.map((t) => t.name.value));\n const usage =\n operations.length > 0 ? observe(operations, nodeTypes) : undefined;\n\n const out = visit(doc, {\n ObjectTypeDefinition(t) {\n if (!nodeNames.has(t.name.value)) return undefined;\n const type = t.name.value;\n let directives = migrateDirectives(\n t.directives ?? [],\n type,\n undefined,\n todos,\n );\n if (!has(directives, \"node\"))\n directives = [...directives, directive(\"node\")];\n const ops = usage?.mutations.get(type);\n if (!has(directives, \"mutation\")) {\n if (!usage) {\n directives = [...directives, directive(\"mutation\")];\n todos.push(\n `${type}: @mutation added (@neo4j/graphql generates mutations for every type); remove it or narrow its operations`,\n );\n } else if (ops && ops.size > 0) {\n directives = [\n ...directives,\n directive(\"mutation\", {\n operations: enumList([...ops].sort()),\n }),\n ];\n }\n }\n const idFields = (t.fields ?? []).filter((f) => has(f.directives, \"id\"));\n if (idFields.length === 0) {\n todos.push(\n `${type}: no @id field; add a required @key field (the sort tie-breaker and mutation address)`,\n );\n } else if (idFields.length > 1) {\n todos.push(`${type}: several @id fields; keep one as the @key`);\n }\n const fields = (t.fields ?? []).map((f) =>\n migrateField(f, type, usage, todos),\n );\n return { ...t, directives, fields };\n },\n });\n return { typeDefs: print(out), todos };\n}\n\nfunction migrateField(\n f: FieldDefinitionNode,\n type: string,\n usage: Usage | undefined,\n todos: string[],\n): FieldDefinitionNode {\n let directives = migrateDirectives(\n f.directives ?? [],\n type,\n f.name.value,\n todos,\n );\n const id = directives.find((d) => d.name.value === \"id\");\n if (id) {\n directives = directives.filter(\n (d) => d.name.value !== \"id\" && d.name.value !== \"unique\",\n );\n directives.push(directive(\"key\", { generate: bool(true) }));\n }\n const used = usage?.filters.get(type)?.get(f.name.value);\n if (used && used.size > 0 && !has(directives, \"filterable\")) {\n directives.push(\n has(directives, \"relationship\")\n ? directive(\"filterable\")\n : directive(\"filterable\", { byValue: enumList([...used].sort()) }),\n );\n }\n if (\n usage?.sorts.get(type)?.has(f.name.value) &&\n !has(directives, \"sortable\")\n ) {\n directives.push(directive(\"sortable\"));\n }\n return { ...f, directives };\n}\n\nfunction migrateDirectives(\n directives: readonly ConstDirectiveNode[],\n type: string,\n field: string | undefined,\n todos: string[],\n): ConstDirectiveNode[] {\n const at = field ? `${type}.${field}` : type;\n const out: ConstDirectiveNode[] = [];\n for (const d of directives) {\n const name = d.name.value;\n if (name in UNSUPPORTED) {\n todos.push(`${at}: ${UNSUPPORTED[name]}`);\n continue;\n }\n if (name === \"key\" && !field) {\n todos.push(`${at}: federation @key(fields:) is not supported`);\n continue;\n }\n if (name === \"unique\") {\n out.push(directive(\"unique\"));\n continue;\n }\n if (name === \"relationship\") {\n out.push(migrateRelationship(d, at, todos));\n continue;\n }\n if (name === \"fulltext\") {\n out.push(renameInList(d, \"indexes\", \"indexName\", \"name\"));\n continue;\n }\n if (name === \"subscription\") {\n out.push(migrateSubscription(d, at, todos));\n continue;\n }\n if (name === \"authorization\" || name === \"authentication\") {\n todos.push(\n `${at}: check the @${name} rule's filters: operators are written { field: { eq: ... } } here`,\n );\n }\n out.push(d);\n }\n return out;\n}\n\nfunction migrateRelationship(\n d: ConstDirectiveNode,\n at: string,\n todos: string[],\n): ConstDirectiveNode {\n const args: ConstArgumentNode[] = [];\n for (const a of d.arguments ?? []) {\n const name = a.name.value;\n if (name === \"queryDirection\" && a.value.kind === Kind.ENUM) {\n if (a.value.value.includes(\"UNDIRECTED\")) {\n args.push(arg(\"queryDirection\", enumValue(\"UNDIRECTED\")));\n }\n continue;\n }\n if (name === \"nestedOperations\" && a.value.kind === Kind.LIST) {\n const kept = a.value.values.filter(\n (v) => v.kind === Kind.ENUM && v.value !== \"CONNECT_OR_CREATE\",\n );\n if (kept.length < a.value.values.length) {\n todos.push(`${at}: connectOrCreate is not supported; use upsert`);\n }\n args.push(arg(\"nestedOperations\", { kind: Kind.LIST, values: kept }));\n continue;\n }\n args.push(a);\n }\n return { ...d, arguments: args };\n}\n\nfunction migrateSubscription(\n d: ConstDirectiveNode,\n at: string,\n todos: string[],\n): ConstDirectiveNode {\n const events = d.arguments?.find((a) => a.name.value === \"events\")?.value;\n if (!events || events.kind !== Kind.LIST) return d;\n const ops = new Set<string>();\n let relationships = false;\n for (const e of events.values) {\n if (e.kind !== Kind.ENUM) continue;\n if (e.value.startsWith(\"CREATED\") && !e.value.includes(\"RELATIONSHIP\"))\n ops.add(\"CREATE\");\n else if (e.value.startsWith(\"UPDATED\")) ops.add(\"UPDATE\");\n else if (e.value.startsWith(\"DELETED\") && !e.value.includes(\"RELATIONSHIP\"))\n ops.add(\"DELETE\");\n else if (e.value.includes(\"RELATIONSHIP\")) relationships = true;\n }\n todos.push(\n `${at}: subscriptions see writes made through this library (or the engine change feed), not CDC`,\n );\n return directive(\"subscription\", {\n operations: enumList([...ops].sort()),\n ...(relationships ? { relationships: bool(true) } : {}),\n });\n}\n\n/** What the client's operations use: filters, sorts and mutations per type. */\nfunction observe(\n operations: DocumentNode[],\n types: ObjectTypeDefinitionNode[],\n): Usage {\n const usage: Usage = {\n filters: new Map(),\n sorts: new Map(),\n mutations: new Map(),\n };\n // Root fields as either naming would call them: this package's plural\n // and @neo4j/graphql's (which knows irregular plurals, e.g. people).\n const byPlural = new Map<string, ObjectTypeDefinitionNode>();\n for (const t of types) {\n byPlural.set(defaultPlural(t.name.value), t);\n byPlural.set(neo4jPlural(t.name.value), t);\n }\n const byName = new Map(types.map((t) => [t.name.value, t]));\n const note = (type: string, field: string, op: string) => {\n const fields = usage.filters.get(type) ?? new Map<string, Set<string>>();\n const ops = fields.get(field) ?? new Set<string>();\n ops.add(op);\n fields.set(field, ops);\n usage.filters.set(type, fields);\n };\n const where = (type: ObjectTypeDefinitionNode, value: ValueNode) => {\n if (value.kind !== Kind.OBJECT) return;\n for (const f of value.fields) {\n const key = f.name.value;\n if (key === \"AND\" || key === \"OR\") {\n if (f.value.kind === Kind.LIST)\n for (const v of f.value.values) where(type, v);\n continue;\n }\n if (key === \"NOT\") {\n where(type, f.value);\n continue;\n }\n // neo4j 5 relationship quantifiers: `actors_SOME: { name_EQ: ... }`.\n const quantifier = /^(.+)_(SOME|ALL|NONE|SINGLE)$/.exec(key);\n if (quantifier) {\n const rel = type.fields?.find((x) => x.name.value === quantifier[1]);\n const target = rel && byName.get(namedTypeOf(rel));\n if (rel && target) {\n note(type.name.value, quantifier[1]!, \"EQ\");\n where(target, f.value);\n }\n continue;\n }\n const suffix = SUFFIX_OPS.find(([s]) => key.endsWith(s));\n const fieldName = suffix ? key.slice(0, -suffix[0].length) : key;\n const def = type.fields?.find((x) => x.name.value === fieldName);\n if (!def) continue;\n const target = byName.get(namedTypeOf(def));\n if (target) {\n note(type.name.value, fieldName, \"EQ\");\n // `some` / `all` / `none` / `single`, or a nested where.\n if (f.value.kind === Kind.OBJECT) {\n for (const inner of f.value.fields) where(target, inner.value);\n where(target, f.value);\n }\n continue;\n }\n if (suffix) note(type.name.value, fieldName, suffix[1]);\n else if (f.value.kind === Kind.OBJECT) {\n for (const op of f.value.fields) {\n const mapped = NESTED_OPS[op.name.value];\n if (mapped) note(type.name.value, fieldName, mapped);\n }\n } else note(type.name.value, fieldName, \"EQ\");\n }\n };\n const walk = (set: SelectionSetNode | undefined, root: boolean) => {\n for (const sel of set?.selections ?? []) {\n if (sel.kind !== Kind.FIELD) continue;\n const name = sel.name.value;\n if (root) {\n const mutation = /^(create|update|delete|upsert)(.+)$/.exec(name);\n const plural = name.replace(/(Connection|Aggregate)$/, \"\");\n const type =\n byPlural.get(plural) ??\n (mutation ? byPlural.get(lowerFirst(mutation[2]!)) : undefined);\n if (type && mutation) {\n const ops = usage.mutations.get(type.name.value) ?? new Set<string>();\n const op = mutation[1]!.toUpperCase();\n if (op === \"UPSERT\") {\n ops.add(\"CREATE\");\n ops.add(\"UPDATE\");\n } else ops.add(op);\n usage.mutations.set(type.name.value, ops);\n }\n if (type) {\n for (const a of sel.arguments ?? []) argumentUse(type, a);\n }\n }\n walk(sel.selectionSet, false);\n }\n };\n const argumentUse = (type: ObjectTypeDefinitionNode, a: ArgumentNode) => {\n if (a.name.value === \"where\") where(type, a.value);\n if (a.name.value === \"sort\" || a.name.value === \"options\") {\n const sorts = usage.sorts.get(type.name.value) ?? new Set<string>();\n const collect = (v: ValueNode) => {\n if (v.kind === Kind.LIST) v.values.forEach(collect);\n else if (v.kind === Kind.OBJECT) {\n for (const f of v.fields) {\n if (f.name.value === \"sort\") collect(f.value);\n else if (f.value.kind === Kind.ENUM) sorts.add(f.name.value);\n }\n }\n };\n collect(a.value);\n usage.sorts.set(type.name.value, sorts);\n }\n };\n for (const doc of operations) {\n for (const def of doc.definitions) {\n if (def.kind === Kind.OPERATION_DEFINITION) walk(def.selectionSet, true);\n }\n }\n return usage;\n}\n\nfunction namedTypeOf(f: FieldDefinitionNode): string {\n let t = f.type;\n while (t.kind !== Kind.NAMED_TYPE) t = t.type;\n return t.name.value;\n}\n\nfunction has(\n directives: readonly ConstDirectiveNode[] | undefined,\n name: string,\n): boolean {\n return (directives ?? []).some((d) => d.name.value === name);\n}\n\nfunction directive(\n name: string,\n args: Record<string, ConstValueNode> = {},\n): ConstDirectiveNode {\n return {\n kind: Kind.DIRECTIVE,\n name: { kind: Kind.NAME, value: name },\n arguments: Object.entries(args).map(([k, v]) => arg(k, v)),\n };\n}\n\nfunction arg(name: string, value: ConstValueNode): ConstArgumentNode {\n return { kind: Kind.ARGUMENT, name: { kind: Kind.NAME, value: name }, value };\n}\n\nconst enumValue = (value: string): ConstValueNode => ({\n kind: Kind.ENUM,\n value,\n});\nconst bool = (value: boolean): ConstValueNode => ({\n kind: Kind.BOOLEAN,\n value,\n});\nconst enumList = (values: string[]): ConstValueNode => ({\n kind: Kind.LIST,\n values: values.map(enumValue),\n});\n\n/** Rename a key inside each object of a list argument. */\nfunction renameInList(\n d: ConstDirectiveNode,\n argName: string,\n from: string,\n to: string,\n): ConstDirectiveNode {\n return {\n ...d,\n arguments: (d.arguments ?? []).map((a) =>\n a.name.value === argName && a.value.kind === Kind.LIST\n ? arg(argName, {\n kind: Kind.LIST,\n values: a.value.values.map((v) =>\n v.kind === Kind.OBJECT\n ? {\n ...v,\n fields: v.fields.map((f) =>\n f.name.value === from\n ? { ...f, name: { kind: Kind.NAME, value: to } }\n : f,\n ),\n }\n : v,\n ),\n })\n : a,\n ),\n };\n}\n\nconst IRREGULAR: Record<string, string> = {\n person: \"people\",\n man: \"men\",\n woman: \"women\",\n child: \"children\",\n mouse: \"mice\",\n goose: \"geese\",\n foot: \"feet\",\n tooth: \"teeth\",\n};\n\nfunction neo4jPlural(typeName: string): string {\n const base = lowerFirst(typeName);\n const lower = base.toLowerCase();\n for (const [one, many] of Object.entries(IRREGULAR)) {\n if (lower.endsWith(one))\n return base.slice(0, base.length - one.length) + many;\n }\n return defaultPlural(typeName);\n}\n\nfunction lowerFirst(s: string): string {\n return s.charAt(0).toLowerCase() + s.slice(1);\n}\n","// lora-graphql: the build-time half of the library.\n//\n// lora-graphql print <schema.graphql>\n// lora-graphql directives\n// lora-graphql requirements <schema.graphql> [--ddl]\n// lora-graphql check <schema.graphql> [--operations <file|dir>]... [--variables <file>]\n// [--baseline <file> [--update-baseline]] [--row-budget <n>]\n// [--database <dir> [--name <db>]] [--json]\n// lora-graphql compile <schema.graphql> --operations <file|dir>... [--out <dir>]\n// lora-graphql analyze <schema.graphql> --database <dir> [--name <db>] [--sample <n>]\n// lora-graphql migrate neo4j <schema.graphql> [--operations <file|dir>]...\n// lora-graphql diff <old.graphql> <new.graphql> [--allow-breaking] [--json]\n\nimport { mkdir, readdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\nimport {\n getNamedType,\n isEnumType,\n isInputObjectType,\n isListType,\n isNonNullType,\n Kind,\n parse,\n print as printAst,\n typeFromAST,\n visit,\n type DefinitionNode,\n type FragmentDefinitionNode,\n type GraphQLInputType,\n type GraphQLSchema,\n type OperationDefinitionNode,\n} from \"graphql\";\nimport { diffSchemas } from \"./analyze/diff.js\";\nimport { formatProblem, ModelError } from \"./errors.js\";\nimport { buildModel } from \"./model/build.js\";\nimport { directiveTypeDefs } from \"./model/directives.js\";\nimport {\n describeRequirement,\n inferRequirements,\n requirementDdl,\n} from \"./analyze/indexes.js\";\nimport { LoraGraphQL, type CheckOptions } from \"./lora-graphql.js\";\nimport { loraDriver, type LoraDriver } from \"./driver.js\";\nimport { usedFragments } from \"./codegen.js\";\nimport { migrateNeo4j } from \"./migrate.js\";\n\nconst USAGE = `lora-graphql <command>\n\n print <schema.graphql> the public SDL clients see\n directives the directive definitions, for editors\n requirements <schema.graphql> [--ddl] constraints and indexes the API needs\n check <schema.graphql> [--operations <file|dir>]... [--json]\n [--variables <file>] [--baseline <file> [--update-baseline]]\n [--row-budget <n>] [--database <dir> [--name <db>]]\n CI gate: model, lint, @cypher statements and\n the plans of your operations, on an in-memory\n LoraDB (or an existing one with --database)\n compile <schema.graphql> --operations <file|dir>... [--out <dir>]\n persisted-operation manifest.json and\n operations.d.ts types\n analyze <schema.graphql> --database <dir> [--name <db>] [--sample <n>]\n statistics JSON for useStatistics()\n migrate neo4j <schema.graphql> [--operations <file|dir>]...\n rewrite an @neo4j/graphql SDL; TODOs for\n what has no equivalent\n diff <old.graphql> <new.graphql> [--allow-breaking] [--json]\n database statements and API changes`;\n\ninterface Io {\n out: (line: string) => void;\n err: (line: string) => void;\n}\n\nexport async function main(\n argv: string[],\n io: Io = defaultIo,\n): Promise<number> {\n const [command, ...rest] = argv;\n const flags = new Set<string>();\n const values = new Map<string, string>();\n const positional: string[] = [];\n const operations: string[] = [];\n for (let i = 0; i < rest.length; i++) {\n const a = rest[i]!;\n if (a === \"--operations\") operations.push(rest[++i] ?? \"\");\n else if (VALUE_FLAGS.has(a)) values.set(a, rest[++i] ?? \"\");\n else if (a.startsWith(\"--\")) flags.add(a);\n else positional.push(a);\n }\n try {\n switch (command) {\n case \"print\":\n return await print(need(positional, 1), io);\n case \"directives\":\n io.out(directiveTypeDefs.trim());\n return 0;\n case \"requirements\":\n return await requirements(need(positional, 1), flags.has(\"--ddl\"), io);\n case \"check\":\n return await check(need(positional, 1), operations, flags, values, io);\n case \"compile\":\n return await compile(need(positional, 1), operations, values, io);\n case \"analyze\":\n return await analyzeCommand(need(positional, 1), values, io);\n case \"migrate\": {\n const [from, file] = need(positional, 2);\n if (from !== \"neo4j\") throw new UsageError(\"migrate supports neo4j\");\n const docs = [];\n for (const path of operations) {\n for (const f of await graphqlFiles(path)) docs.push(parse(f.source));\n }\n const result = migrateNeo4j(await read(file!), docs);\n for (const t of result.todos) io.out(`# TODO(migrate): ${t}`);\n if (result.todos.length > 0) io.out(\"\");\n io.out(result.typeDefs);\n return 0;\n }\n case \"diff\": {\n const [before, after] = need(positional, 2);\n return await diff(before!, after!, flags, io);\n }\n default:\n io.err(USAGE);\n return 2;\n }\n } catch (err) {\n if (err instanceof UsageError) {\n io.err(`${err.message}\\n\\n${USAGE}`);\n return 2;\n }\n if (err instanceof ModelError) {\n io.err(err.message);\n return 1;\n }\n io.err(err instanceof Error ? err.message : String(err));\n return 1;\n }\n}\n\nclass UsageError extends Error {}\n\nconst VALUE_FLAGS = new Set([\n \"--out\",\n \"--variables\",\n \"--baseline\",\n \"--row-budget\",\n \"--database\",\n \"--name\",\n \"--sample\",\n]);\n\nfunction need(positional: string[], n: number): string[] {\n if (positional.length < n)\n throw new UsageError(`expected ${n} file argument(s)`);\n return positional;\n}\n\nconst read = (path: string) => readFile(path, \"utf8\");\n\n/** A LoraGraphQL over a driver that refuses to run anything. */\nfunction offline(typeDefs: string): LoraGraphQL {\n const driver: LoraDriver = {\n run: () => Promise.reject(new Error(\"no database\")),\n };\n return new LoraGraphQL({ typeDefs, driver });\n}\n\nasync function print([file]: string[], io: Io): Promise<number> {\n io.out(offline(await read(file!)).printPublicSchema());\n return 0;\n}\n\nasync function requirements(\n [file]: string[],\n ddl: boolean,\n io: Io,\n): Promise<number> {\n const model = buildModel(await read(file!));\n for (const r of inferRequirements(model)) {\n io.out(\n ddl\n ? `${requirementDdl(r)};`\n : `${describeRequirement(r)}, because ${r.reason}`,\n );\n }\n return 0;\n}\n\n/** The node binding's createDatabase, or a message saying how to get it. */\nasync function nodeBinding(\n io: Io,\n command: string,\n): Promise<\n | ((name?: string, options?: { databaseDir?: string }) => Promise<unknown>)\n | undefined\n> {\n try {\n const { createDatabase } =\n (await import(\"@loradb/lora-node\")) as unknown as {\n createDatabase: (\n name?: string,\n options?: { databaseDir?: string },\n ) => Promise<unknown>;\n };\n return createDatabase;\n } catch {\n io.err(\n `${command} needs @loradb/lora-node: npm install --save-dev @loradb/lora-node`,\n );\n return undefined;\n }\n}\n\nasync function check(\n [file]: string[],\n operationPaths: string[],\n flags: Set<string>,\n values: Map<string, string>,\n io: Io,\n): Promise<number> {\n const json = flags.has(\"--json\");\n const typeDefs = await read(file!);\n const createDatabase = await nodeBinding(io, \"check\");\n if (!createDatabase) return 1;\n // An existing database is checked as it is; an in-memory one gets what\n // the API needs, so only the plans are under test.\n const databaseDir = values.get(\"--database\");\n const db = await createDatabase(\n databaseDir ? (values.get(\"--name\") ?? \"app\") : undefined,\n databaseDir ? { databaseDir } : {},\n );\n const lora = new LoraGraphQL({\n typeDefs,\n driver: loraDriver(db as Parameters<typeof loraDriver>[0]),\n });\n if (!databaseDir) await lora.assertSchema({ create: true });\n const schema = lora.getSchema();\n const fixtures = values.has(\"--variables\")\n ? (JSON.parse(await read(values.get(\"--variables\")!)) as Record<\n string,\n Record<string, unknown>\n >)\n : {};\n const operations: NonNullable<CheckOptions[\"operations\"]> = [];\n for (const path of operationPaths) {\n for (const f of await graphqlFiles(path)) {\n for (const op of operationsIn(schema, f.path, f.source)) {\n const given =\n fixtures[op.name!] ?? fixtures[op.name!.split(\"#\")[1] ?? \"\"];\n operations.push(given ? { ...op, variables: given } : op);\n }\n }\n }\n const rowBudget = values.has(\"--row-budget\")\n ? Number(values.get(\"--row-budget\"))\n : undefined;\n const report = await lora.check({\n operations,\n ...(rowBudget !== undefined ? { rowBudget } : {}),\n });\n\n // Plan baseline: the operators of every statement, so a plan change\n // shows up in review.\n const baselinePath = values.get(\"--baseline\");\n const current: Record<string, string[][]> = {};\n for (const p of report.plans) {\n current[`${p.operation} › ${p.field}`] = p.reports.map((r) => r.operators);\n }\n const changed: string[] = [];\n if (baselinePath) {\n let before: Record<string, string[][]> | undefined;\n try {\n before = JSON.parse(await read(baselinePath)) as Record<\n string,\n string[][]\n >;\n } catch {\n before = undefined;\n }\n if (flags.has(\"--update-baseline\") || !before) {\n await writeFile(baselinePath, JSON.stringify(current, null, 2) + \"\\n\");\n } else {\n for (const key of new Set([\n ...Object.keys(before),\n ...Object.keys(current),\n ])) {\n if (JSON.stringify(before[key]) !== JSON.stringify(current[key])) {\n changed.push(key);\n }\n }\n }\n }\n const ok = report.ok && changed.length === 0;\n\n if (json) {\n io.out(JSON.stringify({ ...report, ok, planChanges: changed }, null, 2));\n return ok ? 0 : 1;\n }\n for (const w of report.warnings) io.out(`warning ${formatProblem(w)}`);\n for (const w of report.lint) io.out(`lint ${formatProblem(w)}`);\n for (const u of report.unused) {\n io.out(\n `unused ${u.type} index ${u.name} on :${u.labels.join(\":\")}(${u.properties.join(\", \")})`,\n );\n }\n for (const m of report.missing)\n io.out(`error missing ${describeRequirement(m)}`);\n for (const c of report.cypher)\n io.out(`error ${c.type}.${c.field}: ${c.message}`);\n for (const e of report.errors)\n io.out(`error ${e.operation}: ${e.message}`);\n for (const p of report.plans) {\n for (const r of p.reports) {\n for (const f of r.findings) {\n io.out(`error ${p.operation} › ${p.field}: ${f.message}`);\n }\n }\n }\n for (const key of changed) {\n io.out(\n `error ${key}: the plan differs from the baseline (--update-baseline to accept)`,\n );\n }\n const checked = report.plans.length;\n io.out(\n ok\n ? `ok ${checked} root field(s) in ${operations.length} operation(s) seek as expected`\n : \"failed\",\n );\n return ok ? 0 : 1;\n}\n\n/** Persisted operations from .graphql files (one per operation) or JSON (id → source). */\nasync function persistedOperations(\n paths: string[],\n): Promise<Record<string, string>> {\n const out: Record<string, string> = {};\n for (const path of paths) {\n const info = await stat(path);\n if (info.isFile() && path.endsWith(\".json\")) {\n Object.assign(\n out,\n JSON.parse(await read(path)) as Record<string, string>,\n );\n continue;\n }\n for (const f of await graphqlFiles(path)) {\n const doc = parse(f.source);\n const fragments = new Map(\n doc.definitions\n .filter(\n (d): d is FragmentDefinitionNode =>\n d.kind === Kind.FRAGMENT_DEFINITION,\n )\n .map((d) => [d.name.value, d]),\n );\n const rel = relative(process.cwd(), f.path);\n doc.definitions\n .filter(\n (d): d is OperationDefinitionNode =>\n d.kind === Kind.OPERATION_DEFINITION,\n )\n .forEach((op, i) => {\n const id = `${rel}#${op.name?.value ?? i + 1}`;\n out[id] = printAst({\n kind: Kind.DOCUMENT,\n definitions: [op, ...usedFragments(op, fragments)],\n });\n });\n }\n }\n return out;\n}\n\nasync function compile(\n [file]: string[],\n operationPaths: string[],\n values: Map<string, string>,\n io: Io,\n): Promise<number> {\n if (operationPaths.length === 0) {\n throw new UsageError(\"compile needs --operations <file|dir>\");\n }\n const lora = offline(await read(file!));\n const manifest = lora.buildManifest(\n await persistedOperations(operationPaths),\n );\n const outDir = values.get(\"--out\") ?? \"lora-graphql\";\n await mkdir(outDir, { recursive: true });\n await writeFile(\n join(outDir, \"manifest.json\"),\n JSON.stringify(manifest) + \"\\n\",\n );\n await writeFile(\n join(outDir, \"operations.d.ts\"),\n lora.generateTypes(manifest),\n );\n io.out(\n `wrote ${Object.keys(manifest.operations).length} operation(s) to ${join(outDir, \"manifest.json\")} and ${join(outDir, \"operations.d.ts\")}`,\n );\n return 0;\n}\n\nasync function analyzeCommand(\n [file]: string[],\n values: Map<string, string>,\n io: Io,\n): Promise<number> {\n const databaseDir = values.get(\"--database\");\n if (!databaseDir) throw new UsageError(\"analyze needs --database <dir>\");\n const createDatabase = await nodeBinding(io, \"analyze\");\n if (!createDatabase) return 1;\n const db = await createDatabase(values.get(\"--name\") ?? \"app\", {\n databaseDir,\n });\n const lora = new LoraGraphQL({\n typeDefs: await read(file!),\n driver: loraDriver(db as Parameters<typeof loraDriver>[0]),\n });\n const sample = values.has(\"--sample\")\n ? Number(values.get(\"--sample\"))\n : undefined;\n const stats = await lora.analyze(sample !== undefined ? { sample } : {});\n io.out(JSON.stringify(stats, null, 2));\n (db as { dispose?: () => void }).dispose?.();\n return 0;\n}\n\nasync function graphqlFiles(\n path: string,\n): Promise<Array<{ path: string; source: string }>> {\n const info = await stat(path);\n if (info.isFile()) return [{ path, source: await read(path) }];\n const out: Array<{ path: string; source: string }> = [];\n for (const entry of await readdir(path, { withFileTypes: true })) {\n const full = join(path, entry.name);\n if (entry.isDirectory()) out.push(...(await graphqlFiles(full)));\n else if (/\\.(graphql|gql)$/.test(entry.name)) {\n out.push({ path: full, source: await read(full) });\n }\n }\n return out;\n}\n\n/** Each query in a file, with example values for its required variables. */\nfunction operationsIn(\n schema: GraphQLSchema,\n path: string,\n source: string,\n): NonNullable<CheckOptions[\"operations\"]> {\n const doc = parse(source);\n const fragments = new Map(\n doc.definitions\n .filter(\n (d): d is FragmentDefinitionNode => d.kind === Kind.FRAGMENT_DEFINITION,\n )\n .map((f) => [f.name.value, f]),\n );\n // The fragments an operation spreads, transitively.\n const used = (root: DefinitionNode): FragmentDefinitionNode[] => {\n const seen = new Map<string, FragmentDefinitionNode>();\n const walk = (node: DefinitionNode) =>\n visit(node, {\n FragmentSpread(spread) {\n const f = fragments.get(spread.name.value);\n if (f && !seen.has(f.name.value)) {\n seen.set(f.name.value, f);\n walk(f);\n }\n },\n });\n walk(root);\n return [...seen.values()];\n };\n return doc.definitions\n .filter(\n (d): d is OperationDefinitionNode =>\n d.kind === Kind.OPERATION_DEFINITION && d.operation === \"query\",\n )\n .map((op, i) => {\n const variables: Record<string, unknown> = {};\n for (const v of op.variableDefinitions ?? []) {\n if (v.defaultValue || v.type.kind !== Kind.NON_NULL_TYPE) continue;\n const type = typeFromAST(schema, v.type) as\n | GraphQLInputType\n | undefined;\n if (type) variables[v.variable.name.value] = sample(type);\n }\n return {\n name: `${path}${op.name ? `#${op.name.value}` : `#${i + 1}`}`,\n document: { kind: Kind.DOCUMENT, definitions: [op, ...used(op)] },\n variables,\n };\n });\n}\n\nconst SAMPLES: Record<string, unknown> = {\n String: \"x\",\n ID: \"x\",\n Int: 1,\n Float: 1,\n Boolean: true,\n BigInt: \"1\",\n Date: \"2026-01-01\",\n Time: \"12:00:00Z\",\n LocalTime: \"12:00:00\",\n DateTime: \"2026-01-01T12:00:00Z\",\n LocalDateTime: \"2026-01-01T12:00:00\",\n Duration: \"P1D\",\n};\n\nfunction sample(type: GraphQLInputType): unknown {\n const inner = isNonNullType(type) ? type.ofType : type;\n if (isListType(inner)) return [sample(inner.ofType)];\n const named = getNamedType(inner);\n if (isEnumType(named)) return named.getValues()[0]?.value;\n if (isInputObjectType(named)) {\n const out: Record<string, unknown> = {};\n for (const f of Object.values(named.getFields())) {\n if (isNonNullType(f.type) && f.defaultValue === undefined) {\n out[f.name] = sample(f.type);\n }\n }\n return out;\n }\n return SAMPLES[named.name] ?? \"x\";\n}\n\nasync function diff(\n before: string,\n after: string,\n flags: Set<string>,\n io: Io,\n): Promise<number> {\n const result = diffSchemas(await read(before), await read(after));\n const breaking = result.api.breaking.length > 0;\n const code = breaking && !flags.has(\"--allow-breaking\") ? 1 : 0;\n if (flags.has(\"--json\")) {\n io.out(JSON.stringify(result, null, 2));\n return code;\n }\n io.out(\"# Database\");\n if (result.database.statements.length === 0) io.out(\"no changes\");\n for (const s of result.database.statements) {\n io.out(`${s.destructive ? \"// destructive: \" : \"// \"}${s.reason}`);\n io.out(`${s.text};`);\n }\n io.out(\"\\n# API\");\n if (!breaking && result.api.dangerous.length === 0) io.out(\"no changes\");\n for (const c of result.api.breaking) io.out(`breaking ${c.description}`);\n for (const c of result.api.dangerous) io.out(`dangerous ${c.description}`);\n for (const n of result.notes) io.out(`note ${n}`);\n return code;\n}\n\nconst defaultIo: Io = {\n out: (line) => process.stdout.write(line + \"\\n\"),\n err: (line) => process.stderr.write(line + \"\\n\"),\n};\n\nconst invokedDirectly =\n typeof process !== \"undefined\" &&\n process.argv[1] !== undefined &&\n /lora-graphql(\\.js)?$|cli\\.js$/.test(process.argv[1]);\nif (invokedDirectly) {\n main(process.argv.slice(2)).then((code) => process.exit(code));\n}\n"],"names":["ROOT","UNSUPPORTED","SUFFIX_OPS","NESTED_OPS","migrateNeo4j","sdl","operations","doc","parse","todos","nodeTypes","d","Kind","has","nodeNames","t","usage","observe","out","visit","type","directives","migrateDirectives","directive","ops","enumList","idFields","f","fields","migrateField","print","bool","used","field","at","name","migrateRelationship","renameInList","migrateSubscription","args","a","arg","enumValue","kept","v","events","relationships","e","types","byPlural","defaultPlural","neo4jPlural","byName","note","op","where","value","key","quantifier","rel","x","target","namedTypeOf","suffix","s","fieldName","def","inner","mapped","walk","set","root","sel","mutation","plural","lowerFirst","argumentUse","sorts","collect","k","values","argName","from","to","IRREGULAR","typeName","base","lower","one","many","USAGE","main","argv","io","defaultIo","command","rest","flags","positional","VALUE_FLAGS","need","directiveTypeDefs","requirements","check","compile","analyzeCommand","file","UsageError","docs","path","graphqlFiles","result","read","before","after","diff","err","ModelError","readFile","offline","typeDefs","driver","LoraGraphQL","ddl","model","buildModel","r","inferRequirements","requirementDdl","describeRequirement","nodeBinding","createDatabase","operationPaths","json","databaseDir","db","lora","loraDriver","schema","fixtures","operationsIn","given","rowBudget","report","baselinePath","current","p","changed","writeFile","ok","w","formatProblem","u","m","c","checked","persistedOperations","paths","stat","fragments","relative","i","id","printAst","usedFragments","manifest","outDir","mkdir","join","sample","stats","entry","readdir","full","source","seen","node","spread","variables","typeFromAST","SAMPLES","isNonNullType","isListType","named","getNamedType","isEnumType","isInputObjectType","diffSchemas","breaking","code","n","line","invokedDirectly"],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { DocumentNode, FragmentDefinitionNode, GraphQLSchema, OperationDefinitionNode, ValidationRule } from 'graphql';
2
+ export interface OperationManifest {
3
+ version: 1;
4
+ /** Hash of the public schema the operations were validated against. */
5
+ schemaHash: string;
6
+ operations: Record<string, ManifestOperation>;
7
+ }
8
+ export interface ManifestOperation {
9
+ name: string | undefined;
10
+ kind: "query" | "mutation" | "subscription";
11
+ /** Root fields, by response key. */
12
+ rootFields: string[];
13
+ /** The validated document, as a GraphQL AST without locations. */
14
+ document: DocumentNode;
15
+ }
16
+ /** Hash of the schema clients see: a manifest is valid for it only. */
17
+ export declare function schemaHash(schema: GraphQLSchema): string;
18
+ /**
19
+ * Parse and validate persisted operations (id → source) into a manifest.
20
+ * Throws with every problem at once.
21
+ */
22
+ export declare function buildManifest(schema: GraphQLSchema, operations: Record<string, string>, rules?: ValidationRule[]): OperationManifest;
23
+ /**
24
+ * TypeScript declarations for each operation: `<Name>Variables` and
25
+ * `<Name>Result`, plus the enums and input types they use. `ids` name the
26
+ * operations (the manifest's ids when they have no operation name).
27
+ */
28
+ export declare function generateTypes(schema: GraphQLSchema, manifest: OperationManifest,
29
+ /** Custom scalars (`@storedAs`) and their storage types. */
30
+ storage?: ReadonlyMap<string, string>): string;
31
+ /** Fragments reachable from `root`, transitively. */
32
+ export declare function usedFragments(root: OperationDefinitionNode, fragments: Map<string, FragmentDefinitionNode>): FragmentDefinitionNode[];
@@ -0,0 +1,17 @@
1
+ import { CompileContext } from './context.js';
2
+ import { Expr } from './cypher.js';
3
+ export type ListAggregate = "min" | "max" | "sum" | "avg" | "count" | "shortest" | "longest" | "shortestLength" | "longestLength" | "averageLength";
4
+ export interface AggregateOptions {
5
+ /**
6
+ * The values are durations: sums start from the first value rather than
7
+ * 0, and an average divides the sum (LoraDB's own `sum` / `avg` / `max`
8
+ * over durations are wrong, see E25).
9
+ */
10
+ duration?: boolean;
11
+ }
12
+ export declare function listAggregate(ctx: CompileContext, kind: ListAggregate, list: Expr, options?: AggregateOptions): Expr;
13
+ /**
14
+ * The number of distinct values in a list: related nodes counted once
15
+ * even when several relationships lead to the same node.
16
+ */
17
+ export declare function distinctCount(ctx: CompileContext, keys: Expr): Expr;
@@ -0,0 +1,46 @@
1
+ import { AuthOperation, Authorization, AuthorizationWhere, NodeType } from '../model/types.js';
2
+ import { Expr } from './cypher.js';
3
+ import { CompileContext } from './context.js';
4
+ /** Throws UNAUTHENTICATED when reading `field` needs a jwt the request lacks. */
5
+ export declare function checkFieldAuthentication(ctx: CompileContext, owner: string, field: {
6
+ name: string;
7
+ authentication: ReadonlySet<AuthOperation> | undefined;
8
+ authenticationJwt?: AuthorizationWhere | undefined;
9
+ }, op?: AuthOperation): void;
10
+ /** Throws UNAUTHENTICATED when `op` on `node` needs a jwt the request lacks. */
11
+ export declare function checkAuthentication(ctx: CompileContext, node: NodeType, op: AuthOperation): void;
12
+ /**
13
+ * The filter `op` applies to `variable` (a `node` of that type): nodes
14
+ * failing it are invisible. Rules grant: any passing rule admits the node.
15
+ * Undefined when the type has no filter rule for `op`.
16
+ */
17
+ export declare function authFilter(ctx: CompileContext, node: NodeType, variable: string, op: AuthOperation): Expr | undefined;
18
+ /**
19
+ * The condition `op` must satisfy at `when`, or the request fails with
20
+ * FORBIDDEN. Undefined when no rule applies; throws right away when the
21
+ * claims alone already decide against the request.
22
+ */
23
+ export declare function authValidate(ctx: CompileContext, node: NodeType, variable: string, op: AuthOperation, when: "BEFORE" | "AFTER"): Expr | undefined;
24
+ /**
25
+ * Field-level validate rules for `op` on `field` of `variable`: the
26
+ * condition reading (or writing) the field needs. Undefined when none.
27
+ */
28
+ export declare function fieldValidate(ctx: CompileContext, node: NodeType, field: {
29
+ authorization?: Authorization | undefined;
30
+ }, variable: string, op: AuthOperation, when?: "BEFORE" | "AFTER"): Expr | undefined;
31
+ export declare function forbidden(node: NodeType, op: AuthOperation): import('graphql').GraphQLError;
32
+ /**
33
+ * A claim by name. With a `@jwt` type, the name's first segment maps to its
34
+ * `@jwtClaim(path:)`, whether the token arrived decoded or not.
35
+ */
36
+ export declare function claim(ctx: CompileContext, path: string): unknown;
37
+ /**
38
+ * A value by dotted path, through own properties only: `$context.x` must
39
+ * not reach `constructor`, `__proto__` or anything else inherited.
40
+ */
41
+ export declare function lookupPath(root: unknown, path: string): unknown;
42
+ /**
43
+ * Structural equality for claim values: arrays in order, objects by own
44
+ * keys in any order, bigints and numbers by value.
45
+ */
46
+ export declare function sameValue(a: unknown, b: unknown): boolean;
@@ -0,0 +1,43 @@
1
+ import { GraphModel } from '../model/types.js';
2
+ import { Expr } from './cypher.js';
3
+ import { SelectionContext } from './selection.js';
4
+ /** State shared while compiling one root field into one statement. */
5
+ export interface CompileContext extends SelectionContext {
6
+ model: GraphModel;
7
+ params: Record<string, unknown>;
8
+ vars: Set<string>;
9
+ /** Labels and relationship types the statement reads (S5 read-set). */
10
+ reads: {
11
+ labels: Set<string>;
12
+ relationships: Set<string>;
13
+ };
14
+ /** The request's claims, or undefined when unauthenticated. */
15
+ jwt: Record<string, unknown> | undefined;
16
+ /** Compiling an authorization rule: nested rules are not applied. */
17
+ inAuth: boolean;
18
+ /** Estimated rows the statement touches (for the cost limit). */
19
+ cost: number;
20
+ /** Degree statistics from `analyze()`, by `Owner.field`. */
21
+ degrees: ReadonlyMap<string, number>;
22
+ /** The GraphQL context, for `"$context.path"` values in rules. */
23
+ requestContext: unknown;
24
+ /**
25
+ * Variables holding computed (`@cypher`) field values in the current
26
+ * statement, by `variable + "\0" + field`: set by the root match.
27
+ */
28
+ computed: Map<string, string>;
29
+ /**
30
+ * `$context` paths the compile read, with their values: a cached
31
+ * compile is reused only for a context that agrees on them.
32
+ */
33
+ contextReads: Array<[string, unknown]>;
34
+ }
35
+ export declare function newContext(base: SelectionContext, model: GraphModel, options?: {
36
+ jwt?: Record<string, unknown> | undefined;
37
+ degrees?: ReadonlyMap<string, number>;
38
+ requestContext?: unknown;
39
+ }): CompileContext;
40
+ /** Bind a value as the next positional parameter `$pN`. */
41
+ export declare function bind(ctx: CompileContext, value: unknown): Expr;
42
+ /** A variable name derived from `base`, unique within the statement. */
43
+ export declare function freshVar(ctx: CompileContext, base: string): string;
@@ -0,0 +1,4 @@
1
+ export declare function encodeCursor(sort: string, values: unknown[], secret?: string): string;
2
+ export declare function decodeCursor(cursor: string, sort: string, arity: number, secret?: string): unknown[];
3
+ export declare function toBase64Url(text: string): string;
4
+ export declare function fromBase64Url(encoded: string): string;
@@ -0,0 +1,175 @@
1
+ export type BinaryOp = "=" | "<>" | "<" | "<=" | ">" | ">=" | "AND" | "OR" | "IN" | "CONTAINS" | "STARTS WITH" | "ENDS WITH" | "+" | "-" | "*" | "/";
2
+ export type Expr = {
3
+ kind: "var";
4
+ name: string;
5
+ } | {
6
+ kind: "param";
7
+ name: string;
8
+ } | {
9
+ kind: "literal";
10
+ value: null | boolean | number | string;
11
+ } | {
12
+ kind: "prop";
13
+ target: Expr;
14
+ key: string;
15
+ } | {
16
+ kind: "binary";
17
+ op: BinaryOp;
18
+ left: Expr;
19
+ right: Expr;
20
+ } | {
21
+ kind: "not";
22
+ expr: Expr;
23
+ } | {
24
+ kind: "isNull";
25
+ expr: Expr;
26
+ negated: boolean;
27
+ } | {
28
+ kind: "call";
29
+ fn: string;
30
+ args: Expr[];
31
+ } | {
32
+ kind: "list";
33
+ items: Expr[];
34
+ } | {
35
+ kind: "map";
36
+ entries: MapEntry[];
37
+ } | {
38
+ kind: "mapProjection";
39
+ variable: string;
40
+ entries: ProjectionEntry[];
41
+ } | {
42
+ kind: "comprehension";
43
+ pattern: Pattern;
44
+ where: Expr | undefined;
45
+ projection: Expr;
46
+ } | {
47
+ kind: "slice";
48
+ target: Expr;
49
+ from: Expr | undefined;
50
+ to: Expr | undefined;
51
+ } | {
52
+ kind: "case";
53
+ when: Expr;
54
+ then: Expr;
55
+ else: Expr;
56
+ }
57
+ /** `[v IN list WHERE … | projection]` */
58
+ | {
59
+ kind: "listComprehension";
60
+ variable: string;
61
+ list: Expr;
62
+ where: Expr | undefined;
63
+ projection: Expr | undefined;
64
+ }
65
+ /** `reduce(acc = init, v IN list | step)` */
66
+ | {
67
+ kind: "reduce";
68
+ accumulator: string;
69
+ init: Expr;
70
+ variable: string;
71
+ list: Expr;
72
+ step: Expr;
73
+ }
74
+ /** `v:Label1:Label2` */
75
+ | {
76
+ kind: "hasLabels";
77
+ variable: string;
78
+ labels: string[];
79
+ };
80
+ export interface MapEntry {
81
+ key: string;
82
+ value: Expr;
83
+ }
84
+ export type ProjectionEntry = {
85
+ kind: "property";
86
+ key: string;
87
+ } | {
88
+ kind: "entry";
89
+ key: string;
90
+ value: Expr;
91
+ };
92
+ export interface NodePattern {
93
+ variable?: string;
94
+ labels: string[];
95
+ }
96
+ export interface RelPattern {
97
+ variable?: string;
98
+ type: string;
99
+ /** BOTH: an undirected pattern, `-[:T]-`. */
100
+ direction: "OUT" | "IN" | "BOTH";
101
+ }
102
+ /** A linear pattern: node (rel node)*. */
103
+ export interface Pattern {
104
+ start: NodePattern;
105
+ hops: Array<{
106
+ rel: RelPattern;
107
+ node: NodePattern;
108
+ }>;
109
+ }
110
+ export interface SortItem {
111
+ expr: Expr;
112
+ direction: "ASC" | "DESC";
113
+ }
114
+ export interface ReturnItem {
115
+ expr: Expr;
116
+ alias?: string;
117
+ }
118
+ export type Clause = {
119
+ kind: "match";
120
+ pattern: Pattern;
121
+ where: Expr | undefined;
122
+ } | {
123
+ kind: "unwind";
124
+ expr: Expr;
125
+ alias: string;
126
+ }
127
+ /** `CALL proc(args) YIELD item AS alias, … [WHERE …]` */
128
+ | {
129
+ kind: "procedure";
130
+ procedure: string;
131
+ args: Expr[];
132
+ yields: Array<{
133
+ item: string;
134
+ alias?: string;
135
+ }>;
136
+ where?: Expr | undefined;
137
+ }
138
+ /** A hand-written statement (`@cypher`), parameters already renamed. */
139
+ | {
140
+ kind: "raw";
141
+ text: string;
142
+ } | {
143
+ kind: "with";
144
+ distinct?: boolean;
145
+ items: ReturnItem[];
146
+ where?: Expr | undefined;
147
+ orderBy?: SortItem[] | undefined;
148
+ limit?: Expr | undefined;
149
+ } | {
150
+ kind: "call";
151
+ imports: string[];
152
+ body: Clause[];
153
+ } | {
154
+ kind: "return";
155
+ items: ReturnItem[];
156
+ orderBy?: SortItem[] | undefined;
157
+ limit?: Expr | undefined;
158
+ };
159
+ export declare const v: (name: string) => Expr;
160
+ export declare const param: (name: string) => Expr;
161
+ export declare const lit: (value: null | boolean | number | string) => Expr;
162
+ export declare const prop: (target: Expr, key: string) => Expr;
163
+ export declare const bin: (op: BinaryOp, left: Expr, right: Expr) => Expr;
164
+ export declare const not: (expr: Expr) => Expr;
165
+ export declare const isNull: (expr: Expr, negated?: boolean) => Expr;
166
+ export declare const fn: (name: string, ...args: Expr[]) => Expr;
167
+ /** AND of every defined operand; undefined when there are none. */
168
+ export declare function and(...operands: Array<Expr | undefined>): Expr | undefined;
169
+ /** OR of every defined operand; undefined when there are none. */
170
+ export declare function or(...operands: Array<Expr | undefined>): Expr | undefined;
171
+ /** Escape an identifier (variable, label, type, property or map key). */
172
+ export declare function name(id: string): string;
173
+ export declare function printExpr(e: Expr): string;
174
+ export declare function printPattern(p: Pattern): string;
175
+ export declare function printClauses(clauses: Clause[], indent?: string): string;
@@ -0,0 +1,19 @@
1
+ import { AbstractType, NodeType, RelationshipField, RelationshipPropertiesType } from '../model/types.js';
2
+ import { CompileContext } from './context.js';
3
+ import { Expr, Pattern } from './cypher.js';
4
+ type Where = Record<string, unknown>;
5
+ export declare function compileNodeWhere(ctx: CompileContext, node: NodeType, variable: string, where: Where | null | undefined): Expr | undefined;
6
+ export declare function compilePropsWhere(ctx: CompileContext, props: RelationshipPropertiesType, variable: string, where: Where | null | undefined): Expr | undefined;
7
+ /**
8
+ * `(from)-[:TYPE]->(to:Target)` for a relationship field. Reads follow an
9
+ * UNDIRECTED relationship both ways.
10
+ */
11
+ export declare function relationshipPattern(from: string, rel: RelationshipField, targetLabel: string, to: string, relVariable?: string): Pattern;
12
+ /**
13
+ * The `where` of an interface or union, for one member type: an
14
+ * interface's filters apply to every implementation (and `typename` picks
15
+ * implementations); a union's where names members and leaves out the
16
+ * ones it does not name. False when `where` excludes the member.
17
+ */
18
+ export declare function compileMemberWhere(ctx: CompileContext, abstract: AbstractType | undefined, member: NodeType, variable: string, where: Where | null | undefined): Expr | undefined | false;
19
+ export {};
@@ -0,0 +1,4 @@
1
+ export declare function sha256(data: Uint8Array): Uint8Array;
2
+ export declare function hmacSha256(key: Uint8Array, message: Uint8Array): Uint8Array;
3
+ /** Equality that takes the same time wherever the inputs differ. */
4
+ export declare function constantTimeEqual(a: Uint8Array, b: Uint8Array): boolean;
@@ -0,0 +1,89 @@
1
+ import { FieldNode, SelectionSetNode } from 'graphql';
2
+ import { QueryResult, Statement } from '../driver.js';
3
+ import { AbstractType, CypherField, NodeType, SearchIndex, PageLimit } from '../model/types.js';
4
+ import { CompileContext } from './context.js';
5
+ import { Clause, Expr } from './cypher.js';
6
+ export type RootKind = "list" | "single" | "connection" | "aggregate" | "grouped";
7
+ /** How the plan of a statement is expected to find its first rows (S2). */
8
+ export interface SeekExpectation {
9
+ statement: number;
10
+ label: string;
11
+ access: "exact" | "range" | "text" | "point";
12
+ reason: string;
13
+ }
14
+ export interface ReadSet {
15
+ labels: string[];
16
+ relationships: string[];
17
+ }
18
+ export interface CompiledRead {
19
+ statements: Statement[];
20
+ /** Turns the statements' results into the root field's value. */
21
+ shape: (results: QueryResult[]) => unknown;
22
+ /** Result columns the first statement must produce. */
23
+ columns: string[];
24
+ reads: ReadSet;
25
+ expectations: SeekExpectation[];
26
+ /** Estimated rows touched: the bound the cost limit checks. */
27
+ cost: number;
28
+ /** `read` for queries; `write` for @cypher mutations. */
29
+ mode: "read" | "write";
30
+ }
31
+ type Args = Record<string, unknown>;
32
+ /** A connection value before its resolvers turn it into edges/pageInfo. */
33
+ export interface RawConnection {
34
+ __rows: RawEdge[];
35
+ __first: number;
36
+ /** A cursor (`after` or `before`) was given. */
37
+ __after: boolean;
38
+ /** `last` / `before`: rows arrive in reverse and are flipped back. */
39
+ __backward: boolean;
40
+ __sort: string;
41
+ __totalCount?: number;
42
+ }
43
+ export interface RawEdge {
44
+ node: unknown;
45
+ properties?: unknown;
46
+ __cursor: unknown[];
47
+ }
48
+ export declare function compileRoot(ctx: CompileContext, kind: RootKind, node: NodeType, args: Args, fieldNodes: readonly FieldNode[]): CompiledRead;
49
+ export declare function finish(ctx: CompileContext, clauses: Clause[], columns: string[], shape: CompiledRead["shape"], expectation: Omit<SeekExpectation, "statement"> | undefined, extra?: Statement[], mode?: "read" | "write"): CompiledRead;
50
+ export declare function readSet(ctx: CompileContext): ReadSet;
51
+ /**
52
+ * A root `@cypher` field on Query or Mutation: the statement runs in a
53
+ * `CALL { }`, and returned nodes are projected like any other read.
54
+ */
55
+ export declare function compileCypherRoot(ctx: CompileContext, field: CypherField, args: Args, fieldNodes: readonly FieldNode[]): CompiledRead;
56
+ /** `events(where, sort, limit)` over an interface's implementations or a union's members. */
57
+ export declare function compileAbstractRoot(ctx: CompileContext, abstract: AbstractType, args: Args, fieldNodes: readonly FieldNode[]): CompiledRead;
58
+ /** A search root field's value: nodes with their scores. */
59
+ export interface SearchResult {
60
+ node: unknown;
61
+ score: number;
62
+ }
63
+ /**
64
+ * A search as a connection (`connection: true`): pages forward by keyset
65
+ * on (score DESC, key ASC). A vector index returns its top candidates
66
+ * before any filter, so vector connections page within a fixed pool of
67
+ * `4 × @limit(max:)` candidates.
68
+ */
69
+ export declare function compileSearch(ctx: CompileContext, node: NodeType, index: SearchIndex, args: Args, fieldNodes: readonly FieldNode[], connection?: boolean): CompiledRead;
70
+ /**
71
+ * Nodes by @key, in one statement, for mutation payloads: the read runs
72
+ * inside the mutation's transaction and sees its writes.
73
+ */
74
+ export declare function compileByKeys(ctx: CompileContext, node: NodeType, keys: unknown[], sets: SelectionSetNode[]): CompiledRead;
75
+ export declare function keyOf(value: unknown): string;
76
+ /** The statement text with its parameters renamed to bound `$pN`s. */
77
+ export declare function bindStatement(ctx: CompileContext, field: CypherField, args: Args): string;
78
+ export declare function resolveLimit(value: unknown, limit: PageLimit, argument: string): number;
79
+ export interface Projection {
80
+ /** Subqueries that must run before the projection is evaluated. */
81
+ pre: Clause[];
82
+ expr: Expr;
83
+ }
84
+ /**
85
+ * Project `variable` (a `node`) with the selection sets. `rows` is how
86
+ * many parents this projection runs for, for the cost estimate.
87
+ */
88
+ export declare function projectNode(ctx: CompileContext, node: NodeType, variable: string, sets: SelectionSetNode[], rows: number): Projection;
89
+ export {};
@@ -0,0 +1,18 @@
1
+ import { FieldNode, FragmentDefinitionNode, GraphQLField, GraphQLObjectType, GraphQLSchema, SelectionSetNode } from 'graphql';
2
+ export interface SelectionContext {
3
+ schema: GraphQLSchema;
4
+ fragments: Record<string, FragmentDefinitionNode>;
5
+ variables: Record<string, unknown>;
6
+ }
7
+ /** The fields selected on an object type, grouped by response key. */
8
+ export type FieldsByKey = Map<string, FieldNode[]>;
9
+ /**
10
+ * Collect the fields that apply to `type` from one or more selection
11
+ * sets: follows fragment spreads and inline fragments whose condition
12
+ * matches, honours `@skip` / `@include`, groups by response key.
13
+ */
14
+ export declare function collectFields(ctx: SelectionContext, type: GraphQLObjectType, selectionSets: ReadonlyArray<SelectionSetNode | undefined>): FieldsByKey;
15
+ /** The merged sub-selections of every field node under one response key. */
16
+ export declare function subSelections(nodes: readonly FieldNode[]): SelectionSetNode[];
17
+ /** Coerced argument values of a field, variables substituted. */
18
+ export declare function fieldArgs(ctx: SelectionContext, def: GraphQLField<unknown, unknown>, node: FieldNode): Record<string, unknown>;