Node.js: how to 'inherit' from abstract class? - node.js

I'm building a web app with node.js (+ angular, etc.).
The app will have to retrive some data (something like a catalog items list) from different providers, who expose their data in different ways.
In that module, I will have some function common to all providers, and some function unique to any of them.
My current (poor) implementation is something like this:
var providers = [
{ name: 'Apple', /* ... */ },
{ name: 'Samsung', /* ... */ },
{ name: 'Google', /* ... */ },
];
exports.syncCatalogues = function(search, callback) {
var allItems = [];
for (var p = 0; p < providers.length; p++) {
exports.getCatalog(providers[p], function(err, catalog) {
if (err) {
return callback(err);
}
exports.getItems(providers[p], catalog, function(err, items) {
if (err) {
return callback(err);
}
allItems = allItems.concat(items);
callback(null);
});
});
}
};
And my getCatalog() and getItems() implementation are as ugly as this:
exports.getCatalog(provider, callback) {
if (provider.name === 'Apple') {
// code for Apple provider ...
}
// and so on ...
};
exports.getItems(provider, callback) {
if (provider.name === 'Apple') {
// code for Apple catalog ...
}
// and so on ...
};
I know with ES5 (I'm stuck to it) abstract classes are not easy to implement, but I'm sure there is a better way (code more readable, maintainable, testable) than this... :-(

There are many ways to implement the inheritance in JavaScript.
Here is one, which I think the simplest, since you just operate with plain objects and use prototypal inheritance.
Instead of the base class you have a prototype object where you can place the common code.
Then you create an object based on the prototype and add specific code to it.
var providerPrototype = {
name: 'Prototype',
alertName: function() { // this is common function, all objects
alert(this.name); // will have it
}
};
var appleProvider = Object.create(providerPrototype);
appleProvider.name = 'Apple';
// this is a specific function for 'Apple'
appleProvider.getCatalog = function(callback) {
return callback(null, ['iPhone', 'Mac Mini']);
}
appleProvider.alertName = function() {
// call 'base' method
providerPrototype.alertName.call(this);
alert('All rights reserved.');
}
var samsungProvider = Object.create(providerPrototype);
samsungProvider.name = 'Samsung';
// this is a specific function for 'Samsung'
samsungProvider.getCatalog = function(callback) {
return callback(null, ['Galaxy S3', 'Galaxy S4']);
}
var providers = [
appleProvider, samsungProvider
];
var syncCatalogues = function(search, callback) {
var allItems = [];
for (var p = 0; p < providers.length; p++) {
var aProvider = providers[p];
aProvider.getCatalog(function(err, catalog) {
if (err) {
return callback(err);
}
aProvider.alertName(); // call the base method
alert(catalog);
});
}
};
syncCatalogues();
Check also Inheritance and the prototype chain in Mozilla javascript documentation.
And here is an example of splitting classes over node.js modules.

I'm new in nodeJS but I think my code below is possible only after ES6. I hope to help newbies like me. Follows:
class BaseClass {
constructor(){
console.log('Object created INHERITED');
}
toCallFromChild(){
console.log('Called by child');
this.toOverride();
}
toOverride(){} //to override
}
class childClass extends BaseClass{
toOverride(){
console.log ('Override by child');
}
}
var instance = new childClass();
instance.toCallFromChild();

My response is a possible alternative solution.
I personnally do not like the native javascript object mecanics. So i generaly use a library like Mootools for making clean objects.
Example from Mootools documentation :
var Animal = new Class({
initialize: function(age){
this.age = age;
}
});
var Cat = new Class({
Extends: Animal,
initialize: function(name, age){
this.parent(age); // calls initalize method of Animal class
this.name = name;
}
});
var myCat = new Cat('Micia', 20);
alert(myCat.name); // alerts 'Micia'.
alert(myCat.age); // alerts 20.
Se the online doc on : http://mootools.net/

Related

How we call recursive function in node js

My code is below:
module.exports = {
cleanCode: function(){
return 'clean code helper'
},
nestedChildren: function(arr, parentId) {
var out = []
for (var i in arr) {
if (arr[i].parent_id == parentId) {
var children = nestedChildren(arr, arr[i].id)
if (children.length) {
arr[i].subCate = children
}
out.push(arr[i])
}
}
return out
}
}
Getting following error {"message":"nestedChildren is not defined"}
As #jonrsharpe suggested, move the function outside of the export:
let nestedChildren = function(arr, parentId) {
var out = [];
for (var i in arr) {
if (arr[i].parent_id == parentId) {
var children = nestedChildren(arr, arr[i].id);
if (children.length) {
arr[i].subCate = children;
}
out.push(arr[i]);
}
}
return out;
};
module.exports = {
nestedChildren,
cleanCode: function(){
return 'clean code helper';
}
};
Properties of an JavaScript Object cannot reference themselves or any other property of the same object. Thus, a recursive function within an object is not possible.
To work around this problem, you can move the function to the upper scope (outside of the object) where it's accessible from within the object.
So what I did was defining the function outside of the object as standalone function and then I referenced it in your export.
module.exports = {
nestedChildren,
...
};
is just a shorthand for
module.exports = {
nestedChildren: nestedChildren,
...
};

Transform publish MeteorJS with count of show

I try to use limit : count with transform observer in Meteor and don't understand how to do it without "dirty" solutions.
Code I have on Client (not all, but main part)
var self = this;
self.autorun(function() {
self.subscribe('posts', Session.get('count')); // some Number like 10
}); // client
And on server where I try to use it
Meteor.publish('posts', function(count){
check(count, Number);
let i = 0;
var transform = function(doc) {
console.log(i,count);
if (i < count){ // I try something here
doc.description = new Date();
i++;
return doc;
}
else self.ready();
}
var self = this;
var observer = Posts.find().observe({
added: function (document) {
self.added('posts', document._id, transform(document));
},
changed: function (newDocument, oldDocument) {
self.changed('posts', document._id, transform(newDocument));
},
removed: function (oldDocument) {
self.removed('posts', oldDocument._id);
}
});
self.onStop(function () {
observer.stop();
});
self.ready();
});
Any idea how to limit count of shown documents with transform in publish ?
Just use Posts.find({},{limit:count}) in your query.

REST data source in NodeJS/ Express MVC Pattern

What are the best practice to include external REST data sources in an Express MVC application?
Should we create a Model for the entities that we retrieve from external REST sources?
Let's take this practical example :
Our starting point is a user.js model that use mongoose for ODM.
var mongoose = require('mongoose');
var userModel = function () {
//Define a simple schema for our user.
var userSchema = mongoose.Schema({
name: String,
twitterId: Number
});
return mongoose.model('User', userSchema);
};
module.exports = new userModel();
Our objective is to show all tweets for a specific user, so we create a controller controller/userTweets.js where we prepare the data for our View.
How should we include the Twitter REST API in our application to handle this use case? (let's say we are using a nodejs client for twitter apis)
I'm more comfortable to use a specific model for the tweet entity, and then retrieve users tweet from the controller using our model, but how should our tweet.js model looks like?
Or should we design our REST API integration in a different way?
I would create a class called Tweet and a corresponding repository for it.
Assuming you are using es6, because why not.
lets call it tweets.js
'use strict';
module.exports = function (cfg) {
class Tweet {
constructor() {
this.userid = null;
this.text = null;
}
}
class Repo {
static getTweetsForUser(usedId) {
// make a call to twitter api, use https://www.npmjs.com/package/request
// psuedo code
let _ = require('lodash');
getTweets(userid, function (err, tweets) {
return new Promise(function (resolve, reject) {
if (err) {
return reject(err);
}
let data = [],
tweet = new Tweet;
if (! tweets.length) {
return resolve(data);
}
resolve(_.collect(tweets, function (t) {
tweet.userId = userId;
tweet.text = t.getTheTweet;
return tweet;
}));
});
});
}
}
return {
'tweet': Tweet,
'repo' : Repo
}
}
// export whatever modules, like above, lets call it index.js
'use strict';
let _ = require('lodash');
let modules = [
'tweets',
];
// cfg = any app configs that you might need in modules
function init(cfg) {
let core = {};
return _.collect(modules, function (m) {
core[m] = require('./' + m)(cfg);
});
}
module.exports = init;
Example - https://github.com/swarajgiri/express-bootstrap/blob/master/core/index.js
Now in routing side, in your main whatever is your server.js, inject the modules into an instance of express()
app.set('core', require('path/to/core/index')(whateverConfigYouMightNeed))
Once that is done, your route can look something like
'use strict'
let wrap = require('co-wrap');
route.get(':userId/tweets'), wrap(function* (req, res, next) {
let tweets = [];
try {
tweets = yield req.app.get('core').tweets.Repo.getTweetsForUser(req.params.userId)
} catch(e) {
// let the common error handler do its job.
return next(e);
}
// render whatever view you want.
});

Serialization of a polymorphic array in node.js

I am looking for a method for serialization of a Javascript object, that contains several other objects of different classes, with function arguments.
Here is a simple test-case:
// Paper class:
function Paper(name) {
this.name = name;
}
Paper.prototype = {
string: function() { return "Paper:"+this.name; }
};
// Book class:
function Book(name) {
this.name = name;
}
Book.prototype = {
string: function() { return "Book:"+this.name; }
};
// Library class:
function Library(name) {
this.items = [];
}
Library.prototype = {
add: function(item) { this.items.push(item); },
string: function () {
var titles = this.items.map(function(item) { return item.string(); });
return titles.join(",");
},
};
///// Define a library:
var lib = new Library();
lib.add(new Paper("MyPaper"));
lib.add(new Book("MyBook"));
assert(lib.string() == "Paper:MyPaper,Book:MyBook");
///// Serialize, de-serialize and compare:
// var libString = serialize(lib);
// var newLib = deserialize(libString);
// assert(newLib.string() == "Paper:MyPaper,Book:MyBook");
NOTE: The main usage of de/serialization (at least in my case) is for moving complex objects to distant computers. For example, I want to build a big Library on my computer, then serialize it, put on a file, send the file to another computer, deserialize it there, and have the exact same Library.
You need to extend JSON semantics. If I were you, I would to something like this:
var protos = {}, //hash of prototypes
base = { //base prototype
toJSON: function () {
var props = {}; //properties to be serialized
for (var prop in this) { //this can be custimized, like taking `attrs` hash or something
if (this.hasOwnProperty(prop)) props[prop] = this[prop];
}
props.$proto = this.$proto; //need to copy this manually since it's not an `own propery`
return props;
}
};
function Paper(name) {
this.name = name;
}
protos.paper = Paper.prototype = Object.create(base);
Paper.prototype.$proto = 'paper';
Paper.prototype.toString = function() {
return 'Paper: ' + this.name;
}
function Book(name) {
this.name = name;
}
protos.book = Book.prototype = Object.create(base);
Book.prototype.$proto = 'book';
Book.prototype.toString = function() {
return 'Book: ' + this.name;
}
function Library(name) {
this.items = [];
}
Library.prototype = {
add: function(item) { this.items.push(item); },
toString: function () {
var titles = this.items.map(function(item) {
return item.toString();
});
return titles.join(',');
},
toJSON: function () {
return this.items.map(function(item) { return item.toJSON()});
}
};
Library.fromJSON = function (json) {
return json.map(function(item) {
var object = Object.create(protos[item.$proto]);
for (var prop in item) object[prop] = item[prop];
return object;
});
};
//test
var lib = new Library();
lib.add(new Paper('MyPaper'));
lib.add(new Book('MyBook'));
console.log(lib.toString());
var json = JSON.stringify(lib.toJSON());
console.log(Library.fromJSON(JSON.parse(json)).toString());
Here is a fiddle: http://jsfiddle.net/cSTT5/
I want to build a big Library on my computer, then serialize it, put on a file, send the file to another computer, deserialize it there, and have the exact same Library.
I've made an npm module named esserializer to solve this problem: save JavaScript class instance values recursively during serialization, in plain JSON format, together with its class name information. Then, during the deserialization stage, esserializer can recursively deserialize object instance, with all types/functions information retained, using the same class definition.
For your scenario, the code is pretty simple. It works if the serialized string is taken to another computer, as long as the same class definition exists on that machine:
const ESSerializer = require('esserializer');
// Paper class:
function Paper(name) {
this.name = name;
}
Paper.prototype = {
string: function() { return "Paper:"+this.name; }
};
Paper.prototype.constructor = Paper; // We need to redefine the constructor of Paper's prototype.
// Book class:
function Book(name) {
this.name = name;
}
Book.prototype = {
string: function() { return "Book:"+this.name; }
};
Book.prototype.constructor = Book;
// Library class:
function Library(name) {
this.items = [];
}
Library.prototype = {
add: function(item) { this.items.push(item); },
string: function () {
var titles = this.items.map(function(item) { return item.string(); });
return titles.join(",");
},
};
Library.prototype.constructor = Library;
///// Define a library:
var lib = new Library();
lib.add(new Paper("MyPaper"));
lib.add(new Book("MyBook"));
// assert(lib.string() == "Paper:MyPaper,Book:MyBook");
var serializedString = ESSerializer.serialize(lib);
// Later, on another machine, deserializedObj is a perfect copy of "lib":
var deserializedObj = ESSerializer.deserialize(serializedString, [Library, Book, Paper]);
console.log(deserializedObj.string()); // Paper:MyPaper,Book:MyBook

mongodb data async in a for-loop with callbacks?

Here is a sample of the working async code without mongodb. The problem is, if i replace the vars (data1_nodb,...) with the db.collection.find(); function, all needed db vars received at the end and the for()-loop ends not correct. Hope someone can help. OA
var calc = new Array();
function mach1(callback){
error_buy = 0;
// some vars
for(var x_c99 = 0; x_c99 < array_temp_check0.length;x_c99++){
// some vars
calc[x_c99] = new Array();
calc[x_c99][0]= new Array();
calc[x_c99][0][0] = "dummy1";
calc[x_c99][0][1] = "dummy2";
calc[x_c99][0][2] = "dummy3";
calc[x_c99][0][3] = "dummy4";
calc[x_c99][0][4] = "dummy5";
function start_query(callback) {
data1_nodb = "data1";
data2_nodb = "data2";
data3_nodb = "data3";
data4_nodb = "data4";
calc[x_c99][0][0] = data1_nodb;
calc[x_c99][0][1] = data2_nodb;
calc[x_c99][0][2] = data3_nodb;
callback(data1_nodb,data2_nodb,etc..);
}
start_query(function() {
console.log("start_query OK!");
function start_query2(callback) {
data4_nodb = "data5";
data5_nodb = "data6";
data6_nodb = "data7";
calc[x_c99][0][3] = data4_nodb;
calc[x_c99][0][4] = data5_nodb;
callback(data5_nodb,data6_nodb,etc..);
}
start_query2(function() {
console.log("start_query2 OK!");
function start_query3(callback) {
for(...){
// do something
}
callback(vars...);
}
start_query3(function() {
console.log("start_query3 OK!");
});
});
});
}
callback(calc);
};
function mach2(callback){
mach1(function() {
console.log("mach1 OK!");
for(...){
// do something
}
});
callback(calc,error_buy);
};
mach2(function() {
console.log("mach2 OK 2!");
});
You need to work with the async nature of the collection.find() method and wait for all of them to be done. A very popular approach is to use the async module. This module allows you run several parallel tasks and wait for them to finish with its async.parallel() method:
async.parallel([
function (callback) {
db.foo.find({}, callback);
},
function (callback) {
db.bar.find({}, callback);
},
function (callback) {
db.baz.find({}, callback);
}
], function (err, results) {
// results[0] is the result of the first query, etc
});

Resources