-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Relational database schemas for subgraphs #1020
Comments
GoalsWe want to switch the storage of entities from JSONB to a relational schema, meaning that each entity type is stored in its own table. The relational schema for a subgraph is generated from the GraphQL schema. Storage in a relational schema will be added in such a way that already existing subgraphs that use JSONB storage will continue to function. Only newly deployed subgraphs will be stored in a relational schema. Migrating existing subgraphs to relational storage is not currently planned. Mapping GraphQL to a relational schemaThe mapping from GraphQL to SQL is generated from the GraphQL schema we already store, and needs to be passed into We will continue to store all entities for a subgraph in a subgraph-specific database schema/namespace. Each type in the GraphQL schema is mapped to a database table, and each attribute of the type is stored in a column of that table. GraphQL types are mapped to SQL types in the following manner:
Note that for We will only support lists of scalars, i.e., not lists of lists. Not-null constraints in GraphQL will be mapped to Properties that reference other entities, either a single entity, or an array of entities, will be stored as the For example, the GraphQL entity type type Musician @entity {
id: ID!
name: String!
mainBand: Band
bands: [Band!]!
writtenSongs: [Song]! @derivedFrom(field: "writtenBy")
} would be stored in a SQL table create table musicians (
id varchar primary key,
name varchar not null,
main_band varchar,
bands varchar[] not null
-- derived fields (not stored in this table)
-- written_songs varchar[] not null
); InterfacesThe biggest headache in generating a relational schema for a GraphQL schema are interfaces. The fact that a certain entity implements an interface has no bearing on the relational schema, but GraphQL attributes that reference interfaces need to be treated specially. Assume we have the GraphQL schema interface Pet {
name: String!
}
type Cat implements Pet @entity {
id: ID!,
name: String!
}
type Dog implements Pet @entity {
id: ID!,
name: String!
}
type Owner @entity {
id: ID!,
firstPet: Pet!,
pets: [Pet!]!
} The tables for create table owners (
id varchar primary key,
first_pet_type varchar,
first_pet_id varchar,
pets_type varchar[],
pets_id varchar[]
-- add check constraints to ensure that
-- first_pet_type and pets_type only contain
-- 'Cat' and 'Dog'
) SerializationCurrently, we serialize entities into JSON objects before storing them in the database. For relational schemas, we will need to convert each attribute of an entity to the corresponding SQL type, and use attribute values directly in queries. Writing entitiesApart from serialization, writing entities is fairly straightforward, and a
The above will of course use bind variables in real code. Updating and deleting entities will be handled similarly. Querying entitiesCurrently, we only ever query one entity type in the same query; queries against the relational schema therefore only ever reference a single table. The biggest change for querying will be in how we turn an Time-travel queriesWe will not implement the current scheme of storing entity history in a separate history table; instead, we will follow the approach outlined in this issue All tables that are generated will have a The time-travel support will also be used to perform block reversions. |
Plan looks good. I have a comment about interfaces. Currently we do not require mappings to tell us the concrete type of an interface relationship, and instead require all types implementing an interface to not have conflicting ids. So we wouldn't know what to put in |
We can create schema that way - it'll cause more work when querying, since we have to look at all |
@leoyvens One thing we could do there is to perform lookups by ID/IDs to identify the type before writing the references to the db. This requires the referenced entities to already exist before referencing them — which feels like a good constraint. @lutter A few comments:
Other than that, this looks good. |
We made a decision to not enforce referential integrity when writing data at all. According to @yanivtal, we want to make it possible to write an entity that references a
The relational schema follows the GraphQL schema pretty closely: for 1->n relationships, we'd store an array of
Yes, I think on the storage side, unions and interfaces are pretty much the same, both for storing references to them, as well as when we query them. |
Huge chunk of this was merged with PR #1159. Remaining work:
|
@lutter I suppose we can close this, right? |
Yep! |
This is required for #297.
The text was updated successfully, but these errors were encountered: