I have Major categories and Minor Categories that belong to a Major category.
Both are ENUM type.
I want client to choose matching minor category ENUM to submit with its Major category.
I don't want to include all different minor category ENUMs as fields.
I first tried doing
union MinorCategories = Minor1 | Minor2
However this failed because union only works with ObjectTypes
Enforcing minor category depending on the major category is not necessary. I only want to receive one field that can be selective by the client by ENUM.
Is there any work around?
GraphQL does not support union types for scalar values, only for object types.
One option, albeit an ugly one, is to wrap your enums in an object type.
type Minor1Wrapper {
value: Minor1!
}
type Minor2Wrapper {
value: Minor2!
}
union MinorCategories = Minor1Wrapper | Minor2Wrapper
Related
I am using a python script with requests to update various properties of a shopify shop using graphql and it works fine.
The problem is I can't figure out how to update a product price when there is no product variant using Graphql
All the documentation refers to mutations on product variants, but most of the products on this shop don't have any variants.
However I read somewhere that products without variants are "default variants" themselves, but i can't find the id for this.
If I pass the product id, or global id, the response is just no id found.
I have spent hours on the documentation and I can't find the correct reference.
I even asked our banned friend, but wasn't really helpful:)
Here is the working graphql query for updating variants for reference.
query = '''
mutation productVariantUpdate($input1: ProductVariantInput!) {
item1: productVariantUpdate(input: $input1) {
productVariant {
id,
price
}
userErrors {
field
message
}
}
'''
variables = {
"input2":{"id":"gid://shopify/ProductVariant/42177699971252","price":15.20}
}
A product has many variants. Between one, and one hundred. End of story. If you have a product ID, you can get the variant IDs. End of story. If you have a variant ID, you can get the variant details. With those, you will find that a variant has an inventory_item_id. Or inventoryItemId. You get the picture? With that, you can get the item! The item has a price. You can use a mutation to set the price. That is how it is done.
If you say you have a product without a variant, that is false. Impossible.
Sounds like you're confusing the number of options with variants.
The Product object also has a totalVariants count and hasOnlyDefaultVariant fields
Ok,
The confusing part was, when you have a product the uri has a product id, if you create a variant, there is a variant id in the uri as well.
But i didn't realize that the existance of a default variant id as i never came across of this in the gui, so i never tried to run a variant query on a product without multiple variants.
So running:
{
product(id: "gid://shopify/Product/123456798"){
variants(first:5 ){
nodes {
id
price
}
}
}
}
Does return the dafault variant id which i can then use for updating.
So I have some code like the following:
input Data {
activityValue: Int
}
But I need it to be something more like
input Data {
activityValue: Int | String!
}
I know in typescript, even though frowned upon you can use any or number | string. Is there anything like this in graphql?
There is no real such thing as multiple types in the GraphQL specification. However, Unions can fit your needs.
From the specification:
GraphQL Unions represent an object that could be one of a list of GraphQL Object types, but provides for no guaranteed fields between those types.
That means that Unions can include types but no scalars or lists.
For example, a union can be declared like this:
union Media = Book | Movie
And then be used as a type:
type Query {
allMedia: [Media] # This list can include both Book and Movie objects
}
Example is taken from Apollo Docs.
If you want to check in your query if you have some type of the Union type, then you need to do that with inline fragments.
query Test {
singleMedia(id: 123) {
name
... on Book {
author
}
... on Movie {
musicTitle
}
}
}
I'm new to graphQL and Hasura. I'm trying(in Hasura) to let me users provide custom aggregation (ideally in the form of a normal graphQL query) and have then each item the results compared against the aggreation.
Here's a example. Assume I have this schema:
USERTABLE:
userID
Name
Age
City
Country
Gender
HairColor
INCOMETABLE:
userID
Income
I created a relationship in hasura and I can query the data but my users want to do custom scoring of users' income level. For example, one user may want to query the data broken down by country and gender.
For the first example the result maybe:
{Country : Canada
{ gender : female
{ userID: 1,
Name: Nancy Smith,..
#data below is on aggregated results
rank: 1
%fromAverage: 35%
}...
Where I'm struggling is the data showing the users info relative to the aggregated data.
for Rank, I get the order by sorting but I'm not sure how to display the relative ranking and for the %fromAverage, I'm not sure how to do it at all.
Is there a way to do this in Hasura? I suspected that actions might be able to do this but I'm not sure.
You can use track a Postgres view. Your view would have as many fields as you'd like calculated in SQL and tracked as a separate "table" on your graphql api.
I am giving examples below based on a simplification where you have just table called contacts with just a single field called: id which is an auto-integer. I am just adding the id of the current contact to the avg(id) (a useless endeavor to be sure; just to illustrate...). Obviously you can customize the logic to your liking.
A simple implementation of a view would look like this (make sure to hit 'track this' in hasura:
CREATE OR REPLACE VIEW contact_with_custom AS
SELECT id, (SELECT AVG(ID) FROM contacts) + id as custom FROM contacts;
See Extend with views
Another option is to use a computed field. This is just a postgres function that takes a row as an argument and returns some data and it just adds a new field to your existing 'table' in the Graphql API that is the return value of said function. (you don't 'track this' function; once created in the SQL section of Hasura, you add it as a 'computed field' under 'Modify' for the relevant table) Important to note that this option does not allow you to filter by this computed function, whereas in a view, all fields are filterable.
In the same schema mentioned above, a function for a computed field would look like this:
CREATE OR REPLACE FUNCTION custom(contact contacts)
RETURNS Numeric AS $$
SELECT (SELECT AVG(ID) from contacts ) + contact.id
$$ LANGUAGE sql STABLE;
Then you select this function for your computed field, naming it whatever you'd like...
See Computed fields
when I have a parent Object type that needs to point to a child Object type but that child Object's type can be of several types and only one can be chosen and populated. I see 2 options I can do with regard to graphql schema design.
option 1 - use union
type child1{......}
type child2{......}
union chooseOne = child1 | child2
type parent{
ref: chooseOne
}
option 2 use multiple props and have only one with data - the rest with nulls
type child1{......}
type child2{......}
type parent{
ref1: child1
ref2: child2
}
is there a 3rd option I am not thinking of? I am not that please with either. I feel like I am missing something... can anyone please comment? thanks! (edited)
am I missing a third possible option?
using an array
type Meeting{
.........(some properties)
recurrences : [Recurrence]
}
union Recurrence = Once | WeeklyRecurrence | MonthlyRecurrence | DailyRecurrence
Of course it looks like a relation ... and it is ... and gives you more possibilities.
all of them can have validFrom and validUntil times - you can filter out all historical entries automatically without manual disabling/removing
you can have AND combinations instead OR, for example 'every working day at 10.00, additionally at 15.00 on fridays'
you can process recurrence entries separately f.e. for notifications (having meeting id just fetch attendees from another relation)
But in fact maybe you don't need separate recurrence types at all, only one field/property (enumerated types) to know which fields are required for render/forms/resolver/mutations etc.
... all of them can use the same DB table, the same record structures in both cases (types mapped to enumed type field).
Update
I prefer 2nd option:
it's more readable/debuggable
it's easier to handle - if(ref1)...<Ref1Component data={ref1}/> ... passing union data object you don't have info about type!
unions sometimes leads to troubles like this
While experimenting with the Union types in GraphQL here: https://graphql.github.io/learn/schema/#union-types I ran into the following:
I initially thought that the fields you specify in the query are the fields that going to be searched for the text: "Millenium", however that's not the case because I'm still getting the Millenium Falcon's data even after removing the name field from the query for the Startship type.
I did another test: R2-D2's primaryFunction is Astromech, if you search for Astromech you'll get nothing, even if primaryFunction is specified for Droid type.
Note that name is still specified on Starship because otherwise it wouldn't show up in the results given that Starship is not a Character!
That simply means that because we are using a Union type, given two types that are part of the Union that both have a name field, you still have to request the name field for each type in their inline fragment. Omitting the name for the Starship fragment, but including it on Character, means if the returned type is a Character the name field will be present but it will not be present on the Starship type.
The docs are mentioning this to highlight the difference between Unions and Interfaces. If SearchResult was an Interface that included the name field and Character and Starship implemented that Interface, you could do something like this instead:
{
search(text: "an") {
name
__typename
... on Human {
height
}
... on Droid {
primaryFunction
}
... on Starship {
length
}
}
}
But because Unions don't guarantee any fields are shared between their types, it's not possible to do so with Unions.
With regards to search, that's not something that's baked into GraphQL. This particular schema happens to have a search field on its Query type and that field resolves a particular way. If you were creating a server, you could write a search field that considered the requested fields as part of the search criteria. But this is an implementation detail and not related to how GraphQL works in general.