Reputation: 43
I am new to Javascript and don't know how to solve this problem. I am creating a GraphQL service to provide query to a database, I would like to define three type: Person, Company and Relationship
type Relation: {
person: Person
company: Company
}
type Person: {
relationship: Relation
}
type Company: {
relationship: Relation
}
As you can see, they are mutually depended, I will got Person and Company undefined
, is there a way to resolve this?
database schema:
// -------------------- Object(company) --------------------
objectType = new GraphQLObjectType ({
name: 'Object',
description: 'Object could be a Company, FinancialOrg, Person or Product.',
fields: {
id: {
type: new GraphQLNonNull(GraphQLString),
},
entity_type: {
type: new GraphQLNonNull(GraphQLString),
description: 'could be Company, FinancialOrg, Person or Product.'
},
entity_id: {
type: new GraphQLNonNull(GraphQLInt),
},
parent_id: {
type: GraphQLString,
},
name: {
type: new GraphQLNonNull(GraphQLString),
},
normalized_name: {
type: new GraphQLNonNull(GraphQLString),
},
permalink: {
type: new GraphQLNonNull(GraphQLString),
}
},
resolveType: function(object) {
return dbHandler.findObjectById(object.id);
}
})
// -------------------- Relationship --------------------
var relationshipType = new GraphQLObjectType({
name: 'Relationship',
description: 'Describe the relationship between a person and a object(Corporation, fund)',
fields: {
id: {
type: new GraphQLNonNull(GraphQLInt),
},
relationship_id: {
type: new GraphQLNonNull(GraphQLInt),
},
person_object_id: {
type: new GraphQLNonNull(GraphQLString),
},
relationship_object_id: {
type: new GraphQLNonNull(GraphQLString),
description: 'A Corporation or a Fund',
},
}
});
// -------------------- Person Type --------------------
personType = new GraphQLObjectType ({
name: 'Person',
fields: {
id: {
type: new GraphQLNonNull(GraphQLInt),
},
object_id: {
type: new GraphQLNonNull(GraphQLString),
},
first_name: {
type: new GraphQLNonNull(GraphQLString),
},
last_name: {
type: new GraphQLNonNull(GraphQLString),
},
birthplace: {
type: GraphQLString
},
affiliation_name: {
type: GraphQLString
},
},
});
Upvotes: 3
Views: 871
Reputation: 1154
Normally you wouldn't define a special Relationship type. In GraphQL, relationships among types are defined in the types themselves.
As examples, within your personType
, you can have a field called companies
, which resolves to a list of companies (companyType
s) that person is part of. In your companyType
, you could similarly define a field people
that would resolve to a list of personType
s.
This would give you essentially a many-to-many relationship between the two types, which it sounds like is defined in your database.
A personType
in this style might look like:
personType = new GraphQLObjectType ({
name: 'Person',
fields: () => ({
id: {
type: new GraphQLNonNull(GraphQLInt),
},
companies: {
type: new GraphQLList(companyType),
resolve: person => dbHandler.getAssociatedCompanies(person.id),
},
},
}),
});
As for circular dependency issues, notice above that rather than using an object literal for fields
, you can instead use a function which returns the object, which will not cause any problems (though your linter might complain).
I would definitely suggest reading through the GraphQL Types as well and making sure you've chosen appropriate types for your fields. Once you're comfortable enough you will definitely want to investigate GraphQLInterfaceType
, which allows you to define common fields other types can implement. Ultimately it's probably a better route to define your types separately and have them implement an interface rather than having a generic objectType
.
Also note that resolveType
probably doesn't do what you think it does. From the GraphQL Types: "[resolveType is] a function to determine which type is actually used when the field is resolved." You see that on GraphQL types that can be composed of multiple types, like GraphQLInterfaceType
and GraphQLUnionType
.
The Star Wars example helped me wrap my head around this stuff.
Upvotes: 3
Reputation: 2068
Try to restructure your GraphQL endpoints to something like this
type Person: {
employers: [Company],
...personAttributes
}
type Company: {
employees: [Person],
...companyAttributes
}
In the database schema (I guess you're using a relational database) you'll need 3 tables:
This article explains how to model many-to-many relationships like the one you have.
Note: If one person can only work at one company at a time, the schema is much simpler.
Upvotes: 0