Relationships
Introduction
Defining a relationship allows you to make queries across linked information.
Relationships are defined in metadata from an object type, to a model or command.
This enables you to create complex queries, where you can fetch related data in a single query.
By defining a Relationship
object, all models or commands whose output type is the
source object type defined in the relationship will now have a connection to the target model or command.
So from this relationship definition, all models or commands in the supergraph whose output type is the orders
object
type will now have a connection to the customers
model via the customer
relationship field on the orders
type.
So, as in example 1 below, you can now fetch the customer when you query orders. Note that also, if you had, for
instance an arbitrary command such as getCustomerLastOrder
which also returned an order from a customer id, you can
now also return the customer's details for that returned order in the same single query from this relationship.
How relationships work
Lifecycle
You can automatically add foreign-key relationships to your metadata using the CLI.
Additionally, you can manually define relationships from an object type to a model or command in your metadata using the VS Code extension. The extension knows about your data sources and can help you write relationships more efficiently.
Simply start by typing a delimiter (---
) at the end of a model's metadata file and start typing Relationship
. The
extension will provide you with auto-completion, syntax highlighting, and error checking as you write your
relationships. At any point in the process, you can type Ctrl + Space
to see the available options and tab through the
fields to fill in the required information.
To make a relationship available in your supergraph, you'll need to create a new build using the CLI.
Examples
---
kind: Relationship
version: v1
definition:
name: customer
sourceType: orders
target:
model:
name: customers
subgraph: customers
relationshipType: Object
mapping:
- source:
fieldPath:
- fieldName: customerId
target:
modelField:
- fieldName: customerId
Field | Description | Reference |
---|---|---|
kind | Indicates that this object is defining a relationship between two data types or models. | Relationship |
version | Specifies the version of the relationship's structure. | RelationshipV1 |
definition.name | The name of the relationship, representing the link between the source and target. | RelationshipName |
definition.sourceType | Defines the source object type that the relationship starts from. | CustomTypeName |
definition.target.model.name | The name of the target model to which the source is related. | ModelName |
definition.target.model.subgraph | Specifies the subgraph in which the target model resides. | ModelRelationshipTarget |
definition.target.model.relationshipType | Indicates the type of relationship (Object or Array), determining whether one or many related items can be fetched. | RelationshipType |
definition.mapping | Defines how fields from the source map to fields or arguments in the target, establishing the connection between them. | RelationshipMapping |
Object Type to a Model
As mentioned above, in an e-commerce context, you will likely have customers and orders, and you want to relate them so that when you query orders you can easily fetch the customer on that order.
To do this in DDN metadata for this example, you might have an orders
model which returns an orders
object
type and you want to relate that to a customers
model and whatever object type it returns.
Example: Fetch a list of orders along with the customer details for each order:
Here is the corresponding relationship configuration which enables this query:
kind: Relationship
version: v1
definition:
name: customer
sourceType: orders
target:
model:
name: customers
subgraph: customers
relationshipType: Object
mapping:
- source:
fieldPath:
- fieldName: customerId
target:
modelField:
- fieldName: customerId
description: The customer details for an order
Now, you can also retrieve the customer details for any model or command in your schema that returns the orders
object
type.
For convenience, this relationship configuration would best be located with your orders
object type and model.
Object Type to a Command
Let's say you have a user
object type in your graph, and also a command which responds with the current logged-in user
information (say getLoggedInUserInfo
). Now you can link these two, by defining a relationship from the user
object
type to getLoggedInUserInfo
.
Let's say we name the relationship currentSession
. Now you can make a single query from your client to get a user's
data and their current session information.
Example: fetch a list of users and the current session information of each user:
Here is the corresponding relationship configuration which enables this query:
kind: Relationship
version: v1
definition:
name: currentSession
sourceType: user
target:
command:
name: getLoggedInUserInfo
subgraph: users
mapping:
- source:
fieldPath:
- fieldName: id
target:
argument:
argumentName: user_id
description: The current session information for the user
Command to Command
Hasura DDN also allows you to link commands together from a source type to query related data.
Example: fetch the result of one command and use it as input for another command:
And the corresponding relationship configuration which enables this query:
kind: Relationship
version: v1
definition:
name: shippingDetails
sourceType: trackOrder
target:
command:
name: getShippingDetails
subgraph: orders
mapping:
- source:
fieldPath:
- fieldName: trackingNumber
target:
argument:
argumentName: trackingNumber
description: The shipping details for an order based on its tracking number
Relationships are written in your various HML files. If you're using a compatible editor (such as VS Code with the Hasura VS Code extension), assisted authoring will help you create relationships more efficiently. It will provide you with auto-completion, syntax highlighting, and error checking as you write your relationships.
The CLI also works to automatically track your relationships for you whenever you add or update a data connector.
Metadata structure
Relationship
Definition of a relationship on an OpenDD type which allows it to be extended with related models or commands.
Key | Value | Required | Description |
---|---|---|---|
kind | Relationship | true | |
version | v1 | true | |
definition | RelationshipV1 | true | Definition of a relationship on an OpenDD type which allows it to be extended with related models or commands. |
Example:
kind: Relationship
version: v1
definition:
name: Articles
sourceType: author
target:
model:
name: Articles
subgraph: null
relationshipType: Array
mapping:
- source:
fieldPath:
- fieldName: author_id
target:
modelField:
- fieldName: author_id
description: Articles written by an author
RelationshipV1
Definition of a relationship on an OpenDD type which allows it to be extended with related models or commands.
Key | Value | Required | Description |
---|---|---|---|
name | RelationshipName | true | The name of the relationship. |
sourceType | CustomTypeName | true | The source type of the relationship. |
target | RelationshipTarget | true | The target of the relationship. |
mapping | [RelationshipMapping] | true | The mapping configuration of source to target for the relationship. |
description | string / null | false | The description of the relationship. Gets added to the description of the relationship in the graphql schema. |
deprecated | Deprecated / null | false | Whether this relationship is deprecated. If set, the deprecation status is added to the relationship field's graphql schema. |
graphql | RelationshipGraphQlDefinition / null | false | Configuration for how this relationship should appear in the GraphQL schema. |
RelationshipGraphQlDefinition
The definition of how a relationship appears in the GraphQL API
Key | Value | Required | Description |
---|---|---|---|
aggregateFieldName | FieldName / null | false | The field name to use for the field that represents an aggregate over the relationship |
Deprecated
OpenDd configuration to indicate whether an object type field, relationship, model root field or command root field is deprecated.
Key | Value | Required | Description |
---|---|---|---|
reason | string / null | false | The reason for deprecation. |
RelationshipMapping
Definition of a how a particular field in the source maps to a target field or argument.
Key | Value | Required | Description |
---|---|---|---|
source | RelationshipMappingSource | true | The source configuration for this relationship mapping. |
target | RelationshipMappingTarget | true | The target configuration for this relationship mapping. |
Example:
source:
fieldPath:
- fieldName: author_id
target:
modelField:
- fieldName: author_id
RelationshipMappingTarget
The target configuration for a relationship mapping.
Must have exactly one of the following fields:
Key | Value | Required | Description |
---|---|---|---|
argument | ArgumentMappingTarget | false | An argument target for a relationship mapping. |
modelField | [RelationshipSourceFieldAccess] | false |
ArgumentMappingTarget
An argument target for a relationship mapping.
Key | Value | Required | Description |
---|---|---|---|
argumentName | ArgumentName | true |
ArgumentName
The name of an argument.
Value: string
RelationshipMappingSource
The source configuration for a relationship mapping.
Must have exactly one of the following fields:
Key | Value | Required | Description |
---|---|---|---|
value | ValueExpression | false | An expression which evaluates to a value that can be used in permissions and various presets. |
fieldPath | [RelationshipSourceFieldAccess] | false |
RelationshipSourceFieldAccess
A field access in a relationship mapping.
Key | Value | Required | Description |
---|---|---|---|
fieldName | FieldName | true |
FieldName
The name of a field in a user-defined object type.
Value: string
ValueExpression
An expression which evaluates to a value that can be used in permissions and various presets.
Must have exactly one of the following fields:
Key | Value | Required | Description |
---|---|---|---|
literal | false | ||
sessionVariable | string | false |
RelationshipTarget
The target for a relationship.
Must have exactly one of the following fields:
Key | Value | Required | Description |
---|---|---|---|
model | ModelRelationshipTarget | false | The target model for a relationship. |
command | CommandRelationshipTarget | false | The target command for a relationship. |
Example:
model:
name: Articles
subgraph: null
relationshipType: Array
CommandRelationshipTarget
The target command for a relationship.
Key | Value | Required | Description |
---|---|---|---|
name | CommandName | true | The name of the command. |
subgraph | string / null | false | The subgraph of the target command. Defaults to the current subgraph. |
CommandName
The name of a command.
Value: string
ModelRelationshipTarget
The target model for a relationship.
Key | Value | Required | Description |
---|---|---|---|
name | ModelName | true | The name of the data model. |
subgraph | string / null | false | The subgraph of the target model. Defaults to the current subgraph. |
relationshipType | RelationshipType | true | Type of the relationship - object or array. |
aggregate | ModelRelationshipTargetAggregate / null | false | How to aggregate over the relationship. Only valid for array relationships |
ModelRelationshipTargetAggregate
Which aggregate expression to use to aggregate the array relationship.
Key | Value | Required | Description |
---|---|---|---|
aggregateExpression | AggregateExpressionName | true | The name of the aggregate expression that defines how to aggregate across the relationship. |
description | string / null | false | The description of the relationship aggregate. Gets added to the description of the aggregate field in the GraphQL schema |
AggregateExpressionName
The name of an aggregate expression.
Value: string
RelationshipType
Type of the relationship.
One of the following values:
Value | Description |
---|---|
Object | Select one related object from the target. |
Array | Select multiple related objects from the target. |
ModelName
The name of data model.
Value: string
CustomTypeName
The name of a user-defined type.
Value: string
RelationshipName
The name of the GraphQL relationship field.
Value: string