I'm starting working with graphQL with couchbase, and I have a small problem when I run a mutation, what I'm doing is save 2 object:
key: email#email.it
{
type: 'credential',
user_id: 'xxxx-xxxx-xxxx-xxxx',
password: 'jknelkjf'
}
key: xxxx-xxxx-xxxx-xxxx
{
type: 'user',
name: 'aaaa',
surname: 'bbbb'
}
this is my mutation function:
export default {
createUser: {
type: User,
args: {
email: { type: GraphQLString },
password: { type: GraphQLString },
name: { type: GraphQLString },
surname: { type: GraphQLString }
},
resolve(source, args, req) {
const _id = uuid();
return new Promise((resolve, reject) => {
bcrypt.hash(args.password, 10)
.then(hash => req.db.insert({}, args.email, {
password: hash,
user_id: _id,
type: "credential"
}))
.then(cred => req.db.insert({}, cred.user_id, {
name: args.name,
surname: args.surname,
type: "user"
}))
.then(user => {
return resolve(user);
})
.catch(err => {
return reject(err);
});
});
}
}
}
and these are my schemas
export const UserCredential = new GraphQLObjectType({
name: 'UserCredential',
fields: () => ({
user_id: { type: GraphQLString },
type: { type: GraphQLString },
id: { type: GraphQLString },
password: { type: GraphQLString }
})
});
export const User = new GraphQLObjectType({
name: 'User',
fields: () => ({
name: { type: GraphQLString },
surname: { type: GraphQLString },
type: { type: GraphQLString },
id: { type: GraphQLString },
credential: {
type: UserCredential,
resolve: (root, args, req) => {
const query = `SELECT META(credential).id,credential.* FROM {{bucket}} as credential WHERE credential.type="credential" AND credential.user_id=$1`;
return new Promise((resolve, reject) => {
req.db.runQuery(null, query, [root.id])
.then((res) => {
return resolve(res[0]);
})
.catch((err) => {
return reject(err);
})
});
}
}
})
});
the problem is that when I run the mutation the result is the user object with the credential field null, but if I add a timeout on the resolve of the mutation I get the user with the credential object...the insert function is something like this:
db.insert(result => {
return db.find(result.id)
})
do you have any advice?
Related
I have an address in my database that I've put into a location hash. The hash contains separate keys for streetAddress, city, state, and zipCode. I've nested the data like so in my graphql schema file:
location: {
streetAddress: {
type: String,
required: true,
unqiue: true
},
city: {
type: String,
required: true
},
state: {
type: String,
required: true
},
zipCode: {
type: Number,
required: true
}
}
And I've implemented the schema type like this:
fields: () => ({
id: { type: GraphQLID },
name: { type: GraphQLString },
id: {type: GraphQLID},
phoneNum: { type: GraphQLString },
location: {
streetAddress: { type: GraphQLString },
city: { type: GraphQLString },
state: { type: GraphQLString },
zipCode: { type: GraphQLInt }
}
...
However, I get an error message saying that the output type is undefined when I try to do a query in graphql:
"message": "The type of RestaurantType.location must be Output Type but got: undefined."
I believe I understand where the error is coming from; I'm assuming that it expects location to have a type as well. What would be the correct syntax for doing this/fixing this error message?
As you guessed, you cannot have nested fields like that. You need to create a separate type for every object in your schema. First create the type:
const Location = new GraphQLObjectType({
name: 'Location',
fields: () => ({
streetAddress: { type: GraphQLString },
city: { type: GraphQLString },
state: { type: GraphQLString },
zipCode: { type: GraphQLInt }
}),
})
Then use it:
const Restaurant = new GraphQLObjectType({
name: 'Restaurant',
fields: () => ({
id: { type: GraphQLID },
name: { type: GraphQLString },
location: { type: Location },
}),
})
or if you don't need to reuse the type, you can define it inline like this:
const Restaurant = new GraphQLObjectType({
name: 'Restaurant',
fields: () => ({
id: { type: GraphQLID },
name: { type: GraphQLString },
location: {
type: new GraphQLObjectType({
name: 'Location',
fields: () => ({
streetAddress: { type: GraphQLString },
city: { type: GraphQLString },
state: { type: GraphQLString },
zipCode: { type: GraphQLInt }
}),
})
},
}),
})
I'm really new to graphQL
I have a simple graphQL schema here
const graphql = require('graphql');
const _ = require('lodash');
const {
GraphQLObjectType,
GraphQLString,
GraphQLSchema,
GraphQLID
} = graphql
const books = [
{ name: "book 1", genre: "book-1", id: "1" },
{ name: "book 2", genre: "book-2", id: "2" },
{ name: "book 3", genre: "book-3", id: "3" }
]
const BookType = new GraphQLObjectType({
name: 'Book',
fields: () => ({
id: { type: GraphQLID },
name: { type: GraphQLString },
genre: { type: GraphQLString }
})
})
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
book: {
type: BookType,
args: { id: { type: GraphQLID } },
resolve(parent, args) {
return _.find(books, { id: args.id })
}
}
}
})
module.exports = new GraphQLSchema({
query: RootQuery
})
I can return one book using the id
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
book: {
type: BookType,
args: { id: { type: GraphQLID } },
resolve(parent, args) {
return _.find(books, { id: args.id })
}
}
}
})
How would I return all the books, I was thinking something like:
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
book: {
type: BookType,
args: {},
resolve(parent, args) {
return _.find(books, {})
}
}
}
})
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: {
book: {
type: BookType,
args: { displayall: { type: GraphQLID } },
resolve(parent, args) {
return _.find(books, { displayall: args.displayall })
}
}
books:{
type: new GraphQLList(BookType),
resolve(parent, args) {
return books
}
}
}
})
my whole schema
const Films = new GraphQLObjectType({
name: 'films',
interfaces: () => [MovieStream],
fields: () => ({
movie_id: {
type: GraphQLString,
},
id:{
type: GraphQLID
},
name: {
type: GraphQLString,
},
})
})
Films._typeConfig = {
sqlTable: "films",
uniqueKey: 'id',
}
const MovieStream = new GraphQLInterfaceType({
name: 'MovieStream',
fields: () => ({
id: {
type: GraphQLID,
},
movie_id: {
type: GraphQLString,
},
})
})
MovieStream._typeConfig = {
sqlTable: "movie_streams",
uniqueKey: 'id'
}
const QueryRoot = new GraphQLObjectType({
name: 'Query',
fields: () => ({
getContentList:{
type: new GraphQLList(Films),
args: {
id: {
type: GraphQLInt
},
permalink: {
type: GraphQLString
},
language: {
type: GraphQLString
},
content_types_id: {
type: GraphQLString
},
oauth_token:{
type: GraphQLString
}
},
resolve: (parent, args, context, resolveInfo) => {
return joinMonster.default(resolveInfo,{}, sql => {
return FilmDb.query(sql).then(function(result) {
return result[0];
});
} ,{dialect: 'mysql'});
},
}
})
})
module.exports = new GraphQLSchema({
query: QueryRoot
})
I have again modified my code still got the error
{
"errors": [
{
"message": "Unknown column 'getContent.movie_id' in 'field list'",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"getContentList"
]
}
],
"data": {
"getContentList": null
}
}
My previous post Is it possible to fetch data from multiple tables using GraphQLList
Please check and tell me where i am wrong??? I have already add the field still it does not access the field of that object type
const QueryRoot = new GraphQLObjectType({
name: 'Query',
fields: () => ({
getContentDetails: {
type: new GraphQLList(Films),
args: {
id: {
type: GraphQLInt
},
permalink: {
type: GraphQLString
},
studio_id: {
type: GraphQLString
},
content_types_id: {
type: GraphQLString
}
},
where: (filmTable, args, context) => {
return ` ${filmTable}.permalink = "${args.permalink}" and ${filmTable}.content_types_id = "${args.content_types_id}"`
},
resolve: (parent, args, context, resolveInfo) => {
return joinMonster.default(resolveInfo, {}, sql => {
return FilmDb.query(sql).then(function(result) {
return result[0];
});
},{dialect: 'mysql'});
}
}
})
})
I've greated a simple relay flavoured mutation that works just fine. I've got a simple client side component that commits the mutation with the required data.
My question is how do I send back multiple errors to the client? Currently I can simply throw an error (or reject a promise) in mutateAndGetPayload and I will receive an error on the client side, but this currently only works with a string message. Should I simply reject the promise with a JSON string of an errors array? Or is there a better way?
const createCashAccountMutation = mutationWithClientMutationId({
name: 'CreateCashAccount',
inputFields: {
name: {
type: new GraphQLNonNull(GraphQLString),
description: 'Cash account name'
},
code: {
type: GraphQLString,
description: 'Optional code'
},
businessId: {
type: new GraphQLNonNull(GraphQLString),
description: 'Business ID'
},
currencyId: {
type: new GraphQLNonNull(GraphQLString),
description: 'Currency ID'
},
isActive: {
type: new GraphQLNonNull(GraphQLInt)
}
},
outputFields: {
name: {
type: GraphQLString,
resolve: (payload) => payload.name
},
code: {
type: GraphQLString,
resolve: (payload) => payload.code
},
businessId: {
type: GraphQLString,
resolve: (payload) => payload.businessId
},
currencyId: {
type: GraphQLString,
resolve: (payload) => payload.currencyId
},
isActive: {
type: GraphQLString,
resolve: (payload) => payload.isActive
}
},
mutateAndGetPayload: async (options) => {
throw 'wtf';
return options;
}
});
Update 1.
I've come up with the following example:
const graphQLCashAccount = new GraphQLObjectType({
name: 'cashAccount',
fields: {
name: {
type: GraphQLString,
resolve: (payload) => payload.name
},
code: {
type: GraphQLString,
resolve: (payload) => payload.code
},
businessId: {
type: GraphQLString,
resolve: (payload) => payload.businessId
},
currencyId: {
type: GraphQLString,
resolve: (payload) => payload.currencyId
},
isActive: {
type: GraphQLString,
resolve: (payload) => payload.isActive
}
}
});
const graphQLErrors = new GraphQLList(new GraphQLObjectType({
name: 'errors',
fields: {
key: {
type: GraphQLString,
resolve: (payload) => payload.key
},
message: {
type: GraphQLString,
resolve: (payload) => payload.message
}
}
}));
const graphQlInput = new GraphQLInputObjectType({
name: 'data',
fields: {
name: {
type: new GraphQLNonNull(GraphQLString),
description: 'Cash account name'
},
code: {
type: GraphQLString,
description: 'Optional code'
},
businessId: {
type: new GraphQLNonNull(GraphQLString),
description: 'Business ID'
},
currencyId: {
type: new GraphQLNonNull(GraphQLString),
description: 'Currency ID'
},
isActive: {
type: new GraphQLNonNull(GraphQLInt)
}
}
});
const createCashAccountMutation = mutationWithClientMutationId({
name: 'CreateCashAccount',
inputFields: {
data: {
type: graphQlInput
}
},
outputFields: {
data: {
type: graphQLCashAccount,
resolve: (payload) => payload.data
},
errors: {
type: graphQLErrors,
resolve: (payload) => payload.errors
}
},
mutateAndGetPayload: async (options) => {
const payload = {
errors: [{ key: 'asd', message: 'asd failed' }],
data: options
};
return payload;
}
});
This will actually resolve the transaction and simply return 2 fields, a data field and an errors field. One of them will be populated.
Is this a better approach? I'm stumped on how I should apply the update in Relays fatquery though.
Update 2.
Relay Mutation client side example.
export class NewCashAccountMutation extends Relay.Mutation {
getMutation () {
return Relay.QL`mutation {
createCashAccount
}`;
}
getVariables() {
return { data: this.props.cashAccount };
}
getFatQuery() {
return Relay.QL`
fragment on CreateCashAccountPayload {
data, errors
}
`;
}
getConfigs() {
return [{
type: 'FIELDS_CHANGE',
fieldIDs: {
data: this.props.cashAccount.id,
},
}];
}
}