WebStorm marks $query() of Objection.js as unresolved - javascript

I'm currently using Objection.js with WebStorm to build a Rest API. But, when I want to make a relationQuery of Objection.js, my WebStorm shows me one out of two times that $query() is unresolved.
I have installed the Objection.js TypeScript, but it doesn't work. I also tried to invalidate the WebStorm cache, but no better results.
Here are some screenshots of the errors
$query() unresolved:
$query() resolved:
I also watched with Visual Studio Code, and the code in the first screenshot is well detected and solved
$query() resolved inside VSCode:
I use Node 12.17, WebStorm 2020.1 and Objection 2.1.3
Hoping you can help me.
Here is the complete code snipper of the error:
const Users = require('../../../database/Users');
const sendReset = require('../../../email/reset');
const { nanoid } = require('nanoid');
/**
* #api {post} /v1/users/reset ✔ Set a reset email for an account
* #apiName resetPassword
* #apiGroup Users
* #apiVersion 1.0.0
*
* #apiParam {String} email email address of the user
*
* #apiSuccessExample {json} Success-Response :
* HTML 200 Success
* {
* "text": "success"
* }
*/
async function resetPassword(req, res) {
let email = req.body["email"];
if (email) {
try {
let toEdit = await Users.query().findOne("email", email);
if (toEdit) {
let token = nanoid(42);
let edited = await toEdit.$query().patchAndFetch({'token': token});
if (edited)
await sendReset(edited);
}
res.status(200).json({"message": "success"});
} catch (e) {
res.status(500).json({"error": "Internal server error"});
}
}
}
module.exports = resetPassword;
Users.js:
/*
** Created by Frederic GOMEL on 03/03/2020 at 18:07
** Project: api
*/
const knex = require('../init/database');
const {Model} = require('objection');
Model.knex(knex);
class Users extends Model {
static get tableName() {
return 'users';
}
static get jsonSchema() {
return {
type: 'object',
required: ["email", "group_right", "firstName", "lastName", "token"],
properties: {
id: {type: 'integer'},
email: {type: 'string'},
group_right: {type: 'integer'},
firstName: {type: 'string'},
lastName: {type: 'string'},
password: {type: ['string', 'null']},
rfid_uid: {type: ['string', 'null']},
token: {type: ['string', 'null']}
}
};
}
static get relationMappings() {
const Racks = require('./Racks');
return {
racks: {
relation: Model.ManyToManyRelation,
modelClass: Racks,
join: {
from: 'users.id',
through: {
from: 'link_users_racks.user',
to: 'link_users_racks.rack'
},
to: 'racks.id'
}
}
};
}
}
module.exports = Users;
reset.js:
const mail = require('../init/mails');
const twig = require('twig');
function sendReset(user) {
return new Promise((resolve, reject) => {
twig.renderFile('./email/templates/resetPassword.twig', {
name: `${user["firstName"]} ${user["lastName"]}`,
support_email: global["config"]["support_email"],
url: `${process.env["APP_URL"]}/activate?email=${user["email"]}&token=${user["token"]}`,
title: `Demande de changement de mot de passe`,
favicon: `${process.env["API_URL"]}/assets/images/favicon.ico`,
logo: `${process.env["API_URL"]}/assets/images/logo.png`
}, async (err, html) => {
if (err) {
reject(err);
} else {
mail.sendMail({
sender: `JAD Technologie <${process.env["MAIL_MAIL"]}>`,
to: user['email'],
subject: `Demande de changement de mot de passe`,
html: html
}).then(() => {
resolve();
}).catch((err) => {
reject({"mail": true, err});
});
}
});
});
}
module.exports = sendReset;
I use Express.js 4.16.0

Related

Error parsing url when connecting to redis cloud enterprise

I'm trying to use the redis-om package to connect to a Redis server, but I'm getting the following error: "TypeError: url_1.URL is not a constructor" when using the built-in URL class from Node.js.
I have tried using the url.parse() function from the url module instead, but the error persists.
Here is my code with an altered password:
import { Client, Entity, Schema, Repository } from "redis-om";
const client = new Client(); async function connect() { console.log("Will connect to redis"); console.log({ client }); if (!client.isOpen()) {
try {
console.log("Attempting to connect to redis");
const res = await client.open("redis://default:0dOoaiVcvwRsadRdOQVqLDdXmhnRR6HA#redis-15206.c269.eu-west-1-3.ec2.cloud.redislabs.com:15206");
console.log({ res });
} catch (err) {
console.log("Error connecting to redis:");
console.log(err);
} } }
class Post extends Entity {}
let schema = new Schema(Post, { media: { type: "string" }, author: { type: "string" }, caption: { type: "string" }, created: { type: "number" }, });
interface Data { media: string; author: string; caption: string; created: number; }
export async function createPost(data: Data) { await connect();
const repository = client.fetchRepository(schema);
const post = repository.createEntity(data as any);
const id = await repository.save(post);
return id; }
Here is the error client.open() throws:
TypeError: url_1.URL is not a constructor

I can't create a post in my db, the problem is that it returns the user id as null

My postman request :
{
"content": "my content",
"likes": 0
}
Response in postman :
{
null
}
Here is my code:
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Post extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
models.Post.belongsTo(models.User, {
foreignKey: {
allowNull: false,
name: "userId"
}
})
}
};
Post.init({
content: DataTypes.STRING,
comments: DataTypes.STRING,
attachment: DataTypes.STRING,
likes: DataTypes.INTEGER
}, {
sequelize,
modelName: 'Post',
});
return Post;
};
controllers :
module.exports.createPost = async (req, res, next) => {
const token = req.cookies.jwt;
const decoded = jwtAuth.verify(token, process.env.TOKEN_SECRET);
console.log(decoded);
const userIdFound = await User.findByPk(decoded.id);
I can't get the user id despite the request it returns a null value :
try {
const { body } = req;
console.log(body);
await User.findOne({ where: { id: userIdFound } })
.then((userFound) => {
//Create a Post if User Id is valid
if (userFound) {
const newPost = Post.create(
{ ...body, userId }
).then(() => res.status(201).json(newPost))
.catch(err => res.status(404).json('Unauthorizated request !'))
}})
Les erreurs :
} catch (err) {
throw new Error(err);
}
}
thank you very much for your help (I'm still a beginner, there will surely be some mistakes).
I don't understand from where you "pushing" the userIdFound on your where clause in the querie.
But I think you can try to insert the value id in a const, and use him on the where. Supposing the id field name in your HTML sending the post or get request is "id", you can insert it like this:
const userIdFound = req.body.id;
await User.findOne({ where: { id: userIdFound } })
//Some code for the logic
You can see more in the documentation here

Graphql query into SQL query using join-monster

I used join-monster to convert graphql query into SQL query to fetch date from postgres. I have implemented a small example with the help of join-monster docs to achieve it. But when i try to run the graphql query I get error '"Must call joinMonster in a resolver on a field where the type is decorated with "sqlTable"."'
Can someone please point out what exactly i am missing. Below is my schema.js code
const graphql = require('graphql');
var _ = require('lodash');
const { Client } = require('pg');
const joinMonster = require('join-monster').default;
const knex = require('knex');
const client = new Client({
user: 'postgres',
host: 'l662.us-east-1.rds.amazonaws.com',
database: 'graphqldb',
password: 'Password01',
port: 5432,
});
client.connect();
var q = "SELECT * FROM graphql_user_details";
client.query(q, function(err, results){
if(err) throw err;
console.log("results are",results);
client.end();
});
const {
GraphQLObjectType,
GraphQLID,
GraphQLString,
GraphQLInt,
GraphQLList,
GraphQLSchema
} = graphql
const User = new GraphQLObjectType({
name: 'User',
sqlTable: 'graphql_user_details',
uniqueKey: 'id',
fields: () => ({
id: {
type: GraphQLInt
},
name: {
description: 'A user\'s first and last name',
type: GraphQLString,
extensions: {
joinMonster: {
// if the column name is different, it must be specified
sqlColumn: 'name'
}
}
},
age: {
description: 'A user\'s age',
type: GraphQLInt,
extensions: {
joinMonster: {
// if the column name is different, it must be specified
sqlColumn: 'age'
}
}
}
})
})
const QueryRoot = new GraphQLObjectType({
name: 'Query',
fields: () => ({
user: {
type: User,
args: {id:{type: GraphQLInt}},
// how to write the WHERE condition
where: (usersTable, args, context) => {
if (args.id) return `${usersTable}.id = ${args.id}`
},
resolve: (parent, args, context, resolveInfo) => {
return joinMonster(resolveInfo, {}, sql => {
// knex is a query library for SQL databases
return knex.raw(sql)
})
}
}
})
})
module.exports = new GraphQLSchema({
query: QueryRoot
})

How to add each result of the last loop within two nested searches in an array to show the full result in NodeJS and Mongoose?

I'm a beginner in both Stackoverflow and NodeJS/Mongoose, I'm sorry if I have an error or break a rule. Thank you in advance.
I need a function that it return all the nearby products there are in my location, this is given through the user wich "id" is a request called "user".
I try making this function, where finalProducts return all the products that they exit at the search, but when I try to add as component of result body finalProducts return data empty.
The error is the following:
throw er; // Unhandled 'error' event
^
Error: Can't set headers after they are sent.
at ServerResponse.setHeader (_http_outgoing.js:371:11)
at ServerResponse.header (/home/frangaliana/Escritorio/client-thingy/node_modules/express/lib/response.js:730:10)
at ServerResponse.send (/home/frangaliana/Escritorio/client-thingy/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/home/frangaliana/Escritorio/client-thingy/node_modules/express/lib/response.js:256:15)
at ServerResponse.send (/home/frangaliana/Escritorio/client-thingy/node_modules/express/lib/response.js:158:21)
at /home/frangaliana/Escritorio/client-thingy/controllers/product.js:200:41
at /home/frangaliana/Escritorio/client-thingy/node_modules/mongoose/lib/query.js:2916:18
at newTickHandler (/home/frangaliana/Escritorio/client-thingy/node_modules/mpromise/lib/promise.js:234:18)
at _combinedTickCallback (internal/process/next_tick.js:73:7)
at process._tickCallback (internal/process/next_tick.js:104:9)
I show the code and the models for help to understand the trouble:
Function that search nearby products in controller product.js:
function getNearbyProducts(req, res) {
let userId = req.user;
let point;
var geoOptions = {
spherical: true,
maxDistance: 500
}
User.findById(userId, {password:0})
.populate('location','coordinates')
.exec(function (err, result) {
if (err) console.log('No se ha podido encontrar la localización')
point = {
type: "Point",
coordinates: [parseFloat(result.location.coordinates[0]),parseFloat(result.location.coordinates[1])]
}
Location.geoNear(point,geoOptions, function(err, resultLocations) {
for(var i = resultLocations.length - 1 ; i >= 0 ; i--){
var nearLocation = resultLocations[i].obj.id
var queryUser = {"location": nearLocation}
User.find(queryUser)
.exec(function (err, resultUsers) {
for(var j = resultUsers.length - 1 ; j >= 0; j--) {
if(resultUsers[j] !== undefined){
var exactUser = resultUsers[j].id
var limit;
if(req.query.limit) {
limit = parseInt(req.query.limit)
if(isNaN(limit)){
return next(new Error())
}
} else {
limit = 10;
}
var queryProduct = {"user": exactUser}
if(req.query.before) {
queryProduct = {"user": exactUser, "_id" : {$lt: req.query.before}};
}else if (req.query.after) {
queryProduct = {"user": exactUser, "_id" : {$gt: req.query.after}};
}
Product.find(queryProduct)
.limit(limit)
.populate('user')
.exec(function (err, resultProducts) {
var finalProducts = [];
for(var k = resultProducts.length - 1 ; k >= 0; k--){
if(resultProducts[k] !== undefined){
finalProducts.push(resultProducts[k])
}
}
if(finalProducts.length > 0){
if(req.query.before){
products.reverse();
}
var finalResult = {
data: finalProducts,
paging: {
cursors: {
before: finalProducts[0].id,
after: finalProducts[finalProducts.length-1].id
},
previous: 'localhost:3000/api/products?before='+finalProducts[0].id,
next: 'localhost:3000/api/products?after='+finalProducts[finalProducts.length-1].id,
},
links: {
self: 'localhost:3000/api/products',
users: 'localhost:3000/api/users'
}
}
} else {
var finalResult = {
data: finalProducts,
paging: {
cursors: {
before:undefined,
after:undefined
},
previous: undefined,
next: undefined
},
links: {
self: 'localhost:3000/api/products',
users: 'localhost:3000/api/users'
}
}
}
res.status(200).send(finalResult);
})
}
}
})
}
})
})
})
Models:
user.js
'use strict';
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const bcrypt = require('bcrypt-nodejs');
const Location = require('../models/location');
const crypto = require('crypto');
const UserSchema = new Schema({
email: {
type: String,
lowercase: true,
//Añadir campo unique: true para que sólo se pueda registrar un email
},
name: String,
password: String,
userimg: String,
gender: Boolean,
birthdate: Date,
signUpDate: {
type: Date,
default: Date.now(),
},
location:{
type: Schema.ObjectId,
ref: 'Location'
}
});
UserSchema.pre('save', function(next) {
let user = this;
if (!user.isModified('password')) return next();
bcrypt.genSalt(10, (err, salt) => {
if (err) return next(err);
bcrypt.hash(user.password, salt, null, (err, hash) => {
if (err) return next(err);
user.password = hash;
next();
});
});
});
UserSchema.methods.gravatar = function() {
if(!this.email) return `https://gravatar.com/avatar/?s=200&d=retro`
const md5 = crypto.createHash('md5').update(this.email).digest('hex')
return `https://gravatar.com/avatar/${md5}?s=200&d=retro`
}
module.exports = mongoose.model('User', UserSchema);
product.js
'use strict'
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const User = require('../models/user');
var max = [5 , 'The value of ({VALUE}) exceeds the limit ({MAX}). ']
var min = [1 , 'The value of ({VALUE}) is beneath the limit ({MIN}). ']
const ProductSchema = Schema({
title: String,
price: {
type: Number,
default: 0
},
user: {
type: Schema.ObjectId,
ref: 'User'
},
categoryproduct: {
type: String,
enum:['Moda y Accesorios', 'Motor', 'Electrónica', 'Deporte', 'Libros, Música y Películas', 'Electrodomésticos', 'Servicios', 'Muebles y Decoración', 'Otros'],
default: 'Electrónica'
},
description: {
type: String,
default: 'Objeto para vender'
},
visits: {
type: Number,
default: 0
},
status: {
type: Boolean,
default: false
},
publicationdate: {
type: Date,
default: Date.now()
},
salesrating: {
type: Number,
max: max,
min: min,
default: 1
},
salescomment: {
type: String,
default: 'Perfecto'
}
})
module.exports = mongoose.model('Product', ProductSchema);
location.js
'use strict';
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const LocationSchema = new Schema({
type: {
type: String,
default: "Point"
},
coordinates: {
type: [Number],
index: "2dsphere",
default: [38.280153, -0.712901]
}
})
module.exports = mongoose.model('Location', LocationSchema);
I hope this question can be resolved or at least someone explain me because it doesn't work well. A lot of thanks again!
EDIT: (Because I have fix the problem)
Thanks to skirtle who gave me the idea to solve this.
I didn't control the asynchronous calls that threw the searches with Mongoose and that generated multiple responses, so as he told me I started using Promises to keep track of them when the result was throwing me an array of id's whether they were from User, Location or Product I treated them one by one.
I recalled that a Mongoose query could be accompanied by a filter {$in:[array]} that returned all results containing any of these id's (in my case) that had the array looking like this:
function getNearbyProducts(req, res) {
var userId = req.user;
var promiseUser = User.findById(userId, {password: 0})
.populate('location')
.exec()
promiseUser
.then(function(result){
return result.location;
})
.then( function(resultUser){
return Location.geoNear(
{type:'Point', coordinates: [parseFloat(resultUser.coordinates[0]),parseFloat(resultUser.coordinates[1])]},
{maxDistance:100000, spherical: true}
).then(function(locsGeoNear){
var resultGeoNear = []
for(var i = locsGeoNear.length - 1; i >= 0; i--){
if(resultUser.id != locsGeoNear[i].obj.id){
resultGeoNear.push(locsGeoNear[i].obj.id)
}
}
return resultGeoNear
})
})
.then(function(resultSearchLocs){
var queryUsersByLocation = {'location': {$in: resultSearchLocs}}
return User.find(queryUsersByLocation, {password: 0})
.exec()
.then(function(usersSearchs){
var resultUsers = []
for(var i = usersSearchs.length - 1; i >= 0; i--){
if(userId != usersSearchs[i].id){
resultUsers.push(usersSearchs[i].id)
}
}
return resultUsers
})
})
.then(function(resultSearchUsers){
var limit;
if(req.query.limit) {
limit = parseInt(req.query.limit)
if(isNaN(limit)){
return next(new Error())
}
} else {
limit = 10;
}
var queryProductsByUsers = {'user': {$in: resultSearchUsers}}
//Para obtener la página anterior a un id
if (req.query.before) {
queryProductsByUsers = {'user': {$in: resultSearchUsers}, "_id" : {$lt: req.query.before}};
//Para obtener la página posterior a un id
} else if (req.query.after) {
queryProductsByUsers = {'user': {$in: resultSearchUsers}, "_id": {$gt: req.query.after}};
}
return Product.find(queryProductsByUsers)
.limit(limit)
.exec()
})
.then(function(resultSearchProducts){
if(resultSearchProducts.length > 0){
if(req.query.before){
resultSearchProducts.reverse();
}
var resultFinal = {
data: resultSearchProducts,
paging: {
cursors: {
before: resultSearchProducts[0].id,
after: resultSearchProducts[resultSearchProducts.length-1].id
},
previous: 'localhost:3000/api/products?before='+resultSearchProducts[0].id,
next: 'localhost:3000/api/products?after='+resultSearchProducts[resultSearchProducts.length-1].id,
},
links: {
self: 'localhost:3000/api/products',
users: 'localhost:3000/api/users'
}
}
} else {
var resultFinal = {
data: resultSearchProducts,
paging: {
cursors: {
before:undefined,
after:undefined
},
previous: undefined,
next: undefined
},
links: {
self: 'localhost:3000/api/products',
users: 'localhost:3000/api/users'
}
}
}
res.setHeader('Content-Type', 'application/json');
res.status(200).send(resultFinal);
})
.catch(function(err){
console.log(`${err}`)
})
}
Many thanks to the community but above all to skirtle who gave me the keys to reach my solution.
Greetings!
If you add the following logging before you call send:
console.log('sending response');
res.status(200).send(finalResult);
I believe you'll find that you're calling send multiple times on the same request, which isn't allowed. When you call send the first time the request/response is over and any attempt to send more data will result in an error.
I'm struggling to follow the code but I believe the cause is all that looping you're doing. You need to wait until all your DB queries are done and you've gathered your final data before you call send.
You may find Promises a useful way to reduce the complexity in products.js but even if you don't fancy using them I highly recommend a bit of refactoring to make that file intelligible. As a general rule the Pyramid of Doom is a sign that you've got problems https://en.wikipedia.org/wiki/Pyramid_of_doom_(programming)

What is the best way to seed data in nodejs mongoose

I need to seed data into the database in my application. What is the best way to do that? Where should I write the code for seeding the data? what should be the folder structure for this?
I am a rails developer and rails framework has a nice way of seeding the data in seeds.rb, and I want to achieve the same thing in my node.js application.
Since I am new to node.js, I am confused between different available resources on the web.
First create your model in models folder.
models/product.js
const mongoose = require("mongoose");
const productSchema = new mongoose.Schema({
image: { type: String, required: true },
title: { type: String, required: true },
author: { type: String, required: true },
description: { type: String, required: true },
price: { type: Number, required: true }
});
const Product = mongoose.model("Product", productSchema);
module.exports = Product;
Then create a seeder folder
seeder/seedProducts.js
const Product = require("../models/product");
const mongoose = require("mongoose");
const dev = require("../config/dev"); //get your mongoose string
//create your array. i inserted only 1 object here
const products = [
new Product({
image:
"https://static.seattletimes.com/wp-content/uploads/2018/01/a8e801dc-f665-11e7-bf8f-ddd02ba4a187-780x1181.jpg",
title: "Origin",
author: "Dan Brown",
description:
"2017 mystery thriller novel. Dan Brown is back with another thriller so moronic you can feel your IQ points flaking away like dandruff",
price: 12
}),]
//connect mongoose
mongoose
.connect(String(dev.db), { useNewUrlParser: true })
.catch(err => {
console.log(err.stack);
process.exit(1);
})
.then(() => {
console.log("connected to db in development environment");
});
//save your data. this is an async operation
//after you make sure you seeded all the products, disconnect automatically
products.map(async (p, index) => {
await p.save((err, result) => {
if (index === products.length - 1) {
console.log("DONE!");
mongoose.disconnect();
}
});
});
Finally you will run seedProducts.js on the terminal only once.
node seedProducts.js
You can use the mongoose-data-seed package to handle this job.
https://github.com/sharvit/mongoose-data-seed
With mongoose-data-seed you are basically creating seeders files that look like that:
import { Seeder } from 'mongoose-data-seed';
import { User } from '../server/models';
const data = [{
email: 'user1#gmail.com',
password: '123123', password_confirmation: '123123',
isAdmin: true
}, {
email: 'user2#gmail.com',
password: '123123', password_confirmation: '123123',
isAdmin: false
}];
class UsersSeeder extends Seeder {
async shouldRun() {
const usersCount = await User.count().exec();
return usersCount === 0;
}
async run() {
return User.create(data);
}
}
export default UsersSeeder;

Categories

Resources