Skip to content

3-level nested materialize is dropped when the middle level is shared by more than one parent row #1685

Description

@Jaime02

Describe the bug
Shape of the collections:

 root 1 ──> mid 1 ─┐
                   ├──> shared 1 ──> leaf 1
 root 2 ──> mid 2 ─┘

Both root rows resolve to the same shared 1 row, which includes leaf 1.

Expected: both rows have mid.shared.leaf
Actual: only one row does; the other has leaf: undefined

To Reproduce: Stackblitz demo

Reproducible example:

import {
  createCollection,
  createLiveQueryCollection,
  eq,
  localOnlyCollectionOptions,
  materialize,
} from "@tanstack/db";

const leaves = createCollection(
  localOnlyCollectionOptions({
    getKey: (r: { id: number }) => r.id,
    initialData: [{ id: 1 }],
  }),
);

// The shared level: a single row that both `mid` rows point at.
const shareds = createCollection(
  localOnlyCollectionOptions({
    getKey: (r: { id: number; leafId: number }) => r.id,
    initialData: [{ id: 1, leafId: 1 }],
  }),
);

const mids = createCollection(
  localOnlyCollectionOptions({
    getKey: (r: { id: number; sharedId: number }) => r.id,
    initialData: [
      { id: 1, sharedId: 1 },
      { id: 2, sharedId: 1 },
    ],
  }),
);

const roots = createCollection(
  localOnlyCollectionOptions({
    getKey: (r: { id: number; midId: number }) => r.id,
    initialData: [
      { id: 1, midId: 1 },
      { id: 2, midId: 2 },
    ],
  }),
);

const live = createLiveQueryCollection((q) =>
  q.from({ root: roots }).select(({ root }) => ({
    ...root,
    mid: materialize(
      q
        .from({ mid: mids })
        .where(({ mid }) => eq(mid.id, root.midId))
        .select(({ mid }) => ({
          ...mid,
          shared: materialize(
            q
              .from({ shared: shareds })
              .where(({ shared }) => eq(shared.id, mid.sharedId))
              .select(({ shared }) => ({
                ...shared,
                leaf: materialize(
                  q
                    .from({ leaf: leaves })
                    .where(({ leaf }) => eq(leaf.id, shared.leafId))
                    .findOne(),
                ),
              }))
              .findOne(),
          ),
        }))
        .findOne(),
    ),
  })),
);

await live.preload();

let failed = false;
for (const row of live.toArray) {
  const shared = row.mid?.shared;
  const ok = shared?.leaf != null;
  if (!ok) failed = true;
  console.log(
    `root=${row.id} mid=${row.mid?.id} shared=${shared?.id} leafId=${shared?.leafId} ` +
      `leaf=${shared?.leaf ? `{ id: ${shared.leaf.id} }` : "undefined"}  ${ok ? "OK" : "<-- DROPPED"}`,
  );
}

console.log(failed ? "\nFAIL: leaf missing on at least one row" : "\nPASS");
process.exit(failed ? 1 : 0);

Desktop (please complete the following information):

(Not relevant I guess)

  • OS: Windows 11
  • Browser: Chrome

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions