Remove user while also removing unused tags in many-to-many relationship in GraphQL? - graphql

I'm using Hasura for this.
Say for example I have a users, tags and users_tags table in a many-to-many relationship.
User's can define multiple tags (like a persons hobbies) and each tag can belong to multiple people.
Table users {
id int [pk increment]
}
Table tags {
id int [pk increment]
name text
}
Table users_tags {
id int [pk increment]
user [ref: - user.id]
tag [ref: - tags.id]
}
The users_tags table is a many-to-many table.
When a new user is created, I can create new tags and associate them with users just fine.
But when a user is deleted, what GraphQL mutation can I use to remove tags from both tags and users_tags if they don't point to other users.

This depends on your desired data model. If a tag is always associated with one user only, you can get rid of the users_tags table and add the user to the tags table.
Then, if you've set up a foreign key on the tag table that references the id field on the user table then this can be done automatically.
You will be given 4 options on deletion:
restrict: Does not allow you to delete a user that is referenced on a tag
cascade: Deletes the tag if the user is deleted
set null: Sets this row as null if the user is deleted
set default: Sets this row as the default value if the user is deleted
You'll want to select the cascade option here.
If you want to keep your current data model you will be able to do this cascading on the users_tags table if the tag or user is deleted but will need some process in place to delete tags that have no users associated to them.
The easiest way would probably be to add a custom SQL function but you could also have the following graphql query to find the tags that have 0 users_tags associated with them and then provide a list of primary keys to a delete tags mutation.
query CountOfUsersTagsForTag {
tags {
id
users_tags_aggregate {
aggregate {
count
}
}
}
}

Related

Data normalization in GraphQL query

I'm using GraphQL to query a database that has two data types: User and Group.
Groups have a field users which is an array of User objects which are in that group. I have one field at root named groups which returns an array of all of my groups.
A typical query might look something like this:
{
groups {
id,
name,
users {
id,
name,
address,
email,
phone,
attitude,
job,
favoriteQuote,
favoriteColor,
birthday
}
}
}
The problem is that a lot of those users can belong to multiple groups and, seeing as User has a lot of fields, this can make responses quite large.
Is there any way to get one set of fields for the first instance of an object, and a different set for every other instance in the response?
I only need name, job, email etc etc once per user in the response, and just the id thereafter (I can do my own normalization afterwards).
alternatively
Is there any way to only get id fields for all users in groups and return a separate array of all unique User objects that have been referenced in the query (which is not all User objects)?
Is there any way to get one set of fields for the first instance of an object, and a different set for every other instance in the response?
No. The same set of fields will be returned for each item in a list unless the type of the individual item is different, since a separate selection set can be specified for each type returned at runtime.
Is there any way to only get id fields for all users in groups and return a separate array of all unique User objects that have been referenced in the query (which is not all User objects)?
You could design your schema to accommodate this. Something like
{
groups {
nodes {
id
name
users {
id
}
}
uniqueUsers {
id
# other fields
}
}
}
Your groups resolver would need to handle all the normalization and return the data in the appropriate shape. However, a simpler solution might be to just invert your relationship:
{
users {
id
name
address
email
phone
attitude
job
favoriteQuote
favoriteColor
birthday
groups {
id
name
}
}
}
Generally - usually
... normalization ... of course ... f.e. using apollo and it's normalized cache.
All records returned from API has to be the same shape.
You can get data and render some <MembersList/> component using query for ids and names only (full/paginated).
Later you can render details in some <UserProfile/> component with own query (hook useQuery inside) to fetch additional data from cache/api (controllable).
Your specific requirements - possible
1st option:
Usually response is of one common shape (as requested), but you can decide on resolver level what to return. This requires query structure changes that allows (API, backend) to null-ify some properties. F.e.
group {
id
name
users {
id
name
profile {
photo
email
address
With profile custom json type ... you can construct users resolver to return full data only for 1st record and null for all following users.
2nd option:
You can use 2 slightly different queries in one request. Use aliases (see docs), in short:
groupWithFullMember: group ( groupId:xxx, limitUsers:1 ) {
id
name
users {
id
name
address
email
...
}
}
groupMembers: group ( groupId:xxx ) {
id
name // not required
users {
id
name
}
}
Group resolver can return it's child users ... or users resolver can access limitUsers param to limit response/modify db query.

Soft deleting both rows from two tables in Laravel

I'm new to Laravel and trying to soft-delete both rows from two tables.
Vehicles table,
id
license
brand
is_taken
Taken_bies table,
id
name
phone
vehicle_id
In vehicles table, if is_taken is true, I grab the id of vehicle and fill it to vehicle_id from taken_bies table with other information.
In my TakenBy model, I've implemented relationship as follow:
public function vehicle() {
return $this->belongsTo('App\Vehicle');
}
My Requiremnet:
If I soft-delete the vehicle, I want to delete the related taken_bies information from taken_bies table. How can I achieve that? I'm using Laravel 5.8. Thank you.
you can delete it like below
$vehicle = Vehicle::find(1);
$vehicle->taken_bies()->delete();
$vehicle->delete();

GraphQL with apollo-client, Is it possible to have same id's and different typenames

I had a question and can't find it in documentation.
For example I have a list
products with ids 1,2,3,4
And I have another list, categories with ids 1,2,3,4.
example query
{
products {
id
name
categories {
id
name
}
}
}
We can see that they both have same ids but different typename inside apollo.
Will it create any problem while caching the data? As Apollo normalizes our data with the id's,
Help would be appreciated.
Apollo normalizes using both the __typename and id (or _id) fields, so having a Product and a Category with the same id will normally not cause any problems.
The client normally appends the __typename for every selection set in your query -- so you do not have to actually add the __typename field yourself.
The config object passed to InMemoryCache includes a addTypename property, which defaults to true. If you set this to false, then the __typename field will not be added and you will see issues with the cache in this scenario unless you have universally unique IDs.

How to check id which I used from a table that related with other multiple table?

When I want to delete a row from table I want to check the tables which use the id of this row. If used then it doesn't allow to delete.
You can simply check whether specific column(containing other table's key) in the row is empty or null and if it is empty then delete the row otherwise skip it.
You have two ways in which you can do it-
using eloquent get the row by primary key and check the property on collection.
write a stored procedure in the database and call it in your Laravel code.
You can use the deleting model event to check if the relationships exist. If they do, then prevent the delete.
https://laravel.com/docs/5.7/eloquent#events
If you create an observer for your model, you can use something like this:
public function deleting($model)
{
if($model->someRelation->count()) { // replace ->someRelation with whatever you want to check
return false; // prevent delete
}
if($model->anotherRelation->count()) {
return false; // prevent delete
}
}

Laravel relationship between two tables

I'd like your input on this.
I have a Customer_table with a field name. I have another table called Reservation_table with a Customer_name field.
How can I relate them in such a way that I'd see all the bookings by the specific customer?
In Reservation_table you should have a field(foreign key) userid in order ta have a user for each reservation.
You can using primary key - foreign key relationship to relate/join those two tables. Also, instead of having a 'Customer_name' field as your FK referring to 'name' field in 'Customer_table' table, it is better to have an id (unique) generated for each customer; This way you can have an efficient way of uniquely identifying and relating customer across tables; can save space on Database side as well. Hope this helps!
If you want to use eloquent you must first define a relationship.
One reservation belongs to a user. Here is how to define the relationships:
Inside the Reservation model:
public function user()
{
return $this->belongsTo('App/User'); //User model
}
To define the inverse you do the following:
Inside User model:
public function reservations()
{
return $this->hasMany('App/Reservation'); // Reservation Model
}
Now you can do the following in your controller:
$reservations = Auth::user()->reservations;
Now you have all reservations by the currently logged in user.
I am not sure if I got the question right so ask away.

Resources