Skip to content

Commit

Permalink
feat: on-chain sql queries in MUD
Browse files Browse the repository at this point in the history
  • Loading branch information
yonadaaa committed May 19, 2023
1 parent 76be5d2 commit 9050977
Show file tree
Hide file tree
Showing 12 changed files with 702 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ export type StringStructStruct = { value: PromiseOrValue<string> };

export type StringStructStructOutput = [string] & { value: string };

export type MoreStructStruct = {
selectionType: PromiseOrValue<BigNumberish>;
fieldIndex: PromiseOrValue<BigNumberish>;
value: PromiseOrValue<BytesLike>;
};

export type MoreStructStructOutput = [number, number, string] & {
selectionType: number;
fieldIndex: number;
value: string;
};

export interface IWorldInterface extends utils.Interface {
functions: {
"call(bytes16,bytes16,bytes)": FunctionFragment;
Expand All @@ -57,6 +69,7 @@ export interface IWorldInterface extends utils.Interface {
"installModule(address,bytes)": FunctionFragment;
"installRootModule(address,bytes)": FunctionFragment;
"isStore()": FunctionFragment;
"moreStruct(bytes32,uint8[],(uint8,uint8,bytes)[])": FunctionFragment;
"pickUp(uint32,uint32)": FunctionFragment;
"popFromField(bytes16,bytes16,bytes32[],uint8,uint256)": FunctionFragment;
"popFromField(bytes32,bytes32[],uint8,uint256)": FunctionFragment;
Expand Down Expand Up @@ -108,6 +121,7 @@ export interface IWorldInterface extends utils.Interface {
| "installModule"
| "installRootModule"
| "isStore"
| "moreStruct"
| "pickUp"
| "popFromField(bytes16,bytes16,bytes32[],uint8,uint256)"
| "popFromField(bytes32,bytes32[],uint8,uint256)"
Expand Down Expand Up @@ -249,6 +263,14 @@ export interface IWorldInterface extends utils.Interface {
values: [PromiseOrValue<string>, PromiseOrValue<BytesLike>]
): string;
encodeFunctionData(functionFragment: "isStore", values?: undefined): string;
encodeFunctionData(
functionFragment: "moreStruct",
values: [
PromiseOrValue<BytesLike>,
PromiseOrValue<BigNumberish>[],
MoreStructStruct[]
]
): string;
encodeFunctionData(
functionFragment: "pickUp",
values: [PromiseOrValue<BigNumberish>, PromiseOrValue<BigNumberish>]
Expand Down Expand Up @@ -527,6 +549,7 @@ export interface IWorldInterface extends utils.Interface {
data: BytesLike
): Result;
decodeFunctionResult(functionFragment: "isStore", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "moreStruct", data: BytesLike): Result;
decodeFunctionResult(functionFragment: "pickUp", data: BytesLike): Result;
decodeFunctionResult(
functionFragment: "popFromField(bytes16,bytes16,bytes32[],uint8,uint256)",
Expand Down Expand Up @@ -849,6 +872,13 @@ export interface IWorld extends BaseContract {

isStore(overrides?: CallOverrides): Promise<[void]>;

moreStruct(
tableId: PromiseOrValue<BytesLike>,
projectionFieldIndices: PromiseOrValue<BigNumberish>[],
arg2: MoreStructStruct[],
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<ContractTransaction>;

pickUp(
item: PromiseOrValue<BigNumberish>,
itemVariant: PromiseOrValue<BigNumberish>,
Expand Down Expand Up @@ -1171,6 +1201,13 @@ export interface IWorld extends BaseContract {

isStore(overrides?: CallOverrides): Promise<void>;

moreStruct(
tableId: PromiseOrValue<BytesLike>,
projectionFieldIndices: PromiseOrValue<BigNumberish>[],
arg2: MoreStructStruct[],
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<ContractTransaction>;

pickUp(
item: PromiseOrValue<BigNumberish>,
itemVariant: PromiseOrValue<BigNumberish>,
Expand Down Expand Up @@ -1491,6 +1528,13 @@ export interface IWorld extends BaseContract {

isStore(overrides?: CallOverrides): Promise<void>;

moreStruct(
tableId: PromiseOrValue<BytesLike>,
projectionFieldIndices: PromiseOrValue<BigNumberish>[],
arg2: MoreStructStruct[],
overrides?: CallOverrides
): Promise<void>;

pickUp(
item: PromiseOrValue<BigNumberish>,
itemVariant: PromiseOrValue<BigNumberish>,
Expand Down Expand Up @@ -1858,6 +1902,13 @@ export interface IWorld extends BaseContract {

isStore(overrides?: CallOverrides): Promise<BigNumber>;

moreStruct(
tableId: PromiseOrValue<BytesLike>,
projectionFieldIndices: PromiseOrValue<BigNumberish>[],
arg2: MoreStructStruct[],
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<BigNumber>;

pickUp(
item: PromiseOrValue<BigNumberish>,
itemVariant: PromiseOrValue<BigNumberish>,
Expand Down Expand Up @@ -2181,6 +2232,13 @@ export interface IWorld extends BaseContract {

isStore(overrides?: CallOverrides): Promise<PopulatedTransaction>;

moreStruct(
tableId: PromiseOrValue<BytesLike>,
projectionFieldIndices: PromiseOrValue<BigNumberish>[],
arg2: MoreStructStruct[],
overrides?: Overrides & { from?: PromiseOrValue<string> }
): Promise<PopulatedTransaction>;

pickUp(
item: PromiseOrValue<BigNumberish>,
itemVariant: PromiseOrValue<BigNumberish>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,46 @@ const _abi = [
stateMutability: "view",
type: "function",
},
{
inputs: [
{
internalType: "bytes32",
name: "tableId",
type: "bytes32",
},
{
internalType: "uint8[]",
name: "projectionFieldIndices",
type: "uint8[]",
},
{
components: [
{
internalType: "enum SelectionType",
name: "selectionType",
type: "uint8",
},
{
internalType: "uint8",
name: "fieldIndex",
type: "uint8",
},
{
internalType: "bytes",
name: "value",
type: "bytes",
},
],
internalType: "struct MoreStruct[]",
name: "",
type: "tuple[]",
},
],
name: "moreStruct",
outputs: [],
stateMutability: "nonpayable",
type: "function",
},
{
inputs: [
{
Expand Down
5 changes: 5 additions & 0 deletions packages/world/mud.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ export default mudConfig({
schema: "address[]",
tableIdArgument: true,
},
Customer: {
directory: "../test/tables",
schema: { balance: "uint32", name: "string" },
tableIdArgument: true,
},
},
enums: {
Resource: ["NONE", "NAMESPACE", "TABLE", "SYSTEM"],
Expand Down
1 change: 1 addition & 0 deletions packages/world/src/Tables.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ import { UsedKeysIndex, UsedKeysIndexTableId } from "./modules/keysintable/table
import { UniqueEntity } from "./modules/uniqueentity/tables/UniqueEntity.sol";
import { Bool } from "./../test/tables/Bool.sol";
import { AddressArray } from "./../test/tables/AddressArray.sol";
import { Customer, CustomerData } from "./../test/tables/Customer.sol";
4 changes: 3 additions & 1 deletion packages/world/src/interfaces/IBaseWorld.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { IAccessManagementSystem } from "./IAccessManagementSystem.sol";
import { IEphemeralRecordSystem } from "./IEphemeralRecordSystem.sol";
import { IModuleInstallationSystem } from "./IModuleInstallationSystem.sol";
import { IWorldRegistrationSystem } from "./IWorldRegistrationSystem.sol";
import { IQuerySystem } from "./IQuerySystem.sol";

/**
* The IBaseWorld interface includes all systems dynamically added to the World
Expand All @@ -23,7 +24,8 @@ interface IBaseWorld is
IAccessManagementSystem,
IEphemeralRecordSystem,
IModuleInstallationSystem,
IWorldRegistrationSystem
IWorldRegistrationSystem,
IQuerySystem
{

}
16 changes: 16 additions & 0 deletions packages/world/src/interfaces/IQuerySystem.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

/* Autogenerated file. Do not edit manually. */

import { IStore } from "@latticexyz/store/src/IStore.sol";
import { SelectionFragment, Record } from "./../modules/query/systems/structs.sol";

interface IQuerySystem {
function query(
IStore store,
bytes32 tableId,
uint8[] memory projectionFieldIndices,
SelectionFragment[] memory fragments
) external view returns (Record[] memory records);
}
68 changes: 68 additions & 0 deletions packages/world/src/modules/query/systems/QuerySystem.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import { IStore } from "@latticexyz/store/src/IStore.sol";
import { System } from "../../../System.sol";
import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol";
import { getKeysInTable } from "../../keysintable/getKeysInTable.sol";
import { Record, SelectionFragment, SelectionType } from "./structs.sol";

function isEqual(bytes memory a, bytes memory b) pure returns (bool) {
return keccak256(a) == keccak256(b);
}

function passesSelectionFragment(SelectionFragment memory fragment, bytes memory value) pure returns (bool) {
if (fragment.selectionType == SelectionType.Equal && !isEqual(fragment.value, value)) {
return false;
}
if (fragment.selectionType == SelectionType.NotEqual && isEqual(fragment.value, value)) {
return false;
}

return true;
}

// This implements SQL-style queries like:
// SELECT * FROM table WHERE name=""
contract QuerySystem is System {
function query(
IStore store,
bytes32 tableId,
uint8[] memory projectionFieldIndices,
SelectionFragment[] memory fragments
) public view returns (Record[] memory records) {
bytes32[][] memory keys = getKeysInTable(store, tableId);

records = new Record[](0);

for (uint256 i; i < keys.length; i++) {
bool passes = true;
for (uint256 j; j < fragments.length; j++) {
bytes memory blob = store.getField(tableId, keys[i], fragments[j].fieldIndex);

if (!passesSelectionFragment(fragments[j], blob)) {
passes = false;
break;
}
}

if (passes) {
// Increase the length of array
uint256 length = records.length;

Record[] memory newRecords = new Record[](length + 1);
for (uint256 k; k < length; k++) {
newRecords[k] = records[k];
}
records = newRecords;

records[length].key = keys[i];
records[length].value = new bytes[](projectionFieldIndices.length);

for (uint256 j; j < projectionFieldIndices.length; j++) {
records[length].value[j] = store.getField(tableId, keys[i], projectionFieldIndices[j]);
}
}
}
}
}
18 changes: 18 additions & 0 deletions packages/world/src/modules/query/systems/structs.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

enum SelectionType {
Equal,
NotEqual
}

struct SelectionFragment {
SelectionType selectionType;
uint8 fieldIndex;
bytes value;
}

struct Record {
bytes32[] key;
bytes[] value;
}
16 changes: 16 additions & 0 deletions packages/world/src/modules/query/world/IQuerySystem.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

/* Autogenerated file. Do not edit manually. */

import { IStore } from "@latticexyz/store/src/IStore.sol";
import { SelectionFragment, Record } from "../systems/structs.sol";

interface IQuerySystem {
function query_system_query(
IStore store,
bytes32 tableId,
uint8[] memory projectionFieldIndices,
SelectionFragment[] memory fragments
) external view returns (Record[] memory records);
}
16 changes: 16 additions & 0 deletions packages/world/src/modules/query/world/IWorld.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

/* Autogenerated file. Do not edit manually. */

import { IBaseWorld } from "../../../interfaces/IBaseWorld.sol";

import { IQuerySystem } from "./IQuerySystem.sol";

/**
* The IWorld interface includes all systems dynamically added to the World
* during the deploy process.
*/
interface IWorld is IBaseWorld, IQuerySystem {

}
Loading

0 comments on commit 9050977

Please sign in to comment.