{"version":3,"file":"pooled-live-query.cjs","sources":["../../../src/query/pooled-live-query.ts"],"sourcesContent":["import { SortedMap } from '../SortedMap.js'\nimport { codedMessage, devBuild } from '../error-message.js'\nimport { CleanupQueue } from '../collection/cleanup-queue.js'\nimport {\n  UNSUBSCRIBED_GC_FLOOR_MS,\n  describeProblem,\n  problemOf,\n} from '../collection/lifecycle.js'\nimport { buildHealthTree, healthNode } from '../collection/health-tree.js'\nimport { makeComparator } from '../utils/comparison.js'\nimport { reportUncaught, runAllCallbacks } from '../utils/callbacks.js'\nimport { isVirtualPropName } from '../virtual-props.js'\nimport { getWhereExpression } from './ir.js'\nimport { equalityConjunct, equalityKey, readPath } from './equality-conjunct.js'\nimport { compileExpression, toBooleanPredicate } from './compiler/evaluators.js'\nimport { buildCompareOptions } from './compiler/order-by.js'\nimport { createLiveQueryCollection } from './live-query-collection.js'\nimport { registerPooledSource } from './pooled-source.js'\nimport type { BasicExpression, OrderBy, QueryIR } from './ir.js'\nimport type { BaseQueryBuilder } from './builder/index.js'\nimport type { Collection, CollectionImpl } from '../collection/index.js'\nimport type { CollectionSubscription } from '../collection/subscription.js'\nimport type {\n  ChangeMessage,\n  CollectionDependent,\n  CollectionStatus,\n  HealthNode,\n  HealthProblem,\n} from '../types.js'\nimport type {\n  CollectionEventHandler,\n  CollectionStatusChangeEvent,\n} from '../collection/events.js'\n\n/**\n * Live queries that filter one source Collection only by `eq(field, literal)`\n * share one partition of that source per filtered field set. Each query reads\n * the group for its literal tuple, so mounting many queries of one shape\n * costs a lookup each instead of a compiled graph and a source subscription.\n *\n * A group holds the rows the partition's source subscription has published,\n * keyed by the same normalized equality that `eq` uses: a Date equals its\n * timestamp, `NaN` equals `NaN`, `-0` equals `0`, and nullish values match no\n * literal.\n */\n\ntype Row = Record<string, unknown>\ntype Listener = (changes: Array<ChangeMessage<Row, string | number>>) => void\ntype StatusListener = CollectionEventHandler<`status:change`>\n\ninterface PartitionGroup {\n  key: string\n  // Key order, as in a live-query Collection without orderBy.\n  rows: SortedMap<string | number, Row>\n  listeners: Set<Listener>\n  revision: number\n  layoutRevision: number\n}\n\nconst partitionsBySource = new WeakMap<object, Map<string, Partition>>()\n\n// What a view reads for a value with no rows and no watchers. Real groups\n// draw revisions from their partition's clock, which starts above 0.\nconst EMPTY_GROUP: PartitionGroup = {\n  key: ``,\n  rows: new SortedMap(),\n  listeners: new Set(),\n  revision: 0,\n  layoutRevision: 0,\n}\n\n// Length-prefixed, so no two part lists share an encoding.\nfunction appendGroupKeyPart(groupKey: string, part: string): string {\n  return `${groupKey}${part.length}:${part}`\n}\n\nclass Partition {\n  private readonly groups = new Map<string, PartitionGroup>()\n  // Revisions for every group, so a recreated group never repeats one.\n  private clock = 0\n  private subscription: CollectionSubscription | undefined\n  private stopStatusEvents: (() => void) | undefined\n  // One source status listener serves every view of this partition.\n  readonly statusListeners = new Set<StatusListener>()\n  private listenerCount = 0\n  // Views built on this partition and not yet cleaned up.\n  private views = 0\n  private gcTime = 0\n  /**\n   * Set when the partition ends for good: `crashed` when its source starts\n   * cleanup under it (groups keep their last rows), `cleaned-up` when the\n   * source's cleanup ends its dependents first (groups empty, as a cleaned-up\n   * live-query Collection's rows do).\n   */\n  terminated: `crashed` | `cleaned-up` | undefined = undefined\n  // This partition as its source's `subscribers` list it: one pooled live\n  // query for every view it serves.\n  private readonly dependent: CollectionDependent = ((partition) => ({\n    kind: `live-query` as const,\n    get active(): boolean {\n      return partition.listenerCount > 0\n    },\n    end: () => {\n      partition.end()\n      return Promise.resolve()\n    },\n  }))(this)\n\n  constructor(\n    private readonly source: CollectionImpl<any, any, any, any, any>,\n    private readonly paths: Array<Array<string>>,\n    // Row order for an `orderBy` shape; key order otherwise.\n    private readonly compareRows: ((a: Row, b: Row) => number) | undefined,\n    // The partition's entry in its source's map, which a mount looks up.\n    private readonly registry: { add: () => void; remove: () => void },\n  ) {}\n\n  groupKeyOf(row: Row | undefined): string | undefined {\n    if (row === undefined) return undefined\n    let groupKey = ``\n    for (const path of this.paths) {\n      const key = equalityKey(readPath(row, path))\n      if (key === undefined) return undefined\n      groupKey = appendGroupKeyPart(groupKey, key)\n    }\n    return groupKey\n  }\n\n  // Whether two versions of a row hold the same value in every field.\n  private sameFields(a: Row, b: Row): boolean {\n    return this.paths.every((path) =>\n      Object.is(readPath(a, path), readPath(b, path)),\n    )\n  }\n\n  group(key: string): PartitionGroup {\n    let group = this.groups.get(key)\n    if (!group) {\n      const revision = ++this.clock\n      group = {\n        key,\n        rows: new SortedMap(this.compareRows),\n        listeners: new Set(),\n        revision,\n        layoutRevision: revision,\n      }\n      this.groups.set(key, group)\n    }\n    return group\n  }\n\n  /** A group for reading, without creating one. */\n  peek(key: string): PartitionGroup {\n    return this.groups.get(key) ?? EMPTY_GROUP\n  }\n\n  // A group with no rows and no watchers holds nothing anyone can read.\n  private dropIfUnused(group: PartitionGroup): void {\n    if (group.rows.size === 0 && group.listeners.size === 0) {\n      this.groups.delete(group.key)\n    }\n  }\n\n  /**\n   * Keep the shared source subscription open. Each view brings its query's\n   * `gcTime`; the partition keeps the longest, so it never releases before\n   * one of its views' own live-query Collection would have.\n   */\n  retain(gcTime?: number): void {\n    this.views++\n    if (gcTime !== undefined) {\n      // As for a Collection, a non-positive or non-finite gcTime disables GC.\n      const delay = gcTime > 0 && Number.isFinite(gcTime) ? gcTime : Infinity\n      this.gcTime = Math.max(this.gcTime, delay)\n    }\n    if (this.terminated) return\n    // Building a view reads the rows the source already holds; it starts no\n    // provider work until a view has a subscriber or a preload.\n    this.subscribe(true)\n    // Like a Collection that synced before anything subscribed, a view built\n    // during a render gets a grace period to subscribe when it commits.\n    this.scheduleRelease(UNSUBSCRIBED_GC_FLOOR_MS)\n  }\n\n  subscribe(deferAcquisition = false): void {\n    if (!deferAcquisition) this.subscription?.resumeDeferredAcquisition()\n    if (!this.terminated && !this.subscription) {\n      // A released partition that subscribes again serves new mounts too.\n      this.registry.add()\n      const stopStatus = this.source.on(`status:change`, (event) => {\n        this.deliverStatus(event)\n      })\n      this.stopStatusEvents = stopStatus\n      // Like a live query, a pooled view crashes when its source starts\n      // cleanup, before the adapter's cleanup settles; queries mounted later\n      // get a new partition.\n      // A cleanup already under way ends the partition inside this\n      // registration, so a listener's throw fails the caller's attachment.\n      let registering = true\n      const stopCleanupStart = this.source._onCleanupStart(() =>\n        this.end(`crashed`, registering),\n      )\n      registering = false\n      // Late registration can terminate before either release handle exists.\n      if (this.terminated as Partition[`terminated`]) {\n        stopCleanupStart()\n        return\n      }\n      this.stopStatusEvents = () => {\n        stopStatus()\n        stopCleanupStart()\n      }\n      try {\n        const subscription = this.source.subscribeChanges(\n          (changes) =>\n            this.apply(changes as Array<ChangeMessage<Row, string | number>>),\n          {\n            includeInitialState: true,\n            deferAcquisition,\n            owner: this.dependent,\n          },\n        )\n        // Cleanup can re-enter while source sync starts, before assignment.\n        if (this.terminated as Partition[`terminated`])\n          subscription.unsubscribe()\n        else this.subscription = subscription\n      } catch (error) {\n        // Failed admission transfers no ownership; the partition is over.\n        this.terminate(`crashed`)\n        throw error\n      }\n    }\n  }\n\n  private terminate(status: `crashed` | `cleaned-up`): void {\n    this.terminated = status\n    CleanupQueue.getInstance().cancel(this)\n    this.release()\n  }\n\n  /** End the partition for good and tell its views. */\n  private end(\n    status: `crashed` | `cleaned-up` = `cleaned-up`,\n    rethrow = false,\n  ): void {\n    if (this.terminated) return\n    const previousStatus = this.source.status\n    this.terminate(status)\n    if (status === `cleaned-up`) {\n      // Emptying is a state change, as a live-query Collection's cleanup\n      // advances its revision, so a detached reader re-reads the rows.\n      for (const group of this.groups.values()) {\n        group.rows.clear()\n        group.revision = group.layoutRevision = ++this.clock\n      }\n    }\n    this.deliverStatus(\n      {\n        type: `status:change`,\n        collection: this.source as unknown as Collection,\n        previousStatus,\n        status,\n      },\n      rethrow,\n    )\n  }\n\n  private deliverStatus(\n    event: CollectionStatusChangeEvent,\n    rethrow = false,\n  ): void {\n    const delivered = this.terminated\n      ? { ...event, status: this.terminated }\n      : event\n    // Each listener gets its own call. During a source event, as from a\n    // Collection's emitter, a throw is reported uncaught; during the\n    // caller's own registration it is rethrown after every call. `release()`\n    // already stopped source events for a terminated partition.\n    const calls = [...this.statusListeners].map(\n      (listener) => () => listener(delivered),\n    )\n    if (rethrow) runAllCallbacks(calls)\n    else\n      for (const call of calls)\n        try {\n          call()\n        } catch (error) {\n          reportUncaught(error)\n        }\n  }\n\n  addListener(group: PartitionGroup, listener: Listener): void {\n    this.subscribe()\n    group.listeners.add(listener)\n    this.listenerCount++\n  }\n\n  removeListener(group: PartitionGroup, listener: Listener): void {\n    if (!group.listeners.delete(listener)) return\n    this.listenerCount--\n    this.dropIfUnused(group)\n    this.scheduleRelease(0)\n  }\n\n  private release(): void {\n    this.stopStatusEvents?.()\n    this.stopStatusEvents = undefined\n    this.subscription?.unsubscribe()\n    this.subscription = undefined\n    this.registry.remove()\n  }\n\n  // Releases on the Collections' shared GC queue, after the longest\n  // `gcTime` of this partition's views.\n  private scheduleRelease(minDelay: number): void {\n    if (this.listenerCount > 0 || !Number.isFinite(this.gcTime)) return\n    const delay = Math.max(this.gcTime, minDelay)\n    CleanupQueue.getInstance().schedule(this, delay, this.releaseIfUnused)\n  }\n\n  /**\n   * One view was cleaned up. The last one releases the source subscription\n   * now if no view listens, as cleaning up a live-query Collection releases\n   * its source subscriptions at once; a sibling view keeps its rows and its\n   * own grace period. A later mount subscribes again.\n   */\n  releaseView(): void {\n    if (--this.views > 0) return\n    CleanupQueue.getInstance().cancel(this)\n    this.releaseIfUnused()\n  }\n\n  private readonly releaseIfUnused = (): void => {\n    if (this.listenerCount > 0) return\n    // Views read groups by key, so a later subscription refills new ones.\n    this.groups.clear()\n    this.release()\n  }\n\n  private apply(changes: Array<ChangeMessage<Row, string | number>>): void {\n    const touched = new Map<\n      PartitionGroup,\n      Array<ChangeMessage<Row, string | number>>\n    >()\n    const record = (\n      group: PartitionGroup,\n      change: ChangeMessage<Row, string | number>,\n    ) => {\n      const list = touched.get(group)\n      if (list) list.push(change)\n      else touched.set(group, [change])\n      if (change.type !== `update`) group.layoutRevision = ++this.clock\n    }\n    for (const change of changes) {\n      const next =\n        change.type === `delete` ? undefined : this.groupKeyOf(change.value)\n      const previous =\n        change.type === `insert`\n          ? undefined\n          : change.type === `update` &&\n              change.previousValue !== undefined &&\n              this.sameFields(change.value, change.previousValue)\n            ? next\n            : this.groupKeyOf(\n                change.type === `delete` ? change.value : change.previousValue,\n              )\n      if (previous !== undefined && previous !== next) {\n        const group = this.group(previous)\n        const old = group.rows.get(change.key)\n        if (group.rows.delete(change.key)) {\n          record(group, { type: `delete`, key: change.key, value: old! })\n        }\n      }\n      if (next !== undefined) {\n        const group = this.group(next)\n        const existed = group.rows.has(change.key)\n        group.rows.set(change.key, change.value)\n        record(\n          group,\n          existed\n            ? change.type === `update`\n              ? change\n              : { ...change, type: `update` }\n            : { type: `insert`, key: change.key, value: change.value },\n        )\n      }\n    }\n    for (const [group, groupChanges] of touched) {\n      group.revision = ++this.clock\n      for (const listener of [...group.listeners]) listener(groupChanges)\n      this.dropIfUnused(group)\n    }\n  }\n}\n\ntype Conjunct = { path: Array<string>; pathKey: string; literalKey: string }\n\ntype PoolableShape = {\n  paths: Array<Array<string>>\n  shapeKey: string\n  groupKey: string\n  // Conjuncts each view evaluates over its group's rows.\n  residual: Array<BasicExpression>\n  orderBy: OrderBy | undefined\n}\n\n// Whether an expression reads only this query's own row fields, so a view\n// can evaluate it with the compiler's evaluator.\nfunction readsOnlyRow(expression: BasicExpression, alias: string): boolean {\n  if (expression.type === `val`) return true\n  if (expression.type === `ref`) {\n    const [root, field] = expression.path\n    return root === alias && field !== undefined && !isVirtualPropName(field)\n  }\n  return expression.args.every((arg) => readsOnlyRow(arg, alias))\n}\n\n// Splits a conjunct into `eq(alias.field, literal)` groups and residual\n// conjuncts; false for an expression a view cannot evaluate.\nfunction collectConjuncts(\n  expression: BasicExpression,\n  alias: string,\n  out: Array<Conjunct>,\n  residual: Array<BasicExpression>,\n): boolean {\n  if (expression.type === `func` && expression.name === `and`) {\n    for (const arg of expression.args) {\n      if (!collectConjuncts(arg, alias, out, residual)) return false\n    }\n    return true\n  }\n  const conjunct = equalityConjunctOf(expression, alias)\n  if (conjunct) out.push(conjunct)\n  else if (readsOnlyRow(expression, alias)) residual.push(expression)\n  else return false\n  return true\n}\n\nfunction equalityConjunctOf(\n  expression: BasicExpression,\n  alias: string,\n): Conjunct | undefined {\n  const conjunct = equalityConjunct(expression, (ref) =>\n    ref.path[0] === alias ? ref.path.slice(1) : undefined,\n  )\n  return conjunct && { ...conjunct, pathKey: JSON.stringify(conjunct.path) }\n}\n\n// Whether a row passes every residual conjunct, as a WHERE filter decides.\nfunction rowPredicate(\n  residual: Array<BasicExpression>,\n  alias: string,\n): (row: Row) => boolean {\n  const conjuncts = residual.map((expression) => compileExpression(expression))\n  // One namespaced row, reused so a check allocates nothing.\n  const namespaced: Record<string, unknown> = {}\n  return (row) => {\n    namespaced[alias] = row\n    return conjuncts.every((conjunct) =>\n      toBooleanPredicate(conjunct(namespaced as any)),\n    )\n  }\n}\n\n/**\n * The equality conjuncts of a query that a partition can serve, or undefined\n * when any other clause or operand is present.\n */\nfunction poolableShape(query: QueryIR): PoolableShape | undefined {\n  if (\n    query.from.type !== `collectionRef` ||\n    query.select ||\n    query.join ||\n    query.groupBy ||\n    query.having ||\n    query.limit !== undefined ||\n    query.offset !== undefined ||\n    query.distinct ||\n    query.singleResult ||\n    query.fnSelect ||\n    query.fnWhere?.length ||\n    query.fnHaving?.length ||\n    !query.where?.length\n  ) {\n    return undefined\n  }\n  const conjuncts: Array<Conjunct> = []\n  const residual: Array<BasicExpression> = []\n  for (const where of query.where) {\n    if (\n      !collectConjuncts(\n        getWhereExpression(where),\n        query.from.alias,\n        conjuncts,\n        residual,\n      )\n    ) {\n      return undefined\n    }\n  }\n  // A partition needs at least one equality to group by.\n  if (conjuncts.length === 0) return undefined\n  const orderBy = query.orderBy?.length ? query.orderBy : undefined\n  const orderKey = orderBy\n    ? orderByKey(orderBy, query.from.alias, query.from.collection)\n    : ``\n  if (orderKey === undefined) return undefined\n  // Most shapes have one or two fields; a general sort costs more than both.\n  if (conjuncts.length === 2) {\n    if (conjuncts[1]!.pathKey < conjuncts[0]!.pathKey) conjuncts.reverse()\n  } else if (conjuncts.length > 2) {\n    conjuncts.sort((a, b) => (a.pathKey < b.pathKey ? -1 : 1))\n  }\n  const paths: Array<Array<string>> = []\n  let shapeKey = ``\n  let groupKey = ``\n  for (const { path, pathKey, literalKey } of conjuncts) {\n    paths.push(path)\n    // Each JSON path delimits itself, so concatenation stays unambiguous.\n    shapeKey += pathKey\n    groupKey = appendGroupKeyPart(groupKey, literalKey)\n  }\n  // Groups of one shape share a row order, so the order is part of it.\n  if (orderKey) shapeKey += `|${orderKey}`\n  return { paths, shapeKey, groupKey, residual, orderBy }\n}\n\n// A key for an `orderBy` over this query's own row fields, or undefined for\n// one a partition cannot share by value, such as a custom string comparator.\nfunction orderByKey(\n  orderBy: OrderBy,\n  alias: string,\n  source: CollectionImpl<any, any, any, any, any>,\n): string | undefined {\n  let key = ``\n  for (const clause of orderBy) {\n    const { expression } = clause\n    if (\n      expression.type !== `ref` ||\n      !readsOnlyRow(expression, alias) ||\n      expression.path.length < 2\n    ) {\n      return undefined\n    }\n    const options = buildCompareOptions(clause, source)\n    if (options.stringSort === `custom`) return undefined\n    key += JSON.stringify([expression.path.slice(1), options])\n  }\n  return key\n}\n\n// Orders rows as a live-query Collection's `orderBy` does; the group's\n// SortedMap breaks ties by key.\nfunction rowComparator(\n  orderBy: OrderBy,\n  alias: string,\n  source: CollectionImpl<any, any, any, any, any>,\n): (a: Row, b: Row) => number {\n  const terms = orderBy.map((clause) => ({\n    read: compileExpression(clause.expression),\n    compare: makeComparator(buildCompareOptions(clause, source)),\n  }))\n  // One namespaced row, reused so a comparison allocates nothing.\n  const namespaced: Record<string, unknown> = {}\n  return (a, b) => {\n    for (const { read, compare } of terms) {\n      namespaced[alias] = a\n      const left = read(namespaced as any)\n      namespaced[alias] = b\n      const result = compare(left, read(namespaced as any))\n      if (result !== 0) return result\n    }\n    return 0\n  }\n}\n\n/**\n * One query's view of its group, read by the live-query observer. Users get\n * `publicCollection` instead, which builds the query's live-query Collection\n * on first use and forwards every member to it.\n */\nclass PooledLiveQuery {\n  readonly isLoadingSubset = false\n  // No persisted readiness, single-result config, or layout channel.\n  readonly config = undefined\n  readonly _subscribeLayoutChanges = undefined\n  private collection: Collection<any, any, any> | undefined = undefined\n  private listenerCount = 0\n  // This view's share of its partition ends once, at its first cleanup.\n  private released = false\n  private collectionHold: { unsubscribe: () => void } | undefined = undefined\n\n  constructor(\n    readonly source: CollectionImpl<any, any, any, any, any>,\n    private readonly query: BaseQueryBuilder,\n    private readonly partition: Partition,\n    private readonly groupKey: string,\n    private readonly gcTime: number,\n    // The query's conjuncts beyond its group's equalities, if any.\n    private readonly passes: ((row: Row) => boolean) | undefined,\n    private readonly alias: string,\n  ) {\n    partition.retain(gcTime)\n    registerPooledSource(this, source)\n  }\n\n  // Cleanup discards a view's state, as it does any Collection's (law 14).\n  get status(): CollectionStatus {\n    return this.released\n      ? `cleaned-up`\n      : (this.partition.terminated ?? this.source.status)\n  }\n\n  private endedProblem: HealthProblem | undefined\n\n  /** The same health tree a live-query Collection over this source exposes. */\n  get health(): HealthNode {\n    // Cache keys apart from the alias, which a query may name `root`.\n    const source = buildHealthTree(\n      this.source,\n      { alias: this.alias, id: `source` },\n      this,\n    )\n    // The view shows its source's status error. A terminated partition also\n    // ended this view, for example when its source was cleaned up under it.\n    const error =\n      this.source._lifecycle.statusProblem ??\n      (this.partition.terminated === `crashed`\n        ? (this.endedProblem ??= problemOf([\n            describeProblem(\n              new Error(\n                devBuild() && process.env.NODE_ENV !== `production`\n                  ? `The pooled live query's source ended`\n                  : codedMessage(258),\n              ),\n            ),\n          ]))\n        : null)\n    return healthNode(this, `view`, {\n      alias: `root`,\n      collectionId: this.source.id,\n      kind: `live-query`,\n      status: this.status,\n      failureReason: null,\n      error,\n      reloading: false,\n      sources: [source],\n    })\n  }\n\n  // Read by key: the partition drops a group nobody watches once it empties.\n  private get group(): PartitionGroup {\n    return this.partition.peek(this.groupKey)\n  }\n\n  // A cleaned-up view's revisions never match a group's, which start at 0,\n  // so a reader that cached its rows reads them again.\n  get _stateRevision(): number {\n    return this.released ? -1 : this.group.revision\n  }\n\n  get _layoutRevision(): number {\n    return this.released ? -1 : this.group.layoutRevision\n  }\n\n  entries(): Iterable<[string | number, Row]> {\n    if (this.released) return []\n    const rows = this.group.rows.entries()\n    const passes = this.passes\n    return passes ? [...rows].filter(([, row]) => passes(row)) : rows\n  }\n\n  subscribeChanges(\n    callback: Listener,\n    options: { includeInitialState?: boolean } = {},\n  ): { unsubscribe: () => void } {\n    // A released partition refills its group here, so seed the filter after.\n    this.partition.subscribe()\n    const listener = this.passes ? this.filterChanges(callback) : callback\n    const group = this.partition.group(this.groupKey)\n    this.partition.addListener(group, listener)\n    this.listenerCount++\n    let subscribed = true\n    const unsubscribe = () => {\n      if (!subscribed) return\n      subscribed = false\n      this.partition.removeListener(group, listener)\n      if (--this.listenerCount === 0) {\n        this.collectionHold?.unsubscribe()\n        this.collectionHold = undefined\n      }\n    }\n    try {\n      this.holdCollection()\n      if (options.includeInitialState) {\n        callback(\n          Array.from(this.entries(), ([key, value]) => ({\n            type: `insert`,\n            key,\n            value,\n          })),\n        )\n      }\n    } catch (error) {\n      // A failed bootstrap returned no handle; retire its listener now.\n      unsubscribe()\n      throw error\n    }\n    return { unsubscribe }\n  }\n\n  // While the view is observed, its built Collection stays subscribed, as\n  // the Collection would be if it served the observer itself.\n  private holdCollection(): void {\n    if (this.collection && this.listenerCount > 0) {\n      this.collectionHold ??= this.collection.subscribeChanges(() => {})\n    }\n  }\n\n  // Turns the group's changes into this query's, tracking which rows have\n  // passed its residual conjuncts for this subscription.\n  private filterChanges(callback: Listener): Listener {\n    const passes = this.passes!\n    const visible = new Map(this.entries())\n    return (changes) => {\n      const out: Array<ChangeMessage<Row, string | number>> = []\n      for (const change of changes) {\n        const { key, value } = change\n        const previous = visible.get(key)\n        const next = change.type !== `delete` && passes(value)\n        if (next) visible.set(key, value)\n        else visible.delete(key)\n        if (previous && next) {\n          out.push({ type: `update`, key, value, previousValue: previous })\n        } else if (previous) {\n          out.push({ type: `delete`, key, value: previous })\n        } else if (next) {\n          out.push({ type: `insert`, key, value })\n        }\n      }\n      if (out.length > 0) callback(out)\n    }\n  }\n\n  on(...args: Parameters<CollectionImpl[`on`]>): () => void {\n    const [event, listener] = args\n    // A partition that ended stops following its source, as a cleaned-up or\n    // crashed live-query Collection does: its views announce no later change.\n    if (event === `health:change`)\n      return this.source.on(event, (change) => {\n        if (!this.partition.terminated) listener(change as never)\n      })\n    if (event !== `status:change`) return this.source.on(...args)\n    const listeners = this.partition.statusListeners\n    listeners.add(listener as StatusListener)\n    return () => listeners.delete(listener as StatusListener)\n  }\n\n  preload(): Promise<void> {\n    return this.source.preload()\n  }\n\n  cleanup(options?: { dependents?: boolean }): Promise<void> {\n    const cleanup = this.collection?.cleanup(options) ?? Promise.resolve()\n    // A cleanup that a live query reading the built Collection refuses\n    // changes nothing (law 14): the view keeps its share of the partition.\n    if (\n      !this.released &&\n      (this.collection?._lifecycle.hasStartedCleanup() ?? true)\n    ) {\n      this.released = true\n      this.partition.releaseView()\n    }\n    return cleanup\n  }\n\n  private proxy: Collection<any, any, any> | undefined = undefined\n\n  /** This view as the Collection it stands in for. */\n  get publicCollection(): Collection<any, any, any> {\n    return (this.proxy ??= new Proxy(\n      this,\n      forwardToCollection,\n    ) as unknown as Collection<any, any, any>)\n  }\n\n  materialize(): Collection<any, any, any> {\n    if (!this.collection) {\n      this.collection = createLiveQueryCollection({\n        query: this.query,\n        startSync: true,\n        gcTime: this.gcTime,\n      })\n      this.holdCollection()\n    }\n    return this.collection\n  }\n}\n\n// The observer reads the view itself; users get the live-query Collection.\nconst forwardToCollection: ProxyHandler<PooledLiveQuery> = {\n  get(view, property) {\n    const collection = view.materialize()\n    const value = Reflect.get(collection, property, collection)\n    return typeof value === `function` ? value.bind(collection) : value\n  },\n  has(view, property) {\n    return Reflect.has(view.materialize(), property)\n  },\n  // So `instanceof` and query sources accept it as the Collection it is.\n  getPrototypeOf(view) {\n    return Reflect.getPrototypeOf(view.materialize())\n  },\n}\n\n/**\n * The identity of a query a partition can serve with no residual conjunct:\n * its source and its `eq` fields and literals, which determine its rows.\n * Undefined for any other query, which keeps the full structural identity.\n */\nexport function getPooledQueryIdentity(\n  query: BaseQueryBuilder,\n): string | undefined {\n  const ir = query._getQuery()\n  if (ir.from.type !== `collectionRef`) return undefined\n  const shape = poolableShape(ir)\n  if (!shape || shape.residual.length > 0) return undefined\n  return JSON.stringify([ir.from.collection.id, shape.shapeKey, shape.groupKey])\n}\n\n/**\n * A pooled view for a query a partition can serve, or undefined. The view is\n * typed as the Collection it stands in for.\n */\nexport function createPooledLiveQuery(\n  query: BaseQueryBuilder,\n  // A live-query Collection's default when the adapter gives none.\n  { gcTime = 5_000 }: { gcTime?: number } = {},\n): Collection<any, any, any> | undefined {\n  const ir = query._getQuery()\n  const shape = poolableShape(ir)\n  if (!shape || ir.from.type !== `collectionRef`) return undefined\n  const source = ir.from.collection\n  // On-demand loading needs the live-query Collection.\n  if (source.config.syncMode === `on-demand`) return undefined\n  let partitions = partitionsBySource.get(source)\n  if (!partitions) {\n    partitions = new Map()\n    partitionsBySource.set(source, partitions)\n  }\n  const { shapeKey } = shape\n  let partition = partitions.get(shapeKey)\n  if (!partition) {\n    const owner = partitions\n    // A released partition may subscribe again; it must not then replace or\n    // remove a newer partition created under its key.\n    const created: Partition = new Partition(\n      source,\n      shape.paths,\n      shape.orderBy && rowComparator(shape.orderBy, ir.from.alias, source),\n      {\n        add: () => {\n          if (!owner.has(shapeKey)) owner.set(shapeKey, created)\n        },\n        remove: () => {\n          if (owner.get(shapeKey) === created) owner.delete(shapeKey)\n        },\n      },\n    )\n    partition = created\n    partitions.set(shapeKey, partition)\n  }\n  // Observers read the view directly; users get its `publicCollection`.\n  return new PooledLiveQuery(\n    source,\n    query,\n    partition,\n    shape.groupKey,\n    gcTime,\n    shape.residual.length > 0\n      ? rowPredicate(shape.residual, ir.from.alias)\n      : undefined,\n    ir.from.alias,\n  ) as unknown as Collection<any, any, any>\n}\n\n/**\n * Pooled live queries for framework hooks. Pass it as `pool` in a hook's\n * query config to serve equality-filtered queries of one shape from a shared\n * partition. Apps that do not pass it do not bundle pooling.\n */\nexport const pooledLiveQueries = {\n  createPooledLiveQuery,\n  getPooledQueryIdentity,\n}\n\nexport type PooledLiveQueries = typeof pooledLiveQueries\n"],"names":["SortedMap","compareRows","registry","clock","views","releaseIfUnused","equalityKey","readPath","sameFields","dropIfUnused","scheduleRelease","UNSUBSCRIBED_GC_FLOOR_MS","deliverStatus","stopStatusEvents","CleanupQueue","reportUncaught","isVirtualPropName","equalityConjunct","compileExpression","toBooleanPredicate","getWhereExpression","orderBy","buildCompareOptions","makeComparator","passes","collectionHold","registerPooledSource","buildHealthTree","endedProblem","problemOf","describeProblem","devBuild","codedMessage","healthNode","filterChanges","holdCollection","createLiveQueryCollection","ir"],"mappings":"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"}