GraphQL so is it possible to determine the Types that will be return dynamically based on the query Parameter in? - graphql

like the title said but i came accros the fact that my front part does not know anything about GraphQL , so is it possible to determine the Types that will be return dynamically based on the query Parameter in?

You can query the field "__typename" on objects, interfaces and unions.

Related

Filtering CassandraRepository by multiple fields dynamically

I need to filter on multiple fields of an entity dynamically when searching the CassandraRepository.
Specifically, there are multiple String fields of the entity. The user can indicate which (if any) of these fields they want to match a specified Regular expression (e.g., ".*").
However, it looks like CassandraRepository doesn't provide support for JpaSpecificationExecutor, which is what resources online typically suggest using for this purpose, giving the following issue:
Could not create query for public abstract Page JpaSpecificationExecutor.findAll(Specification, Pageable)! Reason: Page queries are not supported. Use a Slice query.
What is the appropriate way to approach this issue?
Based on the research I have done, the closest you can get is creating your own CQL Query String based on the inputs provided, and executing them on a CassandraOperations Object that you can autowire into the necessary class.

How to create a GraphQL query that returns data from multiple tables/models within one field using Laravel Lighthouse

Im trying to learn GraphQL with Laravel & Lighthouse and have a question Im hoping someone can help me with. I have the following five database tables which are also defined in my Laravel models:
users
books
user_books
book_series
book_copies
I'd like to create a GraphQL endpoint that allows me to get back an array of users and the books they own, where I can pull data from multiple tables into one subfield called "books" like so:
query {
users {
name
books {
title
issue_number
condition
user_notes
}
}
}
To accomplish this in SQL is easy using joins like this:
$users = User::all();
foreach ($users as $user) {
$user['books'] = DB::select('SELECT
book_series.title,
book.issue_number
book_copies.condition,
user_books.notes as user_notes
FROM user_books
JOIN book_copies ON user_books.book_copy_id = book_copies.id
JOIN books ON book_copies.book_id = books.id
JOIN book_series ON books.series_id = book_series.id
WHERE user_books.user_id = ?',[$user['id']])->get();
}
How would I model this in my GraphQL schema file when the object type for "books" is a mashup of properties from four other object types (Book, UserBook, BookCopy, and BookSeries)?
Edit: I was able to get all the data I need by doing a query that looks like this:
users {
name
userBooks {
user_notes
bookCopy {
condition
book {
issue_number
series {
title
}
}
}
}
}
However, as you can see, the data is separated into multiple child objects and is not as ideal as getting it all in one flat "books" object. If anyone knows how I might accomplish getting all the data back in one flat object, Id love to know.
I also noticed that the field names for the relationships need to match up exactly with my controller method names within each model, which are camelCase as per Laravel naming conventions. Except for my other fields are matching the database column names which are lower_underscore. This is a slight nitpick.
Ok, after you edited your question, I will write the answer here, to answer your new questions.
However, as you can see, the data is separated into multiple child objects and is not as ideal as getting it all in one flat "books" object. If anyone knows how I might accomplish getting all the data back in one flat object, Id love to know.
The thing is, that this kind of fetching data is a central idea of GraphQL. You have some types, and these types may have some relations to each other. So you are able to fetch any relations of object, in any depth, even circular.
Lighthouse gives you out of the box support to eloquent relations with batch loading, avoiding the N+1 performance problem.
You also have to keep in mind - every field (literally, EVERY field) in your GraphQL definition is resolved on server. So there is a resolve function for each of the fields. So you are free to write your own resolver for particular fields.
You actually can define a type in your GraphQL, that fits your initial expectation. Then you can define a root Query field e.g. fetchUsers, and create you custom field resolver. You can read in the docs, how it works and how to implement this: https://lighthouse-php.com/5.2/the-basics/fields.html#hello-world
In this field resolver you are able to make your own data fetching, even without using any Laravel/Eloquent API. One thing you have to take care of - return a correct data type with the same structure as your return type in GraphQL for this field.
So to sum up - you have the option to do this. But in my opinion, you have to write more own code, cover it with tests on you own, which turns out in more work for you. I think it is simpler to use build-in directives, like #find, #paginate, #all in combination with relations-directives, which all covered with tests, and don't care about implementation.
I also noticed that the field names for the relationships need to match up exactly with my controller method names within each model, which are camelCase as per Laravel naming conventions.
You probably means methods within Model class, not controller.
Lighthouse provides a #rename directive, which you can use to define different name in GraphQL for your attributes. For the relation directives you can pass an relation parameter, which will be used to fetch the data. so for your example you can use something like this:
type User {
#...
user_books: [Book!]! #hasMany(relation: "userBooks")
}
But in our project we decided to use snak_case also for relations, to keep GraphQL clean with consistent naming convention and less effort

Spring JPA Derived query method groupBy

Hi I was building an app and was wondering on how I can convert this query into a derived query method without using the annotation #Query:
SELECT address, COUNT(*) address FROM `employee` GROUP BY address ORDER BY address DESC LIMIT 5
I have tried it here is how I did it
List<Employee> countByAddressGroupByAddressByOrderByAddressDescLimit5();
This throws the following error
Invalid derived query! No property groupByAddressBy found for type String! Traversed path: Employee.address.
I was wondering if what am I doing wrong here thank you in advance.
I don't think query derivation supports group by.
You can't.
Derived queries don't support GROUP BY.
Derived queries are intended only for simple queries, where the mapping between a normal method name that you might choose independently from Spring Data and the query needed for implementation is obvious.
For more complex cases like the one you describe other mechanisms are available, like annotated or named queries. Nobody wants to use a method name like countByAddressGroupByAddressByOrderByAddressDescLimit5 anyway.
As others said, derived queries do not support this. There might be other reasons besides simply not being a 'practical' solution.
AFAIK derived query methods are restricted to retrieving instances just for the entity type managed by the repository (you can retrieve MyEntity, Optional<MyEntity>, Collection<MyEntity>, etcetera) or projections that match the fields/columns used for the managed entity.
When you use 'Group By', you break with this resultset structure, you usually have to explicitly indicate which columns you want to retrieve or which operations you want to perform on the grouped columns (which would be impossible using just a method name).
TL;DR
You can't easily indicate the columns you want to include in a 'Grouped By' query result, so no, I don't think there is a way to use this technique with 'Group By'.

Does GraphQL ever redundantly visit fields during execution?

I was reading this article and it used the following query:
{
getAuthor(id: 5){
name
posts {
title
author {
name # this will be the same as the name above
}
}
}
}
Which was parsed and turned into an AST like the one below:
Clearly it is bringing back redundant information (the Author's name is asked for twice), so I was wondering how GraphQL Handles that. Does it redundantly fetch that information? Is the diagram a proper depiction of the actual AST?
Any insight into the query parsing and execution process relevant to this would be appreciated, thanks.
Edit: I know this may vary depending on the actual implementation of the GraphQl server, but I was wondering what the standard / best practice was.
Yes, GraphQL may fetch the same information multiple times in this scenario. GraphQL does not memoize the resolver function, so even if it is called with the same arguments and the same parent value, it will still run again.
This is a fairly common problem when working with databases in GraphQL. The most common solution is to utilize DataLoader, which not only batches your database requests, but also provides a cache for those requests for the duration of the GraphQL request. This way, even if a particular record is requested multiple times, it will only be fetched from the database once.
The alternative (albeit more complicated) approach is to compose a single database query based on the requested fields that executes at the root level. For example, our resolver for getAuthor could constructor a single query that would return the author, their posts and each of that post's author. With this approach, we can skip writing resolvers for the posts field on the Author type or the author field on the Post type and just utilize the default resolver behavior. However, in order to do this and avoid overfetching, we have to parse the GraphQL request inside the getAuthor resolver in order to determine which fields were requested and should therefore be included in our database query.

Same query method and parameters with different return in Spring Data

I want to use projections in order to return less elements for the same queries.
Page<Network> findByIdIn(List<Long> ids);
Page<NetworkSimple> findByIdIn(List<Long> ids);
Since the queries are created using the name of the method, what options do I have to do the same query but with different name ?
I ran into this today, and the accepted answer is actually incorrect; you can change the method name without altering the behavior. According to the Spring Data documentation:
Any text between find (or other introducing keywords) and By is considered to be descriptive unless using one of the result-limiting keywords such as a Distinct to set a distinct flag on the query to be created or Top/First to limit query results.
Thus you can have a method named findByIdIn and another named findNetworkSimpleByIdIn and the two will return the same data (optionally converted to a different form depending on the defined return type).
Spring Data query via method is constructed by convention and you can't change the name and yet expecting a same behavior.
You can try to use #Query annotations which doesn't depend on the method name, or possibly implementing custom DAO using JPAQuery plus FactoryExpression which has the same effect as projections.

Resources