Skip to content

Commit b974a50

Browse files
committed
feat: add ToriiQueryBuilder and ClauseBuilder
1 parent 49cca3b commit b974a50

File tree

10 files changed

+726
-71
lines changed

10 files changed

+726
-71
lines changed

.changeset/witty-moons-care.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
"@dojoengine/sdk": patch
3+
"@dojoengine/core": patch
4+
"@dojoengine/create-burner": patch
5+
"@dojoengine/create-dojo": patch
6+
"@dojoengine/predeployed-connector": patch
7+
"@dojoengine/react": patch
8+
"@dojoengine/state": patch
9+
"@dojoengine/torii-client": patch
10+
"@dojoengine/torii-wasm": patch
11+
"@dojoengine/utils": patch
12+
"@dojoengine/utils-wasm": patch
13+
---
14+
15+
Added experimental ToriiQueryBuilder and ClauseBuilder to be closer to how we should query ECS through torii

examples/example-vite-react-sdk/README.md

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,45 +6,3 @@ Currently, two official plugins are available:
66

77
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
88
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9-
10-
## Expanding the ESLint configuration
11-
12-
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
13-
14-
- Configure the top-level `parserOptions` property like this:
15-
16-
```js
17-
export default tseslint.config({
18-
languageOptions: {
19-
// other options...
20-
parserOptions: {
21-
project: ["./tsconfig.node.json", "./tsconfig.app.json"],
22-
tsconfigRootDir: import.meta.dirname,
23-
},
24-
},
25-
});
26-
```
27-
28-
- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked`
29-
- Optionally add `...tseslint.configs.stylisticTypeChecked`
30-
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config:
31-
32-
```js
33-
// eslint.config.js
34-
import react from "eslint-plugin-react";
35-
36-
export default tseslint.config({
37-
// Set the react version
38-
settings: { react: { version: "18.3" } },
39-
plugins: {
40-
// Add the react plugin
41-
react,
42-
},
43-
rules: {
44-
// other rules...
45-
// Enable its recommended rules
46-
...react.configs.recommended.rules,
47-
...react.configs["jsx-runtime"].rules,
48-
},
49-
});
50-
```

examples/example-vite-react-sdk/src/App.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,26 @@ function App() {
3131
return BigInt(0);
3232
}, [account]);
3333

34+
// This is experimental feature.
35+
// Use those queries if you want to be closer to how you should query your ecs system with torii
36+
// useEffect(() => {
37+
// async function fetchToriiClause() {
38+
// const res = await sdk.client.getEntities(
39+
// new ToriiQueryBuilder()
40+
// .withClause(
41+
// new ClauseBuilder()
42+
// .keys([], [undefined], "VariableLen")
43+
// .build()
44+
// )
45+
// .withLimit(2)
46+
// .addOrderBy(ModelsMapping.Moves, "remaining", "Desc")
47+
// .build()
48+
// );
49+
// return res;
50+
// }
51+
// fetchToriiClause().then(console.log);
52+
// });
53+
3454
useEffect(() => {
3555
let unsubscribe: (() => void) | undefined;
3656

@@ -248,7 +268,7 @@ function App() {
248268
className="text-gray-300"
249269
>
250270
<td className="border border-gray-700 p-2">
251-
{entityId}
271+
{addAddressPadding(entityId)}
252272
</td>
253273
<td className="border border-gray-700 p-2">
254274
{position?.player ?? "N/A"}
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
import { describe, expect, it } from "vitest";
2+
import { ClauseBuilder } from "../clauseBuilder";
3+
import {
4+
ComparisonOperator,
5+
LogicalOperator,
6+
PatternMatching,
7+
} from "@dojoengine/torii-client";
8+
import { SchemaType } from "../types";
9+
10+
// Test models interface
11+
interface TestModels extends SchemaType {
12+
dojo_starter: {
13+
Moves: {
14+
fieldOrder: string[];
15+
remaining: number;
16+
player: string;
17+
};
18+
Position: {
19+
fieldOrder: string[];
20+
x: number;
21+
y: number;
22+
};
23+
GameState: {
24+
fieldOrder: string[];
25+
active: boolean;
26+
score: number;
27+
gameId: string;
28+
};
29+
};
30+
}
31+
32+
describe("ClauseBuilder", () => {
33+
describe("whereKeys", () => {
34+
it("should create a Keys clause with default pattern matching", () => {
35+
const builder = new ClauseBuilder<TestModels>();
36+
const clause = builder
37+
.keys(["dojo_starter-Moves"], ["player1"])
38+
.build();
39+
40+
expect(clause).toEqual({
41+
Keys: {
42+
keys: ["player1"],
43+
pattern_matching: "FixedLen" as PatternMatching,
44+
models: ["dojo_starter-Moves"],
45+
},
46+
});
47+
});
48+
49+
it("should create a Keys clause with custom pattern matching", () => {
50+
const builder = new ClauseBuilder<TestModels>();
51+
const clause = builder
52+
.keys(["dojo_starter-Moves"], ["player1"], "VariableLen")
53+
.build();
54+
55+
expect(clause).toEqual({
56+
Keys: {
57+
keys: ["player1"],
58+
pattern_matching: "VariableLen" as PatternMatching,
59+
models: ["dojo_starter-Moves"],
60+
},
61+
});
62+
});
63+
});
64+
65+
describe("where", () => {
66+
it("should create a Member clause with number value", () => {
67+
const builder = new ClauseBuilder<TestModels>();
68+
const clause = builder
69+
.where("dojo_starter-Moves", "remaining", "Gt", 10)
70+
.build();
71+
72+
expect(clause).toEqual({
73+
Member: {
74+
model: "dojo_starter-Moves",
75+
member: "remaining",
76+
operator: "Gt" as ComparisonOperator,
77+
value: { Primitive: { U32: 10 } },
78+
},
79+
});
80+
});
81+
82+
it("should create a Member clause with string value", () => {
83+
const builder = new ClauseBuilder<TestModels>();
84+
const clause = builder
85+
.where("dojo_starter-Moves", "player", "Eq", "player1")
86+
.build();
87+
88+
expect(clause).toEqual({
89+
Member: {
90+
model: "dojo_starter-Moves",
91+
member: "player",
92+
operator: "Eq" as ComparisonOperator,
93+
value: { String: "player1" },
94+
},
95+
});
96+
});
97+
});
98+
99+
describe("compose", () => {
100+
it("should create a composite OR then AND clause", () => {
101+
const clause = new ClauseBuilder<TestModels>()
102+
.compose()
103+
.or([
104+
new ClauseBuilder<TestModels>().where(
105+
"dojo_starter-Position",
106+
"x",
107+
"Gt",
108+
0
109+
),
110+
new ClauseBuilder<TestModels>().where(
111+
"dojo_starter-Position",
112+
"y",
113+
"Gt",
114+
0
115+
),
116+
])
117+
.and([
118+
new ClauseBuilder<TestModels>().where(
119+
"dojo_starter-GameState",
120+
"active",
121+
"Eq",
122+
true
123+
),
124+
])
125+
.build();
126+
127+
expect(clause).toEqual({
128+
Composite: {
129+
operator: "And",
130+
clauses: [
131+
{
132+
Member: {
133+
model: "dojo_starter-GameState",
134+
member: "active",
135+
operator: "Eq" as ComparisonOperator,
136+
value: { Primitive: { Bool: true } },
137+
},
138+
},
139+
{
140+
Composite: {
141+
operator: "Or",
142+
clauses: [
143+
{
144+
Member: {
145+
model: "dojo_starter-Position",
146+
member: "x",
147+
operator:
148+
"Gt" as ComparisonOperator,
149+
value: { Primitive: { U32: 0 } },
150+
},
151+
},
152+
{
153+
Member: {
154+
model: "dojo_starter-Position",
155+
member: "y",
156+
operator:
157+
"Gt" as ComparisonOperator,
158+
value: { Primitive: { U32: 0 } },
159+
},
160+
},
161+
],
162+
},
163+
},
164+
],
165+
},
166+
});
167+
});
168+
169+
it("should handle single composite operation", () => {
170+
const builder = new ClauseBuilder<TestModels>();
171+
const clauseA = new ClauseBuilder<TestModels>().where(
172+
"dojo_starter-Position",
173+
"x",
174+
"Gt",
175+
0
176+
);
177+
const clauseB = new ClauseBuilder<TestModels>().where(
178+
"dojo_starter-Position",
179+
"y",
180+
"Gt",
181+
0
182+
);
183+
184+
const clause = builder.compose().or([clauseA, clauseB]).build();
185+
186+
expect(clause).toEqual({
187+
Composite: {
188+
operator: "Or",
189+
clauses: [
190+
{
191+
Member: {
192+
model: "dojo_starter-Position",
193+
member: "x",
194+
operator: "Gt" as ComparisonOperator,
195+
value: { Primitive: { U32: 0 } },
196+
},
197+
},
198+
{
199+
Member: {
200+
model: "dojo_starter-Position",
201+
member: "y",
202+
operator: "Gt" as ComparisonOperator,
203+
value: { Primitive: { U32: 0 } },
204+
},
205+
},
206+
],
207+
},
208+
});
209+
});
210+
});
211+
});

0 commit comments

Comments
 (0)