{"version":3,"file":"public-key-reduction.cjs","sources":["../../../../src/query/live/public-key-reduction.ts"],"sourcesContent":["import { map, reduce, serializeValue } from '@tanstack/db-ivm'\nimport { deepEquals } from '../../utils.js'\nimport { getParentContextIdentity } from '../equality-value-identity.js'\nimport { INCLUDES_ROUTING } from '../compiler/route-metadata.js'\nimport { codedMessage, devBuild } from '../../error-message.js'\nimport type { ValueIdentity } from '../equality-value-identity.js'\nimport type { CompilationResult } from '../compiler/index.js'\nimport type { ResultStream } from '../../types.js'\n\n// Public-key reduction. A joined query with a custom key needs only this\n// part of materialization, so it ships in core without the include\n// materializer.\n\nexport type ResultTuple = [\n  value: Record<PropertyKey, any>,\n  order: string | undefined,\n  correlationKey?: unknown,\n  parentContext?: Record<string, any> | null,\n  routing?: IncludesRouting,\n  publicKey?: unknown,\n]\n\nexport type IncludesRouting = Record<string, IncludeRoute>\n\nexport type IncludeRoute = {\n  active: boolean\n  correlationKey: unknown\n  parentContext: Record<string, any> | null\n}\n\nexport type CanonicalResult = {\n  publicKey: unknown\n  tuple: ResultTuple\n}\n\nexport type RelationScope = `root` | `child`\n\nexport function exposeRouting(pipeline: ResultStream): ResultStream {\n  return pipeline.pipe(\n    map(([key, rawTuple]) => {\n      const tuple = rawTuple as ResultTuple\n      return [\n        key,\n        [\n          tuple[0],\n          tuple[1],\n          tuple[2],\n          tuple[3],\n          tuple[0][INCLUDES_ROUTING],\n          tuple[4],\n        ],\n      ]\n    }),\n  ) as unknown as ResultStream\n}\n\nexport function canonicalizeByPublicKey(\n  pipeline: ResultStream,\n  getKey: ((row: any) => unknown) | undefined,\n  scope: RelationScope,\n  valueIdentity: ValueIdentity,\n): ResultStream {\n  return pipeline.pipe(\n    map(([internalKey, rawTuple]) => {\n      const tuple = rawTuple as ResultTuple\n      const publicKey = getKey ? getKey(tuple[0]) : (tuple[5] ?? internalKey)\n      const relationKey =\n        scope === `root`\n          ? serializeValue([`root`, publicKey])\n          : serializeValue([\n              routeKey(tuple[2], tuple[3], valueIdentity),\n              publicKey,\n            ])\n      return [relationKey, { publicKey, tuple }] as [string, CanonicalResult]\n    }),\n    reduce((values: Array<[CanonicalResult, number]>) => {\n      const totalMultiplicity = values.reduce(\n        (total, [, multiplicity]) => total + multiplicity,\n        0,\n      )\n      if (totalMultiplicity === 0) return []\n      if (totalMultiplicity < 0) {\n        throw new Error(\n          devBuild() && process.env.NODE_ENV !== `production`\n            ? `Canonical query row has negative multiplicity`\n            : codedMessage(154),\n        )\n      }\n\n      const visible = values.find(([, multiplicity]) => multiplicity > 0)?.[0]\n      if (!visible) {\n        throw new Error(\n          devBuild() && process.env.NODE_ENV !== `production`\n            ? `Canonical query row has no positive contributor`\n            : codedMessage(155),\n        )\n      }\n\n      for (const [candidate, multiplicity] of values) {\n        if (multiplicity <= 0) continue\n        assertCongruentContributors(visible, candidate)\n      }\n\n      return [[visible, 1]]\n    }),\n    map(([relationKey, { publicKey, tuple }]) => [\n      scope === `root` ? publicKey : relationKey,\n      tuple,\n    ]),\n  ) as ResultStream\n}\n\nfunction assertCongruentContributors(\n  left: CanonicalResult,\n  right: CanonicalResult,\n): void {\n  const [leftValue, leftOrder, leftCorrelation, leftContext, leftRouting] =\n    left.tuple\n  const [rightValue, rightOrder, rightCorrelation, rightContext, rightRouting] =\n    right.tuple\n\n  if (\n    leftOrder !== rightOrder ||\n    !deepEquals(leftValue, rightValue) ||\n    !deepEquals(leftCorrelation, rightCorrelation) ||\n    !deepEquals(leftContext, rightContext) ||\n    !deepEquals(leftRouting, rightRouting)\n  ) {\n    throw new Error(\n      devBuild() && process.env.NODE_ENV !== `production`\n        ? `Query contributors for public key ${serializeValue(left.publicKey)} are not congruent`\n        : codedMessage(156, { publicKey: left.publicKey }),\n    )\n  }\n}\n\nexport function routeKey(\n  correlationKey: unknown,\n  parentContext: Record<string, any> | null | undefined,\n  valueIdentity: ValueIdentity,\n): string {\n  return serializeValue([\n    valueIdentity.equality(correlationKey ?? null),\n    getParentContextIdentity(parentContext ?? null),\n  ])\n}\n\n/** Reduces a query without includes to one canonical row per public key. */\nexport function reducePublicKeys(\n  compilation: CompilationResult,\n  getKey: (row: any) => unknown,\n): { pipeline: ResultStream; facades: undefined } {\n  return {\n    pipeline: canonicalizeByPublicKey(\n      exposeRouting(compilation.pipeline),\n      getKey,\n      `root`,\n      compilation.valueIdentity,\n    ),\n    facades: undefined,\n  }\n}\n"],"names":["map","INCLUDES_ROUTING","serializeValue","reduce","devBuild","codedMessage","deepEquals","getParentContextIdentity"],"mappings":"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"}