npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

dbconnect

v0.3.2

Published

A simple database interface for NodeJS

Downloads

7

Readme

DBConnect - A Simple Database Interface for NodeJS

DBConnect is a simple database interface for NodeJS.

By default DBConnect comes with MongoDB and Postgresql interface.

Installation

npm install dbconnect

Usage

var DBConnect = require('dbconnect');
DBConnect.setup({
    name: 'test',
    type: 'mongo',
    module: <path_to_require_module>,
    args...
});

var conn = DBConnect.make('test');

conn.open(function(err) {
    // handle processing here...

    // query the database.
    conn.query(..., cb);

    // to close.
    conn.close(cb);
});

Setup

DBConnect has a setup process that's a bit different from other database interfaces. The design is meant to make the abstraction over the different drivers as uniform as possible.

DBConnect.setup takes the following options

  • name - this is the key to the name of the connection. You can refer to this later in DBConnect.make

  • type - this is the type of the driver for the connection.

    For example, the built-in MongoDBDriver's type is mongo.

  • module - this points to a node module that holds an initiation routine for the prepared statements

  • other_args - these are driver specific args that are expected by the driver.

    For example, MongoDBDriver expects the foll

Connection Creation

DBConnect.make creates the connection object (without connecting).

You just need to pass in the name of the option that are previously registered via DBConnect.setup call.

Opening the Connection

Either .connect or .open will do the same thing. It expects a callback.

Closing the Connection

Either .disconnect or .close will close the connection. It expects a callback.

Database Query

The database query is specific to the underlying driver. For example, the built-in MongoDBDriver expects the following

// for selection
conn.query({select: 'table', query: {id: 2}}, cb);

// for insertion
conn.query({insert: 'table', args: {id: 3, name: 'test'}}, cb);

// for update
conn.query({update: 'table', $set: {name: 'foo'}, query: {id: 3}}, cb);

// for delete
conn.query({delete: 'table', query: {id: 3}}, cb);

For the Postgresql driver it would look like the following

conn.query("select * from table", cb);

conn.query("insert into table (id, name) values (3, 'test')", cb)

...

The way DBConnect abstracts over these differences is via prepared statements.

queryOne is used the same way as query, except that it will return the first item in the result (i.e. using it with insert/update/delete will result in errors).

Prepared Statements

A prepared statements has the following signature.

conn.prepare(<key>, <procedure_running_the_prepare_statement>);

The prepare procedure is a function that has the following signature

function(conn, args, cb) { ... }

Given that it's an Javascript function, you can do anything you want within the function.

For example, let's say that we have a prepared statement called 'getUser' for the MongoDBDriver.

conn.prepare('getUser', function(conn, args, cb) {
   conn.query({select: 'user', query: args}, cb);
});

And we can also have the following prepared statement called 'getUser' for an RDBMS driver.

conn.prepare('getUser', function(conn, args, cb) {
   conn.query("select * from user where id = ?", args.id, cb);
});

With the above, we can swap out the underlying driver as long as we setup the appropriate prepare statement function, as we just have to call the following.

conn.query('getUser', {id: 5}, cb);

As a matter of fact, getUser is also now available from conn itself

conn.getUser({id: 5}, cb);

Yes, prepare is equivalent of an extension method. So take care when you are choosing the name of the query, you don't want to override the existing methods on the conn object and its prototype.

Module for Prepare Statements

You can organize all your prepare statements in a module, and specify it in the module parameter of the option object passed to DBConnect.setup.

The module can export the following

  • a Function expecting the connection object. You can manually call prepare or perform any other task as required.
  • an object where the key is the name of the prepared statement, and the value is the body for the prepared statement.

Special Prepare

There is one more function that's called prepareSpecial, and this is driver-specific helper to handle mundane task of generating prepare statement.

For example, the following is what prepareSpecial does for MongoDBDriver.

  • it expects an object and convert the object into the appropriate prepare function
  • the prepare function closes over the object and use it for converting the incoming args into the appropriate query object then pass into .query.

ORM & Schema

dbconnect has its own mini-ORM. You can access it via the DBConnect.Schema object.

// create a schema object.
var schema = new DBConnect.Schema('test');

// add table

schema.defineTable('User', [
    {col: 'uuid', type: 'uuid', default: {proc: 'makeUUID'}, primary: true}
    {col: 'login', type: 'string', unique: true}
    // more columns ...
]);

// ... more schema options.

DBConnect.setup({
    name: 'test',
    type: 'mongo',
    schema: schema // NOTE - adding schema here.
});

var conn = DBConnect.make('test');

// now the schema object is accessible via conn.schema

// insert a record into User table
// NOTE - these functions will throw error unless a schema object is registered.
conn.insert('User', {login: 'foobar'}, // NOTE - uuid has a default function to auto-generate an UUID.
  function(err, user) {
    // ...



    conn.delete('User', user, function(err, user) { ... });
  });

The object returned by conn.insert is an DBConnect.Schema.Record object, which also holds the table it represents as well as the connection object, so it can perform the following functions.

// the object returned is user
user.update({key: val, ...}, function(err) { /* callback */ });

user.delete(function(err) { /* callback */ });

Active Record Relation

Based on your schema definition (by using the reference in the index), you can setup relationship for the tables.

For example, let's say that we have the following schema:

schema.defineTable('User', [
  {col: 'uuid', type: 'uuid', default: {proc: 'makeUUID'}, unique: true}
  , {col: 'login', type: 'string', unique: true}
  , {col: 'email', type: 'email', unique: true}
]);

schema.defineTable('Password', [
  {col: 'type', type: 'string', default: 'sha256'}
  , {col: 'salt', type: 'hexString', unique: true, default: {proc: 'randomBytes'}}
  , {col: 'hash', type: 'hexString'}
  , {col: 'userUUID', type: 'uuid', index: true, reference: {table: 'User', columns: ['uuid']}}
]);

Once you have created an user object via either conn.insert, conn.select, or conn.selectOne, you can then access a password object via

user.selectOne('Password', {}, function(err, pass) {
  if (err) {

  } else {
    // pass is an active record as well.
  }
});

The object.insert, object.select, and object.selectOne has exactly the same interface as the conn version, but the valid tables are currently limited to those that have direct reference to object.table.