Async table query in sequelize getter method - node.js

I have a sequelize instance method that performs a DB query:
getPropertyDays() {
const queryString = `
SELECT
state
FROM property_days
WHERE
DATE(day) = CURDATE() AND
property_id = :propertyId;`;
const replacements = {propertyId: this.id};
return this.sequelize.query(queryString, {replacements: replacements, type: sequelize.QueryTypes.SELECT});
},
that gets called by the getter:
getterMethods: {
propertyState() {
var self = this;
const blockedDay = 'x';
const unavailableDay = 'u';
this.getPropertyDays().then(function(result) {
var state = result[0]['state'];
if (self.prospect || state == unavailableDay) {
return 'unavailable';
}
if (state == blockedDay) {
return 'occupied';
}
else {
return 'available';
}
});
}
},
The problem is that the result that is returned from the getter is undefined because he's not able to solve the promise before returning.
Since I don't have a model for the table, how can I solve this issue? Been around this for one day already!
Thanks a lot.

Won't returning the promise returned from this.getPropertyDays do the trick?
getterMethods: {
propertyState() {
var self = this;
const blockedDay = 'x';
const unavailableDay = 'u';
return this.getPropertyDays().then(function(result) {
var state = result[0]['state'];
if (self.prospect || state == unavailableDay) {
return 'unavailable';
}
if (state == blockedDay) {
return 'occupied';
}
else {
return 'available';
}
});
}
},

Related

How to make a transaction in cosmos DB with NodeJS

** Edited **
I am trying to insert data to Azure cosmos DB if its not exist but can't find a way to do it in one transaction.
the current way I'm doing it is by first getting it from cosmos and if it's throwing Not found exception then insert, otherwise update it.
the issue with that is that between the get and insert someone can push an object so this approach is unsafe.
code snippet:
static async fetchOrgConfigurationTableByQuery(orgId: string): Promise<OrgConfigurationTable> {
const { container } = await getContainer(Constants.CosmosRegional, Constants.OrgConfigurationTableName);
const orgConfigurations = await container.items.query(`SELECT * from c WHERE c.OrgId = "${orgId}"`).fetchAll();
const orgConfiguration = orgConfigurations.resources.find(() => true) as OrgConfigurationTable;
if (!orgConfiguration) {
return;
}
const orgConfigurationWithDefaults = new OrgConfigurationTable();
for (const [key] of Object.entries(orgConfiguration)) {
orgConfigurationWithDefaults[key] = orgConfiguration[key];
}
return orgConfigurationWithDefaults;
}
static async upsertOrgConfiguration(
orgConfiguration: OrgConfigurationTable,
failOnEtagMismatch = false
): Promise<OrgConfigurationTable> {
const requestOptions = getRequestOptions(orgConfiguration, failOnEtagMismatch);
const { container } = await getContainer(Constants.CosmosRegional, Constants.OrgConfigurationTableName);
const returnValue = await container.items.upsert<OrgConfigurationTable>(orgConfiguration, requestOptions);
return returnValue?.resource;
}
what I have:
let orgConfig: Cosmos.OrgConfigurationTable = null;
try {
orgConfig = await fetchOrgConfigurationTableByQuery(orgId);
} catch (error) {
if (!error instanceof Cosmos.OrgNotFoundException) {
log(error)
}
}
orgConfig = {
...orgConfig,
attribute: value,
...(!orgConfig && { Key: { Value: orgId } }),
};
await upsertOrgConfiguration(orgConfig)
what I want - to dont get before upsert:
let orgConfig = {
attribute: value,
Key: { Value: orgId },
};
await upsertOrgConfiguration(orgConfig) // if exist update, else insert - in single transuction.
or some way to do somthing like this:
transaction {
let orgConfig: Cosmos.OrgConfigurationTable = null;
try {
orgConfig = await fetchOrgConfigurationTableByQuery(orgId);
} catch (error) {
if (!error instanceof Cosmos.OrgNotFoundException) {
log(error)
}
}
await upsertOrgConfiguration(orgConfig)
}
commit
any ideas?

I need help to get a simple query for MongoDB (SQL equivalent: "select speed from values")

I need help to get a simple query for MongoDB (SQL equivalent: "select speed from values"). But I can't find a solution for that.
Node.js backend for Vue.js
// a Part of Init-function:
await collection.replaceOne({}, {
speed: {
value: 65,
type: 2,
},
eightSpeed: {
value: 0.0043,
type: 2,
},
oSpeed: {
value: 0.31,
type: 2,
},
minusSpeed: {
value: 2.42,
type: 2,
}
}
//...
Now I need the query like this: http://192.168.220.220:3000/settings/getValue/speed to get an object speed.
const express = require("express");
const mongodb = require("mongodb");
const SettingsRouter = new express.Router();
SettingsRouter.get("/getValue/:value", async function (req, res) {
try {
const val = req.params.value; // req.body.text;
const select = {};
select[`${val}.value`] = 1;
console.log("settings.js:", "/getValue/:name", select);
const collection = await loadMongoCollection();
const value = await collection.findOne({},select)//.toArray();
res.status(201).send(value);
} catch (error) {
res.status(500).send("Failed to connect Database");
console.error("settings.js:", "/getValue/:name:", error);
}
});
async function loadMongoCollection() {
const dbUri = process.env.MONGODB_CONNSTRING || config.dbUri;
const MongoDB = process.env.MONGODB_DB || config.db;
try {
const client = await mongodb.MongoClient.connect(dbUri, {
useNewUrlParser: true,
});
const conn = client.db(MongoDB).collection("values");
return conn;
} catch (error) {
console.error("settings.js:", "loadMongoCollection:", error);
}
}
When I try it, I get all (not only the Speed Object) what I expected, or nothing.
What I do wrong?
EDIT 2022.01.06:
I try it to change my database:
data = {
speed: {
value: 65,
type: 2,
},//...
}
//...
await collection.replaceOne({}, {values:data}, { upsert: true });
And then the query:
const select = {[`values.${val}.value`]:"1"};
const where = {}; //{"values":val};
const value = await collection.find(where,select,).toArray();
But it will not work in rest... is there an issue in mongo package?
When I do it in https://cloud.mongodb.com - it works:
But my request returns all values...
Log shows:"'settings.js:', '/getValue/:name', { 'values.speed.value': '1' }"
In the screenshot you show the projection is values.speed.value, but in your endpoint you have:
const select = {};
select[`${val}.value`] = 1;
Which would evaluate to speed.value. To mimic what you have on the MongoDB console this should be:
const select = {};
select[`values.${val}.value`] = 1;
So, I changed my Frondend (vue) to spred all Values. I maked some Helper Functions:
CheckForChangedObj
check two object for changes
updateObj
copy all data from object into another
export function CheckForChangedObj(targetObject, obj) {
if (targetObject === typeof undefined || targetObject == {}) {
return true
}
if (JSON.stringify(targetObject) !== JSON.stringify(obj)) {
return true
}
return false
}
export function updateObj(targetObject, obj) {
let keys = Object.keys(obj)
for (let k in keys) {
try {
let key = keys[k]
if (!targetObject.hasOwnProperty(key)) {
//define target, if not exist
targetObject[key] = {}
}
//Workaround for References
if (obj[key].hasOwnProperty("__v_isRef")) {
if (targetObject[key].hasOwnProperty("__v_isRef")) {
targetObject[key].value = obj[key].value
} else {
targetObject[key] = obj[key].value
}
} else {
//Source i a Norm Value
//check for an Object inside, then go in...
if ("object" === typeof obj[key] && !Array.isArray(obj[key])) {
updateObj(targetObject[key], obj[key]) // recurse
} else {
//not else-if!!! __v_isRef: true
if (targetObject[key].hasOwnProperty("__v_isRef")) {
targetObject[key].value = obj[key]
} else {
targetObject[key] = obj[key]
}
}
}
} catch (error) {
console.log(
"key:",
keys[k],
"Error:",
error
)
}
}
}
Then spreading...
import {updateObj,CheckForChangedObj } from "../tools/tools"
beforeMount() {
this.getAllValuesAPI()
setInterval(() => {
this.checkForChanges()
// ml("TABLE", this.values)
}, 10000)
},
setup() {
let prevValues = {}
let values = {
speed: {
id:1,
type: SettingType.Slider,
value: ref(0)
}
//...
}
function checkForChanges() {
//intervaled function to get changes from API
let changed = CheckForChangedObj(this.values, this.prevValues)
if (changed) {
updateObj(this.prevValues, this.values)
setValuesToAPI()
}
else{
getAllValuesFromAPI()
}
}
async function getAllValuesFromAPI() {
//get ALL Settings-Data from API, and put them in values
const res = await axios.get(`settings/getAll`)
return updateObj(this.values, res.data[0].values) u
}
}
When you have a better solution, please help...

how to clear global var between tests in nodejs?

I have 2 tests which each one them pass but when i run them together the second test fails.
I have this global var (CURR_GUID) which i want to clear between the tests but i am not sure how to do that.
Since it is not cleared between the tests , its value is still "1111111" and not null.
Any idea?
Class W
"use strict";
var CURR_GUID = null;
class W {
constructor() {
console.log("W ctor")
}
async getDataFromDb() {
if (CURR_GUID) {
return CURR_GUID;
} else {
this.db = require("./Connection").getDb();
console.log("W getDataFromDb")
let res = null;
res = await this.db.one("SELECT guid FROM table", ["NONE"]);
return res.guid;
}
}
async saveGuid(guid) {
this.db = require("./Connection").getDb();
await this.db.none("update table set guid=$1", [guid]);
CURR_GUID = guid;
console.log("currr is" + CURR_GUID);
}
}
module.exports = W;
Class X
"use strict";
const wDao = new (require("../db/W"))();
class X {
async getGuid() {
console.log("X getGuid")
let guid = await wDao.getDataFromDb();
console.log("got guid " + guid);
await wDao.saveGuid(guid);
return guid;
}
}
module.exports = X;
Test.spec.js
const chai = require("chai");
const expect = chai.expect;
const X = require("../src/service/X");
const Connection = require("../src/db/Connection");
const sinon = require("sinon");
describe("component_test", function () {
afterEach(function () {
this.dbStub.restore();
});
it("X_component_test", async function () {
var db = {
one: async () => {
return {
guid: '1111111',
created_on: "123"
}
},
none: async () => {
}
};
this.dbStub = sinon.stub(Connection, "getDb").returns(db);
var dao = new X();
var guid = await dao.getGuid();
expect(guid).to.equal('1111111');
});
it("X_component_test_2", async function () {
var db = {
one: async () => {
return {
guid: '222222',
created_on: "123"
}
},
none: async () => {
}
};
this.dbStub = sinon.stub(Connection, "getDb").returns(db);
var dao = new X();
var guid = await dao.getGuid();
expect(guid).to.equal('222222');
});
});
While it should be possible to achieve the desired result by deleting W and X modules from require.cache in afterEach hook, it might be better to modify the source code a bit so that it can be tested without cache manipulations.
Class W
Turn CURR_GUID variable into an instance property.
"use strict";
class W {
constructor() {
console.log("W ctor");
this.CURR_GUID = null;
}
async getDataFromDb() {
if (this.CURR_GUID) {
return this.CURR_GUID;
} else {
this.db = require("./Connection").getDb();
console.log("W getDataFromDb")
let res = null;
res = await this.db.one("SELECT guid FROM table", ["NONE"]);
return res.guid;
}
}
async saveGuid(guid) {
this.db = require("./Connection").getDb();
await this.db.none("update table set guid=$1", [guid]);
this.CURR_GUID = guid;
console.log("currr is" + this.CURR_GUID);
}
}
module.exports = W;
Class X
Turn wDao from variable into an instance property
"use strict";
const WDao = require("../db/W");
class X {
constructor() {
this.wDao = new WDao();
}
async getGuid() {
console.log("X getGuid")
let guid = await this.wDao.getDataFromDb();
console.log("got guid " + guid);
await this.wDao.saveGuid(guid);
return guid;
}
}
module.exports = X;
In this way every test should work with fresh instances of W and X that do not depend on the closure state.

Why doesn't my async function return any result?

I wrote this small program to fetch data. This however is done async. Since I nonetheless need to use the function holeVertreter(kzl) as a function in another module, I'd like to get a return value which I can eventually pass on.
Excuse my spaghetti code (I usually prettify the code when I am done with my task ...).
Credentials are stored in a file and are therefore not found in this file.
I'd like to end up with "vertreter" as a return value.
Thank you in advance.
const node = require("deasync");
const DSB = require('dsbapi');
const tabletojson = require('tabletojson');
const https = require('https');
const cred = require("./vertrCred");
const dsb = new DSB(cred["dsb"]["user"], cred["dsb"]["passw"]); //Sanitized - no Credentials here
//Stackoverflow 2332811
String.prototype.capitalize = function(lower) {
return (lower ? this.toLowerCase() : this).replace(/(?:^|\s)\S/g, function(a) { return a.toUpperCase(); });
};
function holePlan(kuerzel) {
dsb.fetch()
.then(data => {
const timetables = DSB.findMethodInData('timetable', data);
const tiles = DSB.findMethodInData('tiles', data);
var tilesStr = JSON.stringify(tiles["data"][0]["url"]);
var url = JSON.parse(tilesStr);
https.get(url, (resp) => {
let data = '';
resp.on('data', (chunk) => {
data += chunk;
});
resp.on('end',() => {
var tableasjson = tabletojson.convert(data);
var erstetab = tableasjson[0];
var zweitetab = tableasjson[1];
var drittetab = tableasjson[2];
var viertetab = tableasjson[3];
var fuenftetab = tableasjson[4];
var sechstetab = tableasjson[5];
var siebtetab = tableasjson[6];
var achtetab = tableasjson[7];
if (typeof kuerzel === "undefined")
{
var regenechse = '(Aaa|Aaa[A-Za-z?]|[A-Za-z?]Aaa)';
}
else {
var name = kuerzel.capitalize(true);
var regenechse = '('+name+'|'+name+'[A-Za-z?]|[A-Za-z?]'+name+')';
}
const regex = new RegExp(regenechse,'g');
var sammel = Object.assign(drittetab,fuenftetab);
var z= 0;
var vertreter = {}
var y = JSON.parse(JSON.stringify(sammel));
for (i=0;i<y.length;i++) {
if (typeof y[i].Vertreter =='undefined') {
}
else {
if(y[i].Vertreter.match(regex))
{
z += 1;
vertreter[z] = y[i];
}
}
}
if (z == 0) {
// console.log("Es gibt nichts zu vertreten");
}
else {
//console.log("Es werden "+z+" Stunden vertreten");
return (vertreter);
} ;
});
})
})
.catch(e => {
// An error occurred :(
console.log(e);
});
}
//Stackoverflow
function warte(promise) {
var done = 0;
var result = null;
promise.then(
function (value) {
done = 1;
result = value;
return (value);
},
function (reason) {
done = 1;
throw reason;
}
);
while (!done)
node.runLoopOnce();
return (result);
}
function holeVertretung(kzl) {
var aufgabe = new Promise((resolve,reject) => {
setTimeout(resolve,1000,holePlan(kzl));
});
var ergebnis = warte(aufgabe);
if (typeof ergebnis === "undefined") {
console.log("Mist");
}
else {
console.log(ergebnis);
}
return ergebnis;
}
holeVertretung("Aaa");
That's not the right way to work with promises. If you do such infinite loop, it beats the whole purpose of using promises. Instead, return value from the promise, and use async-await like this:
function warte(promise) {
var done = 0;
var result = null;
return promise.then(
...
}
async function holeVertretung(kzl) {
var aufgabe = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, holePlan(kzl));
});
var ergebnis = await warte(aufgabe);
...
If async-await does not work for some reason, use then clause:
warte(aufgabe).then(value => {
var ergebnis = value;
});

Node.js - TypeError: Object #<Object> has no method

I am trying to include a module i found that will help manage users:
http://www.codeproject.com/Articles/382561/Session-Management-in-Nodejs
Ive copied the code and put it in the same directory as my server.js
I require it by doing:
var express = require('express');
var http = require('http'),
mysql = require("mysql");
var server = http.createServer(app);
var io = require('socket.io').listen(server);
var sessionMgm = require("./sessionManagement");
Now in my socket i do this:
io.sockets.on('connection', function (socket) {
socket.on('setUserInfo', function (data) {
var sess = new Object();
sess.sessionId = socket.id;
sess.userId = data.userId;
sess.username = data.username;
sess.role = data.role;
sessionMgm.add(sess);
});
socket.on("private", function(data) {
if(data.agentName.length <= 0) {
data.agentName = 'Besökare';
}
io.sockets.in('Room_' + data.user_id).emit('updatechat', data.agentName, data.msg);
var user = sessionMgm.getSessionByUserId(data.id);
console.log('::: A socket with ID ' + user + ' connected! ::: ');
});
});
However i keep getting this error:
TypeError: Object # has no method 'getSessionByUserId'
Cant seem to figure out whats wrong, any ideas?
sessionManagement.js:
module.exports = sessionManagement;
var sessions = [];
//User roles list
var userRoles = {
Admin: "administrator",
User: "user",
Supervisor: "supervisor"
};
var sessionManagement = {
indexOf: function(sessionId) {
for(var i in sessions) {
if(sessions[i].sessionId == sessionId)
return i;
}
return null;
},
indexOfUser: function(userId) {
for(var i in sessions) {
if(sessions[i].userId == userId)
return i;
}
return null;
},
add: function(sessionData) {
sessions.push(sessionData);
},
remove: function(sessionId) {
var index = this.indexOf(sessionId);
if(index != null) {
sessions.splice(index, 1);
} else {
return null;
}
},
removeByUserId: function(userId) {
var index = this.indexOf(userId);
if(index != null) {
sessions.splice(index, 1);
} else {
return null;
}
},
getSessionById: function(userId) {
var index = this.indexOfUser(userId);
if(index != null) {
return sessions[index];
} else {
return null;
}
},
getSessionByUserId: function(sessionId) {
var index = this.indexOfUser(userId);
if(index != null) {
return sessions[index];
} else {
return null;
}
},
isAdmin: function(userId) {
var index = this.indexOfUser(userId);
if(index != null) {
if(users[index].role == userRoles.Admin) {
return true;
} else {
return false;
}
} else {
return null;
}
},
getUsersByRole: function(role) {
var usersByRole = [];
for(var i in users) {
if(users[i].role == role)
usersByRole.push(users[i]);
}
return usersByRole;
}
};
As madflow mentioned, you were missing module.exports = sessionManagement in sessionManagement.js
Then you got the error, because you were exporting sessionManagement, before initializing it. Moving the export line to the end of sessionManagement.js should fix that.
module.exports = sessionManagement; // <- you export here
...
...
...
var sessionManagement = { // and initialize here
Although sessionManagement declaration gets hoisted to the top of the module (and that's why you don't get Unexpected identifier or ReferenceError when assigning it to module.exports), it's initialization does not, so what really happens behind the scenes is something like that:
var sessionManagement; // undefined at this point
module.exports = sessionManagement; // <- you export here,
// but sessionManagement is undefined at this point
// and so will be module.exports after this line
...
...
...
sessionManagement = { // and initialize here

Resources