GraphQL - How retrieve id of previous mutation, during query of multiple mutations - graphql

i would like run multiple mutations in the same query.
In the example below, i create an order and after i create a product record, concerning previously created.
I must have 2 mutations.
First, i insert an order. In output, i retrieve among others, idorder.
Then, i insert an product. This product
mutation {
createOrder(input: {
order: {
ordername: "My order"
}
}) {
order {
idorder
ordername
}
},
createProduct(input: {
product: {
quantity: 3
idrefproduct: 25 # link to refProduct
idorder: XXXX # how can i retrieve idorder from output of createOrder above ? 🤔
}
}) {
product {
idproduct
}
}
}
Real example with SQL structure :
user(iduser, othersFields);
scenarios(idscenario, iduser, name, otherFields);
cultA(idcultA, idscenario, ...); // this table need of idscenario field
cultB(idcultB, idscenario, ...); // this table need of idscenario field
cultC(idcultC, idscenario, ...); // this table need of idscenario field
how can i retrieve idorder from output of createOrder above ? 🤔
It is possible ?
If i forgot some informations, don't hesitate.
Thanks in advance.
EDIT :
With PostGraphile, plugin "postgraphile-plugin-nested-mutations" or "custom mutations" (with PL PGSQL function)
Without PostGraphile, a resolver as the example of #xadm permits this particular nested mutation.

IMHO you can search for "nested mutations" - not described here, you'll easily find examples/tutorials.
Proposed DB structure (n-to-n relation):
order{orderID,lines[{orderLineID}] } >
order_line{orderLineID, productID, anount, price} >
product {productID}
... created in nested mutations (in reverse order product>order_line>order)
Product don't need orderID, but when you ask for it [in product resolver]
query product(id) {
id
orderedRecently {
orderID
date
price
}
}
... you can simply get it (or rather many - array) from orderLines and orders tables [using simple SQL query - where price will be read from orderLines]
orderedRecently resolver can get product id from parent object (usually 1st param)
Of course you can (and should) return data as order and orderLine types (to be cached separately, normalized):
query product($id: ID!) {
product(id: $id) {
id
orderedRecently {
id
date
orderLine {
id
amount
price
}
}
}
}
where type orderedRecently: [Order!] - array can be empty, not eordered yet
update
I slightly misunderstood your requirements (naming convention) ... you already have proper db structure. Mutation can be 'feeded' with complex data/input:
mutation {
createOrder(input: {
order: {
ordername: "My order"
products: [
{
quantity: 3
idrefproduct: 25
},
{
quantity: 5
idrefproduct: 28
}
]
}
}) {
order {
id
ordername
products {
id
idrefproduct
quantity
}
}
}
}
Your product is my orderLine, idrefproduct is product.
createOrder creates/inserts order and then use its id for creation of product records (order.id, idrefproduct and quantity). Resolver can return only order id or structured data (as above).

Related

Hasura complex search of products

How can i solve this problem with complex searching in products?
This is what i have now as a standard get products and search on them.
query getProducts($limit: Int, $offset: Int, $searchQuery: String) {
products_products(limit: $limit, offset: $offset, where: {_or: [{title: {_ilike: $searchQuery}}, {shortDescription: {_ilike: $searchQuery}}], active: {_eq: true}}) {
__typename
id
shortDescription
title
likes {
userId
}
images(where: {main: {_eq: true}}) {
image
}
categories {
category {
title
}
}
}
}
i have products table, categories table, join table(productId, categoryId), later on there would be reviews table, wishlist table
how to show products only in any category (record in join table)?
how to show products with reviews 3.5+ ?
You know how it is with complex filtration.
Can someone show me how it could be done?
Lastly .. im using flutter with optimistic results, so thats why i chose this structure of query. it makes sense when "replicating" the state of wishlist.
how to show products only in any category (record in join table)?
You can filter on related data as well
query {
product(where: { category: { name: { _eq: "Kitchen" } } })
}
how to show products with reviews 3.5+ ?
I assume you mean an average review of 3.5 stars or greater?
There is a brand new feature in Hasura called Aggregation Predicates that lets you do this
See last month's community call demo for how to use it:
https://youtu.be/4LUiztVe8EA?t=1505
By the way, if you are building an e-commerce type application, there is a sample application which already implements much of this functionality so you can see how it is done:
https://hasura.io/reference-app/
https://github.com/hasura/hasura-ecommerce

How to use previously acquired data in the GraphQL query?

Let's say we have two entities.
users that has uuid, name and age
users_books that has user_uuid, book_id and recommended_age.
user_uuid was added as foreign key pointing to uuid in Users
Using user name I want to get all the books that that user reads and have recommended age equal to users age.
Following query will get me all the books that user reads
query getUserBooks($uuid: uuid!) {
users_by_pk(uuid: $uuid) {
uuid
name
age
users_books() {
book_id
recommended_age
}
}
}
And this is the query I am trying to create:
query getUserBooksWithRestrictedAge($uuid: uuid!) {
users_by_pk(uuid: $uuid) {
uuid
name
age
users_books(where:{recommended_age:{_eq: *WHAT_SHOULD_GO_HERE?*}}) {
book_id
recommended_age
}
}
}
Is this even possible?
Hasura supports columns comparison operators only when setting permissions. To accomplish what you need you have to create a view.
CREATE OR REPLACE VIEW users_books_by_age AS
SELECT * from users_books
Set the relationships between the view, user and books table. In the Hasura view permission builder filter the age comparing the columns. Something like
{
user: {
age: {
_ceq: recommended_age
}
}
}
This way you can run your query like:
query getUserBooks($uuid: uuid!) {
users_by_pk(uuid: $uuid) {
uuid
name
age
users_books_by_age {
book_id
recommended_age
}
}
}
Another solution would be to create a computed field. Something like:
CREATE FUNCTION author_full_name(user_row user)
RETURNS SETOF users_books AS $$
SELECT * FROM users_books where recommended_age = user_row.age
$$ LANGUAGE sql STABLE;
I hope that helps.

Is it able to sort by subfields in directus v9 Graphql Query

I am trying to sort a Graphql Query in Directus v9 by a subfield.
There is a small description how to do this... but not for subfields:
https://docs.directus.io/reference/query/#sort
my query looks like this:
query {
invoices(sort: ["customer__name"] ) {
id
status
customer {
id
name
}
}
}
I have tried multiple forms like customer:name, ```customer_name``.
if i sort by field "status" in ascending order the query looks like this and it works:
query {
invoices(sort: ["status"] ) {
id
status
customer {
id
name
}
}
}
if i sort by field "status" in descending order the query looks like this and it works:
query {
invoices(sort: ["-status"] ) {
id
status
customer {
id
name
}
}
}
has anyone tried this?
Unfortunately, sorting by related table's subfield it is not possible by now. See: https://github.com/directus/directus/discussions/4502
Edit: https://github.com/directus/directus/pull/12084 they added support for sorting by nested M2O relation in v9.10.0.

Best practice for schema naming of entity/collection

I am building a Graphql Schema and I was wandering what is the best practice of returning single vs collection items of a type. Let's say we want to retrieve users,
One option (if possible somehow) would be to have a query like this where the ID is optional, if ID is passed we return a single item, if not a collection of all users
query {
user (id: 1234) {
name
}
}
// return a single [User]
query {
user (id: null) {
name
}
}
// return a collection [User,User,User,...]
Another option would be to have user and users
query {
user (id: 1234) {
name
}
}
// return a single User
query {
users {
name
}
}
// return a collection [User,User,User,...]
I was wondering what is the best practice, or if you can pin-point me some resources related to that to read.
I am using the singular and plurals nouns to name the query field that return a single object and a list of object respectively. I think this naming style is very natural to most of the developers.
So to return a single user, it is :
type Query {
user(id:Int!) : User
}
It always return a single user. Just make the id input parameter as mandatory such that it cannot accept NULL.
And to return a list of user , normally it is:
type Query {
users : [User]
}
But in case it can have many users , most probably you need to consider something like pagination that allows developers to get the user page by page. For the offset -based pagination , I am doing something like below :
type Query {
users(offset:Int limit:Int) : UserPage
}
type UserPage {
data : [User]
pageInfo : PageInfo
}
type PageInfo {
# When paginating forwards, are there more items?
hasNextPage : Boolean!
# When paginating backwards, are there more items?
hasPreviousPage: Boolean!
# Total number of records in all page
total : Long
}
Depending on the requirements , you can consider to add an orderBy or a filter input parameter to the users query field to provide more options to the developers to get the result set that they are interested.
If you want to return the user list in the cursor-based pagination style, you can take a look on Relay Specification.

GraphQL with multiple objects: should I keep all objects in a single query?

I´m building a SaaS B2B application composed of several different objects. Examples:
Users
Customers
StockItens
StockLevels
PriceList
Sales
Returns
Etc...
I´ll have around 40 different objects, that can be listed and created, edited, and deleted individually.
Facing the GraphQL concepts for the first time, should I build a large schema for all objects, like the example below, or should I keep each object on its own query.
query {
viewer {
Users {
id
firstName
lastName
address
city
...
}
Customers {
id
firstName
lastName
address
city
rating
...
}
StockItens {
id
item_id
sales {
id
dateTime
qty
unitValue
totalValue
...
}
...
}
StockLevels {
...
}
PriceList {
...
}
Sales {
id
dateTime
qty
unitValue
totalValue
...
}
Returns {
...
}
}
}
Looking for the first option (keeping everything into one single query) seens logical as I will be using fragments to access the desired piece of information, but then I will have a huge schema with lots of inter relations.
PLease advice what would be the best practice on that use case.
I suggest you do not write a query where you add all needed data but use the concept of fragments as you already pointed out.
And you fetch only the data which are needed for the current page. So the throughput is kept minimal.
e.g.
If you have a page where you update a user you just fetch the needed data for this user in a specialized query. The query consists of fragments.
The fragments are related to the subcomponents which are used in the page, for example a form where you show the data of the user.
The fragment of the form defines the data it needs from the user and the update page combines the fragments to the query.
// in user form component
const userFormFragments = {
name: "UserForm",
document: `fragment UserForm on User {
id
name
}`
};
// in update user page
const userQuery = `query getUserQuery($userId: ID!) {
getUser(userId: $userId) {
...${userFormFragment.name}
}
${userFormFragment.document}
}`

Resources