Suppose we have a Rating model with a score field (integer/enum between 1-5) and a text field (string):
Facility has_many Ratings, through: FacilityRatings
Customer has_many Ratings, through : CustomerRatings
How do I do this?
Suppose we have a Rating model with a score field (integer/enum between 1-5) and a text field (string):
Facility has_many Ratings, through: FacilityRatings
Customer has_many Ratings, through : CustomerRatings
How do I do this?
So… I’m trying to work out a solution, though the more I work on it the less I like it!
Here is the idea so far. I wrote a custom resolver called ratingEntity(id: String!)
where when given an rating id, it returns the entity that entity belongs to.
There are no 8base table relationships. The rating table has the following fields.
Ratings
entityId: TEXT
entityType: TEXT
rating: NUMBER
The query looks likes this:
query {
ratingEntity(id: "ck1l6il11002i01l755nkfx6h") {
facility {
id
name
}
customer {
id
nickname
}
}
}
and returns:
{
"data": {
"ratingEntity": {
"facility": {
"id": "ck1l643v5030l01jncwpb4htp",
"name": "Our House"
},
"customer": null
}
}
}
Here is the resolver function handler:
type RatingEntityResult = {
data: {
facility: {
id: ID,
name: String,
createdAt: Date,
updatedAt: Date,
mascot: String
},
customer: {
id: ID,
name: String,
createdAt: Date,
updatedAt: Date,
nickname: String
}
}
};
const fragments = {
facility: `id name createdAt updatedAt mascot`,
customer: `id name createdAt updatedAt nickname`
}
const RATING_QUERY = `
query($id: ID!) {
rating(id: $id) {
entityId
entityType
}
}
`;
const ENTITY_QUERY = (type) => (`
query($entityId: ID!) {
${type}(id: $entityId) {
${fragments[type]}
}
}
`);
export default async (event: any, ctx: any) : Promise<RatingEntityResult> => {
/* Get the rating entityId and entityType */
const typeResponse = await ctx.api.gqlRequest(RATING_QUERY, { id: event.data.id })
/* Unpack required variables */
const { entityType, entityId } = typeResponse.rating;
/* Get the entity */
const entityResponse = await ctx.api.gqlRequest(ENTITY_QUERY(entityType), { entityId })
return {
data: entityResponse
};
};
And the graphql.schema file:
type RatingFacility {
id: ID,
name: String,
createdAt: Date,
updatedAt: Date,
mascot: String
}
type RatingCustomer {
id: ID,
name: String,
createdAt: Date,
updatedAt: Date,
nickname: String
}
type RatingEntityResult {
facility: RatingFacility,
customer: RatingCustomer
}
extend type Query {
ratingEntity(id: ID!): RatingEntityResult
}
Now there are some obvious limitations here. However, we can keep working on it together.
Aye that is a bit of work eh
How about saying (albeit not very DRY-ly):
Facility has many FacilityReviews
Customer has many CustomerReviews
type FacilityReview {
id: ID,
rating: Int,
text: String,
createdAt: Date,
updatedAt: Date,
createdBy: Customer
}
type CustomerReview {
id: ID,
rating: Int,
text: String,
createdAt: Date,
updatedAt: Date,
createdBy: Facility
}
Have you tried that solution? I’m not sure whether the system will allow an override of the createdBy
field. Also, how would you then go about specifying the response?
I have not, should probably give it a shot.
In pseudo-ORM queries, I would expect it to look a bit like:
someCustomer = customer.find()
currentFacility.customerReviews.create({ customer: someCustomer, rating: 3, text: "Lorem ipsum..." })
someFacility = facility.find()
currentCustomer.facilityReviews.create({ facility: someFacility, rating: 3, text: "Lorem ipsum..." })
Absolutely. The issue we are running into here is that the response has to be typed. So we cant have a response on one query return Facility fields and then on the next query return Customer fields. We need to somehow handle them dynamically.
I believe that there is a way to use fragments to accomplish this… but I’m not 100% sure ATM.