@adobe/data 0.9.82 → 0.9.83
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.
- package/dist/ecs/archetype/archetype.d.ts +23 -0
- package/dist/ecs/archetype/archetype.js.map +1 -1
- package/dist/ecs/database/create-plugin.d.ts +2 -1
- package/dist/ecs/database/create-plugin.js.map +1 -1
- package/dist/ecs/database/database.d.ts +6 -5
- package/dist/ecs/database/database.js.map +1 -1
- package/dist/ecs/database/database.partition.test.d.ts +1 -0
- package/dist/ecs/database/database.partition.test.js +45 -0
- package/dist/ecs/database/database.partition.test.js.map +1 -0
- package/dist/ecs/database/database.partition.type-test.d.ts +1 -0
- package/dist/ecs/database/database.partition.type-test.js +41 -0
- package/dist/ecs/database/database.partition.type-test.js.map +1 -0
- package/dist/ecs/database/deep-extends-chain.type-test.d.ts +255 -255
- package/dist/ecs/database/index.d.ts +0 -1
- package/dist/ecs/database/index.js +0 -1
- package/dist/ecs/database/index.js.map +1 -1
- package/dist/ecs/database/transactional-store/transactional-store.d.ts +6 -5
- package/dist/ecs/store/core/core.d.ts +33 -8
- package/dist/ecs/store/core/create-core.d.ts +12 -2
- package/dist/ecs/store/core/create-core.js +141 -22
- package/dist/ecs/store/core/create-core.js.map +1 -1
- package/dist/ecs/store/core/create-core.partition.test.d.ts +1 -0
- package/dist/ecs/store/core/create-core.partition.test.js +229 -0
- package/dist/ecs/store/core/create-core.partition.test.js.map +1 -0
- package/dist/ecs/store/core/select-entities.js +87 -21
- package/dist/ecs/store/core/select-entities.js.map +1 -1
- package/dist/ecs/store/core/select-entities.partition.test.d.ts +1 -0
- package/dist/ecs/store/core/select-entities.partition.test.js +93 -0
- package/dist/ecs/store/core/select-entities.partition.test.js.map +1 -0
- package/dist/ecs/store/entity-select-options.d.ts +5 -1
- package/dist/ecs/store/partition.d.ts +63 -0
- package/dist/ecs/store/partition.js +3 -0
- package/dist/ecs/store/partition.js.map +1 -0
- package/dist/ecs/store/partition.type-test.d.ts +1 -0
- package/dist/ecs/store/partition.type-test.js +15 -0
- package/dist/ecs/store/partition.type-test.js.map +1 -0
- package/dist/ecs/store/public/create-store.d.ts +3 -1
- package/dist/ecs/store/public/create-store.js +19 -50
- package/dist/ecs/store/public/create-store.js.map +1 -1
- package/dist/ecs/store/public/create-store.partition.test.d.ts +1 -0
- package/dist/ecs/store/public/create-store.partition.test.js +111 -0
- package/dist/ecs/store/public/create-store.partition.test.js.map +1 -0
- package/dist/ecs/store/public/create-store.partition.type-test.d.ts +1 -0
- package/dist/ecs/store/public/create-store.partition.type-test.js +61 -0
- package/dist/ecs/store/public/create-store.partition.type-test.js.map +1 -0
- package/dist/ecs/store/store.d.ts +15 -10
- package/dist/ecs/store/store.js.map +1 -1
- package/dist/ecs/store/transaction-functions.d.ts +3 -3
- package/dist/schema/schema.d.ts +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/references/data-lit/package.json +1 -1
- package/references/data-lit-tictactoe/package.json +1 -1
- package/references/data-react/package.json +1 -1
- package/references/data-react-hello/package.json +1 -1
- package/references/data-react-pixie/package.json +1 -1
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
import { describe, it, expect } from "vitest";
|
|
3
|
+
import { createCore } from "./create-core.js";
|
|
4
|
+
import { constBufferType } from "../../../typed-buffer/create-const-buffer.js";
|
|
5
|
+
const positionSchema = {
|
|
6
|
+
type: "object",
|
|
7
|
+
properties: { x: { type: "number" }, y: { type: "number" } },
|
|
8
|
+
};
|
|
9
|
+
// A partition component: every distinct `cell` value gets its own archetype.
|
|
10
|
+
const cellSchema = { type: "integer", partition: true };
|
|
11
|
+
const makeCore = () => createCore({ cell: cellSchema, position: positionSchema });
|
|
12
|
+
describe("partition components", () => {
|
|
13
|
+
describe("ensureArchetype return discrimination", () => {
|
|
14
|
+
it("returns a Router (no dense view) when a partition key is present without a value", () => {
|
|
15
|
+
const core = makeCore();
|
|
16
|
+
const router = core.ensureArchetype(["id", "cell", "position"]);
|
|
17
|
+
expect(typeof router.insert).toBe("function");
|
|
18
|
+
// A family has no single dense column view. `in` (not a cast) — the
|
|
19
|
+
// Router type has no such members, so probe presence structurally.
|
|
20
|
+
expect("columns" in router).toBe(false);
|
|
21
|
+
expect("rowCount" in router).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
it("returns a concrete Archetype when the partition value is supplied", () => {
|
|
24
|
+
const core = makeCore();
|
|
25
|
+
const arch = core.ensureArchetype(["id", "cell", "position"], { cell: 7 });
|
|
26
|
+
expect(arch.columns).toBeDefined();
|
|
27
|
+
expect(arch.rowCount).toBe(0);
|
|
28
|
+
});
|
|
29
|
+
it("returns a concrete Archetype (not a Router) when no partition component is in the set", () => {
|
|
30
|
+
const core = makeCore();
|
|
31
|
+
const arch = core.ensureArchetype(["id", "position"]);
|
|
32
|
+
expect(arch.columns).toBeDefined();
|
|
33
|
+
expect(typeof arch.insert).toBe("function");
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
describe("routing insert", () => {
|
|
37
|
+
it("routes rows with distinct partition values into distinct archetypes", () => {
|
|
38
|
+
const core = makeCore();
|
|
39
|
+
const router = core.ensureArchetype(["id", "cell", "position"]);
|
|
40
|
+
const a = router.insert({ cell: 1, position: { x: 1, y: 1 } });
|
|
41
|
+
const b = router.insert({ cell: 2, position: { x: 2, y: 2 } });
|
|
42
|
+
const c = router.insert({ cell: 1, position: { x: 3, y: 3 } });
|
|
43
|
+
const cell1 = core.ensureArchetype(["id", "cell", "position"], { cell: 1 });
|
|
44
|
+
const cell2 = core.ensureArchetype(["id", "cell", "position"], { cell: 2 });
|
|
45
|
+
// Same value → same archetype; different value → different archetype.
|
|
46
|
+
expect(cell1).not.toBe(cell2);
|
|
47
|
+
expect(cell1.rowCount).toBe(2); // a and c
|
|
48
|
+
expect(cell2.rowCount).toBe(1); // b
|
|
49
|
+
expect(core.locate(a).archetype).toBe(cell1);
|
|
50
|
+
expect(core.locate(c).archetype).toBe(cell1);
|
|
51
|
+
expect(core.locate(b).archetype).toBe(cell2);
|
|
52
|
+
});
|
|
53
|
+
it("stores the partition value as a const column (zero per-row bytes)", () => {
|
|
54
|
+
const core = makeCore();
|
|
55
|
+
core.ensureArchetype(["id", "cell", "position"]).insert({ cell: 42, position: { x: 0, y: 0 } });
|
|
56
|
+
const arch = core.ensureArchetype(["id", "cell", "position"], { cell: 42 });
|
|
57
|
+
expect(arch.columns.cell.type).toBe(constBufferType);
|
|
58
|
+
expect(arch.columns.cell.typedArrayElementSizeInBytes).toBe(0);
|
|
59
|
+
expect(arch.columns.cell.get(0)).toBe(42);
|
|
60
|
+
});
|
|
61
|
+
it("reads the routed partition value back through the entity", () => {
|
|
62
|
+
const core = makeCore();
|
|
63
|
+
const router = core.ensureArchetype(["id", "cell", "position"]);
|
|
64
|
+
const e = router.insert({ cell: 9, position: { x: 5, y: 6 } });
|
|
65
|
+
expect(core.get(e, "cell")).toBe(9);
|
|
66
|
+
expect(core.read(e)).toMatchObject({ cell: 9, position: { x: 5, y: 6 } });
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
describe("queryArchetypes", () => {
|
|
70
|
+
it("returns every value-child of a partitioned component set", () => {
|
|
71
|
+
const core = makeCore();
|
|
72
|
+
const router = core.ensureArchetype(["id", "cell", "position"]);
|
|
73
|
+
router.insert({ cell: 1, position: { x: 0, y: 0 } });
|
|
74
|
+
router.insert({ cell: 2, position: { x: 0, y: 0 } });
|
|
75
|
+
router.insert({ cell: 3, position: { x: 0, y: 0 } });
|
|
76
|
+
const all = core.queryArchetypes(["cell", "position"]);
|
|
77
|
+
expect(all.length).toBe(3);
|
|
78
|
+
});
|
|
79
|
+
it("filters to a single value-child with a partition `where` (broad phase)", () => {
|
|
80
|
+
const core = makeCore();
|
|
81
|
+
const router = core.ensureArchetype(["id", "cell", "position"]);
|
|
82
|
+
router.insert({ cell: 1, position: { x: 0, y: 0 } });
|
|
83
|
+
router.insert({ cell: 2, position: { x: 0, y: 0 } });
|
|
84
|
+
router.insert({ cell: 2, position: { x: 0, y: 0 } });
|
|
85
|
+
const cell2 = core.queryArchetypes(["cell", "position"], { where: { cell: 2 } });
|
|
86
|
+
expect(cell2.length).toBe(1);
|
|
87
|
+
expect(cell2[0].columns.cell.get(0)).toBe(2);
|
|
88
|
+
expect(cell2[0].rowCount).toBe(2);
|
|
89
|
+
const none = core.queryArchetypes(["cell", "position"], { where: { cell: 99 } });
|
|
90
|
+
expect(none.length).toBe(0);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
describe("update migration", () => {
|
|
94
|
+
it("migrates an entity to a new value-child when its partition value changes", () => {
|
|
95
|
+
const core = makeCore();
|
|
96
|
+
const router = core.ensureArchetype(["id", "cell", "position"]);
|
|
97
|
+
const e = router.insert({ cell: 1, position: { x: 7, y: 8 } });
|
|
98
|
+
const cell1 = core.ensureArchetype(["id", "cell", "position"], { cell: 1 });
|
|
99
|
+
const cell2 = core.ensureArchetype(["id", "cell", "position"], { cell: 2 });
|
|
100
|
+
expect(cell1.rowCount).toBe(1);
|
|
101
|
+
expect(cell2.rowCount).toBe(0);
|
|
102
|
+
core.update(e, { cell: 2 });
|
|
103
|
+
// Same entity id, moved archetype, position preserved.
|
|
104
|
+
expect(core.locate(e).archetype).toBe(cell2);
|
|
105
|
+
expect(cell1.rowCount).toBe(0);
|
|
106
|
+
expect(cell2.rowCount).toBe(1);
|
|
107
|
+
expect(core.get(e, "cell")).toBe(2);
|
|
108
|
+
expect(core.read(e)).toMatchObject({ cell: 2, position: { x: 7, y: 8 } });
|
|
109
|
+
});
|
|
110
|
+
it("does not migrate when a non-partition field changes", () => {
|
|
111
|
+
const core = makeCore();
|
|
112
|
+
const router = core.ensureArchetype(["id", "cell", "position"]);
|
|
113
|
+
const e = router.insert({ cell: 5, position: { x: 1, y: 1 } });
|
|
114
|
+
const cell5 = core.locate(e).archetype;
|
|
115
|
+
core.update(e, { position: { x: 9, y: 9 } });
|
|
116
|
+
expect(core.locate(e).archetype).toBe(cell5);
|
|
117
|
+
expect(core.read(e)).toMatchObject({ cell: 5, position: { x: 9, y: 9 } });
|
|
118
|
+
});
|
|
119
|
+
it("does not migrate when a partition value is set to its current value", () => {
|
|
120
|
+
const core = makeCore();
|
|
121
|
+
const router = core.ensureArchetype(["id", "cell", "position"]);
|
|
122
|
+
const e = router.insert({ cell: 3, position: { x: 0, y: 0 } });
|
|
123
|
+
const before = core.locate(e).archetype;
|
|
124
|
+
core.update(e, { cell: 3 });
|
|
125
|
+
expect(core.locate(e).archetype).toBe(before);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
describe("serialization", () => {
|
|
129
|
+
it("round-trips partition children (values + rows) through toData/fromData", () => {
|
|
130
|
+
const core = makeCore();
|
|
131
|
+
const router = core.ensureArchetype(["id", "cell", "position"]);
|
|
132
|
+
const a = router.insert({ cell: 1, position: { x: 1, y: 1 } });
|
|
133
|
+
const b = router.insert({ cell: 2, position: { x: 2, y: 2 } });
|
|
134
|
+
const snapshot = core.toData(true);
|
|
135
|
+
const restored = makeCore();
|
|
136
|
+
restored.fromData(snapshot);
|
|
137
|
+
expect(restored.get(a, "cell")).toBe(1);
|
|
138
|
+
expect(restored.get(b, "cell")).toBe(2);
|
|
139
|
+
expect(restored.read(a)).toMatchObject({ cell: 1, position: { x: 1, y: 1 } });
|
|
140
|
+
expect(restored.read(b)).toMatchObject({ cell: 2, position: { x: 2, y: 2 } });
|
|
141
|
+
const cell1 = restored.ensureArchetype(["id", "cell", "position"], { cell: 1 });
|
|
142
|
+
expect(cell1.columns.cell.type).toBe(constBufferType);
|
|
143
|
+
expect(cell1.rowCount).toBe(1);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
describe("multiple partition components together", () => {
|
|
147
|
+
// Two partition components → archetypes are the *cross product* of the
|
|
148
|
+
// distinct (cell, layer) value pairs actually used.
|
|
149
|
+
const makeGridCore = () => createCore({
|
|
150
|
+
cell: { type: "integer", partition: true },
|
|
151
|
+
layer: { type: "integer", partition: true },
|
|
152
|
+
value: { type: "number" },
|
|
153
|
+
});
|
|
154
|
+
const keys = ["id", "cell", "layer", "value"];
|
|
155
|
+
it("creates one archetype per distinct (cell, layer) pair, each with both const columns", () => {
|
|
156
|
+
const core = makeGridCore();
|
|
157
|
+
const router = core.ensureArchetype(keys);
|
|
158
|
+
const cells = [0, 1];
|
|
159
|
+
const layers = [0, 1, 2];
|
|
160
|
+
for (const cell of cells)
|
|
161
|
+
for (const layer of layers) {
|
|
162
|
+
router.insert({ cell, layer, value: cell * 10 + layer });
|
|
163
|
+
}
|
|
164
|
+
const archetypes = core.queryArchetypes(["cell", "layer", "value"]);
|
|
165
|
+
expect(archetypes.length).toBe(cells.length * layers.length); // 2 × 3 = 6
|
|
166
|
+
const combos = new Set();
|
|
167
|
+
for (const arch of archetypes) {
|
|
168
|
+
expect(arch.rowCount).toBe(1);
|
|
169
|
+
// BOTH partition columns are zero-per-row const buffers.
|
|
170
|
+
expect(arch.columns.cell.type).toBe(constBufferType);
|
|
171
|
+
expect(arch.columns.layer.type).toBe(constBufferType);
|
|
172
|
+
combos.add(`${arch.columns.cell.get(0)},${arch.columns.layer.get(0)}`);
|
|
173
|
+
}
|
|
174
|
+
expect(combos.size).toBe(6);
|
|
175
|
+
});
|
|
176
|
+
it("routes on the full (cell, layer) tuple — same pair shares an archetype, either differing splits", () => {
|
|
177
|
+
const core = makeGridCore();
|
|
178
|
+
const router = core.ensureArchetype(keys);
|
|
179
|
+
const a = router.insert({ cell: 1, layer: 2, value: 0 });
|
|
180
|
+
const b = router.insert({ cell: 1, layer: 2, value: 1 }); // same pair
|
|
181
|
+
const c = router.insert({ cell: 1, layer: 3, value: 2 }); // layer differs
|
|
182
|
+
const d = router.insert({ cell: 9, layer: 2, value: 3 }); // cell differs
|
|
183
|
+
expect(core.locate(a).archetype).toBe(core.locate(b).archetype);
|
|
184
|
+
expect(core.locate(a).archetype).not.toBe(core.locate(c).archetype);
|
|
185
|
+
expect(core.locate(a).archetype).not.toBe(core.locate(d).archetype);
|
|
186
|
+
const arch12 = core.ensureArchetype(keys, { cell: 1, layer: 2 });
|
|
187
|
+
expect(core.locate(a).archetype).toBe(arch12);
|
|
188
|
+
expect(arch12.rowCount).toBe(2);
|
|
189
|
+
expect(core.read(a)).toMatchObject({ cell: 1, layer: 2, value: 0 });
|
|
190
|
+
});
|
|
191
|
+
it("queryArchetypes `where` filters on one or both partition components", () => {
|
|
192
|
+
const core = makeGridCore();
|
|
193
|
+
const router = core.ensureArchetype(keys);
|
|
194
|
+
for (const cell of [0, 1])
|
|
195
|
+
for (const layer of [0, 1, 2]) {
|
|
196
|
+
router.insert({ cell, layer, value: 0 });
|
|
197
|
+
}
|
|
198
|
+
// One component → all pairs sharing it (cell=1 across 3 layers).
|
|
199
|
+
expect(core.queryArchetypes(["cell", "layer", "value"], { where: { cell: 1 } }).length).toBe(3);
|
|
200
|
+
// Both components → exactly the one pair.
|
|
201
|
+
const one = core.queryArchetypes(["cell", "layer", "value"], { where: { cell: 1, layer: 2 } });
|
|
202
|
+
expect(one.length).toBe(1);
|
|
203
|
+
expect(one[0].columns.cell.get(0)).toBe(1);
|
|
204
|
+
expect(one[0].columns.layer.get(0)).toBe(2);
|
|
205
|
+
});
|
|
206
|
+
it("migrating one partition value keeps the other and lands in the correct combined archetype", () => {
|
|
207
|
+
const core = makeGridCore();
|
|
208
|
+
const router = core.ensureArchetype(keys);
|
|
209
|
+
const e = router.insert({ cell: 1, layer: 2, value: 5 });
|
|
210
|
+
core.update(e, { cell: 3 }); // change cell only
|
|
211
|
+
expect(core.get(e, "cell")).toBe(3);
|
|
212
|
+
expect(core.get(e, "layer")).toBe(2); // preserved
|
|
213
|
+
expect(core.locate(e).archetype).toBe(core.ensureArchetype(keys, { cell: 3, layer: 2 }));
|
|
214
|
+
// The old (1, 2) archetype is now empty.
|
|
215
|
+
expect(core.ensureArchetype(keys, { cell: 1, layer: 2 }).rowCount).toBe(0);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
describe("feature is inert without partition components", () => {
|
|
219
|
+
it("a store with no partition component behaves exactly as before", () => {
|
|
220
|
+
const core = createCore({ position: positionSchema });
|
|
221
|
+
const arch = core.ensureArchetype(["id", "position"]);
|
|
222
|
+
// Concrete archetype, direct insert, dense columns — no Router anywhere.
|
|
223
|
+
expect(arch.columns).toBeDefined();
|
|
224
|
+
const e = arch.insert({ position: { x: 1, y: 2 } });
|
|
225
|
+
expect(core.read(e)).toMatchObject({ position: { x: 1, y: 2 } });
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
//# sourceMappingURL=create-core.partition.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-core.partition.test.js","sourceRoot":"","sources":["../../../../src/ecs/store/core/create-core.partition.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
import { selectRows } from "../../../table/select-rows.js";
|
|
3
3
|
import { compare } from "../../../functions/compare.js";
|
|
4
4
|
export const selectEntities = (core, include, options) => {
|
|
5
|
-
|
|
5
|
+
// Pass only archetype-level options (exclude) to queryArchetypes. `options.where`
|
|
6
|
+
// here is a row-level Filter and is applied per-row below via selectRows — it
|
|
7
|
+
// must NOT be forwarded as queryArchetypes' partition-equality `where`.
|
|
8
|
+
const archetypes = core.queryArchetypes(include, options?.exclude ? { exclude: options.exclude } : undefined);
|
|
6
9
|
let length = 0;
|
|
7
10
|
for (const archetype of archetypes) {
|
|
8
11
|
length += archetype.rowCount;
|
|
@@ -30,32 +33,95 @@ export const selectEntities = (core, include, options) => {
|
|
|
30
33
|
}
|
|
31
34
|
return entities;
|
|
32
35
|
}
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
36
|
+
// ── Ordered results ─────────────────────────────────────────────────────
|
|
37
|
+
// When the *leading run* of order keys are partition components, each
|
|
38
|
+
// archetype holds a constant value for them, so the archetypes already
|
|
39
|
+
// bucket the rows on that leading key. We can then sort the buckets by
|
|
40
|
+
// value, sort only the *remaining* keys within each bucket, and concatenate
|
|
41
|
+
// in bucket order — turning an O(N log N) sort into O(N log(N/K)), and O(N)
|
|
42
|
+
// when a partition key is the sole order key. When no leading order key is a
|
|
43
|
+
// partition component (leadCount === 0) this falls back to one full sort,
|
|
44
|
+
// matching the previous behaviour exactly.
|
|
45
|
+
const order = options.order;
|
|
46
|
+
const schemas = core.componentSchemas;
|
|
47
|
+
// Keys of `order` are, by OrderClause<Pick<…, Include>>, exactly the picked
|
|
48
|
+
// component keys — safe to view as Include[].
|
|
49
|
+
const orderKeys = Object.keys(order);
|
|
50
|
+
let leadCount = 0;
|
|
51
|
+
while (leadCount < orderKeys.length && schemas[orderKeys[leadCount]]?.partition === true) {
|
|
52
|
+
leadCount++;
|
|
45
53
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
for (const order in options.order) {
|
|
54
|
+
const compareByKeys = (keys, a, b) => {
|
|
55
|
+
for (const key of keys) {
|
|
49
56
|
// `compare` (code-point for strings, numeric for numbers) — not
|
|
50
57
|
// `a - b`, which is NaN for string order keys, and never locale.
|
|
51
|
-
const cmp = compare(a[
|
|
52
|
-
if (cmp !== 0)
|
|
53
|
-
|
|
54
|
-
|
|
58
|
+
const cmp = compare(a[key], b[key]);
|
|
59
|
+
if (cmp !== 0)
|
|
60
|
+
return order[key] ? cmp : -cmp;
|
|
61
|
+
}
|
|
62
|
+
return 0;
|
|
63
|
+
};
|
|
64
|
+
// Gather ids for `archs`, sorted by `sortKeys` (empty → left in archetype +
|
|
65
|
+
// row order). `where` is applied per row. A stable sort over the same gather
|
|
66
|
+
// order keeps tie-ordering identical to the single full sort.
|
|
67
|
+
const collect = (archs, sortKeys) => {
|
|
68
|
+
if (sortKeys.length === 0) {
|
|
69
|
+
const ids = [];
|
|
70
|
+
for (const archetype of archs) {
|
|
71
|
+
const idTypedArray = archetype.columns.id.getTypedArray();
|
|
72
|
+
for (const row of selectRows(archetype, options.where)) {
|
|
73
|
+
ids.push(idTypedArray[row]);
|
|
74
|
+
}
|
|
55
75
|
}
|
|
76
|
+
return ids;
|
|
77
|
+
}
|
|
78
|
+
const rows = [];
|
|
79
|
+
for (const archetype of archs) {
|
|
80
|
+
const idTypedArray = archetype.columns.id.getTypedArray();
|
|
81
|
+
for (const row of selectRows(archetype, options.where)) {
|
|
82
|
+
const value = { id: idTypedArray[row] };
|
|
83
|
+
for (const key of sortKeys)
|
|
84
|
+
value[key] = archetype.columns[key].get(row);
|
|
85
|
+
rows.push(value);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
rows.sort((a, b) => compareByKeys(sortKeys, a, b));
|
|
89
|
+
return rows.map((r) => r.id);
|
|
90
|
+
};
|
|
91
|
+
if (leadCount === 0) {
|
|
92
|
+
return collect(archetypes, orderKeys);
|
|
93
|
+
}
|
|
94
|
+
// Bucket archetypes by their leading partition-value tuple, preserving
|
|
95
|
+
// archetype iteration order within a bucket (so tie-ordering matches the
|
|
96
|
+
// full sort). A bucket can span multiple archetypes (shape fan-out).
|
|
97
|
+
const leadKeys = orderKeys.slice(0, leadCount);
|
|
98
|
+
const restKeys = orderKeys.slice(leadCount);
|
|
99
|
+
const buckets = new Map();
|
|
100
|
+
for (const archetype of archetypes) {
|
|
101
|
+
const values = leadKeys.map((key) => archetype.columns[key].get(0));
|
|
102
|
+
// JSON is an unambiguous key for a primitive tuple: it distinguishes
|
|
103
|
+
// 1 from "1" and never collides across tuple boundaries.
|
|
104
|
+
const bucketKey = JSON.stringify(values);
|
|
105
|
+
let bucket = buckets.get(bucketKey);
|
|
106
|
+
if (!bucket) {
|
|
107
|
+
bucket = { values, archs: [] };
|
|
108
|
+
buckets.set(bucketKey, bucket);
|
|
109
|
+
}
|
|
110
|
+
bucket.archs.push(archetype);
|
|
111
|
+
}
|
|
112
|
+
const orderedBuckets = [...buckets.values()].sort((a, b) => {
|
|
113
|
+
for (let i = 0; i < leadKeys.length; i++) {
|
|
114
|
+
const cmp = compare(a.values[i], b.values[i]);
|
|
115
|
+
if (cmp !== 0)
|
|
116
|
+
return order[leadKeys[i]] ? cmp : -cmp;
|
|
56
117
|
}
|
|
57
118
|
return 0;
|
|
58
119
|
});
|
|
59
|
-
|
|
120
|
+
const result = [];
|
|
121
|
+
for (const bucket of orderedBuckets) {
|
|
122
|
+
for (const id of collect(bucket.archs, restKeys))
|
|
123
|
+
result.push(id);
|
|
124
|
+
}
|
|
125
|
+
return result;
|
|
60
126
|
};
|
|
61
127
|
//# sourceMappingURL=select-entities.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select-entities.js","sourceRoot":"","sources":["../../../../src/ecs/store/core/select-entities.ts"],"names":[],"mappings":"AAAA,uDAAuD;AAEvD,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAC;AAQxD,MAAM,CAAC,MAAM,cAAc,GAAG,CAI1B,IAAa,EACb,OAAiD,EACjD,OAAiH,EAChG,EAAE;IACnB,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"select-entities.js","sourceRoot":"","sources":["../../../../src/ecs/store/core/select-entities.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
import { describe, it, expect } from "vitest";
|
|
3
|
+
import { createStore } from "../public/create-store.js";
|
|
4
|
+
import { compare } from "../../../functions/compare.js";
|
|
5
|
+
// `cell` and `region` partition; `rank` does not. The partition-aware sort in
|
|
6
|
+
// selectEntities must produce output identical to a naive full sort.
|
|
7
|
+
const schema = {
|
|
8
|
+
components: {
|
|
9
|
+
cell: { type: "integer", partition: true },
|
|
10
|
+
region: { type: "integer", partition: true },
|
|
11
|
+
rank: { type: "integer" },
|
|
12
|
+
},
|
|
13
|
+
resources: {},
|
|
14
|
+
archetypes: { E: ["cell", "region", "rank"] },
|
|
15
|
+
};
|
|
16
|
+
const makeStore = (rows) => {
|
|
17
|
+
const store = createStore(schema);
|
|
18
|
+
const ids = rows.map((r) => store.archetypes.E.insert(r));
|
|
19
|
+
return { store, ids };
|
|
20
|
+
};
|
|
21
|
+
// Independent reference: read every row and sort by the order keys with the
|
|
22
|
+
// same `compare` semantics selectEntities uses.
|
|
23
|
+
const referenceSort = (store, ids, order, where) => {
|
|
24
|
+
const keys = Object.keys(order);
|
|
25
|
+
const withVals = ids
|
|
26
|
+
.map((id) => ({ id, r: store.read(id) }))
|
|
27
|
+
.filter((x) => (where ? where(x.r) : true));
|
|
28
|
+
withVals.sort((a, b) => {
|
|
29
|
+
for (const k of keys) {
|
|
30
|
+
const c = compare(a.r[k], b.r[k]);
|
|
31
|
+
if (c !== 0)
|
|
32
|
+
return order[k] ? c : -c;
|
|
33
|
+
}
|
|
34
|
+
return 0;
|
|
35
|
+
});
|
|
36
|
+
return withVals.map((x) => x.id);
|
|
37
|
+
};
|
|
38
|
+
// Rows with a globally-unique `rank` so every order that ends in `rank` is a
|
|
39
|
+
// total order (no ties → the reference comparison is unambiguous).
|
|
40
|
+
const uniqueRows = (n) => Array.from({ length: n }, (_, i) => ({
|
|
41
|
+
cell: i % 5,
|
|
42
|
+
region: i % 3,
|
|
43
|
+
rank: (i * 7) % n, // a permutation of 0..n-1 (7 and n=100 are coprime)
|
|
44
|
+
}));
|
|
45
|
+
describe("selectEntities partition-aware ordering", () => {
|
|
46
|
+
const orders = [
|
|
47
|
+
["sole partition key (cell asc) + rank tiebreak", { cell: true, rank: true }],
|
|
48
|
+
["partition key descending (cell desc) + rank", { cell: false, rank: true }],
|
|
49
|
+
["compound partition keys (cell, region) + rank", { cell: true, region: true, rank: true }],
|
|
50
|
+
["partition then descending secondary (cell asc, rank desc)", { cell: true, rank: false }],
|
|
51
|
+
["non-partition leading key (rank asc) — fallback path", { rank: true }],
|
|
52
|
+
["non-partition leading then partition (rank asc, cell asc) — fallback", { rank: true, cell: true }],
|
|
53
|
+
];
|
|
54
|
+
for (const [name, order] of orders) {
|
|
55
|
+
it(`matches a naive full sort: ${name}`, () => {
|
|
56
|
+
const rows = uniqueRows(100);
|
|
57
|
+
const { store, ids } = makeStore(rows);
|
|
58
|
+
const got = store.select(["cell", "region", "rank"], { order });
|
|
59
|
+
const expected = referenceSort(store, ids, order);
|
|
60
|
+
expect(got).toEqual(expected);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
it("matches a naive full sort with a where filter (cell asc, rank asc)", () => {
|
|
64
|
+
const rows = uniqueRows(100);
|
|
65
|
+
const { store, ids } = makeStore(rows);
|
|
66
|
+
const order = { cell: true, rank: true };
|
|
67
|
+
const got = store.select(["cell", "region", "rank"], { where: { rank: { ">=": 50 } }, order });
|
|
68
|
+
const expected = referenceSort(store, ids, order, (r) => r.rank >= 50);
|
|
69
|
+
expect(got).toEqual(expected);
|
|
70
|
+
});
|
|
71
|
+
it("large K (many distinct partition values) still matches — exercises bucketing at scale", () => {
|
|
72
|
+
// Distinct cell per entity → one bucket each; sole partition order key is
|
|
73
|
+
// the O(N) path (no within-bucket sort).
|
|
74
|
+
const rows = Array.from({ length: 200 }, (_, i) => ({ cell: i, region: 0, rank: i }));
|
|
75
|
+
const { store, ids } = makeStore(rows);
|
|
76
|
+
const order = { cell: true };
|
|
77
|
+
expect(store.select(["cell", "region", "rank"], { order })).toEqual(referenceSort(store, ids, order));
|
|
78
|
+
});
|
|
79
|
+
it("with ties on the sole partition key, output is correctly ordered and a permutation of the input", () => {
|
|
80
|
+
// Many entities share each cell value → ties the reference can't
|
|
81
|
+
// disambiguate; assert the weaker invariants instead.
|
|
82
|
+
const rows = Array.from({ length: 60 }, (_, i) => ({ cell: i % 4, region: 0, rank: i }));
|
|
83
|
+
const { store, ids } = makeStore(rows);
|
|
84
|
+
const got = store.select(["cell", "region", "rank"], { order: { cell: true } });
|
|
85
|
+
// Non-decreasing by cell.
|
|
86
|
+
for (let i = 1; i < got.length; i++) {
|
|
87
|
+
expect(store.get(got[i - 1], "cell") <= store.get(got[i], "cell")).toBe(true);
|
|
88
|
+
}
|
|
89
|
+
// Same set of entities, none lost or duplicated.
|
|
90
|
+
expect([...got].sort((a, b) => a - b)).toEqual([...ids].sort((a, b) => a - b));
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
//# sourceMappingURL=select-entities.partition.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select-entities.partition.test.js","sourceRoot":"","sources":["../../../../src/ecs/store/core/select-entities.partition.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,9 +3,13 @@ import { ArchetypeQueryOptions } from "./core/core.js";
|
|
|
3
3
|
export type OrderClause<T extends object> = {
|
|
4
4
|
[K in keyof T]?: boolean;
|
|
5
5
|
};
|
|
6
|
-
export type EntitySelectOptions<C extends object, T extends object> = ArchetypeQueryOptions<C> & {
|
|
6
|
+
export type EntitySelectOptions<C extends object, T extends object> = Omit<ArchetypeQueryOptions<C>, "where"> & {
|
|
7
7
|
/**
|
|
8
8
|
* Filter the results by the given condition using a declarative where clause.
|
|
9
|
+
* This is a *row-level* {@link Filter} (supports comparison operators),
|
|
10
|
+
* distinct from `ArchetypeQueryOptions.where`, which is archetype-level
|
|
11
|
+
* partition-value equality. Select owns row filtering, so it replaces the
|
|
12
|
+
* inherited partition `where` rather than intersecting with it.
|
|
9
13
|
*/
|
|
10
14
|
where?: Filter<T>;
|
|
11
15
|
/**
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { StringKeyof } from "../../types/types.js";
|
|
2
|
+
import { ComponentSchemas } from "../component-schemas.js";
|
|
3
|
+
import { RequiredComponents } from "../required-components.js";
|
|
4
|
+
import { Archetype } from "../archetype/archetype.js";
|
|
5
|
+
/**
|
|
6
|
+
* The component keys of a schema map that are declared `partition: true`.
|
|
7
|
+
*
|
|
8
|
+
* Detection is at the *schema* level, where the marker survives — the resolved
|
|
9
|
+
* component value map (`FromSchemas<CS>`) has already dropped it. Requires the
|
|
10
|
+
* schema literal to be `as const` so `partition` is the literal `true`, not
|
|
11
|
+
* `boolean` (the project's `... as const satisfies Schema` idiom guarantees it).
|
|
12
|
+
*/
|
|
13
|
+
export type PartitionKeysOf<CS extends ComponentSchemas> = {
|
|
14
|
+
[K in StringKeyof<CS>]: CS[K] extends {
|
|
15
|
+
partition: true;
|
|
16
|
+
} ? K : never;
|
|
17
|
+
}[StringKeyof<CS>];
|
|
18
|
+
/**
|
|
19
|
+
* Whether a component-key set intersects the store's partition keys.
|
|
20
|
+
*
|
|
21
|
+
* The `[PK] extends [never]` guard is load-bearing: when a store declares no
|
|
22
|
+
* partition components (`PK = never` — the default everywhere), this collapses
|
|
23
|
+
* to `false` *without* inspecting `Keys`. That matters because `Keys` is often a
|
|
24
|
+
* generic indexed access (`A[K][number]` inside a `TransactionContext<C,R,A>`);
|
|
25
|
+
* `Extract<GenericKeys, never>` would otherwise stay a *deferred* conditional,
|
|
26
|
+
* leaving `store.archetypes.<K>` as the unresolved union `Archetype.Router | Archetype`
|
|
27
|
+
* and breaking assignability in every generic store context. Short-circuiting
|
|
28
|
+
* on `PK` keeps non-partition stores paying nothing and resolving eagerly.
|
|
29
|
+
*/
|
|
30
|
+
type IsAny<T> = boolean extends (T extends never ? true : false) ? true : false;
|
|
31
|
+
export type HasPartitionKey<Keys extends string, PK extends string> = [
|
|
32
|
+
PK
|
|
33
|
+
] extends [never] ? false : IsAny<PK> extends true ? boolean : [Extract<Keys, PK>] extends [never] ? false : true;
|
|
34
|
+
/**
|
|
35
|
+
* The `store.archetypes.<Name>` handle for one declared archetype: a
|
|
36
|
+
* {@link Archetype.Router} when it includes a partition component, else the
|
|
37
|
+
* `Concrete` archetype type (`Archetype` or `ReadonlyArchetype`, supplied by the
|
|
38
|
+
* caller). `Has` is a *naked* type parameter so a `boolean` (from `PK = any`)
|
|
39
|
+
* distributes to `Archetype.Router<C> | Concrete`.
|
|
40
|
+
*/
|
|
41
|
+
export type ArchetypeOrRouter<Has extends boolean, C extends RequiredComponents, Concrete> = Has extends true ? Archetype.Router<C> : Concrete;
|
|
42
|
+
/**
|
|
43
|
+
* Return type of `ensureArchetype(keys, values?)`:
|
|
44
|
+
* - a value is supplied → a concrete {@link Archetype} (the resolved member),
|
|
45
|
+
* regardless of partitioning — this is the same-value fast path;
|
|
46
|
+
* - else the key set includes a partition component → a {@link Archetype.Router} that
|
|
47
|
+
* routes each `insert` by the row's partition value;
|
|
48
|
+
* - else → a concrete {@link Archetype} (today's behavior, unchanged).
|
|
49
|
+
*
|
|
50
|
+
* When `Keys` is not statically known to include or exclude a partition
|
|
51
|
+
* component, `HasPartitionKey` stays a union and the result widens to
|
|
52
|
+
* `Archetype<C> | Archetype.Router<C>` — which still exposes `.insert` (both branches
|
|
53
|
+
* share it); only dense column access requires narrowing to `Archetype`.
|
|
54
|
+
*/
|
|
55
|
+
export type EnsureArchetypeResult<C extends RequiredComponents, Keys extends string, PK extends string, ValueProvided extends boolean> = ValueProvided extends true ? Archetype<C> : HasPartitionKey<Keys, PK> extends true ? Archetype.Router<C> : Archetype<C>;
|
|
56
|
+
/**
|
|
57
|
+
* Type of `store.archetypes.<Name>`: a {@link Archetype.Router} when the declared archetype
|
|
58
|
+
* includes a partition component, else a concrete {@link Archetype}. The keys are
|
|
59
|
+
* statically known here (from the schema's `archetypes` map), so this never
|
|
60
|
+
* widens to a union — the discrimination is exact per declared name.
|
|
61
|
+
*/
|
|
62
|
+
export type StoreArchetypeHandle<C extends RequiredComponents, Keys extends string, PK extends string> = HasPartitionKey<Keys, PK> extends true ? Archetype.Router<C> : Archetype<C>;
|
|
63
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"partition.js","sourceRoot":"","sources":["../../../src/ecs/store/partition.ts"],"names":[],"mappings":"AAAA,uDAAuD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// © 2026 Adobe. MIT License. See /LICENSE for details.
|
|
2
|
+
// A Router can insert (routing write) ...
|
|
3
|
+
router.insert({ cell: 1, position: 2 });
|
|
4
|
+
// ... but exposes no dense view:
|
|
5
|
+
// @ts-expect-error - a family has no single dense column view
|
|
6
|
+
router.columns;
|
|
7
|
+
// @ts-expect-error - a family has no row count
|
|
8
|
+
router.rowCount;
|
|
9
|
+
handle.insert({ cell: 1, position: 2 });
|
|
10
|
+
// ... while dense access is correctly gated behind resolving to a concrete
|
|
11
|
+
// archetype (supply a value, or narrow):
|
|
12
|
+
// @ts-expect-error - .columns requires a concrete Archetype, not a possible family
|
|
13
|
+
handle.columns;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=partition.type-test.js.map
|