How can I access methods inside a class from outside of class - javascript

I have a couple questions regarding Class files. I have the below Class
class CouchController {
constructor(couchbase, config) {
// You may either pass couchbase and config as params, or import directly into the controller
this.cluster = new couchbase.Cluster(config.cluster);
this.cluster.authenticate(config.userid, config.password);
this.bucket = cluster.openBucket(config.bucket);
this.N1qlQuery = couchbase.N1qlQuery;
}
doSomeQuery(queryString, callback) {
this.bucket.manager().createPrimaryIndex(function() {
this.bucket.query(
this.N1qlQuery.fromString("SELECT * FROM bucketname WHERE $1 in interests LIMIT 1"),
[queryString],
callback(err, result)
)
});
}
}
my problem is how can I go and access the doSomeQuery function from outside the class file? Inside there is no issue accessing the function but I need to be able to call it from outside.
I tried something like this
const CouchController = require("../controllers/CouchController")(couchbase, config)
let newTest = new CouchController
doing so newTest never exposes the doSomeQuery method.
Also what are the limitations of a method ? Can it only be a simple one or can it be async and use promises etc ?

There are 2 main things that you should consider with the following problem.
Export it properly first. I'm not sure if you meant to leave this out, but it's important to export the class for use outside as a require. Here is the NodeJS exports documentation if you wish for the technical details.
// common module default export
module.exports = class CouchController {
constructor(couchbase, config) {
// You may either pass couchbase and config as params, or import directly into the controller
this.cluster = new couchbase.Cluster(config.cluster);
this.cluster.authenticate(config.userid, config.password);
this.bucket = cluster.openBucket(config.bucket);
this.N1qlQuery = couchbase.N1qlQuery;
}
doSomeQuery(queryString, callback) {
this.bucket.manager().createPrimaryIndex(function() {
this.bucket.query(
this.N1qlQuery.fromString("SELECT * FROM bucketname WHERE $1 in interests LIMIT 1"),
[queryString],
callback(err, result)
)
});
}
}
The class initialization is slightly incorrect. You can see the docs on this here. You can change your require and initialization to...
const CouchController = require('../controllers/CouchController');
const newTest = new CouchController(couchbase, config);
// now you can access the function :)
newTest.doSomeQuery("query it up", () => {
// here is your callback
})
If you were using ES6 modules or typescript you could export something like...
export default class CouchController {
// ...
}
... and import something like...
import CouchController from '../controllers/CouchController';
const newTest = new CouchController(couchbase, config);

You need to instantiate the class after importing it
Change the following
const CouchController = require("../controllers/CouchController")(couchbase, config)
let newTest = new CouchController
to
const CouchController = require("../controllers/CouchController")
let newTest = new CouchController(couchbase, config)
Also you need to export your class like this
export default class CouchController {
and then access method like this
newTest.doSomeQuery(...)

I figured it out after some forth and back, part of my problem was the fact that for some reason visual studio code did not show me the method which threw me off. Manually typing made it ultimately avail.
Here is my Class and i actually moved the config and couchbase itself into the class file so no need to pass it anymore.
const couchbase = require("couchbase")
const config = require("../config/config")
class CouchController {
constructor() {
// You may either pass couchbase and config as params, or import directly into the controller
this.cluster = new couchbase.Cluster(config.cluster);
this.cluster.authenticate(config.userid, config.password);
this.bucket = this.cluster.openBucket(config.bucket);
this.N1qlQuery = couchbase.N1qlQuery;
}
getDoc2(docID){
return new Promise((resolve,reject)=>{
this.bucket.get(docID ,(err, result)=>{
if(err) return reject(err);
return resolve({docID,result});
});
});
}
}
module.exports = CouchController
And here is how i call my Class now and connect to the backend to fetch my data.
const CouchController = require("./controllers/CouchController")
let newTest = new CouchController
const test= async()=>{
let { docID, result } = await newTest.getDoc2("grid_info::20b05192-79e9-4e9d-94c9-91a4fc0a2765")
console.log(docID)
console.log(result)
}

Related

TypeError: is not a function with React, Typescript and Axios

So, I searched for an existing solution, but I could find nothing, or maybe I'm not searching the correct way, thus, sorry if there's an existing thread about it.
In sum, it seems my code is not instantiating an object correctly as a class when it comes from an Axios call to the backend. So, when I call some function, I'm getting the error Uncaught TypeError TypeError: object.method is not a function.
Example:
First, basically, a parent component will call a service that will make a request to the backend. The result is then passed to a child component.
// imports
const Component: React.FC<ComponentProps> = () => {
const { id } = useParams<{ id: string }>();
const [object, setObject] = useState<Class>(new Class());
useEffect(() => {
(async () => {
try {
const object = await Service.getById(id);
setObject(object);
} catch (err) {
//error handling
} finally {
cleanup();
}
})();
return () => {
// cleanup
};
});
return (
<Container title={object.name}>
<Child object={object} />
</Container>
);
};
export default Component;
Then, in child component, let's say I try to call a method that was defined in the Class, there I'm getting the not a function error:
// imports
interface Interface {
object: Class;
}
const Child: React.FC<Interface> = ({ object }) => {
object.callSomeFunction(); // error starts here
return (
<SomeJSXCode />
);
};
export default Child;
Example of the Class code, I tried to write the method as a function, arrow function, and a getter, but none worked. Also, as a workaround, I've been defining a method to instantiate the object and set all properties, but I don't think that's a good long-term solution, and for classes with many properties, it gets huge:
export class Class {
id: string = '';
name: string = '';
callSomeFunction = () => {
// do something;
}
static from(object: Class): Class {
const newInstance = new Class();
newInstance.id = object.id;
newInstance.name = object.name;
// imagine doing this for a class with many attributes
return newInstance;
}
}
Finally, the Service code if necessary to better understand:
// imports
const URL = 'http://localhost:8000';
const baseConfig: AxiosRequestConfig = {
baseURL: URL,
headers: { 'Content-Type': 'application/json' },
withCredentials: true,
};
export const backend = axios.create({
...baseConfig,
baseURL: URL + '/someEndpoint',
});
export const Service = {
async getById(id: string): Promise<Class> {
try {
const { data } = await backend.get<Class>(`/${id}`);
return data;
} catch (err) {
throw new Error(err.response.data.message);
}
},
};
As I can't share the real code due to privacy, please let me know if this is enough or if more information is needed. Thanks in advance.
I thought it was some binding issue as here, but no.
So, I actually fixed this by updating the class validator in the back end, as the parsing was only necessary to parse the strings as number. But, by adding the annotation #Type(() => Number) to my dtos, I won't need to parse the strings anymore.

how to import async modules with JS

Maybe i asked wrong question.
i'm trying to test some site, and have this throw in terminal
terminal output
it's obvious, that function returns uuid after it was called in code.
it work's normaly, when i take element right in code, so the reason, i think, in uncorrect import
here's my code :
file.js
describe('final homeTask', () => {
it('firstassigment', async () => {
let mainPage = require('../page/main.pageHW.js')
await browser.url('https://github.com/')
let signUpButton = await mainPage.topSignUpBtn()
await signUpButton.click()
})
})
main.pageHW.js
class MainPage {
get topSignUpBtn () { return $('a.btn-mktg:nth-child(1)') }
}
module.exports = new MainPage()
It is a problem with Javascript, not about webdriver, you are using a property in the MainPage class:
class MainPage {
/// The get word make it a property
get topSignUpBtn () { return $('a.btn-mktg:nth-child(1)') }
}
module.exports = new MainPage()
That means you DON'T need parentheses to use it, so, replace:
let signUpButton = await mainPage.topSignUpBtn()
By
let signUpButton = await mainPage.topSignUpBtn;
Also, the property doesn't need the await clause.
If you want more info you can check this link.

How to properly reuse MongoDriver connection across NodeJS modules with ES6

First of all it is a similar question like How to properly reuse connection to Mongodb across NodeJs application and modules, but I guess due to the ES6 syntax it's still different.
So I decided to use MongoDriver and created a class for this like in SO answer: dbconnections.js
import { default as mongodb } from 'mongodb';
const MongoClient = mongodb.MongoClient;
const url = "myurl"
let _db;
export const connectToServer = async (callback) => {
try {
MongoClient.connect( url, { useNewUrlParser: true, useUnifiedTopology:true }, ( err, db ) => {
_db = db
return callback( err )
})
} catch (e) {
throw e
}
}
export const getDB = () => _db
export const disconnectDB = () => _db.close()
The problem with this module is, that due to the ES6 syntax is that I can't make like something this
import {getDB} from '../dbconnections.js'
const driverDB=getDB()
export const someFunction= async (req,res) => {
console.log(driverDB)
because I always get undefiened so I have to call my getter in every function.
So my question: how to create properly a structure for a MongoDriver handler and pass this to different modules with ES6?
Pass the client object into objects and functions that need it.
https://en.wikipedia.org/wiki/Dependency_injection

Depency Injection with "awilix"

I am learning dependecy injection using awilix. I tried the code below following a tutorial. I tried differently and each time I get the the kind of error below:
//diSetup.js:13
var config = _ref.config;
TypeError: Cannot read property 'config' of undefined
[Screenshot][1]
I tried the following:
const awilix = require("awilix");
const config = {
server: "8.8.8.8",
};
class UserController {
constructor({ config }) {
this.config = config;
}
}
const container = awilix.createContainer({
injectionMode: awilix.InjectionMode.PROXY,
});
container.register({
config: awilix.asValue(config),
userController: awilix.asClass(UserController),
});
function setup() {
const user = new UserController();
console.log(user.config);
}
module.exports = {
container,
setup,
};
You are creating a UserController instance in your setup function.
You shound use awilix resolve function instead. Try this:
const user = container.resolve("userController");

Property in class is undefined when used in class method

Writing a test REST api with NodeJs for learning purposes.
Currently I only have 1 route which accepts a parameter (which works fine).
I'm using an express router to route the GET request to my controller.
All of the routing is working as expected.
My ServiceController currently has a ctor function which accepts 2 parameters. Both of these parameters are passed into the ctor function by the router during instantiation.
In the ServiceController ctor I store the parameters in to fields.
The issue is, when I try to access these fields in a class method I'm getting a "TypeError: Cannot read property 'exec' of undefined".
I did write both of these values to the console to ensure that the ServiceController was receiving these values correctly (which it is).
So, i'm unsure why im getting this error when I attempt to access either "this.exec" or "this.logger" in the get method.
Router
import express from 'express';
import { exec } from 'child-process-promise';
import ServiceController from '../controllers/serviceController';
let routes = (logger) => {
const router = express.Router();
let controller = new ServiceController(exec, logger);
router.route('/status/:name')
.get(controller.get);
return router;
};
module.exports = routes;
ServiceController
export default class ServiceController {
constructor(childProcess, logger) {
this.logger = logger;
this.exec = childProcess;
}
get(req, res) {
if (!req.params.name) {
res.status(400).send('A service name was not provided');
} else {
this.exec(`sc query ${req.params.name}`).then(result => {
if (result.stderr) {
this.logger.log.warn(`stderr: ${result.stderr}`);
}
const regex = /STATE\s+:\s+\d+\s+(\w+)/;
let [, status] = result.stdout.toString().match(regex);
if (!status) {
throw new Error('Status query unsuccessful');
}
let service = {
name: req.params.name,
status: status
};
res.json(service);
return service;
}).catch(error => {
this.logger.log.error(`${error.name} ${error.message}`);
res.status(500).send('An error occurred while executing command');
});
}
}
}
It's a problem of this context. You use the get method on a context which is not your ServiceController instance.
Bind the method on your instance:
router.route('/status/:name')
.get(controller.get.bind(controller));
Or you can also define an arrow function in the ServiceController class.

Categories