Schemas
Schemas
are the core of Aphrodite
. Schemas capture:
- The nodes in your data model
- Relationships (edges) between them
- Permissions (who can read what nodes and what relationships)
- Persistence (where is the node/edge stored)
- Mutations (what about a node or edge can be changed, how and by who)
- Constraints (uniquness, indices, etc.)
You can describe as much or as little as your data model as you like. The more you describe, the more Aphrodite
can help you.
From the schema definition, Aphrodite generates TypeScript
(and eventually other target languages) classes (models, :query builders, mutators) to interact with your data.
Example Schemas
Schemas are written in a simple DSL
. This DSL
only lets you declare things and not write arbitrary computations. The principle behind this is that if something about your data cannot be described declartively, it does not belong in the schema.
Node Example (foo.aphro)
engine: sqlite
Foo as Node {
id: ID<Foo>
name: string
age: int32
created: Timestamp
height: float32
something: Enumeration<A | B | C>
}
A few things to note here:
- Nodes are defined as
$identifier as Node
- What follows is a list of fields that make up the node
- Fields can be any of the data types listed in docs/data-types
Nodes can be extended with more options via &
. Lets see some extensions.
Node Extensions
The definition of a node can be extended with:
- Edges
- Mutations
- GraphQL definitions
- Permissions
- Constraints & Indices
- 3rd party extensions
All extensions to a node follow a syntax that looks like:
X as Node {
...
} & EXTENSION_1 { EXTENSION_1_ARGS } & EXTENISON_2 { EXTENSION_2_ARGS } & ...
Any number of extensions can be applied to a node. Extensions have access to and augment the definitions that come before them.
Outbound Edges Example
Foo as Node {
...
bazId: ID<Baz>
} & OutboundEdges {
bars: Edge<Bar.fooId>
baz: Edge<Foo.bazId>
}
Edges can be through a field. E.g., the edge from foo
to Baz
is through Foo.bazId
.
Mutations Example
Foo as Node {
id: ID<Foo>
name: string
age: int32
created: Timestamp
height: float32
} & Mutations {
create as Create {
name # args that match field names get their type from the field name
age
height
}
rename as Update {
name
customArg: string # can add custom args
bar: Bar # can take other nodes as input
}
}
GraphQL Example
Foo as Node {
...
} & GraphQL {
read {
# names of fields to expose for read operations
}
write {
# names of mutations to expose for write operations
}
root # generate a root call to load `Foo`
}
Junction Edge
Junction edges / pivot tables allow us to declare many-to-many relationships. Edges can have data if you like or have no fields.
Followers as Edge<Person, Person> {}
Person as Node {
id: ID<Person>
} & OutboundEdges {
followers: Followers
}