js get class of calling object in function - javascript

I have a structure similar to this:
class Person {
greet() {
console.log(this.constructor.name)
}
}
class User extends Person {
}
let user = new User()
user.greet()
Unfortunately it prints window for this.constructor.name instead of User.
Is there some other way to get the actual class Name?
Actual code:
static MeteorMethod(target: MeteorModel, key: string, descriptor: PropertyDescriptor) {
let constructor = target.constructor
let className = target.constructor.name
let methodName = key
let method = descriptor.value
let meteorMethodName = MeteorModelDecorators.generateMethodName(constructor, methodName)
MeteorModelDecorators.MeteorMethodClasses[className] = target
if(Meteor.isServer) {
Meteor.methods({
[meteorMethodName]: (modelClassName: string, modelProps: object, ...args: any[]) => {
let model = new MeteorModelDecorators.MeteorMethodClasses[modelClassName](modelProps)
method.apply(model, args)
}
})
}
else {
descriptor.value = async function(...args: any[]) {
// here I expect this to be Book, but I get Window
return new Promise(function(resolve, reject) {
Meteor.call(meteorMethodName, this.constructor.name, this, args, (error: any, result: any) => {
if(error) reject(error)
resolve(result)
})
})
}
}
}
class MeteorModel {
#MeteorMethod
save() {
console.log('save')
}
}
class Book extends MeteorModel {
}
let book = new Book()
book.save()

Your problem is in this part:
descriptor.value = async function(...args: any[]) {
// here I expect this to be Book, but I get Window
return new Promise(function(resolve, reject) {
Meteor.call(meteorMethodName, this.constructor.name, this, args, (error: any, result: any) => {
if(error) reject(error)
resolve(result)
})
})
}
It needs to be this:
descriptor.value = async function(...args: any[]) {
// With the arrow function, should be Book
return new Promise((resolve, reject) => {
Meteor.call(meteorMethodName, this.constructor.name, this, args, (error: any, result: any) => {
if(error) reject(error)
resolve(result)
})
})
}
The function you were passing to the Promise constructor was setting up a new context, by using the arrow function you pick up the this context from the surrounding method.

Related

Calling other functions of a class inside a Promise in Node

So, I have two methods in a class. Both returns a promise. The second function calls the first function from inside of the promise it returns.
module.exports = {
funcA: () => {
return new Promise((resolve, reject) => {
something ? resolve(something): reject('nope');
});
}
funcB: () => {
return new Promise(async(resolve, reject) => {
try {
const something = await this.funcA();
} catch(err) {
reject('error');
}
}
}
When I am trying to call funcB() from another class, like this:
let something = await someService.funcB();
I am getting:
TypeError: this.funcA() is not a function
Can you shed some light on why this is happening and how to solve this problem?
one way to make it work is to create the function outside of the module.exports block to get a reference of each function. Then this keyword can be omitted
const funcA = () => {
return new Promise((resolve, reject) => {
// code here
});
};
const funcB = () => {
return new Promise(async(resolve, reject) => {
try {
const something = await funcA();
resolve(something);
} catch(err) {
reject('error');
}
})
};
module.exports = {
funcA,
funcB
}
I think this is what you need to do
module.exports = {
funcA: function() {
return new Promise((resolve, reject) => {
something ? resolve(something): reject('nope');
});
}
funcB: function() {
return new Promise(async(resolve, reject) => {
try {
const something = await this.funcA();
} catch(err) {
reject('error');
}
}
}
I've found using arrow functions inside objects as you've done breaks this, but you can fix it this way.

How mock a test for EntityManager.transaction() in TypeOrm?

I have this function in my controller:
async save(req: Request, res: Response) {
try {
const user = new User();
user.nome = 'Jhon Doe';
const admin = new Morador;
admin.user = user;
await getManager().transaction( async entity => {
await entity.save(user);
await entity.save(admin);
});
res.status(201).json(admin);
} catch (e) {
res.sendStatus(500);
}
}
I need to mock this function:
await getManager().transaction( async entity => {
await entity.save(user);
await entity.save(admin);
});
I need to receive the input values from the entity.save function.
How to do this with Jest?
After studying further how the getManager().transaction() function works, I was able to implement the mock like this:
function mockGetManager(objects: Array<any>) {
async function mockEntityManager() {
const entityManager = {} as EntityManager;
entityManager.save = function save(entity: any): Promise<any> {
// todo
return Promise.resolve(true);
}
entityManager.update = function update(entity: any, update: any): Promise<any> {
// todo
return Promise.resolve(true);
}
entityManager.findOne = function findOne(query: any): Promise<any> {
// todo
return Promise.resolve(true);
}
entityManager.find = function find(query?: any): Promise<Array<any>> {
// todo
return Promise.resolve([]);
}
entityManager.delete = function del(query: any): Promise<any> {
// todo
return Promise.resolve(true);
}
await arguments[0](entityManager);
}
getManager().transaction = jest.fn().mockImplementation(mockEntityManager);
}
The function can be called this way when using:
const saved = [];
mockGetManager(saved);
expect(saved).toHaveLength(numberObjectsSaved);
I thought the solution was good because in this case I needed to test only the logic of the controller, so there is no need to test the transaction, as it is tested in the unit tests of the models.
I hope I can have helped someone.

React call export function in same file

I'm new to React!
I have a function...
export const getBookingData = () => dispatch => {
console.log('ran getBookingData');
return new Promise(async (resolve, reject) => {
})
}
Which I then call in another file by doing (which works fine):
import { getBookingData } from "../actions";
getBookingData(); // logs 'ran getBookingData'
However, I would like to try and call getBookingData from within the same file that it is declared.
I have tried:
const getBookingData = () => dispatch => {
console.log('ran getBookingData');
return new Promise(async (resolve, reject) => {
})
}
const moveVisitor = (visitorId, destination, source) => async (dispatch, getState) => {
console.log('error with post api'); // logs ok
getBookingData(); // doesn't log 'ran getBookingData'
let state = getState();
let { entities: { booking: { booking_id } } } = state;
let removeBed = {};
removeBed.booking_visitor_name_id = visitorId;
removeBed.room_id = destination;
removeBed.booking_id = booking_id;
api.post('/accommodation/room/move-participant', removeBed).then(function (response) {
// ok
}).catch(function (error) {
});
}
export { getBookingData, moveVisitor }
You can say that the getBookingData function is curried, as it is a function (accepting no parameter) returning another function (accepting dispatch object as parameter). What you have by just calling getBookingData() is an anonymous function which accepts the dispatch object as the parameter, so you need to call it once more.
Replacing your non-working call of getBookingData() with getBookingData()(dispatch) should work.
Have you tried exporting as below
const getBookingData = () => dispatch => {
return new Promise(async (resolve, reject) => {
// some stuff here
})
}
const moveVisitor = (visitorId, destination, source) => async (dispatch, getState) => {
getBookingData(); // doesn't work
}
export { getBookingData, moveVisitor }

Javascript - serialize async operations

My connections manager is expected to receive connect requests nondeterministically and to handle them in sequence.
How can asynchronous operations be queued such that they are handled later?
I'm not sure of what objects to place in a queue.
Here is my beginner's attempt. Thanks for any help!
class RequestQueue {
private _requests = [];
constructor() {}
public add( rq: any ) {
this._requests.unshift(rq);
}
public remove() {
return this._requests.pop();
}
}
class ConnectionManager {
private requestQueue;
private connecting: boolean = false;
constructor() {
this.requestQueue = new RequestQueue();
}
// ConnectionManager is expected to receive connection requests
// nondeterministically and to handle them in sequence.
public connect(id: string) {
if (!this.connecting) {
this.connecting = true;
return this.asyncConnect(id)
.then(
(result) => result,
(err) => err
)
.then( () => {
this.connecting = false;
if (this.requestQueue.length > 0) {
return this.requestQueue.remove();
}
});
} else {
// how do I queue a someAsyncOp for later?
}
}
private asyncConnect(id: string) : Promise<any> {
return new Promise( (resolve, reject) => {
console.log('begin connect to ', id);
setTimeout(() => {
console.log('end connect to ', id);
resolve();
}, 3000);
});
}
}
function makeConnections() {
const connectionManager = new ConnectionManager();
connectionManager.connect('A');
connectionManager.connect('B');
connectionManager.connect('C');
connectionManager.connect('D');
}
makeConnections();
https://codepen.io/cssbog/pen/BaBMzWW
You have to implement the async serializer pattern
The solution is to keep a queue of Promises that chains them one after the other. It is just a few lines of code and it is a general purpose, allowing any function to be serialized:
const serialize = (fn) => {
let queue = Promise.resolve();
return (...args) => {
const res = queue.then(() => fn(...args));
queue = res.catch(() => {});
return res;
};
};

How to test function that return promises?

trying to write unit test using jest it never get into test case where i retruned promise so i can get the response after then.
if there is any better way of writing test cases for promises i would appreciate that input.
executer.ts
export class Executor {
private passedParam: ILogParams = {} as ILogParams;
constructor(public identity: Identity) {
this._ajv = new Ajv();
}
public execute(moduleName: string): (param1, param2) => any {
const self = this;
// getting rid of the tslint issue with Function
return function(params: any, responseCallback: (param: any , param2: any) => any) {
let _mod;
let _httpRequest;
let _params;
Promise.resolve(getApiModule(self.identity, moduleName))
.then((mod: ModuleBase<any, any>) => {
_mod = mod;
mod.ExecStage = ExecStage.Init;
return mod.init(getHttpModule(self.identity), params);
})
.then((httpRequest: HttpRequestBase) => {
_httpRequest = httpRequest;
if (_mod.Response().Summary.Header) {
throw _mod.Response().Summary;
}
return httpRequest;
})
};
}
}
executer.spec.ts
import {ModuleExecutor} from "../../src/ts/common/executor";
it('should transition with the correct event', (done) => {
const executer = new ModuleExecutor(Identity.node);
const executerSpy = executer.execute("Payments/accountBalance/GetAccountBalance");
new Promise((resolve, reject) => {
resolve(true);
}).then(((mod: ModuleBase<any, any>) => {
done();
}))
.catch((error) => {
done();
});
});

Categories

Resources