How can I pass a library to a lower dependency in node? - node.js

I'm trying to create a library that uses the ORM Bookshelf.js (so basically a wrapper on top of Bookshelf.js if you will). Now Bookshelf.js requires you to run a driver installation to be able to connect to the correct database (such as: npm install mysql) in the root of your project.
My own library also requires this, since Bookshelf.js requires it, but it keeps saying Error: Cannot find module 'mysql' which is normal since the Bookshelf instance does not have the mysql dependency in its node_modules folder.
If I type out the structure it would look like this:
* New Project
** mysql
** LibThatUsesBookshelf
**** Bookshelf
Now Bookshelf.js probably requires this structure:
* New Project
** LibThatUsesBookshelf
**** mysql
**** Bookshelf
Is there a way that I am able to still get bookshelf working with the first structure shown?
P.S. I know the explanation might be confusing, but it is a hard problem and I got no other way of explaining it.

Let the client of your module pass in an instance to bookshelf:
// mysuperfancymodule.js
module.exports = function(bookshelf) {
// do fancy things with the bookshelf instance
}
Then in your client application:
// some app code:
var mySuperFancyModule = require('mysuperfancymodule'); // assuming it is published to npm
var knex = require('knex')({
// init knex...
});
var bookshelf = require('bookshelf')(knex);
mySuperFancyModule(bookshelf); // init my super fancy module

Related

Creating a global Datastore client

What are the conventions around when and where to create datastore client objects?
datastore = new Datastore({});
In the docs a new Datastore instance seems to be created in every single file. Would there be any benefit in creating a singleton that initialises the Datastore connection and returns the same instance to each part of the application that requires it?
It depends on the underlying code if new Datastore({}) actually creates a new instance or returns a singleton, you'd have to check that.
What you could do is move the creation of the datastore instance to a seperate file and require that instance in every file you need access to datastore. Since dependencies you require are cached you will always get the same instance.
Pseudo code:
datastore.js
const datastore = new Datastore({});
module.exports = datastore;
foo.js
const datastore = require('./datastore');
// do something with datastore
In reply to your follow-up question.
If you look at the source code of the nodejs/Datastore module you will see the same pattern:
src/index.js
* #example <caption>Import the client library</caption>
* const Datastore = require('#google-cloud/datastore');
// ...
module.exports = Datastore;
No matter where you require the client library:
const Datastore = require('#google-cloud/datastore');
It will always return the same instance. Datastore will handle scaling and connections (pooling) for you.
In conclusion: There's no functional difference between requiring the client library in each file or wrapping it in a seperate file and require that in the files where you need a connection.
Personally, I prefer wrapping the connection in a seperate file and require that in my data access files. Benefits for this are:
* You abstract away the actual implementation. If you ever need to change datastore or the way you connect to it it will only ever be in one place.
* In case you need to supply connection parameters (like a password) you only have to do that once. It saves you from writing the same code over and over again.

MongoDB database cleaner for Nightwatch.js

Is there any way of wiping a mongo database in between Nightwatch e2e tests?
I'm coming from Ruby, where you can configure RSpec to use a package called database cleaner and wipe your db after each test, and I'm wondering if a similar setup exists in the javascript ecosystem.
I did some research and found a promising-looking package called node-database-cleaner, but at present it is throwing an error.
Code:
require('mongodb');
const DatabaseCleaner = require('database-cleaner');
const databaseCleaner = new DatabaseCleaner('mongodb');
...test assertions
databaseCleaner.clean('mongodb://localhost:27017/my-db')
Error:
TypeError: db.collections is not a function
I'm not bound to using node-database-cleaner—I'd be interested in any solution no matter what library it uses.

node express postgres - why and how to connect to database using pg module?

I am super new to node express and postgres and wondering the following:
const pg=require('pg').native
const client=new pg.Clirnt('postgres ...')
what is const?
pg is used to create a client to connect to the Postgres database-correct?
If so
var db = new Sequelize('postgres://localhost:5432/mydb')
would work too or would I just have created a database without connecting it?
Why exactly do I need to connect at all-to do what?
Thanks a lot!
const is constant in javascript which was introduced in ES6 specification.
node-postgres is a client for PostgreSQL.
Sequelize is using node-postgres for working with PostgreSQL database, so yes, in the nutshell, it will act like node-postgres.
Imagine the warehouse, that's your database, where you have different shelves, that's your tables, to take or put different items into warehouse you need workers that will do your instructions like - INSERT someitem INTO items_shelf;. So worker is the client like Sequelize or node-postgres. The important part, warehouse should be open, otherwise, workers couldn't access to it, so your database should be turned on.
Hope I'm explained understandable enough.
what is const?
TLDR; variables that can't be re-assigned. scoped the same way as var. Part of es6.
pg is used to create a client to connect to the postgres database?
yes, note you need to do npm install --save pg as well as npm install --save sequelize. the save flag adds the packages to the package.json file for your convenience.
would I just have created a database without connecting it?
That bit of code should instantiate a connector - you haven't modified the database, and you also don't really know if the connection works yet.
why exactly do I need to connect at all?
The pg library looks to use a connection pool; this means you set it up once, and then you use it repeatedly as desired and it handles the connections for you. You connect now so you can run queries against the database later.
This snippet of code connects to a postgres instance running locally on my machine, and tests that it can connect - per the docs
const Sequelize = require('sequelize');
var sequelize = new Sequelize('postgres://localhost:5432/postgres');
sequelize.authenticate().then(() => {
console.log('yay');
}).catch((e) => {
console.log('nooo', e);
});

How to deal with calling sequelize.sync() first?

I'm a bit new to developing in nodejs, so this is probably a simple problem. I'm building a typical webapp based on express + sequelize. I'm using sqlite in-memory since I'm just prototyping at the moment. I understand if I were to use a persistent sqlite file, this may not be a problem, but that's not my goal at the moment. Consider the following:
var User = sequelize.define("User", {
"username": DataTypes.STRING,
// etc, etc, etc
});
sequelize.sync();
User.build({
"username": "mykospark"
});
At first, I got an error on User.build() about the Users table not existing yet. I realized that sequelize.sync() was being called async, and the insert was happening before the table was created. I then re-arranged my code so that the User.build() call was inside of sequelize.sync().complete() which fixes the problem, but I'm not sure how to apply this to the rest of my project.
My project uses models in a bunch of different places. It is my understanding that I just want to call sequelize.sync() once after my models are defined, then they can be used freely. I could probably find some way to block the entire nodejs app until sequelize.sync() finishes, but that doesn't seem like good form. I suppose I could wrap every single model operation into a sequelize.sync().complete() call, but that doesn't seem right either.
So how do people usually deal with this?
Your .sync() call should be called once within your app.js file. However, you might have additional calls if you manage multiple databases in one server. Typically your .sync() call will be in your server file and the var User = sequelize.define("ModelName"... will be in your models/modelName.js file. Sequelize suggests this type of guidance to "create a maintainable application where the database logic is collected in the models folder". This will help you as your development grows. Later in the answer, I'll provide an easy step to follow for initializing the file structure.
So for your case, you would have app.js, models/index.js and models/users.js. Where app.js would be your server running the .sync() method. In the models folder you will have the required index.js folder where you configure a connection to the database and collect all the model definitions. Finally you have your user.js files where you add your model with class and instance methods. Below is an example of the models/user.js file you might find helpful.
user.js
module.exports = function(sequelize, DataTypes) {
return sequelize.define('User', {
username: DataTypes.STRING,
},{
classMethods: {
doSomething: function(successcb, errcb, request) {}
},
instanceMethods: {
someThingElse: function(successcb, errcb, request) {}
}
});
};
models/index.js --> See here
EDIT 03/14/17
Now the best option to setup your node app with sequelize is to use sequelize-cli. This is sequelize migrations and has very useful functionality in development and production environments. For the scope of this question and revision to the answer, the best approach is the following:
npm install sequelize-cli
Use npm install sequelize-cli -g if you want it installed globally.
Then initialize sequelize migrations:
sequelize init
It should install the following folders and files structure in the folder you initiated the command:
config:
-config.json
models:
-index.js
seeders:
migrations:
If you want to create a model you can run the following command and it will auto generate the file structure for you. Here is an example
sequelize model:create --name User --attributes "user:string email:string"
Next you should be able to see the new model page in models/page.js.
config:
-config.json
models:
-index.js
-user.js
-page.js
seeders:
migrations:
You'll need to then go into you models/index.js and define your new model for your database to access the correct path for that model. Here is an example:
models/index.js
var sq = new Sequelize(dbname, user, password, config);
db = {
Sequelize: Sequelize,
sequelize: sq,
page: sq.import(__dirname + '/page.js'),
user: sq.import(__dirname + '/user.js')
}
module.exports = db;
If you need to make changes to the model you can go into the migrations folder and add methods. Follow the sequelize migration docs here. Now, about the app.js server. Before you run your server you need to initialize your databases. I use the following script to initialize the database before running the server to setup a postgres db:
postgresInit.sh
[...]
`sudo -u postgres createdb -U postgres -O $PG_USER $PG_DB. `
If you prefer a javascript solution, there is an SO solution here
app.js
[...]
console.log('this will sync your table to your database')
console.log('and the console should read out Executing (default): CREATE TABLE IF NOT EXISTS "TABLE NAME"....')
db.sequelize.sync(function(err){});

NodeJS requiring modules

First off, I am a totally new developer with regards to Node.js.
I have started creating a sample express application, and I wanted to use an additional module to learn more about it. I have installed via npm the "mysql" module, all fine.
I have added it at the beginning of app.'s, like this:
var mysql = require('mysql');
now, as you already know, express created an index.js file inside the directory routes: i would like to be able to access the mysql variable to connect to the db from this index.js page but, using the command
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'root',
});
obviously doesn't work, giving the "500 ReferenceError: mysql is not defined".
Of course, I am sure I need to pass this variable, but I really have no clue, can any good soul enlighten me? I know this is a very small and basic thing, but I tried this already, and doesn't seem to work:
... app.get('/', routes.index, mysql); ...
and on index.js:
exports.index = function(req, res, mysql){ ...
In Node.js, you should require modules in the files you need to use them in; so, if you want to use the mysql package in your routes/index.js file, at the top of that file, do
var mysql = require('mysql');
You may end up requiring a module in more than one file; this is normal and, in many ways, a good thing (no namespacing issues, etc.)
If you want to learn more about modules and packages, you may be interested in these two screencasts:
Modules: http://nodecasts.net/episodes/3-modules
Packages & npm: http://nodecasts.net/episodes/4-packages-and-npm
Passing the mysql object through app.get() would be a normal reaction, but I'm pretty sure you're over-thinking it.
It's as simple as including var mysql = require('mysql'); at the top of routes/index.js. In fact, you may find that you don't even need to require mysql in app.js if all database interactions are done in your routes.

Resources