Why is cache.readQuery returning null? - javascript

I have a project management application built with React and GraphQL for which the Github repo can be found here. One of the functionalities allows for deleting a project.
I am trying to update the cache when I delete an individual project.
const [deleteProject] = useMutation(DELETE_PROJECT, {
variables: { id: projectId },
update(cache, { data: { deleteProject } }) {
const { projects } = cache.readQuery({ query: GET_PROJECTS });
cache.writeQuery({
query: GET_PROJECTS,
data: {
projects: projects.filter(
(project) => project.id !== deleteProject.id
),
},
});
},
onCompleted: () => navigate("/"),
});
However, when I attempt to do so, I am getting the following error: Error: Cannot destructure property 'projects' of 'cache.readQuery(...)' as it is null
Can someone help me figure out what's going on? This is what the getProjects query looks like:
const GET_PROJECTS = gql`
query getProjects {
projects {
id
name
description
status
}
}
`;
Here is the root query:
const RootQuery = new GraphQLObjectType({
name: "RootQueryType",
fields: {
projects: {
type: new GraphQLList(ProjectType),
resolve(parent, args) {
return Project.find();
},
},
project: {
type: ProjectType,
args: { id: { type: GraphQLID } },
resolve(parent, args) {
return Project.findById(args.id);
},
},
clients: {
type: new GraphQLList(ClientType),
resolve(parent, args) {
return Client.find();
},
},
client: {
type: ClientType,
args: { id: { type: GraphQLID } },
resolve(parent, args) {
return Client.findById(args.id);
},
},
},
});

Related

apollo client offsetLimitPagination not working

I have a hook..
export function useLazyProposalList() {
const [getQueueData, { loading, data, error, fetchMore }] = useLazyQuery(PROPOSAL_LIST, {
fetchPolicy: 'no-cache',
});
const proposalList = React.useMemo(() => {
if (!data) {
return null;
}
return transformProposals(data);
}, [data]);
return {
getQueueData,
fetchMore,
loading,
data: proposalList,
error,
};
}
In the component
const {
getQueueData,
data: queueData,
fetchMore: fetchMoreProposals,
// loadMore: loadMore,
} = useLazyProposalList();
If user clicks on fetch more button, I call: fetchMoreProposals .
await fetchMoreProposals({
variables: {
offset: visibleProposalList.length,
},
});
but this doesn't update my data. I read that we should use offsetLimitPagination, but my data from query is not array itself. It's like this: queue { id: '1', items:[] } and because of this, offsetLimitPagination doesn't work. So I tried merge
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
queue: {
keyArgs: false,
merge(existing, incoming) {
console.log(existing, incoming);
if (!incoming) return existing;
if (!existing) return incoming;
},
},
},
},
}
but in the console, it just prints refs instead of real data.
What could be the issue ?

prisma2: how to fetch nested fields?

In prisma 1 I have used fragment to fetch the nested fields.
For example:
const mutations = {
async createPost(_, args, ctx) {
const user = await loginChecker(ctx);
const post = await prisma.post
.create({
data: {
author: {
connect: {
id: user.id,
},
},
title: args.title,
body: args.body,
published: args.published,
},
})
.$fragment(fragment);
return post;
},
};
but seems like in prisma2 it is not supported. because by running this on playground,
mutation CREATEPOST {
createPost(
title: "How to sleep?"
body: "Eat, sleep, repaet"
published: true
) {
title
body
published
author {
id
}
}
}
I am getting,
"prisma.post.create(...).$fragment is not a function",
The include option is used to eagerly load relations in Prisma.
Example from docs:
const result = await prisma.user.findOne({
where: { id: 1 },
include: { posts: true },
})
Assuming a user table with a one-to-many posts relation, this will return back the user object with the posts field as well.
Prisma also supports nesting as well, for example:
const result = await prisma.user.findOne({
where: { id: 1 },
include: {
posts: {
include: {
author: true,
}
},
},
})

Zapier JS conditional statement

I'm noob at JS, trying to write an APP for zapier. I have a test auth function that I can't get to fail when bad info is sent in.
Here is the test function:
require('should');
const zapier = require('zapier-platform-core');
const App = require('../../index');
const appTester = zapier.createAppTester(App);
describe('Triggers - Get Groups', () => {
zapier.tools.env.inject();
it('should get an array', done => {
const bundle = {
authData: { api_key: process.env.API_KEY },
inputData: {}
};
appTester(App.triggers['getgroup'].operation.perform, bundle)
.then(results => {
results.includes('id');
done();
})
.catch(results);
});
});
If successfull, a sample return should look like this:
{"id":1815,"name":"New Contacts","count":2}
A failure looks like this:
{"RESPONSE":"FAIL","REASON":"Invalid API key"}
Here is the getgroup function:
// Trigger stub created by 'zapier convert'. This is just a stub - you will need to edit!
const { replaceVars } = require('../utils');
const getList = (z, bundle) => {
let url = 'https://path.to/apisite?action=getGroups&apiKey={{api_key}}';
url = replaceVars(url, bundle);
const responsePromise = z.request({ url });
return responsePromise.then(response => {
response.throwForStatus();
return z.JSON.parse(response.content);
});
};
module.exports = {
key: 'getgroup',
noun: 'Getgroup',
display: {
label: 'Get Groups',
description: 'Triggers when loaded to pull groups.',
hidden: true,
important: false
},
operation: {
inputFields: [
{
key: 'group',
label: 'Groupget',
type: 'string',
required: false
}
],
outputFields: [
{
key: 'count',
type: 'string'
},
{
key: 'id',
type: 'string',
label: 'groupid'
},
{
key: 'name',
type: 'string',
label: 'groupname'
}
],
perform: getList,
sample: { count: 243, id: 27806, name: 'New Contacts' }
}
};
When I test auth on Zapier's website, I'd like auth to fail, and return the "REASON"
How do I do this?

Field args rejected when return a function not object

I want ask about GraphQL
This code will be failed, and shows error
Error: Mutation.addUser args must be an object with argument names as keys.
here is the code
const Schema = new GraphQLObjectType({
name: "Mutation",
description: "Mutation schema",
fields() {
return {
// Add user
addUser: {
type: UserSchema,
args: () => {
return {
firstName: {
type: GraphQLString
}
};
},
resolve(_, args){
return Db.models.user.update( () => {
return _.mapValues(args, (v, k) => {
return args[k];
});
}, {
returning: true
});
}
}
};
}
});
But, this code work perfectly
const Schema = new GraphQLObjectType({
name: "Mutation",
description: "Mutation schema",
fields() {
return {
// Add user
addUser: {
type: UserSchema,
args: {
firstName: {
type: GraphQLString
},
lastName: {
type: GraphQLString
}
},
resolve(_, args){
return Db.models.user.update( () => {
return _.mapValues(args, (v, k) => {
return args[k];
});
}, {
returning: true
});
}
}
};
}
});
Why args can't return object from function?
The fields itself can be a function, so having another function inside it to define args is kind of redundant.
The purpose of having them as functions is to be able to define types that need to refer to each other, or types that need to refer to themselves in a field.
So having only fields as a function will do the trick.

How to fetch and display item by id using Relay container, react-router and GraphQL

I am having a really hard time trying to get my head around Relay routes, react-router params and building the queries and containers in general!
I want to edit a Feature when the user clicks on a specific Feature in a FeatureList. It passes a param called "id" which is the id of the Feature in Route.js
<Route path='/' component={AppComponent} queries={ViewerQuery}>
<IndexRoute component={FeaturesContainer} queries={ViewerQuery} />
<Route path='/feature' component={FeatureComponent} queries={ViewerQuery} />
<Route path="/feature/edit/:id" component={FeatureEditComponent} queries={FeatureQuery}/>
<Redirect from='*' to='/' />
</Route>
In my FeatureQuery file I have the following query:
export default {
viewer: (Component) => Relay.QL`
query {
viewer {
${Component.getFragment('viewer')}
}
}
`
};
At this point I am completely stuck. How do I expand this to include the "id" and query the features using the "id"?
And what would the relating relay container fragment be shaped like? I only see examples going one level deep.
I tried this but I know it isn't right:
export default {
feature: (Component) => Relay.QL`
query {
viewer {
features(id:$id) {
${Component.getFragment('feature')}
}
}
}
`
};
This is the current relay container that gets a list of the Features, how would this be modified to just return the 1 feature by id? :
export default Relay.createContainer(CreativeEditComponent, {
fragments: {
viewer: () => Relay.QL`
fragment on User {
id,
features(first: 20) {
edges {
node {
id
name
description
}
}
}
}`
}
});
I have tested a query in GraphiQL and it works as expected:
query {
viewer {
features(id:"1") {
edges {
node {
id
name
description
}
}
}
}
}
Result:
{
"data": {
"viewer": {
"features": {
"edges": [
{
"node": {
"id": "Q3JlYXRpdmU6MQ==",
"name": "React",
"description": "A JavaScript library for building user interfaces."
}
}
]
}
}
}
}
schema.js:
const userType = new GraphQLObjectType({
name: 'User',
description: 'A person who uses our app',
fields: () => ({
id: globalIdField('User'),
features: {
type: featureConnection,
description: 'Features that I have',
//args: connectionArgs,
args: {
id: {
type: GraphQLString,
},
after: {
type: GraphQLString,
},
first: {
type: GraphQLInt,
},
before: {
type: GraphQLString,
},
last: {
type: GraphQLInt,
},
},
resolve: (_, args) => {
return resolveGetFeatures(args)
},
},
}),
interfaces: [nodeInterface]
});
const featureType = new GraphQLObjectType({
name: 'Feature',
description: 'Feature integrated in our starter kit',
fields: () => ({
id: globalIdField('Feature'),
name: {
type: GraphQLString,
description: 'Name of the feature'
},
description: {
type: GraphQLString,
description: 'Description of the feature'
}
}),
interfaces: [nodeInterface]
});
You need to pass the router variables to your fragment.
const ViewerQuery = {
viewer: (Component, vars) => Relay.QL`
query {
viewer {
${Component.getFragment('viewer', vars)} # <-- this
}
}
`
}
I copied this code detail from here: https://github.com/relay-tools/react-router-relay/issues/92#issuecomment-235641397
Then you can use the id variable in your component, but you need an initial value for id:
export default Relay.createContainer(CreativeEditComponent, {
initialVariables: {
id: ''
},
fragments: {
viewer: () => Relay.QL`
fragment on User {
id,
feature(id:$id) {
id
name
description
}
}`
}
});
And in schema.js define a field for your user type, that serves only one feature:
const userType = new GraphQLObjectType({
name: 'User',
description: 'A person who uses our app',
fields: () => ({
id: globalIdField('User'),
feature: {
type: featureType,
description: 'feature',
args: {
id: {
type: GraphQLString,
description: 'The id of the feature'
}
},
resolve: (_, args) => resolveGetFeature (args),
},
...

Categories

Resources