From 860b2f6062298e6e98f5007ad44842477983c050 Mon Sep 17 00:00:00 2001 From: Kris Nye Date: Mon, 8 Jun 2026 14:07:09 -0700 Subject: [PATCH 1/2] =?UTF-8?q?test(ecs):=20add=20complex=20sort=20index?= =?UTF-8?q?=20sample=20=E2=80=94=20orderedChildOf=20with=20nested=20parent?= =?UTF-8?q?=20+=20fractional=20index?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- .../src/ecs/database/database.index.test.ts | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/packages/data/src/ecs/database/database.index.test.ts b/packages/data/src/ecs/database/database.index.test.ts index 16a54d9..b56e7e3 100644 --- a/packages/data/src/ecs/database/database.index.test.ts +++ b/packages/data/src/ecs/database/database.index.test.ts @@ -1472,3 +1472,78 @@ describe("registry maintenance", () => { expect([...ext.indexes.byName.find({ name: "alice" })].sort()).toEqual([e1, e2].sort()); }); }); + +describe("complex sort index — orderedChildOf (nested parent + fractional-index order)", () => { + // orderedChildOf bundles the parent entity reference and the fractional-index + // sort key in a single object component. The index uses a computed slot map + // to extract the group key and a custom compare that drills into the nested + // object for the order field — matching the README pattern: + // key: (f) => f.parent, order: { by: ["foo"], compare: (a, b) => a.foo.order < b.foo.order ? -1 : 1 } + const plugin = () => Database.Plugin.create({ + components: { + orderedChildOf: { + type: "object", + properties: { + parent: { type: "number" }, + order: { type: "string" }, + }, + required: ["parent", "order"], + }, + }, + archetypes: { Child: ["orderedChildOf"] }, + indexes: { + orderedChildrenOf: { + key: { parent: (c) => c.orderedChildOf!.parent }, + components: ["orderedChildOf"], + order: { + by: ["orderedChildOf"], + compare: ( + a: { orderedChildOf: { parent: number; order: string } }, + b: { orderedChildOf: { parent: number; order: string } }, + ) => a.orderedChildOf.order < b.orderedChildOf.order ? -1 : 1, + }, + }, + }, + transactions: { + add: (t, args: { parent: number; order: string }) => + t.archetypes.Child.insert({ orderedChildOf: args }), + reorder: (t, args: { entity: number; parent: number; order: string }) => + t.update(args.entity, { orderedChildOf: { parent: args.parent, order: args.order } }), + delete: (t, e: number) => t.delete(e), + }, + }); + + it("returns children sorted by fractional index within the same parent", () => { + const db = Database.create(plugin()); + const c = db.transactions.add({ parent: 1, order: "a2" }); + const a = db.transactions.add({ parent: 1, order: "a0" }); + const b = db.transactions.add({ parent: 1, order: "a1" }); + expect(db.indexes.orderedChildrenOf.find({ parent: 1 })).toEqual([a, b, c]); + }); + + it("children of different parents are in independent buckets", () => { + const db = Database.create(plugin()); + const child1 = db.transactions.add({ parent: 1, order: "a0" }); + const child2 = db.transactions.add({ parent: 2, order: "a0" }); + expect(db.indexes.orderedChildrenOf.find({ parent: 1 })).toEqual([child1]); + expect(db.indexes.orderedChildrenOf.find({ parent: 2 })).toEqual([child2]); + }); + + it("reordering an entity repositions it in the sorted result", () => { + const db = Database.create(plugin()); + const a = db.transactions.add({ parent: 1, order: "a0" }); + const b = db.transactions.add({ parent: 1, order: "a1" }); + const c = db.transactions.add({ parent: 1, order: "a2" }); + db.transactions.reorder({ entity: a, parent: 1, order: "a3" }); + expect(db.indexes.orderedChildrenOf.find({ parent: 1 })).toEqual([b, c, a]); + }); + + it("delete removes the entity from its sorted bucket", () => { + const db = Database.create(plugin()); + const a = db.transactions.add({ parent: 1, order: "a0" }); + const b = db.transactions.add({ parent: 1, order: "a1" }); + const c = db.transactions.add({ parent: 1, order: "a2" }); + db.transactions.delete(b); + expect(db.indexes.orderedChildrenOf.find({ parent: 1 })).toEqual([a, c]); + }); +}); From 2d4ff1938b74e5203032d3432f95921186132b88 Mon Sep 17 00:00:00 2001 From: Kris Nye Date: Mon, 8 Jun 2026 14:15:33 -0700 Subject: [PATCH 2/2] fix(test): use Entity.schema and FractionalIndex.schema in orderedChildOf component Co-Authored-By: Claude Sonnet 4.6 --- packages/data/src/ecs/database/database.index.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/data/src/ecs/database/database.index.test.ts b/packages/data/src/ecs/database/database.index.test.ts index b56e7e3..623e0df 100644 --- a/packages/data/src/ecs/database/database.index.test.ts +++ b/packages/data/src/ecs/database/database.index.test.ts @@ -2,6 +2,8 @@ import { describe, it, expect } from "vitest"; import { Database } from "./database.js"; +import { Entity } from "../entity/entity.js"; +import { FractionalIndex } from "../../schema/fractional-index/fractional-index.js"; // ============================================================================ // Catalogue pattern coverage — each describe corresponds to one of the 12 @@ -1484,8 +1486,8 @@ describe("complex sort index — orderedChildOf (nested parent + fractional-inde orderedChildOf: { type: "object", properties: { - parent: { type: "number" }, - order: { type: "string" }, + parent: Entity.schema, + order: FractionalIndex.schema, }, required: ["parent", "order"], },