Skip to content

Commit ee9a44b

Browse files
feat: support nested
1 parent ae875c8 commit ee9a44b

File tree

4 files changed

+244
-38
lines changed

4 files changed

+244
-38
lines changed

packages/sdk/src/__tests__/parseEntities.test.ts

+197-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { describe, it, expect } from "vitest";
2-
import { parseEntities } from "../getEntities";
32
import { SchemaType } from "../types";
43
import * as torii from "@dojoengine/torii-client";
4+
import { parseEntities } from "../parseEntities";
55

66
// Mock SchemaType for testing
77
interface TestSchema extends SchemaType {
@@ -197,4 +197,200 @@ describe("parseEntities", () => {
197197
player: [{ id: "0x1", name: "Alice" }],
198198
});
199199
});
200+
201+
it("should handle nested entities", () => {
202+
const mockEntities: torii.Entities = {
203+
player: {
204+
"0x1": {
205+
id: {
206+
type: "primitive",
207+
type_name: "felt252",
208+
value: "0x1",
209+
key: true,
210+
},
211+
name: {
212+
type: "primitive",
213+
type_name: "felt252",
214+
value: "Alice",
215+
key: false,
216+
},
217+
score: {
218+
type: "primitive",
219+
type_name: "u32",
220+
value: 100,
221+
key: false,
222+
},
223+
inventory: {
224+
type: "struct",
225+
type_name: "Inventory",
226+
value: {
227+
item1: {
228+
type: "primitive",
229+
type_name: "felt252",
230+
value: "Sword",
231+
key: false,
232+
},
233+
item2: {
234+
type: "primitive",
235+
type_name: "felt252",
236+
value: "Shield",
237+
key: false,
238+
},
239+
},
240+
key: false,
241+
},
242+
},
243+
},
244+
};
245+
246+
const query: { [P in keyof TestSchema]?: Partial<TestSchema[P]> } = {
247+
player: {},
248+
};
249+
250+
const result = parseEntities<TestSchema, keyof TestSchema>(
251+
mockEntities,
252+
query
253+
);
254+
255+
expect(result).toEqual({
256+
player: [
257+
{
258+
id: "0x1",
259+
name: "Alice",
260+
score: 100,
261+
inventory: {
262+
item1: "Sword",
263+
item2: "Shield",
264+
},
265+
},
266+
],
267+
});
268+
});
269+
270+
it("should handle entities with array fields", () => {
271+
const mockEntities: torii.Entities = {
272+
player: {
273+
"0x1": {
274+
id: {
275+
type: "primitive",
276+
type_name: "felt252",
277+
value: "0x1",
278+
key: true,
279+
},
280+
name: {
281+
type: "primitive",
282+
type_name: "felt252",
283+
value: "Alice",
284+
key: false,
285+
},
286+
score: {
287+
type: "primitive",
288+
type_name: "u32",
289+
value: 100,
290+
key: false,
291+
},
292+
achievements: {
293+
type: "array",
294+
type_name: "felt252",
295+
value: [
296+
{
297+
type: "primitive",
298+
type_name: "felt252",
299+
value: "First Blood",
300+
key: false,
301+
},
302+
{
303+
type: "primitive",
304+
type_name: "felt252",
305+
value: "Monster Hunter",
306+
key: false,
307+
},
308+
],
309+
key: false,
310+
},
311+
},
312+
},
313+
};
314+
315+
const query: { [P in keyof TestSchema]?: Partial<TestSchema[P]> } = {
316+
player: {},
317+
};
318+
319+
const result = parseEntities<TestSchema, keyof TestSchema>(
320+
mockEntities,
321+
query
322+
);
323+
324+
expect(result).toEqual({
325+
player: [
326+
{
327+
id: "0x1",
328+
name: "Alice",
329+
score: 100,
330+
achievements: ["First Blood", "Monster Hunter"],
331+
},
332+
],
333+
});
334+
});
335+
336+
it("should handle entities with enum fields", () => {
337+
const mockEntities: torii.Entities = {
338+
player: {
339+
"0x1": {
340+
id: {
341+
type: "primitive",
342+
type_name: "felt252",
343+
value: "0x1",
344+
key: true,
345+
},
346+
name: {
347+
type: "primitive",
348+
type_name: "felt252",
349+
value: "Alice",
350+
key: false,
351+
},
352+
score: {
353+
type: "primitive",
354+
type_name: "u32",
355+
value: 100,
356+
key: false,
357+
},
358+
status: {
359+
type: "enum",
360+
type_name: "Status",
361+
value: {
362+
option: "Online",
363+
value: {
364+
type: "primitive",
365+
type_name: "felt252",
366+
value: "Online",
367+
key: false,
368+
},
369+
},
370+
key: false,
371+
},
372+
},
373+
},
374+
};
375+
376+
const query: { [P in keyof TestSchema]?: Partial<TestSchema[P]> } = {
377+
player: {},
378+
};
379+
380+
const result = parseEntities<TestSchema, keyof TestSchema>(
381+
mockEntities,
382+
query
383+
);
384+
385+
expect(result).toEqual({
386+
player: [
387+
{
388+
id: "0x1",
389+
name: "Alice",
390+
score: 100,
391+
status: "Online",
392+
},
393+
],
394+
});
395+
});
200396
});

packages/sdk/src/getEntities.ts

+1-33
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,8 @@
11
import { convertQueryToClause } from "./convertQuerytoClause";
2+
import { parseEntities } from "./parseEntities";
23
import { SchemaType } from "./types";
34
import * as torii from "@dojoengine/torii-client";
45

5-
export function parseEntities<T extends SchemaType, K extends keyof T>(
6-
entities: torii.Entities,
7-
query: { [P in K]?: Partial<T[P]> }
8-
): { [P in K]: T[P][] } {
9-
const result = {} as { [P in K]: T[P][] };
10-
11-
for (const modelName in query) {
12-
if (entities[modelName]) {
13-
result[modelName as K] = Object.values(entities[modelName]).map(
14-
(entity) => {
15-
const parsedEntity = {} as T[K];
16-
for (const key in entity) {
17-
const value = entity[key];
18-
if (
19-
value &&
20-
typeof value === "object" &&
21-
"value" in value
22-
) {
23-
parsedEntity[key as keyof T[K]] =
24-
value.value as any;
25-
}
26-
}
27-
return parsedEntity;
28-
}
29-
);
30-
} else {
31-
result[modelName as K] = [];
32-
}
33-
}
34-
35-
return result;
36-
}
37-
386
export async function getEntities<T extends SchemaType, K extends keyof T>(
397
client: torii.ToriiClient,
408
query: { [P in K]?: Partial<T[P]> },

packages/sdk/src/parseEntities.ts

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { SchemaType } from "./types";
2+
import * as torii from "@dojoengine/torii-client";
3+
4+
function parseValue(value: torii.Ty): any {
5+
if (value.type === "primitive") {
6+
return value.value;
7+
} else if (value.type === "struct") {
8+
return parseStruct(value.value as Record<string, torii.Ty>);
9+
} else if (value.type === "enum") {
10+
return (value.value as torii.EnumValue).option;
11+
} else if (value.type === "array") {
12+
return (value.value as torii.Ty[]).map(parseValue);
13+
}
14+
return value.value;
15+
}
16+
17+
function parseStruct(struct: Record<string, torii.Ty>): any {
18+
const result: any = {};
19+
for (const key in struct) {
20+
result[key] = parseValue(struct[key]);
21+
}
22+
return result;
23+
}
24+
25+
export function parseEntities<T extends SchemaType, K extends keyof T>(
26+
entities: torii.Entities,
27+
query: { [P in K]?: Partial<T[P]> }
28+
): { [P in K]: T[P][] } {
29+
const result = {} as { [P in K]: T[P][] };
30+
31+
for (const modelName in query) {
32+
if (entities[modelName]) {
33+
result[modelName as K] = Object.values(entities[modelName]).map(
34+
(entity) => {
35+
return parseStruct(entity) as T[K];
36+
}
37+
);
38+
} else {
39+
result[modelName as K] = [];
40+
}
41+
}
42+
43+
return result;
44+
}

packages/sdk/src/subscribeQuery.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
import * as torii from "@dojoengine/torii-client";
22
import { convertQueryToClauses } from "./convertQueryToClauses";
33
import { SchemaType } from "./types";
4-
import { parseEntities } from "./getEntities";
4+
import { parseEntities } from "./parseEntities";
55

66
export async function subscribeQuery<T extends SchemaType, K extends keyof T>(
77
client: torii.ToriiClient,
88
query: { [P in K]?: Partial<T[P]> },
99
callback: (response: { data?: { [P in K]: T[P][] }; error?: Error }) => void
1010
): Promise<torii.Subscription> {
11-
const clauses = convertQueryToClauses(query);
12-
1311
return client.onEntityUpdated(
14-
clauses,
12+
convertQueryToClauses(query),
1513
(_entities: string, data: torii.Entities) => {
1614
try {
1715
callback({ data: parseEntities<T, K>(data, query) });

0 commit comments

Comments
 (0)