Sails/Waterline: Return model relation - mysql

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"
});
}
});
}
});

Related

Sequelize, Mysql how to return deleted ids

I have a GraphQL mutation that deletes items. I'm trying to retrieve the deleted ids. However null ids are returned but items are deleted from the database.
Shema
type Mutation{
deletePropertyItems(id: [ID!]!): DeletePropertyItemsRes!
}
type DeletePropertyItemsRes {
success: Boolean!
message: String!
propertyItem:PropertyItem
}
type PropertyItem {
id: ID!
title: String!
description: String!
}
Mutation Resolver
async deletePropertyItems(_, { id }, { models }) {
try {
const deletedRows = await models.PropertyItem.destroy({
where: { id: id },
});
if (deletedRows) {
return {
success: true,
message: "Property Item(s) Deleted Successfully!",
propertyItem: deletedRows,
};
}
return {
success: false,
message: "Operation not Successful",
};
} catch (error) {
throw new Error(error.message);
}
},
Apollo Studio Error

Sails.JS: AUTO INCREMENT Implementation Failed

I'm developing a Sails.JS app that performs CRUD operations with a MySQL database using waterline ORM. My models have an attribute id set to auto-increment with the beforeCreate function, yet every time I try to call the create function, this error occurs:
{
"error": {
"name": "UsageError",
"code": "E_INVALID_NEW_RECORD",
"details": "Missing value for required attribute id. Expected a number, but instead, got: undefined"
} }
Here's my model:
module.exports = {
primaryKey: 'id',
attributes: {
id: {
type: "number",
required: true,
unique: true,
autoIncrement: true
},
name: {
type: "string",
required: true
},
beforeCreate : function(item, next) {
Counter.native(function(err, collection) {
if (err) console.log(err);
collection.findAndModify(
{ _id: "id" },
null,
{ $inc: { seq: 1 } },
{ new:true, upsert:true },
function(err, object){
if (err) console.log(err);
item.id = object.seq;
next();
}
);
});
}
};
Here's my model controller:
module.exports = {
create :function(req,res,next) {
let params = {name:req.param('name') };
model.create(params , function(err , createdData) {
if(err){
return res.badRequest({
error: err
});
}
else
{
return res.json({ added});
}
});
},

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
},
// ...
};
}
});

Creating Primary and Foreign Key relations in Sequelize

I have 2 models Project model and Task model defined in sequelize as shown below
import { INTEGER, STRING, DATE } from 'sequelize';
import sequelize from '../sequelize';
import Task from './task.model'
const ProjectModel = sequelize.define('project', {
project_id: {
type: INTEGER,
primaryKey: true,
autoIncrement: true
},
phabricator_project_id: {
type: STRING,
allowNull: false
},
name: {
type: STRING
},
description: {
type: STRING
},
start_date: {
type: STRING,
},
end_date: {
type: STRING
}
},
{
timestamps: false
}
);
export default ProjectModel;
and the task model
import { INTEGER, STRING, DATE } from 'sequelize';
import sequelize from '../sequelize';
const TaskModel = sequelize.define('task', {
task_id: {
type: INTEGER,
primaryKey: true,
autoIncrement: true
},
title: {
type: STRING
},
status: {
type: STRING
},
priority: {
type: STRING
},
description: {
type: STRING
},
tool_project_id: {
type: STRING
},
date_modified: {
type: STRING
}
},
{
timestamps: false
}
);
export default TaskModel;
What I want to achieve is to create a relation between tool_project_id in TaskModel and phabricator_project_id in ProjectModel (they are same values only diff column names are given) and write a query for a GET request which outputs the data in form shown below
{ {project1Details,TaskDetails-->{task1, task2, task3},
{project2Details,TaskDetails-->{task4, task5, task6},
{project3Details,TaskDetails-->{task7, task8, task9},
{project4Details,TaskDetails-->{task10, task11, task12} }
All the database design has been done accordingly and another file is called to create all these databases. This is written in typescript and I tried this as a GET method
listByProjects(req, res) {
TaskModel.belongsTo(ProjectModel, { as: 'task' , foreignKey: 'tool_project_id'});
ProjectModel.findAll({
include:[{model:TaskModel}],
where:{status:'open'}
}).then(function(projects) {
res.json(projects);
});
}
Here in this method I define the relation and try to list all 'open' tasks and send them back as response but I am getting the error
Unhandled rejection Error: task is not associated to project!
ANY HELP TO THIS PROBLEM WOULD BE WONDERFULL
The answer to this question is that when creating the table we should create the relation and then create the table such as
Create the relation also the name of the key should be same so as to create relation.
TaskModel.belongsTo(ProjectModel, {foreignKey: 'project_id' });
ProjectModel.hasMany(TaskModel, { foreignKey: 'project_id' });
Then create the table project and then tasks
ProjectModel.sync({ force: false }).then(function () {
console.log('Project table created');
TaskModel.sync({ force: false }).then(function () {
console.log('Task table created');
});
});
then in the API method, you are invoking just include the model which you want to provide to get the required data.
ProjectModel.findAll({
include: [{
model: TimeSheetModel,
where: {
status: "ACTIVE"
},
}],
}).then(function (projects) {
const responseData = {
'status': 1,
'message': 'List successfull.',
'projects': projects,
};
res.json(responseData);
}).catch(error => {
const responseData = {
'status': 1,
'message': error.message,
'projects': [],
};
res.json(responseData);
})
This uses nodemon and sequilize to manage node and relations of the table respectively

Single JSON argument in mutation

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
}
}