multiple SQL queries as one request on sequelize js - express

Is there a way for sequelize to send multiple queries as one request? Or does sequelize already does that?
Below is my code:
const transaction = await db.transaction();
try {
await Resource.bulkCreate(resourcesTable);
await postContacts(contactsTable, locationsTable);
await postResourceTag(resourceTagTable);
await transaction.commit();
} catch (err) {
logger.error(err);
await transaction.rollback();
throw new HttpError(500, "Database Error"); // placeholder until validation setup
}
const postContacts = async ({ contactsTable, locationsTable }) => {
if (contactsTable?.length) {
await Contact.bulkCreate(contactsTable);
if (locationsTable?.length) {
await Location.bulkCreate(locationsTable);
}
}
};
const postResourceTag = async (resourceTagTable) => {
if (resourceTagTable?.length) {
await Resource_Tag.bulkCreate(resourceTagTable);
}
};
Currently, I believe the bulkCreates are sent as separate requests? I'd prefer if they were sent as one single request like how it'd be if the SQL strings was concatenated and then sent.

Based on this answer you can use an array of promises and then handle them all in one point, is that what you might be looking for?

Related

Sequelize, findOrCreate + findAll unexpected behavior

I'm trying to fetch data from a dog API and I want to add to my database only their temperaments. I tried using some loops and a split to isolate the data and then using
findOrCreate() to add only those who are not already in the DB, after that I use findAll()
to get that info from the DB to send it using expressJS.
The unexpected behavior comes when I go to the route that executes all this and the route
only gives about half of the temperaments (they are 124 and it displays arround 54), then when I refresh the page it shows all 124 of them. The DB gets populated with all the 124 in one go so the problem is with findAll()
This is the function that isolates the temperaments and append them to the DB:
module.exports = async () => {
const info = await getAllDogs();
info.forEach(async (element) => {
const { temperament } = element;
if (temperament) {
const eachOne = temperament.split(", ");
for (i in eachOne) {
await Temperament.findOrCreate({
where: { name: eachOne[i] },
});
}
}
});
};
And this is the code that gets executed when I hit my expressJS sv to get the info
exports.temperaments = async (req, res) => {
try {
await getTemperaments(); //this function is the above function
} catch (error) {
res.status(500).send("something gone wrong", error);
}
const temperamentsDB = await Temperament.findAll();
res.json(temperamentsDB);
};
So as you can see the last function executes the function that appends all the data to the DB and then sends it with findAll and res.json()
forEach is a synchronous method so it doesn't await a result of the async callback. You need to do for of in order to get wait for all results:
module.exports = async () => {
const info = await getAllDogs();
for (element of info) {
const { temperament } = element;
if (temperament) {
const eachOne = temperament.split(", ");
for (i in eachOne) {
await Temperament.findOrCreate({
where: { name: eachOne[i] },
});
}
}
}
};

Why am I not getting a response from express server?

Sending a logout request to my server but I'm never getting a reply. The logout function is being called and the userID key is being deleted from my redis cache but I never get a response. Here's my code.
export const logout = async (req, res) => {
console.log("logout called");
const { userID } = req.user;
client.del(userID.toString, (err, reply) => {
console.log("inside client.del");
if (err) {
return res.status(500);
} else {
return res.status(200);
}
});
};
Because of callback, you should use promise
export const logout = async (req, res) => {
return new Promise((resolve,reject) => {
console.log("logout called");
const { userID } = req.user;
client.del(userID.toString, (err, reply) => {
console.log("inside client.del");
if (err) {
reject(res.status(500));
} else {
resolve(res.status(200));
}
});
});
}
res.status() does not send a response from the server. All it does is set the status as a property on the response object that will go with some future call that actually sends the response.
It is meant to be used in something like this:
res.status(500).send("Database error");
If you look at the Express doc for res.status(), you will see these examples:
res.status(403).end()
res.status(400).send('Bad Request')
res.status(404).sendFile('/absolute/path/to/404.png')
And, see that they all are followed by some other method that actually causes the response to be sent.
And, if you still had any doubt, you can look in the Express code repository and see this:
res.status = function status(code) {
this.statusCode = code;
return this;
};
Which shows that it's just setting a property on the response object and not actually sending the response yet.
You can use res.sendStatus() instead which will BOTH set the status and send the response:
export const logout = (req, res) => {
console.log("logout called");
const { userID } = req.user;
client.del(userID.toString, (err, reply) => {
console.log("inside client.del");
if (err) {
res.sendStatus(500);
} else {
res.sendStatus(200);
}
});
};
Note, I removed the two return keywords since they don't accomplish anything useful in this particular context.
I also removed the async keyword from the function definition since it was not doing anything useful in this context.

Reading binary data from fetch response when ArrayBuffer is not present

In a react native project i have a HTTP request that returns a binary file that i need to turn into a NodeJS Buffer object. I cannot for the life of me get this to work because arrayBuffer is not implemented in any form in react native and every single thing out there seems to hinge on that being present.
How can i turn a fetch response into a ANYTHING that can be accepted by Buffer? uint8array, anything.
async getFirmwareDownload(firmwareVersion: FirmwareVersion): Promise<Buffer | null> {
try {
const response = await fetch(`${this.getBaseUrl()}${firmwareVersion.url}`);
const blob = await response.blob();
return Buffer.from(blob);
} catch (err) {
console.error(err);
return null;
}
}
I attempted this and while its not throwing errors trying to convert. It is not converting correctly as it is missing several hundred bytes.
async getFirmwareDownload(firmwareVersion: FirmwareVersion): Promise<Buffer | null> {
try {
const response = await fetch(`${this.getBaseUrl()}${firmwareVersion.url}`);
const text = await response.text();
return Buffer.from(text, 'binary');
} catch (err) {
console.error(err);
return null;
}
}
I was finally able to do it in a VERY roundabout way by converting it to base64 data URL and then back into a Buffer. This is probably horribly inefficient but it at least generates the correct size Buffer that matches the file.
blobToBuffer(blob: Blob): Promise<Buffer> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onerror = reject;
reader.onload = () => {
const data = reader.result.slice(reader.result.indexOf('base64,') + 7);
resolve(Buffer.from(data, 'base64'));
};
reader.readAsDataURL(blob);
});
}
I would greatly appreciate any other method of doing this.

How to prevent multi beginTransactions in Realmjs?

I create a function to handle transaction, then I call it to multi places. I got crash when another transaction not yet complete when I open new transaction.
Here my code:
const RealmMakeTransaction = async (action) => {
try {
realm.GetInstance().beginTransaction();
let response = await action();
realm.GetInstance().commitTransaction();
return response;
} catch (e) {
realm.GetInstance().cancelTransaction();
}
};
You can easily check if realm is already in transaction or not before calling beginTransaction() by calling realm.GetInstance().isInTransaction
Your code will look like :
const RealmMakeTransaction = async (action) => {
//use single instance
let realm = realm.GetInstance();
try {
if( realm.isInTransaction)
realm.cancelTransaction();
realm.beginTransaction();
let response = await action();
realm.commitTransaction();
return response;
} catch (e) {
realm.cancelTransaction();
realm.close();
}
};

Node.js and MSSQL stored procedures

What would be the suggested way (if even possible) to call MSSQL SP from Node.js. The documentation https://www.npmjs.org/package/mssql is great but there is no mention of SP (stored procedure) anywhere.
The linked document does actually mention stored procedures:
var request = new sql.Request(connection);
request.input('input_parameter', sql.Int, 10);
request.output('output_parameter', sql.VarChar(50));
request.execute('procedure_name', function(err, recordsets, returnValue) {
// ... error checks
console.dir(recordsets);
});
Not sure it's wise to answer this question, but it might be valueable for future readers/googlers.
It's getting better with ES6/7 additions to JS. This is how you can do it with async/await:
async function getDataFromProcedure(dbConfig, procedureName) {
try {
await sql.connect(dbConfig);
const request = new sql.Request();
recordsets = await request.execute(procedureName);
return recordsets[0];
} catch (error) {
// handle error here
}
};
Alternate async/await syntax. I like the .then() format.
return await this.sqlConnectionPool.connect().then(async (pool) => {
return await pool
.request()
.input("UserID", sql.Int, id)
.execute("spADF_User_Get")
.then((result) => {
if (result.recordset && result.recordset.length === 1) {
return result.recordset[0];
} else {
//Something bad happened
}
});
});