How to encapsulate data of a type to be specific to the parent type in graphql - graphql

I have this game type:
type Game {
id: ID! #id
goals: [Goal]
}
which have a Goal relationship to:
type Goal {
id: Int! #id(strategy: SEQUENCE) #sequence(name: "IncID", initialValue: 1, allocationSize: 20)
thumbnail: String!
player: String!
minute: Int!
}
what i'm trying to do by that "id" mess is to create an incremental id value for the goal, for the purpose of creating a url for each goal, like this:
domaine.com/game/{id-of-the-game}/goal/{incremental-id(1,2..)}
the problem is, the Goal type looks like it is an entity of its own, it is gonna keep the last incremented id even if it is new game.
so i want to reset the id sequence for each new game.

What you ask for is not possible using the #id annotation. Each type in the prisma model needs to have a unique id to identify the object in the database. If the underlying database used is MongoDB there will be a Goal collection with documents in it, each representing an individual Goal identified by the id. If the underlying database used is MySQL/PostgreSQL the Goals will be stored in a Goal table with each row representing an individual Goal.
Each individual object (no matter if it is stored as a document or row) needs to be uniquely identified to access it and to create relations, e.g. between Goal objects and Game objects.
If the Goal id would start at 1 for each Game this would violate the unique constraint for the id field since two Goals in the table or collection would be identified by the same id (e.g. 1).
What I would suggest is to simply add something like a "numberInGame" field to the Goal type and fill it while creating the Goal (e.g. by taking goals.length in the Game.type into consideration).
Hope that helped to clarify the id field uniqueness constraint.

Related

How can I pass arguements to child fields in Apollo?

I'm trying to build a graphql interface that deals with data from different regions and for each region there's a different DB.
What I'm trying to accomplish is:
TypeDefs= gql`
type Player {
account_id: Int
nickname: String
clan_id:Int
clan_info:Clan
}
type Clan{
name:
}
So right now I can request player(region, id), and this will pull up the player details no issues there.
But the issue is that Clan_info field also requires the region from the parent, so the resolver would look like clan_info({clan_id}, region).
Is there any way to pass down the region from parent to child field? I know I can add it to the details of the player, but would rather not since there would be millions of records and every field counts

Data modelling for ecommerce website using Amplify + GraphQL + DynamoDB

I'm using Amplify from AWS to build a small ecommerce project using React as frontend.
I'd like to know how I should write the "Product" and "Order" types in the schema in order to be able to write productId's to a product array in the Order table when users complete a purchase.
My schema.graphql file:
type Product #model {
id: ID!
name: String!
price: Int!
category: String!
images: [String]!
}
type Order #model {
id: ID!
products: [Product] #connection
}
My question is about the last line, do I need to define that [Product] connection there or I can use [String] to store product id's in a simple string array?
Point 1: In dynamoDB, you only need to define the data type of your partition key and sort key, and these can be string, number etc. For all the other attributes, you don't need to define anything.
Point 2: The dynamoDB designers prefer using a single table per application, unless it's impossible to manage data without multiple tables. Keeping this in mind, your table can be something like this.
Please observe: Only Id aka partition key and Sk aka sort key column is fixed here, all other columns can be anything per item. This is the beauty of DynamoDB. Refer to this document for dynamoDB supported data types.

Graphql ID resolves as string even if it's integer

I'm new to graphql and hope someone can explain me this ID type that is always string.
As sad in docs:
The ID scalar type represents a unique identifier, often used to re-fetch an object or as a key for a cache.
If you use, for example, some caching client like Apollo, each type
should have at least one ID. This allows us to perform a normalization
of queries, making it possible for us to update things in Apollo
internal redux store automatically based on the unique id
Ok, so i can use int, but how then i get my id as integer on client side?
Reason is simple, let's say i have Book type with id of type ID and author_id relation of type Int. Also i have Author type with id of type ID. And after i fetch book and author i will have book.author_id int and author.id string, but it's the same number!
What should i do? Use everywhere ID even for many to many relations? Make new scalar ID type that can be used as ID for re-fetch but will be of type Int?
From the spec:
The ID type is serialized in the same way as a String; however, it is not intended to be human‐readable. While it is often numeric, it should always serialize as a String... GraphQL is agnostic to ID format, and serializes to string to ensure consistency across many formats ID could represent, from small auto‐increment numbers, to large 128‐bit random numbers, to base64 encoded values, or string values of a format like GUID.
It's unclear why the client would care about comparing IDs in this context -- columns like author_id should generally be hidden from the client anyway, with the schema only exposing the related entity, not fields that are only used to link entities. That said, an ID is just an ID and a client shouldn't care whether it's a string or an integer as long as it's consistent. If you have one field returning an integer (Book.author_id) and another returning a string (Author.id), then that's a problem on the part of your schema.
The ID scalar can be used for any number of fields, not just the one field (which may or may not be named id). Similarly, if you want to use Int or String as the type for your id field you can -- this will not impact Apollo's ability to cache your results.
In apollo you can use typePolicies to determintate what field is used as unique identifier. That will resolve a pain of ID! type conversion to string.
const typePolicies = {
Book: {
keyFields: ['id'],
},
BookTag: {
keyFields: ['book_id', 'tag_id'],
}
}
return new ApolloClient({
cache: new InMemoryCache({ typePolicies }),
})

How would I assign meal event guests per attendee per table per event at a conference in a GraphQL schema?

I'm pondering a rebuild of a meal seating assignment app. I'll make use of GraphQL to query for attendees and their guests of a table at a meal event (assigned seating). The delivered data model looks something like this:
meal event 1
table A
attendee 1
guest 1
...
meal event 2
table L
attendee 1 (no guest this time)
...
An attendee may attend multiple meal events e.g. at a multi-day conference. That attendee may have a guest(s) at meal event(s). This could be another attendee record (two meal tickets, same info), noted as a guest however as an attendee and their guest(s) need to be seated at the same table (don't want spouse on other side of the room for example). Attendees will usually have the same guest(s) at multiple events, however not always due to cost or conflicting guest commitments or wanting to rotate guests per meal, etc.
How would I model this in a GraphQL schema? In the database I'd use join tables. However for client-facing GraphQL queries and schema types, I need to model this a bit differently (I think?). Here's what I have so far:
type Attendee {
name: String
** Can't add guests here as this may change per event
}
type Event {
name: String
tables: [Table]
}
type Table {
name: String
attendees: [Attendee]
** How do I "tree" in guests here for attendees for this table?
}
At this point do I need a join type to get guests per attendee per table per event?
When writing our server code, we typically encapsulate our business logic inside domain models like Event, Table, Attendee or Guest. However, these domain models don't have to have a strict one-to-one mapping with the tables we use to persist their data -- for example, an individual model might aggregate data from multiple tables.
Similarly, your GraphQL types do not have to have a one-to-one mapping to your domain models. It can often make sense to represent the same domain model as multiple types. For example, we can do something like:
type EventAttendee {
id: ID!
name: String!
}
type TableAttendee {
id: ID!
name: String!
guests: [Guest!]!
}
type Table {
id: ID!
attendees: [TableAttendee!]!
}
type Event {
id: ID!
name: String!
attendees: [EventAttendee!]!
tables: [Table!]!
}
Your schema effectively represents multiple graphs or views of your data. Depending on where on that graph your domain model ends up should determine what fields it exposes as a type -- in some contexts, exposing certain properties or relationships makes sense, in others it does not.

Using GraphQL with conditional related types

I have an app that has a type with many related types. So like:
type Person {
Name: String!
Address: Address!
Family: [Person!]!
Friends: [Person!]!
Job: Occupation
Car: Car
}
type Address {...}
type Occupation {...}
type Car {...}
(don't worry about the types specifically...)
Anyway, this is all stored in a database in many tables.
Some of these queries are seldom used and are slow. Imagine for example there are billions of cars in the world and it takes time to find the one that is owned by the person we are interested in. Any query to "getPerson" must satisfy the full schema and then graphql will pare it down to the fields that are needed. But since that one is slow and could be requested, we have to perform the query even though the data is thrown out most of the time.
I only see 2 solutions to this.
a) Just do the query each time and it will always be slow
b) Make 2 separate Query options. One for "getPerson" and one "getPersonWithCar" but then you're not able to reuse the schema and now a Person is defined twice. Once in terms of the car and once without.
Is there a way to indicate whether a field is present in the Query requested fields? That way we could say like
if (query.isPresent("Car")) {
car = findCar();
} else {
car = null;
}

Resources