Skip to content

Commit

Permalink
feat: add ToriiQueryBuilder and ClauseBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
MartianGreed committed Jan 17, 2025
1 parent 49cca3b commit 8c138db
Show file tree
Hide file tree
Showing 11 changed files with 727 additions and 31 deletions.
15 changes: 15 additions & 0 deletions .changeset/witty-moons-care.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
"@dojoengine/sdk": patch
"@dojoengine/core": patch
"@dojoengine/create-burner": patch
"@dojoengine/create-dojo": patch
"@dojoengine/predeployed-connector": patch
"@dojoengine/react": patch
"@dojoengine/state": patch
"@dojoengine/torii-client": patch
"@dojoengine/torii-wasm": patch
"@dojoengine/utils": patch
"@dojoengine/utils-wasm": patch
---

Added experimental ToriiQueryBuilder and ClauseBuilder to be closer to how we should query ECS through torii
2 changes: 1 addition & 1 deletion examples/example-vite-react-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:
w

- [@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
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
Expand Down
22 changes: 21 additions & 1 deletion examples/example-vite-react-sdk/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,26 @@ function App() {
return BigInt(0);
}, [account]);

// This is experimental feature.
// Use those queries if you want to be closer to how you should query your ecs system with torii
// useEffect(() => {
// async function fetchToriiClause() {
// const res = await sdk.client.getEntities(
// new ToriiQueryBuilder()
// .withClause(
// new ClauseBuilder()
// .keys([], [undefined], "VariableLen")
// .build()
// )
// .withLimit(2)
// .addOrderBy(ModelsMapping.Moves, "remaining", "Desc")
// .build()
// );
// return res;
// }
// fetchToriiClause().then(console.log);
// });

useEffect(() => {
let unsubscribe: (() => void) | undefined;

Expand Down Expand Up @@ -248,7 +268,7 @@ function App() {
className="text-gray-300"
>
<td className="border border-gray-700 p-2">
{entityId}
{addAddressPadding(entityId)}
</td>
<td className="border border-gray-700 p-2">
{position?.player ?? "N/A"}
Expand Down
1 change: 0 additions & 1 deletion examples/example-vite-react-sdk/src/useSystemCalls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ export const useSystemCalls = () => {
const state = useDojoStore((state) => state);

const { account } = useAccount();

/**
* Generates a unique entity ID based on the current account address.
* @returns {string} The generated entity ID
Expand Down
211 changes: 211 additions & 0 deletions packages/sdk/src/__tests__/clauseBuilder.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
import { describe, expect, it } from "vitest";
import { ClauseBuilder } from "../clauseBuilder";
import {
ComparisonOperator,
LogicalOperator,
PatternMatching,
} from "@dojoengine/torii-client";
import { SchemaType } from "../types";

// Test models interface
interface TestModels extends SchemaType {
dojo_starter: {
Moves: {
fieldOrder: string[];
remaining: number;
player: string;
};
Position: {
fieldOrder: string[];
x: number;
y: number;
};
GameState: {
fieldOrder: string[];
active: boolean;
score: number;
gameId: string;
};
};
}

describe("ClauseBuilder", () => {
describe("whereKeys", () => {
it("should create a Keys clause with default pattern matching", () => {
const builder = new ClauseBuilder<TestModels>();
const clause = builder
.keys(["dojo_starter-Moves"], ["player1"])
.build();

expect(clause).toEqual({
Keys: {
keys: ["player1"],
pattern_matching: "FixedLen" as PatternMatching,
models: ["dojo_starter-Moves"],
},
});
});

it("should create a Keys clause with custom pattern matching", () => {
const builder = new ClauseBuilder<TestModels>();
const clause = builder
.keys(["dojo_starter-Moves"], ["player1"], "VariableLen")
.build();

expect(clause).toEqual({
Keys: {
keys: ["player1"],
pattern_matching: "VariableLen" as PatternMatching,
models: ["dojo_starter-Moves"],
},
});
});
});

describe("where", () => {
it("should create a Member clause with number value", () => {
const builder = new ClauseBuilder<TestModels>();
const clause = builder
.where("dojo_starter-Moves", "remaining", "Gt", 10)
.build();

expect(clause).toEqual({
Member: {
model: "dojo_starter-Moves",
member: "remaining",
operator: "Gt" as ComparisonOperator,
value: { Primitive: { U32: 10 } },
},
});
});

it("should create a Member clause with string value", () => {
const builder = new ClauseBuilder<TestModels>();
const clause = builder
.where("dojo_starter-Moves", "player", "Eq", "player1")
.build();

expect(clause).toEqual({
Member: {
model: "dojo_starter-Moves",
member: "player",
operator: "Eq" as ComparisonOperator,
value: { String: "player1" },
},
});
});
});

describe("compose", () => {
it("should create a composite OR then AND clause", () => {
const clause = new ClauseBuilder<TestModels>()
.compose()
.or([
new ClauseBuilder<TestModels>().where(
"dojo_starter-Position",
"x",
"Gt",
0
),
new ClauseBuilder<TestModels>().where(
"dojo_starter-Position",
"y",
"Gt",
0
),
])
.and([
new ClauseBuilder<TestModels>().where(
"dojo_starter-GameState",
"active",
"Eq",
true
),
])
.build();

expect(clause).toEqual({
Composite: {
operator: "And",
clauses: [
{
Member: {
model: "dojo_starter-GameState",
member: "active",
operator: "Eq" as ComparisonOperator,
value: { Primitive: { Bool: true } },
},
},
{
Composite: {
operator: "Or",
clauses: [
{
Member: {
model: "dojo_starter-Position",
member: "x",
operator:
"Gt" as ComparisonOperator,
value: { Primitive: { U32: 0 } },
},
},
{
Member: {
model: "dojo_starter-Position",
member: "y",
operator:
"Gt" as ComparisonOperator,
value: { Primitive: { U32: 0 } },
},
},
],
},
},
],
},
});
});

it("should handle single composite operation", () => {
const builder = new ClauseBuilder<TestModels>();
const clauseA = new ClauseBuilder<TestModels>().where(
"dojo_starter-Position",
"x",
"Gt",
0
);
const clauseB = new ClauseBuilder<TestModels>().where(
"dojo_starter-Position",
"y",
"Gt",
0
);

const clause = builder.compose().or([clauseA, clauseB]).build();

expect(clause).toEqual({
Composite: {
operator: "Or",
clauses: [
{
Member: {
model: "dojo_starter-Position",
member: "x",
operator: "Gt" as ComparisonOperator,
value: { Primitive: { U32: 0 } },
},
},
{
Member: {
model: "dojo_starter-Position",
member: "y",
operator: "Gt" as ComparisonOperator,
value: { Primitive: { U32: 0 } },
},
},
],
},
});
});
});
});
Loading

0 comments on commit 8c138db

Please sign in to comment.