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(store): add StoreMetadata table for table name and field names #428

Merged
merged 3 commits into from
Feb 28, 2023

Conversation

alvrs
Copy link
Member

@alvrs alvrs commented Feb 21, 2023

  • Adds an internal StoreMetadata table to store metadata like table name and field names.
  • Adds a setMetadata method to StoreCore, IStore and World (with access control based on table ownership)

@holic
Copy link
Member

holic commented Feb 21, 2023

Can we also add table names? (either here or in another PR)

@dk1a
Copy link
Contributor

dk1a commented Feb 22, 2023

I wonder if it'd be better to have a separate IStoreMetadata with its own METADATA_SCHEMA_TABLE, that's optionally called after the main registerSchema. This'd avoid polluting IStore and StoreCore, and allow for example renaming fields (registerSchema can't be called twice)
To validate lengths metadata can query the schema

@alvrs
Copy link
Member Author

alvrs commented Feb 22, 2023

I wonder if it'd be better to have a separate IStoreMetadata with its own METADATA_SCHEMA_TABLE, that's optionally called after the main registerSchema. This'd avoid polluting IStore and StoreCore, and allow for example renaming fields (registerSchema can't be called twice)
To validate lengths metadata can query the schema

Agree with storing it in a separate StoreMetadata table, updated the PR. Still think there should be a method on the store interface (setMetadata) to change the table metadata, since it's optional but still very elemental and setting it should be the default.

@alvrs alvrs changed the title feat(store): add optional field names to registerSchema feat(store): add StoreMetadata table for table name and field names Feb 22, 2023
dk1a
dk1a previously approved these changes Feb 22, 2023
Copy link
Contributor

@dk1a dk1a left a comment

Choose a reason for hiding this comment

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

lgtm, I like how setMetadata is an optional extra method now


// Set metadata
StoreMetadataTable.set(table, tableName, fieldNames);
}
Copy link
Member

Choose a reason for hiding this comment

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

so clean!

@holic
Copy link
Member

holic commented Feb 23, 2023

Is the idea here that we'll add setMetadata to the autogen'ed libraries (alongside registerSchema)?

@holic
Copy link
Member

holic commented Feb 23, 2023

Is it useful or scary to allow overriding metadata after its already been set?

Thinking about the data sync pipeline (events) looking like this:

  • table schema registered
  • table metadata set (e.g. position and {x, y})
  • table record set
  • table record set
  • table metadata updated (e.g. position and {x, z})

What should the client do with the second metadata update? Ignore it? Update all values? If code depends on getting position.y and that changes midway through to position.z, sounds like we'd introduce a lot of runtime errors/bugs.

@dk1a
Copy link
Contributor

dk1a commented Feb 23, 2023

Is the idea here that we'll add setMetadata to the autogen'ed libraries (alongside registerSchema)?

Yep, it's basically 1 line for me

What should the client do with the second metadata update? Ignore it? Update all values? If code depends on getting position.y and that changes midway through to position.z, sounds like we'd introduce a lot of runtime errors/bugs.

The schema is immutable, metadata is just names. I imagine client code can initialize names once per session, and then ignore any changes to them. Haven't thought much about it though

@holic
Copy link
Member

holic commented Feb 23, 2023

The schema is immutable, metadata is just names. I imagine client code can initialize names once per session, and then ignore any changes to them. Haven't thought much about it though

That brings up another question for me: if we're gonna generate some types in the frontend for a given table, and those types depend on field names, and there's multiple events for setMetadata (i.e. field names change), which ones do we use? or do we ask users to pick the particular shape they want?

Detected different field names for table position. Which do you want to use to generate types?
> {x, y}
  {x, z}

These kinds of questions make me wonder if we should make metadata immutable as well, if not required.

@alvrs
Copy link
Member Author

alvrs commented Feb 26, 2023

That brings up another question for me: if we're gonna generate some types in the frontend for a given table, and those types depend on field names, and there's multiple events for setMetadata (i.e. field names change), which ones do we use? or do we ask users to pick the particular shape they want?

I'd say by default the last one, but we could also let users specify custom overrides (for example if you built a frontend for a third party table that changed it's metadata). Once client definitions for the table exist, the client can also just ignore metadata overrides since they're not relevant for decoding. (The client should probably rely on the auto-generated / statically inferred types to name the schema if they exist to avoid the issues you described).

I would assume the rename feature isn't gonna be used too often, but it might be useful in some cases (just like renaming a column in an existing postgres database), so I'd include it by default.

@holic
Copy link
Member

holic commented Feb 27, 2023

Another thing I just realized today: MODE will probably need immutable names, otherwise it means a DB migration of column names? Or I guess MODE could store things as fields without names, then separately store the mapping of field indices to names. cc @authcall

@alvrs
Copy link
Member Author

alvrs commented Feb 28, 2023

I think since the table metadata is optional and possibly added in a separate transaction than the initial registration of the table, the indexer and client would both have to handle renaming anyway (if dynamically picking up new tables is a feature, which is definitely the case for the indexer but unclear for the client). So it might not be much additional effort to also support renaming again after the first metadata was set?

To unblock the network PR work I'd vote for merging this PR as is and possibly add a restriction to being able to modify schema names in a follow up if we the result of our discussion will be that it leads to too much complication too support.

@alvrs alvrs requested a review from a user February 28, 2023 16:31
@alvrs alvrs changed the base branch from v2 to main February 28, 2023 16:31
@alvrs alvrs removed the request for review from a user February 28, 2023 16:31
@holic
Copy link
Member

holic commented Feb 28, 2023

I am kinda wondering/leaning towards the client doing the mapping between field name and field index, then do queries under the hood based on only field indices. Then MODE doesn't need to know about field names.

@dk1a
Copy link
Contributor

dk1a commented Feb 28, 2023

lgtm

I am kinda wondering/leaning towards the client doing the mapping between field name and field index, then do queries under the hood based on only field indices. Then MODE doesn't need to know about field names.

Even with table metadata both the client and MODE could choose to ignore it.
As I understand it, metadata mostly helps network output useful errors during decoding, it doesn't have to be used otherwise

bytes memory _blob = StoreSwitch.getField(_tableId, _primaryKeys, 1);
bytes memory _newBlob = abi.encodePacked(_blob, bytes(_slice));
StoreSwitch.setField(_tableId, _primaryKeys, 1, _newBlob);
}
Copy link
Member

@holic holic Feb 28, 2023

Choose a reason for hiding this comment

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

I realize this is autogen but this seems kinda scary for an abi encoded field. I wonder if we should have a per-field way to enable/disable generating push methods.

Copy link
Contributor

Choose a reason for hiding this comment

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

it totally does, and it shouldn't be used. string[] in general is not in a good place rn

Copy link
Member

Choose a reason for hiding this comment

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

looks like this exists for both bytes and string (not arrays, just dynamic length things)

Copy link
Contributor

Choose a reason for hiding this comment

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

yeah that's intentional, it's just dangerous when you do abi encoded stuff

Copy link
Member

Choose a reason for hiding this comment

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

I added this to my original message but I wonder if we should have a per-field way to enable/disable generating push/slice methods?

Copy link
Contributor

Choose a reason for hiding this comment

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

it's not exactly difficult, I think I could make that option very quickly
But it's part of the bigger question of configurability vs simplicity. Currently fields are a simple Record<string, SchemaType>. Should we make this a shorthand, and allow a field object with various options? I'm kind of leaning yes, but I think I tend to be a bit biased to the configurability side

Copy link
Contributor

Choose a reason for hiding this comment

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

(I have other options in mind that aren't well thought-out yet that could go there too, like enum wrappers)

@alvrs alvrs merged commit ae39ace into main Feb 28, 2023
@holic holic deleted the alvrs/fieldnames branch February 28, 2023 17:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants