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

postgres-gen-dao

v0.18.2

Published

A simple DAO library built on postgres-gen and pg.

Downloads

22

Readme

postgres-gen-dao

postgres-gen-dao is a simple DAO library built on postgres-gen and pg. Its goal is to remove the boilerplate associated with marshalling objects to and from tables.

As an aside, PostgreSQL JSON support is very very nice in node.js. Starting with 9.4 and the hstore-json merger, tilt tables are a thing of the past.

Usage

var db = '...'; // your postgres-gen db here
var dao = require('postgres-gen-dao');
var books = dao({ db: db, table: 'books' });

// let's assume our table is id:bigserial-primarykey, author:varchar, title:varchar, published:integer, details:json, created_at:timestamptz-current_timestamp(3), updated_at:timestamptz-current_timestamp(3)
var b = { author: 'John Public', title: 'I Like Books', published: 1733, details: { binding: 'leather', color: 'red' } };

// upsert will insert or update depending on whether or not dao knows it loaded the record or all of the elidable fields are present
// explicit insert and update are also available
books.upsert(b).then(function() {
  // b will be updated at this point and will be the first argument to this callback
  console.log(b.id + ' - ' + b.createdAt + ' - ' + b.updatedAt); // elidable values are loaded back from the inserted record

  books.find('author = ?', 'John Public').then(function(bs) {
    // bs is an array of books by John Public
  });
  
  books.find().then(function(bs) {
    // bs is an array of all books
  });

  books.findOne('id = ?', 1).then(function(b) {
    // b is book with id 1
  });
});

db.transaction(function*() {
  var b = yield books.findOne('id = ?', 1);
  yield dao.delete(b); // delete by model, will throw if more than one row is affected
  yield dao.delete('published > 1967'); // delete by query, returns count
});

Since all of the query methods return a promise (from postgres-gen), this plays nicely with generator-based flow control.

Init Note

For legacy reasons, the initialization of the DAO object is not fully complete when it is returned. If you need to wait for full initialization, you can use the supplied ready Promise to do so.

var books = dao({ db: db, table: 'books' });
// books is the actual DAO, and query methods can be used. They will just not be started until init is complete.
books.then(bs => {
  // bs === books, but this only fires after init is complete
});

For simple queries, this doesn't matter much in practice, but if you have ql queries that reference multiple DAOs, you can get malformed SQL before init is complete.

ql

ql is the slight adjustment to SQL that allows references to DAO tables and columns to be referenced at a higher level with the details being filled in automatically. It uses @ references with optional aliases to look up which DAO table and columns to inject into the query. For instance, SELECT @b.*, @a.* from @books b join @authors a on b.author_id = a.id; will look up the models with for tables books and authors and replace @b.* and @a.* with a full aliased field list and substitute the tables names for @books and @authors. Individual fields can also be referenced using @b.author_id, which will result in an aliased field reference ("b"."author_id" AS "_b__author_id"), or @:b.author_id, which will result in an alias reference ("_b__author_id"). The former is useful to select single fields from tables, and the latter is useful to reference single fields in complex queries, particularly those with CTEs.

The ql processor returns a substituted query and an alias map so that the load handler can retrieve models using their aliased fields.

Keyless tables

Keyless tables are partially supported in that records can be inserted, loaded, and updated, but the method for doing so is not ideal. When a keyless record is loaded (or inserted), its values are cloned into a generated member, which is then used to target the record for updates and deletes. Keyless records are expected to be unique for updates and deletes.

API

query( sql, [ parameters ], [ options ] )

query allows you to run a ql query with optional parameters and collect the results into a more graph-like form.

options may specify an extra function or map of functions (per-alias) that will be called with each record and result object for every new row. This can be used to add computed fields to the object output of a query.

It may also specify a fetch map or its contents, similar to the way ActiveRecord specifies fetches. For instance, to specify that a book should have one author, { author: '' }. If a book should have multiple authors, { authors: [] }. The specifiers may be nested as needed, for instance, { authors: [{ publisher: '', commisions: [] }] } would return books with and authors array where the authors each had a publisher and an array of comissions. Each key must match an alias in a ql query, or it will be ignored.

Any options keys that match an alias will be automatically included in the fetch map, so a fetch key is optional but may be more clear.

If an exclude map is provided, any fields for a table's alias in the exclude array will not be included in the SELECT statement. The keys of the map must match @ referenced tables, e.g. dao.query('select @t.* from @foo t;', {}, { exclude: { t: [ 'big_array_blob_field' ] } });. In this example, the big_array_blob_field will not be included in the list of the t.* fields.

A transaction option may be specified to make sure that this query participates in the given transaction. There are also aliases for trans and t that can be used conveniently with ES6 object literal e.g. db.transaction(function*(t) { return yield dao.query('select * from foos;', { t }); } ).

find|findOne( [ conditions ], [ parameters ], [ options ] )

Both find and findOne take the same parameters. The only difference is findOne will throw if more than one result, which would otherwise be returned directly, is returned.

options

exclude - an array of column names to exclude from the query.

transaction - may be specified to make sure that this query participates in the given transaction. There are also transaction aliases trans and t that can be used conveniently with ES6 object literal short syntax e.g. db.transaction(function*(t) { return yield dao.query('select * from foos;', { t }); } ).

insert( object, [ options ] )

update( object, [ options ] )

upsert( object, [ options ] )

If the internal generated flag is set on the object from a load, an update will be triggerd. If the given object has its primary key and optimistic concurrency fields present, an updated will be triggered. Otherwise, and insert will be triggered.

delete( object, [ options ] )

Deletes the given object. If more than one record is deleted, the transaction will abort.

delete( conditions, [ options ] )

Deletes all of the records that match the given conditions and returns the deleted record count.