I've been having troubles when I try to call any builder "setter" methods
This is my code, User.js:
class User {
constructor(userBuilder) {
this.email = userBuilder.email;
this.name = userBuilder.name;
this.surname = userBuilder.surname;
this.photo = userBuilder.photo;
this.tokens = userBuilder.tokens;
this.authorized = userBuilder.authorized;
}
getEmail() {
return this.email;
}
getName() {
return this.name;
}
getSurname() {
return this.surname;
}
getPhoto() {
return this.photo;
}
getTokens() {
return this.tokens;
}
isAuthorized() {
return authorized;
}
static get UserBuilder() {
class UserBuilder {
constructor() {
this.email = null;
this.name = null;
this.surname = null;
this.photo = null;
this.tokens = null;
this.authorized = null;
}
email(email) {
this.email = email;
return this;
}
name(name) {
this.name = name;
return this;
}
surname(surname) {
this.surname = surname;
return this;
}
photo(photo) {
this.photo = photo;
return this;
}
tokens(tokens) {
this.tokens = tokens;
return this;
}
authorized(authorized) {
this.authorized = authorized;
return this;
}
build() {
return new User(this);
}
}
return UserBuilder;
}
}
module.exports = User
And my UserTest.spec.js:
process.env.NODE_ENV = 'test'
//Import User class
let User = require('../../../../main/com/auth/user/User');
// Import chai
let chai = require('chai');
// Tell chai that we'll be using the "should" style assertions.
chai.should();
describe('User', () => {
let user;
var email = "a#a";
var name = "a";
var surname = "a";
var photo = "p";
var authorized = true;
beforeEach(() => {
//Create new User object before each test
user = new User.UserBuilder()
.email(email)
.name(name)
.surname(surname)
.photo(photo)
.authorized(authorized)
.build();
});
it('returns the email', () => {
user.getEmail().should.equal(email)
});
it('returns the name', () => {
user.getName().should.equal(name)
});
it('returns the surname', () => {
user.getSurname().should.equal(surname)
});
it('returns the photo', () => {
user.getPhoto().should.equal(photo)
});
it('returns the authorized', () => {
user.getAuthorized().should.equal(authorized)
});
})
I get TypeError: user.email is not a function.
I've tried with UserBuilder outside User class:
In User.js
module.exports = {User: User, UserBuilder: UserBuilder}
In UserTest.spec.js
let {User} = require('../../../../main/com/auth/user/User');
let {UserBuilder} = require('../../../../main/com/auth/user/User');
user = new UserBuilder()
.email(email)
.name(name)
.surname(surname)
.photo(photo)
.authorized(authorized)
.build();
With the same result, what i'm doing wrong?? I can call build method, but I can't call any other methods.
Related
I have a problem where MongoDB says that my object is not a valid JavaScript Object, Even though it is! This has been staying for days!
Basically, this is an account system that uses MongoDB's client, and the ObjectId for the ID.
I want to be able to fix the MongoError that says object (sent to updateOne, not filter) is not a valid JavaScript object.
Here is the code:
const { MongoClient, ObjectId } = require("mongodb");
const fs = require("node:fs");
const uri = "mongodb://127.0.0.1:27017";
if (!fs.existsSync("./db")) {fs.mkdirSync("./db")};
const client = new MongoClient(uri,{ useUnifiedTopology: true });
async function conn() {
await client.connect();
}
conn();
const database = client.db("login");
const accs = database.collection("accounts");
const myfil = {
_id: new ObjectId('63b6441832087ccc7e3edea2')
};
const users = accs.findOne(myfil);
const path = require("node:path");
const bcrypt = require('bcrypt');
const env = process.env;
var saltRounds = 10;
const AddSet = class AddSet {
constructor(user,pass) {
console.log(pass);
this.set = {[user]:pass};
this.set = Object.keys(this.set).reduce((acc, key) => {
acc[key.toString()] = this.set[key];
return acc;
}, {});
console.log(this.set);
return this.set;
}
}
const Account = class Account {
constructor(user,password) {
conn();
if (!users[user]) {
conn();
accs.updateOne(myfil,bcrypt.hash(password, saltRounds, function(err, hash)
{
try {
var a = ""+user;
return new AddSet(a.toString(),hash);
} catch(err) {
console.error("bcrypt",err);
}
}));
this.assetDir = path.join(path.join(env.SAVED_FOLDER,"/"+this.user),"/assets");
this.metaDir = this.assetDir + '/meta';
this.starterDir = path.join(path.join(env.SAVED_FOLDER,"/"+this.user),"/starters");
this.videoDir = path.join(path.join(env.SAVED_FOLDER,"/"+this.user),"/videos");
var fs = require('fs');
if (!fs.existsSync(this.assetDir)) fs.mkdirSync(this.assetDir, { recursive: true });
if (!fs.existsSync(this.starterDir)) fs.mkdirSync(this.assetDir, { recursive: true });
if (!fs.existsSync(this.videoDir)) fs.mkdirSync(this.assetDir, { recursive: true });
}
}
getAssetDir() {
return this.assetDir;
}
getStarterDir() {
return this.starterDir;
}
getVideoDir() {
return this.videoDir;
}
getMetaDir() {
return this.metaDir;
}
checkSession(pswd) {
conn();
bcrypt.compare(pswd, users[this.user], function(err, result) {
if (result) return true;
else return false;
});
}
}
module.exports = { Account, users };
I tried fixing it, making the keys strings, removing the $set, and it did not work.
I trying to create a common database connection class using typescript for my nodejs express application that returns the MongoDB database object as follows but I always get TypeError: dbConn.GetInstance is not a function
const config = require("config");
const MongoClient = require('mongodb').MongoClient;
export class dbConn {
private db = null;
static url = config.database.uri;
static options = {
bufferMaxEntries: 0,
reconnectTries: 5000,
useNewUrlParser: true,
useUnifiedTopology: true,
};
private constructor() { }
private static instance: dbConn;
public static GetInstance() {//I also tried removing static keyword but still the error remains
if (dbConn.instance == null)
{
dbConn.instance = new dbConn();
}
return dbConn.instance;
}
public getDb() {
if (dbConn.instance.db) {
return dbConn.instance.db;
}
MongoClient.connect(dbConn.url, dbConn.options, function(err: any, db: any){
if(err) {
console.log(err);
return null;
}
dbConn.instance.db = db.db(config.database.name);
return dbConn.instance.db;
});
}
}
Updated 01-Aug-2020
I invoke the above instance from app.ts and my controllers as follows:
app.ts file
const dbConn = require('./utils/db/dbConn');
...//code removed for clarity
const app = express();
const server = http.createServer(app);
...//code removed for clarity
server.listen(port, ()=> {
dbConn.GetInstance().getDb();//I get the error here
console.log('Server running')
});
module.exports = app;
my controller file
getAll = async (pageNumber:any, pageSize:any) : Promise<PageResult<Team>> => {
return new Promise<PageResult<Team>>(async function (resolve, reject){
let result = new PageResult<Team>(pageSize, pageNumber);
var dbo = dbConn.GetInstance().getDb();//same error here too.
var query = {};
var recCount = await dbo.collection("teams").find().count();
if (recCount == 0) {
result.IsSuccessful = true;
result.ReasonForFailure = process.env.NO_RECORDS || "No record(s) to show.";
return resolve(result);
}
if (pageSize == -1) { //-1 means to return all records
dbo.collection("teams")
.find(query)
.sort({ name: 1 })
.toArray(function(err: any, resultSet: any) {
if (err) {
result.IsSuccessful = false;
result.ReasonForFailure = err.message;
return reject(result);
} else {
result.IsSuccessful = true;
result.TotalRecords = recCount;
result.PageNumber = parseInt(pageNumber);
result.PageSize = parseInt(pageSize);
result.Data = resultSet;
return resolve(result);
}
});
} else {
dbo.collection("teams")
.find(query)
.sort({ name: 1 })
.skip((parseInt(pageNumber)-1)*parseInt(pageSize))
.limit(parseInt(pageSize)).toArray(function(err: any, resultSet: any) {
if (err) {
result.IsSuccessful = false;
result.ReasonForFailure = err.message;
return reject(result);
} else {
result.IsSuccessful = true;
result.TotalRecords = recCount;
result.PageNumber = parseInt(pageNumber);
result.PageSize = parseInt(pageSize);
result.Data = resultSet;
return resolve(result);
}
});
}
});
}
Can you please assist what is wrong or what is the missing piece to get this to work?
Thanks,
Hemant.
It seems you're using commonjs as module-resolution strategy. Your import will be the problem in that case. Try changing it to:
const dbConn = require('./utils/db/dbConn').dbConn;
or
const { dbConn } = require('./utils/db/dbConn');
or
import {dbConn } from './utils/db/dbConn';
Here's a simple example to show what's going on. Consider this simple ts-class:
export class TestClass {
static test():void {
console.log("it works")
}
}
It will be transpiled into:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TestClass = void 0;
class TestClass {
static test() {
console.log("in workds");
}
}
exports.TestClass = TestClass;
//# sourceMappingURL=index.js.map
If you then require this with const TestClassModule = require('./test-class');, TestClassModule will yield:
{ TestClass: [Function: TestClass] }
Hence, you need to use const { TestClass } = require('./test-class');.
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.
I have a class which has 10 methods, and only 8 of those 10 should be exported, the other 2 are for authenticating tokens and I don't want them to be exported since the user won't need to call them ever ( I'm writing a package for npmjs ), my question is, how to only export the class with those 8 methods while the class itself is using the other two?
Edit: added some code
class StackClass {
constructor(p1, p2) {
this.data = {
p1,
p2,
accessToken: null,
expiresIn: null,
tokenType: null
};
}
async getToken() {
return new Promise(async (resolve, reject) => {
try {
let fetchResponse = await fetch(
"url with this.data.p1 and this.data.p2"
);
let fetchData = await fetchResponse.json();
if (fetchData.status != 200) {
reject("ERROR");
} else {
// get the token and save it in this.data
this.data.accessToken = fetchData.access_token;
this.data.expiresIn = fetchData.expires_in;
this.data.tokenType = fetchData.token_type;
resolve(fetchData);
}
} catch (err) {
console.log(err);
}
});
}
async isTokenValid() {
if (new Date() >= this.data.expiresIn) {
// Generate a new Token
try {
await this.getToken();
} catch (err) {
console.log(err);
}
}
// else - Do nothing and use current token saved in this.data.accessToken
}
async getData() {
try {
await this.isTokenValid();
await fetch("url2 with this.data.accessToken");
} catch (err) {
console.log(err);
}
}
}
let user = new StackClass("username", "password");
user.isTokenValid(); // SHOULD BE PRIVATE
user.getToken(); // SHOULD BE PRIVATE
user.getData(); // SHOULD BE PUBLIC
Define the isTokenValid and getToken as standalone functions instead. You should also avoid the explicit Promise construction antipattern, and only catch in a place where you can sensibly handle the error, which is usually in the caller of the asynchronous function (perhaps getData, perhaps in the consumer of the StackClass class):
class StackClass {
constructor(p1, p2) {
this.data = {
p1,
p2,
accessToken: null,
expiresIn: null,
tokenType: null
};
}
async getData() {
try {
await isTokenValid(this);
await fetch("url2 with this.data.accessToken");
} catch (err) {
// or you can just avoid the `try`/`catch` altogether,
// and have the consumer of getData handle problems
console.log(err);
}
}
}
function isTokenValid(stack) {
if (new Date() >= stack.data.expiresIn) {
// Generate a new Token
return getToken(stack);
}
// else - Do nothing and use current token saved in this.data.accessToken
}
async function getToken(stack) {
const fetchResponse = await fetch(
"url with this.data.p1 and this.data.p2"
);
const fetchData = await fetchResponse.json();
if (fetchData.status != 200) {
throw new Error('error');
} else {
// get the token and save it in this.data
stack.data.accessToken = fetchData.access_token;
stack.data.expiresIn = fetchData.expires_in;
stack.data.tokenType = fetchData.token_type;
}
}
Why don't you export a function that takes a list of arguments, creates an object of your class with those arguments, and then return a new object literal with only public methods? Take a look:
my-class.js
class MyClass {
constructor(f1, f2) {
this.field1 = f1;
this.field2 = f2;
}
m1() {
this.m2();
}
m2() {
console.log('this.field1', this.field1);
this.m3();
}
m3() {
console.log('this.field2', this.field2);
this._m4();
}
_m4() {
console.log('private m4');
this._m5();
}
_m5() {
console.log('private m5');
}
}
module.exports = (f1, f2) => {
const my = new MyClass(f1, f2);
return {
m1: my.m1.bind(my),
m2: my.m2.bind(my),
m3: my.m3.bind(my),
}
}
index.js
const myObj = require('./my-class')('f1', 'f2');
myObj.m1();
Live demo
This way you are hiding the private methods which should not be accessible outside of the module.
I couldnt write function worked automatically (constructor) when file required in node.js..
this is so...file.js
module.exports = {
index: function () {
//code here
}
};
app.js
var file=require("./file");
res.send(file.index());
what I want...
module.exports = {
main :__constructor()
{
this.name="blabla";
},
index: function () {
//code here
this.name // will be used this place name variable
}
};
Use .prototype() to do this. Hope it helps!
const App = function(name) {
this.name = name
}
App.prototype.main = function() {
return this.name
}
b = new App('myName')
console.log(b.main())
//You can do module.exports = App and invoke it in another file
okey..but
module.exports = {
app :function (name)
{
this.name="blabla";
},
app.prototype.index: function () {
}
};
this does not work!!!
/var/www/public/nodeapi/app/v1/blog/index.js:19
app.prototype.index: function () {
const App = function(name) {
this.name = name
}
App.prototype.main = function() {
return this.name
}
b = new App('myName')
console.log(b.main())
//You can do module.exports = App and invoke it in another file
Something like this?
// file.js
class MyClass {
constructor() {
this.name = 'blabla';
}
index() {
console.log('name', this.name);
}
}
module.exports = new MyClass();
class blog {
constructor()
{
this.name="fookey";
}
index(callback)
{
var data={};
data.test=this.name;
callback(data);
}
}
module.exports=new blog();
TypeError: Cannot read property 'name' of undefined
why does not work?