Every node field in an array of edges of a NodeConnection type resolves to the same node object type - relaymodern

I have an object with multiple mockResolvers.This includes a node and a node connection graphql type e.g UserNode which would have the fields of a single user and a UserNodeConnection which has an edges array with all the UsedNode and pageInfo.
When I mock the allUsers query, all the nodes in the edges array resolve back to the single UserNode such that, if my user node is
UserNode: () => (
id :'id-one',
name :'user-one-name',
}
while the UserNodeConnection is
UserNodeConnection:() => (
pageInfo:{
hasNextPage :true,
hasPreviousPage:true,
},
edges:[
{
node:{
id :'id-two',
name :'user-two-name',
},
},
{
node:{
id :'id-three',
name :'user-three-name',
},
},
{
node:{
id :'id-four',
name :'user-four-name',
},
},
],
}
and the query
query AllUsers {
allUsers {
edges {
node {
id
name
}
}
}
}
The result is
[
{
id:"id-one",
name:"user-one-name"
}
{
id:"id-one",
name:"user-one-name"
}
{
id:"id-one",
name:"user-one-name"
}
]
Instead of
[
{
node:{
id :'id-two',
name :'user-two-name',
},
},
{
node:{
id :'id-three',
name :'user-three-name',
},
},
{
node:{
id :'id-four',
name :'user-four-name',
},
},
]
This means for every user in the edges array, the UserNode is being resolved.
How do I get this to return the nodes in the edges array when mocking a fetch for all users and only return the UserNode object when getting a single user(This already works)?

Related

How to cast into a type in GraphQL

For example, through GitHub explorer one can retrieve different types of time line items for a pull request (in this example PULL_REQUEST_COMMIT and PULL_REQUEST_REVIEW):
{
repository(name: "react", owner: "facebook") {
pullRequests(last: 10) {
nodes {
number
timelineItems(last: 10, itemTypes: [PULL_REQUEST_COMMIT, PULL_REQUEST_REVIEW]) {
nodes {
__typename
}
}
}
}
}
}
How can I now access different fields of the types PullRequestEvent or PullRequestReviewEvent? In other words, is there a cast or an if-then-else in GraphQL?
nodes returns an array of PullRequestTimelineItems and a PullRequestTimelineItemsis a GraphQL union type. You can use the ...on notation to query for fields of a specific member in the union type:
{
repository(name: "react", owner: "facebook") {
pullRequests(last: 10) {
nodes {
number
timelineItems(last: 10, itemTypes: [PULL_REQUEST_COMMIT, PULL_REQUEST_REVIEW]) {
nodes {
...on PullRequestReview {
body
}
...on PullRequestCommit {
url
}
}
}
}
}
}
}

HotChocolate GraphQL filtering on GUID

I have very limited knowledge on GraphQL as I am still in the learning process. Now I stumbled upon an issue that I cannot resolve by myself without some help.
I'm using HotChocolate in my service.
I have a class ConsumerProductCategory with a Guid as Id which has a parent that is also a ConsumerProductCategory (think category > sub-category > ...)
Now I want to get the sub categories for a specific category, in linq you would write:
.Where(cat => cat.Parent.Id == id)
First of all lets start with our classes:
public class BaseViewModel : INode
{
public virtual Guid Id { get; set; }
}
public class ConsumerProductCategory : BaseViewModel
{
public ConsumerProductCategory()
{
}
public string Name { get; set; }
[UsePaging]
[UseFiltering]
[UseSorting]
public List<ConsumerProduct> Products { get; set; } = new List<ConsumerProduct>();
public ConsumerProductCategoryImage Image { get; set; }
public ConsumerProductCategory Parent { get; set; } = null;
public bool HasParent => this.Parent != null;
}
The object type definition is like this:
public class ConsumerProductCategoryType : ObjectType<ConsumerProductCategory>
{
protected override void Configure(IObjectTypeDescriptor<ConsumerProductCategory> descriptor)
{
descriptor
.Name(nameof(ConsumerProductCategory));
descriptor
.Description("Categories.");
descriptor
.Field(x => x.Id)
//.Type<UuidType>()
.Type<IdType>()
.Description($"{nameof(ConsumerProductCategory)} Id.");
descriptor
.Field(x => x.Name)
.Type<StringType>()
.Description($"{nameof(ConsumerProductCategory)} name.");
descriptor
.Field(x => x.Parent)
.Description($"{nameof(ConsumerProductCategory)} parent category.");
descriptor
.Field(x => x.Products)
.Description($"{nameof(ConsumerProductCategory)} products.");
descriptor
.ImplementsNode()
.IdField(t => t.Id)
.ResolveNode((context, id) => context.Service<IConsumerProductCategoryService>().GetByIdAsync(id));
}
}
The query to get the "main" categories would be like this:
query GetAllCategories {
consumerProductCategories(
#request: { searchTerm: "2"}
first: 10
after: null
where: { hasParent: { eq: false } }
order: {
name: ASC
}
) {
nodes {
id
name
image {
url
alt
}
}
pageInfo {
endCursor
hasNextPage
}
}
}
This returns this result:
{
"data": {
"consumerProductCategories": {
"nodes": [
{
"id": "Q29uc3VtZXJQcm9kdWN0Q2F0ZWdvcnkKZ2EyOTYxNmRlMWMzMjQ4ZTU4YTU2YzRjYjdhMGQ5NmY5",
"name": "Category 1",
"image": {
"url": "https://picsum.photos/200",
"alt": "Category 1 Image"
}
},
{
"id": "Q29uc3VtZXJQcm9kdWN0Q2F0ZWdvcnkKZ2NmZWI0YzNiMGQyNjQyOWI4MGU0MmQ1NGNjYWE1N2Q4",
"name": "Category 2",
"image": {
"url": "https://picsum.photos/200",
"alt": "Category 2 Image"
}
},
{
"id": "Q29uc3VtZXJQcm9kdWN0Q2F0ZWdvcnkKZ2I0MjhjYWE2NGMxNTQ4MTdiMjM1ZWFhZWU3OGRhYWYz",
"name": "Category 3",
"image": {
"url": "https://picsum.photos/200",
"alt": "Category 3 Image"
}
}
],
"pageInfo": {
"endCursor": "Mg==",
"hasNextPage": false
}
}
}
}
The first thing I noticed was that the Id's (Guid's) are changed to some base64 encoded strings.
Weird, but if I would do this:
query {
node(
id: "Q29uc3VtZXJQcm9kdWN0Q2F0ZWdvcnkKZ2EyOTYxNmRlMWMzMjQ4ZTU4YTU2YzRjYjdhMGQ5NmY5"
) {
... on ConsumerProductCategory {
id
name
}
}
}
this perfectly works, result:
{
"data": {
"node": {
"id": "Q29uc3VtZXJQcm9kdWN0Q2F0ZWdvcnkKZ2EyOTYxNmRlMWMzMjQ4ZTU4YTU2YzRjYjdhMGQ5NmY5",
"name": "Category 1"
}
}
}
However, now I want to filter on the Parent.Id,
query GetSubcategories {
consumerProductCategories(
first: 10
after: null
where: { parent: { id: { eq: "Q29uc3VtZXJQcm9kdWN0Q2F0ZWdvcnkKZ2NmZWI0YzNiMGQyNjQyOWI4MGU0MmQ1NGNjYWE1N2Q4"}} }
order: {
name: ASC
}
) {
nodes {
id
name
image {
url
alt
}
parent {
id
}
}
pageInfo {
endCursor
hasNextPage
}
}
}
This gives an error that the fieldtype where I do the "eq" is not correct, makes sense because in the data it's actually a Guid.
The result:
{
"errors": [
{
"message": "The specified value type of field `eq` does not match the field type.",
"locations": [
{
"line": 5,
"column": 31
}
],
"path": [
"consumerProductCategories"
],
"extensions": {
"fieldName": "eq",
"fieldType": "UUID",
"locationType": "UUID",
"specifiedBy": "http://spec.graphql.org/June2018/#sec-Values-of-Correct-Type"
}
}
]
}
I understand why it gives me this error, but I have no clue how to resolve this.
I looked everywhere on Google but have not found a similar question and in the official docs of HotChocolate I cannot really find a solution for this issue.
Can anyone point me in the right direction?
By the way, is it a good practice to use these "autogenerated" base64 strings as Id's, or is there some way to specify that this generation should not happen and actually return the Guid's instead?
Thanks in advance!
Ok, I can answer my own question, basically it isn't supported yet: github
What I've done for now is just add a second Guid in the base class:
This results in:

How do i connect two types in GraphQL?

So I have two types in GraphQL:
article.mdx
---
title: "Post n.1"
category: "Category"
---
Post Content
categories.json
[
{
"name": "Category",
"description": "This is a description",
"order": 1
}
]
I want to query my post type in order to have this kind of result:
{
"node": {
"title": Post n.1
"category": {
"name": "Category",
"description": "This is a description",
"order": 1
}
}
}
How can i do this? I'm currently using GatsbyJS! Thanks.
its pretty easy as you know you should use gatsby-transformer-remark to read md files , so for the json files you should use gatsby-transformer-json , add it in the gatsby-config.js file under plugins. then you need to query your data , unfortunatly i realy dont think you can combile two files to get data as you ask , but you can try this
first in gatsby-node.js file you need to reference the variables you gonna use for filter the query data , pass those fields in to the context
exports.createPages = async function({ actions, graphql }) {
const { data } = await graphql(`
query {
allMarkdownRemark {
edges {
node {
fields {
slug
}
}
}
}
}
`)
data.allMarkdownRemark.edges.forEach(edge => {
const slug = edge.node.fields.slug
actions.createPage({
path: slug,
component: require.resolve(`./src/templates/article.js`),
context: { category: category},
})
})
}
then in your page query you can accesss the filterd query by this read more in Creating Pages from Data Pro grammatically
export const pageQuery = graphql`
query MyQuery($category: String!) {
allMarkdownRemark(filter: {frontmatter: {category: {eq: $category}}}) {
edges {
node {
frontmatter {
title
}
}
}
}
allDataJson(filter: {name: {eq: $category}}) {
edges {
node {
nodes {
name,
description,
order
}
}
}
}
}`
then access you can access the your data by const {allMarkdownRemark , allDataJson} = data
then combine those two data as you prefer
const item = {node : { title: allMarkdownRemark.edges.node[0].frontmatter }};
item.node.category = allDataJson.edges.node[0].nodes
note this was assuming that edges.node is an array so we need to exact the 1st element of your data by node[0] , please check whether this method is working .
and the structure for the json data was
{ "nodes": [ {
"name": "Category",
"description": "This is a description",
"order": 1
}
]
}

Using graphql union return an array with some empty objects

I'm using graphql union - union FolderOrFile = Folder | File. When I query for only folders I get array containing folder objects with empty objects that are basically the file objects.
TypeDefs
const typeDefs = gql`
union FolderOrFile = Folder | File
type Folder {
name: String
path: String
type: String
children: [FolderOrFile]
}
type File {
name: String
path: String
content: String
type: String
size: Int
ext: String
createdAt: String
}
type Query {
folders: Folder
}
`
Resolvers
const resolvers = {
FolderOrFile: {
__resolveType: obj => {
if (obj.type === "file") {
return 'File'
}
if (obj.type === "folder") {
return 'Folder'
}
},
},
Query: {
folders: async () => {
const data = await folders
.getFolder('./filesystem')
.then(response => response)
const appendData = await {
name: 'Folder',
path: './filesystem',
type: 'folder',
children: data,
}
return appendData
}
}
}
folders query
{
folders {
name
path
type
children {
... on Folder {
name
path
type
children {
... on Folder {
name
path
type
}
}
}
}
}
}
Response I get
{
"data": {
"folders": {
"name": "Folder",
"path": "./filesystem",
"type": "folder",
"children": [
{
"name": "Dishes",
"path": "./filesystem/Dishes",
"type": "folder",
"children": [
{},
{},
{
"name": "Non Vegetarian",
"path": "./filesystem/Dishes/Non Vegetarian",
"type": "folder"
},
{
"name": "Vegetarian",
"path": "./filesystem/Dishes/Vegetarian",
"type": "folder"
}
]
},
]
}
}
}
The response shouldn't have those empty objects which in this case is for files being returned as empty object. Similarly when I query for file I get folders as empty objects.
You have to specify inline fragments for all the possible types when querying a field that returns a union or interface. In your query, you are only using an inline fragment for the Folder type. You're telling the server "if the returned object is a Folder, I want these fields". But if the object resolves to any other type, like File, you end up with an empty selection set because you have not specified which fields you want for that particular type.
{
folders {
name
path
type
children {
... on Folder {
name
path
type
}
... on File {
# whatever your File fields are
}
}
}
}

Parse.com REST How to query relation 3 table?

I am from MySQL so I design parse.com table like so
Vehicle | license, year, & pool_id
Pool | address & city_id
City | name
Pool_id in vehicle pointer to Pool,
City_id in pool pointer to city.
In mySQL we can Join three table and use where clause.
In the relational queries docs says
--data-urlencode 'where={"post":{"__type":"Pointer","className":"Post","objectId":"8TOXdXf3tz"}}'
Which query relation 1 table based on object id
How I query to get vehicle where city name = "somecity"?
In angularJS
var config = {
params: {
where: {
vehicle_year: "2013",
pool_id: {
$inQuery: {
where: {
city_id: {
$inQuery: {
where: {
city_name: "Jakarta"
},
className: "city"
}
}
//pool_address: "JL. DEF"
},
className: "pool"
}
},
car_id: {
$inQuery: {
where: {
car_class_id: {
$inQuery: {
where: {
name: "Box"
},
className: "car_class"
}
}
},
className: "car"
}
}
},
include: 'pool_id.city_id,car_id.car_class_id',
},
headers: { 'X-Parse-Application-Id' : 'gMKfl1wDyk3m6I5x0IrIjJyI87sumz58' }
};
then
$http.get('http://ip/parse/classname', config).then(function(response){
}, function(error){
});

Resources