Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(config,store,world): add namespaceLabel to table config #3039

Merged
merged 9 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/warm-carrots-compare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@latticexyz/config": patch
"@latticexyz/store-sync": patch
"@latticexyz/store": patch
"@latticexyz/world": patch
---

Add a strongly typed `namespaceLabel` to the table config output.
It corresponds to the `label` of the namespace the table belongs to and can't be set manually.
4 changes: 2 additions & 2 deletions packages/cli/src/deploy/getTables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import {
import { Schema, Table } from "@latticexyz/config";
import storeConfig from "@latticexyz/store/mud.config";

// TODO: add label once we register it onchain
type DeployedTable = Omit<Table, "label">;
// TODO: add label and namespaceLabel once we register it onchain
type DeployedTable = Omit<Table, "label" | "namespaceLabel">;

export async function getTables({
client,
Expand Down
1 change: 1 addition & 0 deletions packages/config/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export type Table = {
readonly label: string;
readonly type: satisfy<ResourceType, "table" | "offchainTable">;
readonly namespace: string;
readonly namespaceLabel: string;
readonly name: string;
readonly tableId: Hex;
readonly schema: Schema;
Expand Down
4 changes: 2 additions & 2 deletions packages/store-sync/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ export const internalTableIds = Object.values(mudTables).map((table) => table.ta
export type ChainId = number;
export type WorldId = `${ChainId}:${Address}`;

// TODO: add label once we register it onchain
export type DeployedTable = Omit<ConfigTable, "label">;
// TODO: add label and namespaceLabel once we register it onchain
export type DeployedTable = Omit<ConfigTable, "label" | "namespaceLabel">;

export type TableRecord<table extends DeployedTable = DeployedTable> = {
readonly key: getSchemaPrimitives<getKeySchema<table>>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ describe("createStorageAdapter", async () => {
"label": "Position",
"name": "Position",
"namespace": "",
"namespaceLabel": "",
"schema": {
"player": {
"internalType": "address",
Expand Down Expand Up @@ -113,6 +114,7 @@ describe("createStorageAdapter", async () => {
"label": "Position",
"name": "Position",
"namespace": "",
"namespaceLabel": "",
"schema": {
"player": {
"internalType": "address",
Expand Down Expand Up @@ -164,6 +166,7 @@ describe("createStorageAdapter", async () => {
"label": "Position",
"name": "Position",
"namespace": "",
"namespaceLabel": "",
"schema": {
"player": {
"internalType": "address",
Expand Down Expand Up @@ -215,6 +218,7 @@ describe("createStorageAdapter", async () => {
"label": "Position",
"name": "Position",
"namespace": "",
"namespaceLabel": "",
"schema": {
"player": {
"internalType": "address",
Expand Down
7 changes: 6 additions & 1 deletion packages/store/ts/config/v2/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ export type TableInput = {
* Defaults to the nearest namespace in the config or root namespace if not set.
*/
readonly namespace?: string;
/**
* Human-readable namespace label.
* Defaults to the nearest namespace in the config or root namespace if not set.
*/
readonly namespaceLabel?: string;
/**
* Table name used in table's resource ID.
* Defaults to the first 16 characters of `label` if not set.
Expand All @@ -47,7 +52,7 @@ export type TableShorthandInput = SchemaInput | string;
export type TablesInput = {
// remove label and namespace as these are set contextually
// and allow defining a table using shorthand
readonly [label: string]: Omit<TableInput, "label" | "namespace"> | TableShorthandInput;
readonly [label: string]: Omit<TableInput, "label" | "namespace" | "namespaceLabel"> | TableShorthandInput;
};

export type CodegenInput = Partial<Codegen>;
Expand Down
10 changes: 5 additions & 5 deletions packages/store/ts/config/v2/namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export type resolveNamespace<input, scope extends Scope = AbiTypeScope> = input
{
readonly [label in keyof input["tables"]]: mergeIfUndefined<
expandTableShorthand<input["tables"][label]>,
{ readonly namespace: string }
{ readonly namespace: string; readonly namespaceLabel: input["label"] }
>;
},
scope
Expand All @@ -49,14 +49,14 @@ export function resolveNamespace<const input extends NamespaceInput, scope exten
input: input,
scope: scope = AbiTypeScope as never,
): resolveNamespace<input, scope> {
const label = input.label;
const namespace = input.namespace ?? label.slice(0, 14);
const namespaceLabel = input.label;
const namespace = input.namespace ?? namespaceLabel.slice(0, 14);
Copy link
Member

@frolic frolic Aug 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we may wanna throw here instead of truncating?

I ran into this at some point where it's unclear if its okay to throw in resolve step, like as if it should happen in the validate step. But maybe its fine because its a "resolve error" because we're filling in and inferring info? Or maybe in this case, we can validate the namespaceLabel is <= 14 chars only if namespace isn't supplied too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added the validation logic including throwing to validateTable. Could throw here for sanity but we should be able to assume the input to resolveX is sufficiently validated

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah hadn't pushed yet. Opted for not throwing here for now and putting all validation in validateTable (we weren't throwing if namespace is too long here either)

return {
label,
label: namespaceLabel,
namespace,
tables: resolveTables(
flatMorph(input.tables ?? {}, (label, table) => {
return [label, mergeIfUndefined(expandTableShorthand(table, scope), { namespace })];
return [label, mergeIfUndefined(expandTableShorthand(table, scope), { namespace, namespaceLabel })];
}),
scope,
),
Expand Down
8 changes: 8 additions & 0 deletions packages/store/ts/config/v2/store.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ describe("defineStore", () => {
label: "Example",
type: "table",
namespace: "",
namespaceLabel: "",
name: "Example",
tableId: "0x746200000000000000000000000000004578616d706c65000000000000000000",
schema: {
Expand All @@ -47,6 +48,7 @@ describe("defineStore", () => {
label: "Example",
type: "table",
namespace: "",
namespaceLabel: "",
name: "Example",
tableId: "0x746200000000000000000000000000004578616d706c65000000000000000000",
schema: {
Expand Down Expand Up @@ -80,6 +82,7 @@ describe("defineStore", () => {
readonly Example: {
readonly label: "Example"
readonly type: "table"
readonly namespaceLabel: ""
readonly namespace: string
readonly name: string
readonly tableId: \`0x\${string}\`
Expand Down Expand Up @@ -113,6 +116,7 @@ describe("defineStore", () => {
readonly Example: {
readonly label: "Example"
readonly type: "table"
readonly namespaceLabel: ""
readonly namespace: string
readonly name: string
readonly tableId: \`0x\${string}\`
Expand Down Expand Up @@ -180,6 +184,7 @@ describe("defineStore", () => {
label: "Example",
type: "table",
namespace: "",
namespaceLabel: "root",
name: "Example",
tableId: "0x746200000000000000000000000000004578616d706c65000000000000000000",
schema: {
Expand All @@ -199,6 +204,7 @@ describe("defineStore", () => {
label: "Example",
type: "table",
namespace: "",
namespaceLabel: "root",
name: "Example",
tableId: "0x746200000000000000000000000000004578616d706c65000000000000000000",
schema: {
Expand Down Expand Up @@ -232,6 +238,7 @@ describe("defineStore", () => {
readonly Example: {
readonly label: "Example"
readonly type: "table"
readonly namespaceLabel: "root"
readonly namespace: string
readonly name: string
readonly tableId: \`0x\${string}\`
Expand Down Expand Up @@ -265,6 +272,7 @@ describe("defineStore", () => {
readonly root__Example: {
readonly label: "Example"
readonly type: "table"
readonly namespaceLabel: "root"
readonly namespace: string
readonly name: string
readonly tableId: \`0x\${string}\`
Expand Down
3 changes: 3 additions & 0 deletions packages/store/ts/config/v2/table.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ describe("resolveTable", () => {
label: "",
type: "table",
namespace: "" as string,
namespaceLabel: "",
name: "" as string,
tableId: resourceToHex({ type: "table", namespace: "", name: "" }),
schema: {
Expand All @@ -82,6 +83,7 @@ describe("resolveTable", () => {
label: "",
type: "table",
namespace: "" as string,
namespaceLabel: "",
name: "" as string,
tableId: resourceToHex({ type: "table", namespace: "", name: "" }),
schema: {
Expand Down Expand Up @@ -113,6 +115,7 @@ describe("resolveTable", () => {
label: "",
type: "table",
namespace: "" as string,
namespaceLabel: "",
name: "" as string,
tableId: resourceToHex({ type: "table", namespace: "", name: "" }),
schema: {
Expand Down
21 changes: 19 additions & 2 deletions packages/store/ts/config/v2/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,18 @@ export function validateTable<input, scope extends Scope = AbiTypeScope>(
if (hasOwnKey(input, "namespace") && typeof input.namespace === "string" && input.namespace.length > 14) {
throw new Error(`Table \`namespace\` must fit into a \`bytes14\`, but "${input.namespace}" is too long.`);
}

if (
hasOwnKey(input, "namespaceLabel") &&
typeof input.namespaceLabel === "string" &&
(!hasOwnKey(input, "namespace") || typeof input.namespace !== "string") &&
input.namespaceLabel.length > 14
) {
throw new Error(
`Table \`namespace\` defaults to \`namespaceLabel\`, but must fit into a \`bytes14\` and "${input.namespaceLabel}" is too long. Provide explicit \`namespace\` override.`,
);
}

if (hasOwnKey(input, "name") && typeof input.name === "string" && input.name.length > 16) {
throw new Error(`Table \`name\` must fit into a \`bytes16\`, but "${input.name}" is too long.`);
}
Expand Down Expand Up @@ -140,6 +152,9 @@ export type resolveTable<input, scope extends Scope = Scope> = input extends Tab
? {
readonly label: input["label"];
readonly type: undefined extends input["type"] ? typeof TABLE_DEFAULTS.type : input["type"];
readonly namespaceLabel: undefined extends input["namespaceLabel"]
? typeof TABLE_DEFAULTS.namespace
: input["namespaceLabel"];
readonly namespace: string;
readonly name: string;
readonly tableId: Hex;
Expand All @@ -156,16 +171,18 @@ export function resolveTable<input extends TableInput, scope extends Scope = Abi
input: input,
scope: scope = AbiTypeScope as unknown as scope,
): resolveTable<input, scope> {
const namespaceLabel = input.namespaceLabel ?? TABLE_DEFAULTS.namespace;
const namespace = input.namespace ?? namespaceLabel;
const label = input.label;
const type = input.type ?? TABLE_DEFAULTS.type;
const namespace = input.namespace ?? TABLE_DEFAULTS.namespace;
const name = input.name ?? label.slice(0, 16);
const type = input.type ?? TABLE_DEFAULTS.type;
const tableId = resourceToHex({ type, namespace, name });

return {
label,
type,
namespace,
namespaceLabel,
name,
tableId,
schema: resolveSchema(input.schema, scope),
Expand Down
8 changes: 8 additions & 0 deletions packages/world/ts/config/v2/world.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ describe("defineWorld", () => {
Example: {
label: "Example",
type: "table",
namespaceLabel: "",
namespace: "",
name: "Example",
tableId: "0x746200000000000000000000000000004578616d706c65000000000000000000",
Expand All @@ -163,6 +164,7 @@ describe("defineWorld", () => {
Example: {
label: "Example",
type: "table",
namespaceLabel: "",
namespace: "",
name: "Example",
tableId: "0x746200000000000000000000000000004578616d706c65000000000000000000",
Expand Down Expand Up @@ -205,6 +207,7 @@ describe("defineWorld", () => {
readonly Example: {
readonly label: "Example"
readonly type: "table"
readonly namespaceLabel: ""
readonly namespace: string
readonly name: string
readonly tableId: \`0x\${string}\`
Expand Down Expand Up @@ -255,6 +258,7 @@ describe("defineWorld", () => {
readonly Example: {
readonly label: "Example"
readonly type: "table"
readonly namespaceLabel: ""
readonly namespace: string
readonly name: string
readonly tableId: \`0x\${string}\`
Expand Down Expand Up @@ -324,6 +328,7 @@ describe("defineWorld", () => {
Example: {
label: "Example",
type: "table",
namespaceLabel: "root",
namespace: "",
name: "Example",
tableId: "0x746200000000000000000000000000004578616d706c65000000000000000000",
Expand All @@ -344,6 +349,7 @@ describe("defineWorld", () => {
root__Example: {
label: "Example",
type: "table",
namespaceLabel: "root",
namespace: "",
name: "Example",
tableId: "0x746200000000000000000000000000004578616d706c65000000000000000000",
Expand Down Expand Up @@ -386,6 +392,7 @@ describe("defineWorld", () => {
readonly root__Example: {
readonly label: "Example"
readonly type: "table"
readonly namespaceLabel: "root"
readonly namespace: string
readonly name: string
readonly tableId: \`0x\${string}\`
Expand Down Expand Up @@ -436,6 +443,7 @@ describe("defineWorld", () => {
readonly Example: {
readonly label: "Example"
readonly type: "table"
readonly namespaceLabel: "root"
readonly namespace: string
readonly name: string
readonly tableId: \`0x\${string}\`
Expand Down
Loading