DagQL is a strongly opinionated implementation of a GraphQL server.
Below are a set of assertions that build on one another.
- All Objects are immutable.
- All Objects are Nodes, i.e. all objects have an
id
. - All Objects have their own ID type, e.g.
PointID
. - All Objects have a top-level constructor named after the object, e.g.
point
. - All Objects may be loaded from an ID, which will create the Object if needed.
- An Object's field may be
@impure
which indicates that the field's result shall not be cached. - An Object's field may be
@meta
which indicates that the field may be omitted without affecting the result. - All IDs are derived from the query that constructed the Object.
- An ID is canonicalized by removing any embedded
@meta
selectors. - An ID is impure if it contains any
@impure
selectors or any tainted IDs. - An ID may be loaded on a server that has never seen its Object before.
- When a pure ID is loaded it must always return the same Object.
- When an impure ID is loaded it may return a different Object each time.
- An impure query or ID may return an Object with a pure ID.
- All data may be kept in-memory with LRU-like caching semantics.
- All Arrays returned by Objects have deterministic order.
- An ID may refer to an Object returned in an Array by specifying the nth index (starting at 1).
- All Objects in Arrays have IDs: either an ID of their own, or the field's ID with nth set.
- At the GraphQL API layer, Objects are passed to each other by ID.
- At the code layer, Objects received as arguments are automatically loaded from a given ID.
This repository might be re-integrated into Dagger, but for now is just a personal experiment.
It should replace our use of the following forks:
github.com/dagger/graphql
github.com/dagger/graphql-go-tools
I think it may make sense to leave as its own repo just to make sure there's a clear boundary between the theory and the practice. But it should probably move into the Dagger account.
- parallel query execution
- figure out whether constructor patterns are enshrined or ad-hoc
- ad-hoc; you can now Extend any ObjectType in the Server.
- figure out how to return objects that already have an ID (e.g.
loadFooFromID
should not have itself in the returned ID)- if resolvers return an Object no further wrapping/ID-ing is required
- implement caching semantics, including
@impure
and@meta
- figure out telemetry
- resolvers can be wrapped, have access to the current
*idproto.ID
- resolvers can be wrapped, have access to the current
- support schema docs for everything (types, fields, args, enum values, etc)
- figure out how interfaces work
- don't need this yet, but might be a next step for Dagger interfaces
- IDs should also contain module info
- IDs can now contain a reference to a single module ID which provides the implementation of the field that the ID resolves
- all modules contained recursively by an ID (i.e. in parents or arguments)
are loaded prior to evaluating the ID
- technically we might not need to load all modules, since arguably arguments could be evaluated in a vacuum; TBD
- IDs should also contain digest of result (stretch goal, this is higher level, e.g. we want literal file checksums for objects that represent a file)
- get rid of Identified in favor of Object? (see interfaces + wrapping concern below)