how to use transaction in sequelize using nodejs - node.js

Below code throw "TypeError: sequelize.transaction is not a function" Error
sequelize.transaction(transaction => {
myDb.myTable.findAll({attributes:['IMAGEPATH'],where:{ID : customerId}})
.then((result) => {
....
}).then((commitResult) =>{
//commit
}).catch((rollbackErr) =>{
//rollback
})

It looks like you're trying to reference the transaction function on the definition as opposed to the instance i.e.
const sequelize = require('sequelize');
sequelize.transaction(...); // doesn't exist
You need to create a sequelize instance and use the transaction function on this
const Sequelize = require('sequelize');
const db = new Sequelize(...);
db.transaction(...); // works
See the docs.

Related

Mock require/import modules using cypress

I'm using sequelize with graphql to connect my postgresql in my react nodejs project. And I'm using Cypress for unit testing. While doing that, I got stuck on how to mock the module import.
describe('db config using sequelize', { tags: ['#unit'] }, () => {
before(() => {
const SequelizeStub = {
authenticate: new Cypress.Promise((resolve) => { resolve(true) }),
DataTypes: cy.stub().returns({}),
}
cy.stub('sequelize').returns(SequelizeStub)
})
it('db config authenticate', async () => {
const { connect } = require('#db/common/dbconfig')
assert.isBoolean(connect.authenticate())
})
})
The #db/common/dbconfig file calls the require('sequelize') and creating the object for sequelize and using the Sequelize object I'm connecting to Postgresql.
So while writing the unit test case coverage for dbconfig file, I would like to mock the require('sequelize') itself instead of the module gets loaded for testing.
So I wrote a stub and replacing it with 'sequelize' assuming that it will mock. But not sure this is the right approach. While running it, I'm getting the following error.
TypeError: Cannot read properties of undefined (reading 'value')
Because this error occurred during a before all hook we are skipping the remaining tests in the current suite: db config using sequelize
Although you have test retries enabled, we do not retry tests when before all or after all hooks fail
Can someone help me with this stub mocking?
Learnt that without importing the actual model, it is not possible to mock it.
So I updated the code as follows,
const SEQUELIZE_NAMESPACE = {
Sequelize: require('sequelize'),
}
const mSequalize = {
authenticate: cy.stub().callsFake(
(params, callback) => {
return new Cypress.Promise((resolve) => resolve())
}),
define: cy.stub().callsFake(
(params, callback) => {
return {}
}),
}
cy.stub(SEQUELIZE_NAMESPACE, 'Sequelize').callsFake((params, callback) => mSequalize)
Used the same const SEQUELIZE_NAMESPACE in source file as well as follows,
const SEQUELIZE_NAMESPACE = {
Sequelize: require('sequelize'),
}
And then created object as follows,
const sequelize = new SEQUELIZE_NAMESPACE.Sequelize(...)
and then it worked. Thanks for one of my peer (#rsmuthu) who helped me fix this.

add a subcollection under each document that resulted from geofirestore query

I queried 'users/userid/pros' firestore collection using cloud functions geofirestore, and I get a few specific documents('users/userid/pros/proid') from the query. Now, I want to add a new 'notifs' collection subsequently under each of these specific documents I get from the query. Here is my code to implement that functionality.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
var GeoFirestore = require('geofirestore').GeoFirestore;
admin.initializeApp();
const firestore = admin.firestore();
const geofirestore = new GeoFirestore(firestore);
exports.sendNotification = functions.firestore
.document("users/{userId}/clients/{client}")
.onCreate(async snapshot => {
const clientfield = snapshot.data().field;
const clientgeopoint = snapshot.data().g.geopoint;
const geocollection = geofirestore.collectionGroup('pros');
const query = geocollection.near({center: clientgeopoint, radius:
10}).where('field', '==', clientfield);
await query.get().then( querySnapshot => {
querySnapshot.forEach(async doc => {
await doc.ref.collection('notifs').add({
'field': clientfield, ... });
});
}).catch ((error) =>
console.log(error)
);
})
But this code gives me an error 'TypeError: Cannot read property 'collection' of undefined' on cloud functions console. How can I fix my code in order to add 'notifs' collection right under each of these specific documents like in the picture? Thanks.
I think you're trying to fetch the querysnapshot data wrong. From Muthu's reply it should look like this
let querySnapshot = await admin.firestore().collection('users').doc(userid).collection('pros').get();
querySnapshot.then(querySnapshot => {
querySnapshot.forEach(doc => {
// frame your data here
await doc.ref.collection('notifs').add({ ... });
});
});
If you are going to get the data from your snapshot you need to add the .then() statement after .get to properly reference the query.
DocumentSnapshot carries their reference in a field; For Node.JS - ref and for Dart - reference. You shall use this to perform any action within that document. Assuming the code was written in NodeJS, for creating sub-collection,
query.get().then(querySnapshot => {
querySnapshot.forEach(doc => {
// frame your data here
await doc.ref.collection('notifs').add({ ... });
})
});

Sequelize won't close after bulkcreate

I'm just getting started on Sequelize to write to a MSSQL db - all working well, but my node program never finishes and returns to the terminal. Code looks like this:
const Sequelize = require('sequelize');
var sequelize = new Sequelize(...);
const JournalLine = sequelize.define('journalLine', {...});
JournalLine.sync().then(() => {
JournalLine.bulkCreate([...])
});
Is there something I need to close off in order to end the program?
You did not provided callback function or utilise Promise, following will work
const Sequelize = require('sequelize');
var sequelize = new Sequelize(...);
const JournalLine = sequelize.define('journalLine', {...});
JournalLine.sync().then(() => {
return JournalLine.bulkCreate([...]).then( result => {
console.log('done');
return result;
})
});

Stubbing pg-promise using sinon and mocha

Suppose I have a the following module, as database.js
const initOptions = {}
const pgp = require('pg-promise')(initOptions)
const config = require('../../config')
const db = pgp({
host: config.database.host,
port: config.database.port,
database: config.database.database,
user: config.database.user,
password: config.database.password
})
module.exports = db
And the following module as create.js
const db = require('./database')
function create (name) {
return new Promise((resolve, reject) => {
db.func('create', name)
.then(data => {
return resolve(data)
})
.catch(err => {
return reject(err)
})
})
}
module.exports = create
I'm trying to run a unit test on create.js that will test that db.func is called with 'create' as first argument and 'name' as the second, but without actually needing to set up a database connection (So tests can run offline).
From what I can gather, this is what libraries like sinon.JS can be used for, so I tried creating a test and stubbed the db object.
const chai = require('chai')
const chaiAsPromised = require('chai-as-promised')
chai.use(chaiAsPromised)
const sinon = require('sinon')
const expect = chai.expect
const create = require('./create.js')
describe('Test Module', () => {
it('should test stuff', () => {
const db = require('./database')
const dbStub = sinon.stub(db, 'func').callsFake(Promise.resolve(null))
expect(create('test').then).to.be.a('Function')
})
})
However, it fails with
TypeError: Cannot redefine property: func
Most likely due to my limited exposure to sinon...
How do I go about stubbing (or maybe I need to mock?) the db function so that I can test it an ensure db.func was called?
You can make the properties configurable by disabling locks with the no noLocking option in Initialization Options. This allows sinon to replace the properties:
const initOptions = { noLocking : true };
On a related note:
Your create function is creating an unnecessary promise wrapper, which is a promise anti-pattern. You should just return the result from db.func, which is a promise already:
function create(name) {
return db.func('create', name);
}
Also callsFake takes a function and you are giving it a promise. Use returns instead:
const dbStub = sinon.stub(db, 'func').returns(Promise.resolve(null))
I'm having trouble setting the noLocking option. The docs state it can be set after initialization, however if I set it with db.$config.options.noLocking = true, the same error occurs. However, if I set it in the database.js init options it works fine.
From the author of pg-promise...
It is because at that point the noLocking can only affect tasks and transactions. And since the db level of the protocol is initiated only once, setting noLocking after the library's initialization doesn't effect it.
I have just updated the documentation to clarify it:
This option is dynamic (can be set before or after initialization). However, changing it after the library's initialization will not affect Database objects that have already been created.

Unit testing / Mocking mongoose models with sinon

so I have a node module like:
let mongoose = require('mongoose'),
User = mongoose.model('User');
module.exports = (req, res, next) => {
User.findById(req.user)
.then(user => {
req.body.user = user._id;
req.body.company = user.company;
next();
}, err => {
req.send(400, err);
});
};
So, in this case, I want to ensure the proper things are attached to the req.body. So, how would I go about mocking the User function? I have to load the model first so this code doesn't throw an error before calling mongoose.model so maybe something to do with actually stubbing the global require? Thanks for any advice!
So, I just discovered proxyquire https://www.npmjs.com/package/proxyquire and it was like the heavens opened and shined a light down upon me for the most glorious "ah ha" moment. No more having to load models in mongoose before trying to use them!
The code to mock mongoose looks something like:
const proxyquire = require('proxyquire'),
expect = require('chai').expect,
Promise = require('bluebird'),
_ = require('lodash'),
USERID = 'abc123',
COMPANY = 'Bitwise',
mongooseStub = {
mongoose: {
model: (name, schema) => ({
findById: () => {
return new Promise((resolve, reject) => {
resolve({_id: USERID, company: COMPANY});
});
}
})
}
},
attachUser = proxyquire('../lib/users/attach-user', mongooseStub);
That will effectively load the attach-user module, while stubbing out the mongoose.model function to return something I can control. Then the rest of my test just calls out to the module function and can make assertions as expected.

Resources