UNPKG

@wmfs/pg-model

Version:

Takes a relational database structure and returns model objects for noSQL-like abilities.

317 lines (261 loc) 7.37 kB
# pg-model [![Tymly Package](https://img.shields.io/badge/tymly-package-blue.svg)](https://tymly.io/) [![npm (scoped)](https://img.shields.io/npm/v/@wmfs/pg-model.svg)](https://www.npmjs.com/package/@wmfs/pg-model) [![Build Status](https://travis-ci.org/wmfs/pg-model.svg?branch=master)](https://travis-ci.org/wmfs/pg-model) [![codecov](https://codecov.io/gh/wmfs/pg-model/branch/master/graph/badge.svg)](https://codecov.io/gh/wmfs/pg-model) [![CodeFactor](https://www.codefactor.io/repository/github/wmfs/pg-model/badge)](https://www.codefactor.io/repository/github/wmfs/pg-model) [![Dependabot badge](https://img.shields.io/badge/Dependabot-active-brightgreen.svg)](https://dependabot.com/) [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/wmfs/tymly/blob/master/packages/pg-concat/LICENSE) > Takes a relational database structure and returns model objects for noSQL-like abilities. ## <a name="install"></a>Install ```bash $ npm install pg-model --save ``` ## <a name="usage"></a>Usage ```javascript const pg = require('pg') const pgInfo = require('pg-info') // Make a new Postgres client const client = new pg.Client('postgres://postgres:postgres@localhost:5432/my_test_db') client.connect() //Now get the structure of the 'space' database schema pgInfo( { client: client, schemas: [ 'space', ] }, function (err, dbStructure) { // 'dbStructure' describes the content of the 'space' schema // (i.e. tables, columns, indexes, foreign-key constraints etc.) // Now make some models from that description... models = pgModel( { client: client, dbStructure: dbStructure } ) // We've now one-model-per table. // So, assuming the 'space' schema contained tables named 'planets', 'moons' and 'craters'... // This sort of thing is possible... models.space.planets.create( { name: 'mars', title: 'Mars', type: 'Terrestrial', diameter: 6700, color: 'red', url: 'http://en.wikipedia.org/wiki/Mars', moons: [ { title: 'Phobos', discoveredBy: 'Asaph Hall', discoveryYear: 1875, craters: [ { title: 'Stickney', diameter: 10 } ] }, { title: 'Deimos', discoveredBy: 'Asaph Hall', discoveryYear: 1875 } ] }, {} ).then(() => {{ // * Four rows have been inserted amongst the 'space.planets', 'space.moons' and 'space.craters' tables // * PostgreSQL's column defaults have been used to populate the missing primary key values // * The foreign-key values for 'space.moons' and 'space.craters' have been auto-filled by // inspecting FK constraints } ) } ) ``` ## <a name="api"></a>API Each model offers the following methods. ### create (`jsonData`, `options`) Inserts the supplied JSON documents into relational tables. Resolves to the document's id properties. __Example__ ```javascript models.hr.people.create( { employeeNo: 1 firstName: 'Homer', lastName: 'Simpson', age: 39 }, {} ).then(idProperties => { // idProperties == // { // idProperties: // { // employeeNo: 1 // } // } } ) ``` ### findById (`id`) Finds one 'document' by ID - all nested docs will be assembled too. __Example__ ```javascript models.hr.people.findById(1) .then(doc => { // doc == // { // employeeNo: 1, // firstName: 'Homer', // lastName: 'Simpson', // age: 39, // created: 2017-06-02T22:00:55.221Z, // createdBy: null, // modified: 2017-06-02T22:00:55.221Z, // modifiedBy: null // } } ) ``` ### find (`options`) Find zero-or-more docs - can be filtered, ordered, paginated etc. Resolves to the found document array. __Example__ ```javascript models.hr.people.find( { where: { firstName: {equals: 'Homer'}, lastName: {equals: 'Simpson'} } } ).then(docs => { // docs == // [ // { // employeeNo: 1, // firstName: 'Homer', // lastName: 'Simpson', // age: 39, // created: 2017-06-02T22:00:55.221Z, // createdBy: null, // modified: 2017-06-02T22:00:55.221Z, // modifiedBy: null // } // ] } ) ``` ### findOne (`options`) Like `find` but resolves to a single doc. __Example__ ```javascript models.hr.people.findOne( { orderBy: ['age'], nullsLast: true, offset: 1 } ).then(doc => { // doc == // { // employeeNo: 1, // firstName: 'Homer', // lastName: 'Simpson', // age: 39, // created: 2017-06-02T22:00:55.221Z, // createdBy: null, // modified: 2017-06-02T22:00:55.221Z, // modifiedBy: null // } } ) ``` ### update (`doc`, `options`) Updates a single 'document'. The top-level primary key is inferred from the data - automatically inserts/updates/deletes nested docs. __Example__ ```javascript models.hr.people.update( { employeeNo: 1, firstName: 'Homer', lastName: 'Simpson', age: 39 }, {} ).then(() => { /* All done */ }) ``` ### patch (`doc`, `options`) Same as `update`, but any omitted properties will be retained (i.e. they won't be turned into `null` values like `update` will). __Example__ ```javascript models.hr.people.patch( { employeeNo: 1, age: 39 }, {} ).then(() => { /* All done */ }) ``` ### upsert (`doc`, `options`) A combination of `create` and `update`. If a document already exists then `upsert` will _update_ it, else it'll _create_ it. __Example__ ```javascript models.hr.people.upsert( { employeeNo: 1, firstName: 'Homer', lastName: 'Simpson', age: 39 }, {} ).then(idProperties => { // idProperties == // { // idProperties: // { // employeeNo: 1 // } // } } ) ``` ### destroyById (`id`) Deletes one 'document' by ID - all nested docs will be cascade-deleted too. __Example__ ```javascript models.hr.people.destroyById(1) .then(() => { /* All done */ }) ``` ### parseDoc (`doc`, `options`) Takes a single doc and parses it into a form that's usable by several of the other methods. __Example__ ```javascript const parsedDoc = models.hr.people.parseDoc( { employeeNo: 1, firstName: 'Homer', lastName: 'Simpson', age: 39 }, { includeNullFks: false } ) ``` ## <a name="test"></a>Testing Before running these tests, you'll need a test PostgreSQL database available and set a `PG_CONNECTION_STRING` environment variable to point to it, for example: ```PG_CONNECTION_STRING=postgres://postgres:postgres@localhost:5432/my_test_db``` ```bash $ npm test ``` ## <a name="license"></a>License [MIT](https://github.com/wmfs/pg-model/blob/master/LICENSE)