Single JSON argument in mutation - json

Below I'm trying to set a mutation example with one object-arg credentials. I had this working previously then all the sudden it stopped working failing on the JSON part. Why can't I send json through credentials?
import {
GraphQLSchema,
GraphQLObjectType,
GraphQLString,
GraphQLInt,
GraphQLInputObjectType,
GraphQLNonNull,
graphql
} from 'graphql'
let requestType = new GraphQLInputObjectType({
name: 'Request',
fields: {
name: {type: GraphQLString},
}
})
let responseType = new GraphQLObjectType({
name: 'Response',
fields: {
name: {type: GraphQLString},
age: {type: GraphQLInt}
}
})
let schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Query',
fields: {
author: {
type: GraphQLString,
resolve: (source, args, context, info) => {
return 'Thomas Reggi'
}
}
}
}),
mutation: new GraphQLObjectType({
name: 'Mutation',
fields: {
example: {
type: responseType,
args: {
credentials: {
name: 'credentials',
type: requestType
}
},
resolve: (source, args, context, info) => {
return {
'name': 'Thomas Reggi',
'age': 26
}
}
}
}
})
})
let credentials = { name: "Thomas Reggi" }
let requestString = `
mutation {
example(credentials: ${JSON.stringify(credentials)}) {
name,
age
}
}`
graphql(schema, requestString).then(result => {
console.log(result)
})
Here's the error:
{ errors:
[ Syntax Error GraphQL request (3:25) Expected Name, found String "name: "
2: mutation {
3: example(credentials: {"name":"Thomas Reggi"}) {
^
4: name,
] }
Where does the reference to Name come from? Why is this throwing an error?

Just found out the hard way. You can't have {"name": "Thomas Reggi"} because name is in quotes.
This query works.
mutation {
example(credentials: {name: "Thomas Reggi"}) {
name,
age
}
}

Related

How to delete a record and any relationship records in an explicit many to many relationship?

I'm struggling to find documentation for handling explicit many to many relationships in Prisma. So I have resorted to dev by Stackoverflow....
I have a many to many relationship:
model Fight {
id Int #id #default(autoincrement())
name String
fighters FighterFights[]
}
model Fighter {
id Int #id #default(autoincrement())
name String #unique
fights FighterFights[]
}
model FighterFights {
fighter Fighter #relation(fields: [fighterId], references: [id])
fighterId Int
fight Fight #relation(fields: [fightId], references: [id])
fightId Int
##id([fighterId, fightId])
}
I am trying to delete a fight and delete the relationship in FighterFights but not delete the actual fighter.
I tried the following:
const result = await prisma.fight.delete({
where: {
id: Number(id),
},
})
but get the error:
PrismaClientKnownRequestError:
Invalid `prisma.fight.delete()` invocation:
Foreign key constraint failed on the field: `FighterFights_fightId_fkey (index)`
I then also tried:
const result = await prisma.fight.delete({
where: { id: Number(id) },
data: {
fighterFights: {
deleteMany: {
where: { fightId: id },
},
},
},
})
But I get the error:
PrismaClientValidationError:
Invalid `prisma.fight.delete()` invocation:
{
where: {
id: 1
},
data: {
~~~~
fighterFights: {
deleteMany: {
where: {
fightId: '1'
}
}
}
}
}
Unknown arg `data` in data for type Fight. Available args:
type deleteOneFight {
where: FightWhereUniqueInput
}
I also tried:
const result = await prisma.fight.delete({
where: {
id: Number(id),
},
data: {
fighterFights: {
deleteMany: [{ fightId: { equals: Number(id) } }],
},
},
})
but get the error:
Invalid `prisma.fight.delete()` invocation:
{
where: {
id: 1
},
data: {
~~~~
fighterFights: {
deleteMany: [
{
fightId: {
equals: 1
}
}
]
}
}
}
Unknown arg `data` in data for type Fight. Available args:
type deleteOneFight {
where: FightWhereUniqueInput
}
Here is the Prisma documentation to disconnect related fields
For single disconnect
const updatePost = await prisma.user.update({
where: {
id: 16,
},
data: {
posts: {
disconnect: [{ id: 12 }, { id: 19 }],
},
},
select: {
posts: true,
},
})
To disconnect all
const updateUser = await prisma.user.update({
where: {
id: 16
},
data: {
posts: {
set: []
}
},
include: {
posts: true
}
})
here you go a way to do that:
const { PrismaClient } = require('#prisma/client')
const prisma = new PrismaClient()
const saveData = async () => {
const fighter1 = await prisma.fighter.create({
data: {
name: 'Ryu',
},
})
const fighter2 = await prisma.fighter.create({
data: {
name: 'Ken',
},
})
console.log('FIGHTERS');
console.log(JSON.stringify(fighter1, null, 2));
console.log(JSON.stringify(fighter2, null, 2));
const fight = await prisma.fight.create({
data: {
name: 'Ryu vs Ken',
fighters: {
createMany: {
data: [
{
fighterId: fighter1.id,
},
{
fighterId: fighter2.id,
},
]
},
},
},
select: {
id: true,
fighters: {
select: {
fighter: true,
},
},
},
});
console.log('FIGHTS');
console.log(JSON.stringify(await prisma.fight.findMany({ include: { fighters: true } }), null, 2));
const fighterFightsToDelete = prisma.fighterFights.deleteMany({
where: {
fightId: fight.id,
}
})
const fightToDelete = prisma.fight.delete({
where: {
id: fight.id,
}
})
await prisma.$transaction([ fighterFightsToDelete, fightToDelete ])
console.log('RESULT');
console.log(JSON.stringify(await prisma.fight.findMany({ include: { fighters: true } }), null, 2));
console.log(JSON.stringify(await prisma.fighter.findMany({ include: { fights: true } }), null, 2));
}
saveData()
And the result is the following :)

How can I map an object with index signature?

I'm about to write an app in angular. It receives an answer from an api. Inside this answer is an array indexed with strings (index signature). How can I map this array into a regular array?
The api looks like this
{
"Information": {
"Created": "2019-04-25",
"Version": "1.2"
},
"Files": {
"2019-04-26": {
'name': 'file1',
'size': 5,
},
"2019-04-25": {
'name': 'file2',
'size': 3,
},
...
}
}
And i want to map it an object that looks like this
export class Model {
'Information': {
'Created': string,
'Version': string,
};
'Files': [{
'date': Date,
'name': string,
'size': number,
}];
}
Here I would like to map the answer
getdata(url): void {
this.http.get<>(url).subscribe(data => {
// code
}
);
}
I haven't tested any of this, but, in summary, the for loop retrives all of the keys of the object data.File and the you can access this object through that key.
getdata(url): void {
this.http.get<>(url).subscribe((response: any) => {
const model: Model = new Model();
model.Files = [];
if (response.Information) {
const information: any = response.Information;
if (information.Created && information.Version) {
model.Information = {
'Created': information.Created,
'Version': information.Version
};
}
}
for (const date in data) {
if (data.File.hasOwnProperty(date)) {
const file: any = data.File[date];
model.Files.push({
'date': date,
'name': file.name,
'size': file.size
});
}
}
});
}
Object.keys(o.Files)
.map(function(k ) {
return {date: k, name: o.Files[k].name, size: o.Files[k].size}
});
It should probably look like this:
data: Array<Data>;
getData() {
this.http.get(`url`).subscribe((data) => {
this.data = data.map(item => {
const output = {};
output.information = item.information;
output.files = Object.keys(item.files).map(key => {
return {
date: new Date(key),
name: item.files[key].name,
size: item.files[key].size
};
});
return output;
});
});
}

How to return the result from a raw query (Sequelize) to GraphQL

I'm newbie with GraphQL and Sequelize but I have developed a test where I can make querys and get results from Graphiql using the functions of Sequalize, but I'm interested in making more complex querys with querys with several tables.
Now, this code works fine:
schema.js
import {
GraphQLObjectType,
GraphQLNonNull,
GraphQLID,
GraphQLInt,
GraphQLString,
GraphQLFloat,
GraphQLList,
GraphQLSchema
} from "graphql";
import { DB } from "../db";
import {DateTime} from "../scalar/dateTime";
import {Player} from "./Player";
import {League} from "./League";
import {Group} from "./Group";
import {Season} from "./Season";
const Query = new GraphQLObjectType({
name: "Query",
description: "This is root query",
fields: () => {
return {
players: {
type: GraphQLList(Player),
args: {
id: {
type: GraphQLID
}
},
resolve(root, args){
return DB.db.models.tbl003_player.findAll({where: args});
}
},
leagues: {
type: GraphQLList(League),
args: {
id: {
type: GraphQLID
}
},
resolve(root, args){
return DB.db.models.tbl001_league.findAll({where: args});
}
},
groups: {
type: GraphQLList(Group),
args: {
id: {
type: GraphQLID
}
},
resolve(root, args){
return DB.db.models.tbl024_group.findAll({where: args});
}
},
seasons: {
type:GraphQLList(Season),
args: {
id: {
type: GraphQLID
}
},
resolve(root, args){
return DB.db.models.tbl015_seasons.findAll({where: args})
}
}
}
}
});
const Schema = new GraphQLSchema({
query: Query
});
module.exports.Schema = Schema;
So, I would like to make an easy test to know how to return the data from a raw query to GraphQL. I have read that resolve method returns a promise, and I have tried to return a promise with the result of the query, but it doesn't work.
players: {
type: GraphQLList(Player),
args: {
id: {
type: GraphQLID
}
},
resolve(root, args){
DB.db.query("select * from tbl003_player where id = 14",
{raw: true, type: DB.db.QueryTypes.SELECT}).then((players)=>{
let myPromise = new Promise((resolve, reject)=>{
resolve(players);
});
return myPromise;
}).catch((reject)=>{
console.log("Error: " + reject);
});
}
},
Therefore, how can I return data from a query with Sequelize to GraphQL?
Return the promise you get from sequelize. You are also doing a lot of work that is not required after your promise. Maybe read more about promises before moving on :)
resolve(root, args){
return DB.db.query(
"select * from tbl003_player where id = 14",
{ raw: true, type: DB.db.QueryTypes.SELECT }
);
}

Custom type in GraphQL mutation

I am using GraphQL js.I want to implement One-to-many association in it.I have two types user and Office.One user has many offices.
userType:
var graphql = require('graphql');
const userType = new graphql.GraphQLObjectType({
name: 'user',
fields :()=>{
var officeType=require('./officeSchema');
return {
_id: {
type: graphql.GraphQLID
},
name: {
type: graphql.GraphQLString
},
age: {
type: graphql.GraphQLString
},
office:{
type:officeType
}
};
}
});
module.exports=userType;
officeSchema:
const officeType = new graphql.GraphQLObjectType({
name: 'office',
fields:()=> {
var userType = require('./userSchema');
return {
_id: {
type: graphql.GraphQLID
},
room: {
type: graphql.GraphQLString
},
location: {
type: graphql.GraphQLString
},
users: {
type: new graphql.GraphQLList(userType),
resolve: (obj,{_id}) => {
fetch('http://0.0.0.0:8082/office/user/'+obj._id, {
method: "GET",
headers: {
'Content-Type': 'application/json'
}
})
.then(function(res) {return res});
}
}
};
}
});
Now the mutation code is as follows:
const Adduser = {
type: userType,
args: {
name: {
type: graphql.GraphQLString
},
age: {
type: graphql.GraphQLString
}
},
resolve: (obj, {
input
}) => {
}
};
const Addoffice = {
type: OfficeType,
args: {
room: {
type: graphql.GraphQLString
},
location: {
type: graphql.GraphQLString
},
users: {
type: new graphql.GraphQLList(userInputType)
}
},
resolve: (obj, {
input
}) => {
}
};
const Rootmutation = new graphql.GraphQLObjectType({
name: 'Rootmutation',
fields: {
Adduser: Adduser,
Addoffice: Addoffice
}
});
This code is throwing error as
Rootmutation.Addoffice(users:) argument type must be Input Type but got: [user].
I want to add the actual fields in database as well as associated tables' fields but couldn't figure out the problem.
Updated:
1-Added GraphQLInputObjectType:
const officeInputType = new graphql.GraphQLInputObjectType({
name: 'officeinput',
fields: () => {
return {
room: {
type: graphql.GraphQLString
},
location: {
type: graphql.GraphQLString
}
}
}
});
const userInputType = new graphql.GraphQLInputObjectType({
name: 'userinput',
fields: () => {
return {
name: {
type: graphql.GraphQLString
},
age: {
type: graphql.GraphQLString
}
}
}
});
2-Added userinputtype instead of usertype in AddOffice.
Now the error is
Rootmutation.Addoffice(user:) argument type must be Input Type but got: userinput.
The problem is that you provided userType as one of the argument types for the Addoffice mutation. userType cannot be an argument type. Instead, you must use an input type.
There are two object types: output and input types. Your userType and officeType are output types. You need to create an input type using GraphQLInputObjectType [docs]. It will likely have very similar fields. You can use that as a type on your argument field.
const userInputType = new graphql.GraphQLInputObjectType({
name: 'UserInput',
fields () => {
return {
_id: {
type: graphql.GraphQLID
},
// ...
};
}
});

Sails/Waterline: Return model relation

So, I'm creating a small application using SailsJS. My database is MySQL.
When I'm testing, first I create a "market" record, then a "stock" record linked to "market" and in another moment, I retrieve this stock record.
I have the following models:
Stock model:
module.exports = {
attributes: {
intern_id: {
type: 'string'
},
tick: {
type: 'string'
},
market: {
model: 'market'
}
}
};
Market model:
module.exports = {
attributes: {
tick: {
type: 'string'
},
name: {
type: 'string'
},
description: {
type: 'string'
},
stocks: {
collection: 'stock',
via: 'market'
},
}
}
Then, first I create a "market" and use the object returned to associate with my "stock" object:
Create and get my market record:
Market.create({tick: 'BVMF', name: 'Bovespa', description: 'Bolsa de Valores'}).exec(function(err, market) {
if(err) done(err);
});
var market = Market.findOne({tick: 'BVMF'}).then(function(results){return results;});
Create my stock record:
Stock.create({intern_id: '1234', tick: 'VALE5', description: 'Vale SA', market: market}).exec(function(err, stock) {
if(err) done(err);
});
And then, when I try to get back this stock, the market object is not retrieved, even if I call populate('market'):
Stock.findOne({tick: 'VALE5'}).populate('market').exec(function(err, record) {
console.log(record);
});
Not too much information, but I guess.
Instead:
Stock.findOne({tick: 'VALE5'}).populate('market').exec(function(err, record) {
console.log(marketObj);
});
Should be:
Stock.findOne({tick: 'VALE5'}).populate('market').exec(function(err, record) {
console.log(record);
});
Second answer:
You forgot about asynchronous. You should do this like that:
Market.create({tick: 'BVMF', name: 'Bovespa', description: 'Bolsa de Valores'}).exec(function(err, market) {
if(err){
done(err);
} else {
Stock.create({intern_id: '1234', tick: 'VALE5', description: 'Vale SA', market: market.id}).exec(function(err, stock) {
if(err){
done(err);
} else {
Stock.findOne({tick: stock.tick}).populate('market').exec(function(err, record) {
console.log(record); // and there is your "Stock" with populated "market"
});
}
});
}
});