I am confused. I have the following javascript file:
module.exports = {
connection: 'freshairMysqlServer',
tableName: 'Accounts',
autoCreatedAt: false,
autoUpdatedAt: false,
autoPK: false,
attributes: {
idAccounts: {
type: 'integer',
primaryKey: true
},
AccountName: {
type: 'string'
},
idOrganization: {
type: 'integer'
}
},
GetAccounts: function (page, cb) {
Accounts.query('SELECT Accounts.AccountName as AccountName,' +
' Organizations.Name as Organization FROM Accounts' +
' JOIN Organizations on Accounts.idOrganization = Organizations.idOrganizations',
function (err, results) {
if (err) cb(err)
else cb(null, results);
});
}
}
The module exports a javascript object, {connection: ..., tableName: ..., ...}. This value is used by Sails to extend a Waterline model object.
What is the TypeScript code that accomplishes the same? I have tried several variations but don't seem to be getting it. Help! Thanks.
var objectToExport = {
connection: 'freshairMysqlServer', ... };
export = objectToExport;
and be sure to compile with --module commonjs
Related
I'm developing a NodeJS (Typescript) with Mongoose and when I try to add a virtual to my schema in one of the ways Mongoose's documentation suggests, I get an error saying that the prop virtuals doesn't exist in type SchemaOptions. And a correct error, even though the documentation suggests to use it.
This is what I find in the docs:
// That can be done either by adding it to schema options:
const personSchema = new Schema({
name: {
first: String,
last: String
}
}, {
virtuals: { //--------> I get the error here
fullName: {
get() {
return this.name.first + ' ' + this.name.last;
}
}
}
});
This is what I was trying:
const mySchema = new Schema<MyInterface>(
{
someProp: { type: Types.ObjectId, required: true, ref: "some-collection" },
myList: { type: [listSchema], required: true, default: [] },
},
{
timestamps: true,
toJSON: { virtuals: true },
toObject: { virtuals: true },
virtuals: {
getByType: {
get: (type: string) => {
return this.myList.filter((item: Item) => item.type === type);
}
}
}
}
);
In the other hand, I can set my virtual this way:
mySchema.virtual("getByType").get((type: string) => {
return this.myList.filter((item: Item) => item.type === type);
});
I had to do a few workarounds to sort the issue about not resolving the this keyword, but so far I have no problem about it...
The problem is: I use findOne and then try to call my virtual get with my document, but I get a Type Error saying Property 'getByType' does not exist on type 'MyInterface & Document<any, any, MyInterface>'.
Looks like there is a mix of mistake on the documentation and a Typescript problem here.
What do you suggest?
Virtual is intended to be used by a Class. If you want to use it on an instance, use methods instead.
Virtual
mySchema.virtual("getByType").get((type: string) => {
return this.myList.filter((item: Item) => item.type === type);
});
// Usage
MySchema.getByType(type)
Methods
mySchema.methods.getByType = function (type, cb) {
return this.model('MySchema').find({
myList: { $elemMatch: { type } }, // Fill your logic here
}, cb)
};
// Usage
const instance = MySchema.findOne();
const result = instance.getByType(type);
I can't get this very simple virtual column to work (surnameName). It is not returned in query results, but it does not throw any error either.
My model (I removed irrelevant fields):
const Person = connectionPool.define('person', {
ID: {
type: Sequelize.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true
},
name: Sequelize.STRING,
surname: Sequelize.STRING,
surnameName: {
type: Sequelize.VIRTUAL(Sequelize.STRING, ['surname', 'name']),
get() {
return this.getDataValue('surname') + ' ' + this.getDataValue('name');
}
}
});
This is how I query the model:
const cfg = {
where: {},
limit: 10,
raw: false, // tried with and without this line
attributes: ['surnameName']
}
models.Person.findAll(cfg)
.then(results => {
console.log(results[0]);
})
And this is what I get in the console log:
person {
dataValues: { surname: 'Baggins', name: 'Frodo' }, // all other fields are autoexcluded by Sequelize
...
_options:
{ isNewRecord: false,
_schema: null,
_schemaDelimiter: '',
raw: true, // is true even if I set 'raw' to false in findAll options
attributes: [ 'surnameName', 'surname', 'name' ] // <= surnameName is there!
}
}
Virtual column is not returned in the results, however the logged instance shows that the internal _options.attributes array does contain the field, so Sequelize somehow acknowledges that it should be added. I tried explicitly turning raw=false, as I read that raw excludes virtual columns, but it has no effect. The results are definitely not raw.
What can be wrong here? Any help will be appreciated!
It is possible to hide properties javascript object. Here is an example
function Person(fName, lName) {
this.fName = fName;
this.lName = lName;
Object.defineProperties(this, {
fullName: {
get : function () {
return this.fName + " " + this.lName;
}
}
});
}
const ratul = new Person("Ratul", "sharker");
console.log(ratul);
console.log(ratul.fullName);
Look closely that console.log(ratul) does not print fullName, but fullName is sitting here, returning it's value seen in console.log(ratul.fullName).
Similar thing can be found in this answer.
I made API server with Node.js
Also I use sequelize.js(version 4) for communicate with MySQL.
My table structure is here.
[Article]
no(PK)
subject
content
created_at
updated_at
[Comment]
no(PK)
content
created_at
updated_at
article_no(FK to Article)
[index.controller.js]
import { Article, Comment } from '../model/model';
export const index = (req, res) => {
res.send('controller index');
};
export const getArticle = (req, res) => {
try {
Article.all()
.then(article => {
res.status(200).json({status: true, result: article});
});
} catch(e) {
res.status(500).json({status: false, result: "get article fail"});
}
}
export const addArticle = (req, res) => {
const { subject, content } = req.body;
try {
Article.create({
subject: subject,
content: content
})
res.status(200).json({status: true, result: "article write success"});
} catch(e) {
res.status(500).json({status: false, result: "article fail"});
}
}
export const getComment = (req, res) => {
try {
Comment.all()
.then(comment => {
res.status(200).json({status: true, result: comment})
});
} catch(e) {
res.status(500).json({status: false, result: "get comment fail"});
}
}
export const addComment = (req, res) => {
const { content, article_no } = req.body;
try {
Comment.create({
content: content,
article_no: article_no
})
.then(() => res.status(200).json({status: true, result: "comment write success"}))
} catch(e) {
console.log(e);
res.status(500).json({status: false, result: "comment fail"});
}
}
[index.js]
import express from 'express';
import { index, getArticle, getComment,addArticle, addComment } from './index.controller';
const router = express.Router();
router.get('/', index);
router.get('/article', getArticle);
router.post('/article', addArticle);
router.get('/comment', getComment);
router.post('/comment', addComment);
export default router;
[model.js]
import Sequelize from 'sequelize';
const sequelize = new Sequelize('db', 'id', 'pw', {
host: '127.0.0.1',
dialect: 'mysql'
})
export const Article = sequelize.define('article', {
no: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
subject: {
type: Sequelize.STRING,
allowNull: false
},
content: {
type: Sequelize.STRING,
allowNull: false
}
}, {
freezeTableName: true,
underscored: true
})
export const Comment = sequelize.define('comment', {
no: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
content: {
type: Sequelize.STRING,
allowNull: false
}
}, {
freezeTableName: true,
underscored: true
})
Article.hasMany(Comment, {as: 'Comments'}); // association
Comment.belongsTo(Article); // association
sequelize.sync({
force: false
});
Because of association(hasMany, belongsTo), article_no column will be added to Comment table.
Refer to this document, http://docs.sequelizejs.com/manual/tutorial/associations.html#one-to-many-associations-hasmany-
It says that Instances of Project will get the accessors getWorkers and setWorkers.
In my case, it will be getComments and setComments.
But I don't know exactly how can I get all the comments related articles with using accessor.
Current output is here. (If I connect to GET /article)
{
"status":true,
"result":[
{
"no":1,
"content":"comment test",
"created_at":"2018-07-18T05:00:45.000Z",
"updated_at":"2018-07-18T05:00:45.000Z",
"article_no":1
}
]
}
Desired output is here
{
"status":true,
"result":[
{
"no":1,
"content":"comment test",
"created_at":"2018-07-18T05:00:45.000Z",
"updated_at":"2018-07-18T05:00:45.000Z",
"article_no":1,
"comments": [
// related comments here!
]
}
]
}
Thanks.
When you want to join another model you should use include in your query
User.findAll({
include: [
{ model: Profile, required: true // inner join }
],
limit: 3
});
Check out the Sequelize model usage docs.
To access the comments with accessors you will need do something like this:
const articles = await Article.all();
articles.forEach(article => {
const comments = await article.getComments();
})
The idea behind is that each article sequelize object will have the accessor getComments but internally what it does when you execute getComments it makes a new request to the database with the prepopulated articleId in the comments where query. This is called lazy loading because you can load the data when you need it. But that is not your case.
For the desired output I suggest to use the include method cause it will make a single request to the database.
I'm actually trying to convert mongodb references into those references' documents value (info.value) using mongoose in javascript.
Tried that by using map, for/forEach, and nothing did the job since mongoose requests are async.
Not really used to this kind of code, I feel a bit lost after all those things I tried.
Maybe someone would like to give me a hint about this by taking a look at the code below.
Just for information, no need to worry about loading templates, connecting to mongo, ... since everything else is working just fine.
That's the closest I got to the expected result, but still, it throws me errors when I try to "console.log(cond[c]);/console.log(info);" (cond[c] and info are null and undefined)
Well this function also needs to be prepared to be recursive since I plan to put sub-blocks in the "content" property of the bloc objects.
Thanks a lot for your time guys.
// Input condition
"H1Vf3KTef || false"
// Expected result
"1 || false"
// Buggy Function
var execIfBlock = function recursExec (query, callback) {
IfBlockModel.findOne(query, function(err, ifBlock) {
if (!err) {
var cond = ifBlock.condition.split(" ");
//console.log('Block : ' + ifBlock);
//console.log('Condition : ' + cond);
var calls = new Array();
for (var c = 0, len = cond.length; c < len; c++) {
if (shortId.isValid(cond[c])) {
calls.push(function() {
InfoModel.findOne({ _id: cond[c] }, function(err, info) {
console.log(cond[c]);
console.log(info);
cond[c] = info.value;
});
});
}
}
async.parallel(calls, function(err, result) {
console.log(result);
// Do some job using the final expected result : "1 || false"
});
}
});
};
// Info template
{
"_id": "H1Vf3KTef",
"value": "1"
}
// Bloc template
{
"_id": "rkRBtLTef",
"content": [],
"condition": "H1Vf3KTef || false"
}
// Info schema
var InfoSchema = new Schema({
_id: { type: String, unique: true, required: true, default: shortId.generate },
value: { type: String, default: "0" }
});
// Bloc schema
var IfBlockSchema = new Schema({
_id: { type: String, unique: true, required: true, default: shortId.generate },
condition: { type: String, required: true, default: true },
content: [{ type: String, required: true, default: '', ref: 'block' }]
});
Use promises and break your code in small functions :
var execIfBlock = function recursExec(query, callback) {
IfBlockModel.findOne(query, function (err, ifBlock) {
if (!err) {
var cond = ifBlock.condition.split(" ");
updateMultipeInfo(cond)
.then(values => {
console.log(values) // [values1, values ,...]
});
}
});
};
function updateMultipeInfo(cond){
return Promise.all(cond.map(updateInfo))
}
function updateInfo(id){
if (shortId.isValid(id)) {
return InfoModel
.findOne({ _id: id })
.then(info => info.value);
} else {
return Promise.reject("invalid id");
}
}
In the model :
var Sequelize = require('sequelize');
var sequelize_config = {
"username": process.env.DB_USERNAME || "root",
"password": process.env.DB_PASSWORD || "",
"pool": 200,
"database": "faasos_platform",
"host": "localhost",
"dialect": "mysql",
"dialectOptions": {
"multipleStatements": true
},
"logging": true,
"define": {
"timestamps": true,
"underscored": true
}
}
var sequeliz = new Sequelize(sequelize_config.database, sequelize_config.username, sequelize_config.password, sequelize_config);
module.exports = function (sequeliz, DataTypes) {
var auth = sequeliz.define("auth", {
device_id: {
type: DataTypes.STRING(50),
validate: {
notEmpty: true
}
},
customer_id: {
type: DataTypes.INTEGER,
validate: {
notEmpty: true
}
},
created_at: {
type: DataTypes.DATE,
validate: {
notEmpty: true
}
},
access_token: {
type: DataTypes.STRING(455),
validate: {
notEmpty: true
}
},
ip_address: {
type: DataTypes.STRING(20),
validate: {
notEmpty: true
}
},
is_active: {
type: DataTypes.INTEGER,
validate: {
notEmpty: true
}
}
}, {
classMethods: {
associate: function (models) {},
verify_user: function (req, callback) {
var d = new Date();
var sql = " Select customer_id From auth WHERE access_token =:access_token && is_active = '1' ";
sequelize.query(sql, {
replacements: {
access_token: req.access_token
},
raw: true
}).spread(function (data, metadata) {
callback(null, data);
}).catch(function (err) {
callback(err, null);
});
},
revoke_access_token: function (req, callback) {
var sql = "UPDATE auth SET is_active = 0 " +
"WHERE customer_id = :customer_id";
sequelize.query(sql, {
replacements: {
customer_id: req.id
},
raw: true
}).spread(function (data, metadata) {
callback(null, data);
}).catch(function (err) {
callback(err, null);
});
},
save_access_token_details: function (req, callback) {
var d = new Date();
var sql = "INSERT INTO auth (device_id, customer_id, created_at, access_token, ip_address, is_active)" +
"VALUES (:device_id, :cust_id, :created_at, :access_token, :ip_add, 1) ";
sequelize.query(sql, {
replacements: {
device_id: req.device_code ,
cust_id: req.id ,
created_at: d,
access_token: req.access_token,
ip_add: req.ip_add
},
raw: true
}).spread(function (data, metadata) {
callback(null, data);
}).catch(function (err) {
callback(err, null);
});;
}
},
tableName: 'auth',
timestamps: true,
underscored: true
});
return auth;
};
In my controller :
var models = require('../models/auth.js'); // the above model is saved in file auth.js
models.auth.verify_user(access_token, function (err, data) {
if (err) {
res.status(401).send({
'err': 'Unauthorized!'
});
}
if (data) {
models.revoke_access_token(user, function (err, data) {
if (err) {
res.status(401).send({
'err': 'Unauthorized!'
});
}
});
}
models.save_access_token_details(payload, function (err, data) {
if (err) {
res.status(401).send({
'err': 'Unauthorized!'
});
} else {
console.log(err, data);
res.send(data);
}
});
});
But each time it exists with the error ::
TypeError: Cannot call method 'verify_user' of undefined
at SignStream. (/home/salim/Documents/proj/platform/oAuth/controllers/validate.js:25:19)
at SignStream.EventEmitter.emit (events.js:95:17)
at SignStream.sign (/home/salim/Documents/proj/platform/oAuth/node_modules/jsonwebtoken/node_modules/jws/lib/sign-stream.js:54:8)
at SignStream. (/home/salim/Documents/proj/platform/oAuth/node_modules/jsonwebtoken/node_modules/jws/lib/sign-stream.js:37:12)
at DataStream.g (events.js:180:16)
at DataStream.EventEmitter.emit (events.js:92:17)
at DataStream. (/home/salim/Documents/proj/platform/oAuth/node_modules/jsonwebtoken/node_modules/jws/lib/data-stream.js:20:12)
at process._tickCallback (node.js:415:13)
stream.js:94
throw er; // Unhandled stream error in pipe. ^
Error: read ECONNRESET
at errnoException (net.js:901:11)
at Pipe.onread (net.js:556:19)
Please help where am I going wrong ?? Why is the orm not able to recognize the function ????
Your problem is that models.auth is undefined after you initialize models. Since models.auth is undefined, you cannot call its functions and cannot use its members.
auth is a local variable inside module.exports. Even though you return it, outside its scope you cannot use it.
If require calls module.exports, then your models is the very same object as auth, since you returned auth, therefore models.verify_user is existent in your code. However, I propose the following fix:
var models = {}; //creating an empty object which will hold the models
models.auth = require('../models/auth.js'); // the above model is saved in file auth.js
and then you will be able to use models.auth.