diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d5f4c01 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/node_modules +/bower_components diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..7c22070 --- /dev/null +++ b/.npmignore @@ -0,0 +1,3 @@ +test/ +images/ +docs/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..2e65f53 --- /dev/null +++ b/README.md @@ -0,0 +1,75 @@ +# rekord-knex + +[![Build Status](https://travis-ci.org/Rekord/rekord-knex.svg?branch=master)](https://travis-ci.org/Rekord/rekord-knex +[![devDependency Status](https://david-dm.org/Rekord/rekord-knex/dev-status.svg)](https://david-dm.org/Rekord/rekord-knex#info=devDependencies) +[![Dependency Status](https://david-dm.org/Rekord/rekord-knex.svg)](https://david-dm.org/Rekord/rekord-knex) +[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/Rekord/rekord/blob/master/LICENSE) +[![Alpha](https://img.shields.io/badge/State-Alpha-orange.svg)]() + +A rekord binding to [Knex.js](http://knexjs.org/). + +**Structure** + +The suggested structure for using this library is as follows: + +- src/connections.js: creates and exports knex objects +- src/models.js: takes connection objects and defines & exports models + +**Example** + +```javascript +// ============================================================================= +// connections.js +// ============================================================================= +exports.main = require('knex')({ + client: 'sqlite3', + useNullAsDefault: true, + connection: { + filename: "./mydb.sqlite" + } +}); + +// ============================================================================= +// models.js +// ============================================================================= +var connections = require('./connections.js'); +var Rekord = require('rekord'); + +var Task = Rekord({ + name: 'task', + api: connections.main, // api must be a knex connection + fields: ['name', 'done'], + defaults: { + done: false + } +}); + +// Load models from connections (where load option is used) +Rekord.load(); + +// Export defined models +exports.Task = Task; + +// ============================================================================= +// example.js +// ============================================================================= +var Rekord = require('rekord'); +var Task = require('./models.js').Task; + +var task = new Task({ + name: 'Better Examples' +}); + +Rekord.Promise + .then(function() { + return task.$save(); + }) + .then(function(saved) { + // task saved! let the user know or return a function which returns a promise + }) + .catch(function(error) { + // handle an error! + process.exit(); + }) +; +``` diff --git a/index.js b/index.js new file mode 100644 index 0000000..76030be --- /dev/null +++ b/index.js @@ -0,0 +1,3 @@ + +require('./src/defaults.js'); +require('./src/Rest.js'); diff --git a/package.json b/package.json new file mode 100644 index 0000000..96ff1df --- /dev/null +++ b/package.json @@ -0,0 +1,36 @@ +{ + "name": "rekord-knex", + "version": "1.5.0", + "description": "A rekord binding to Knex.js - implementing Rekord.rest on the server side", + "author": "Philip Diffenderfer", + "license": "MIT", + "main": "index.js", + "repository": { + "type": "git", + "url": "git://github.com/Rekord/rekord-knex.git" + }, + "devDependencies": { + "gulp": "^3.9.0", + "gulp-check-filesize": "^2.0.1", + "gulp-concat": "^2.6.0", + "gulp-insert": "^0.5.0", + "gulp-jshint": "^2.0.1", + "gulp-load-plugins": "^1.1.0", + "gulp-qunit": "^1.4.0", + "gulp-rename": "^1.2.2", + "gulp-shell": "^0.5.1", + "gulp-sourcemaps": "^1.6.0", + "gulp-uglify": "^1.5.3", + "gulp-util": "^3.0.7", + "gulp-watch": "^4.3.6", + "jaguarjs-jsdoc": "1.0.0", + "jsdoc": "^3.4.0", + "jshint": "^2.9.2", + "merge-stream": "^1.0.0", + "sqlite3": "^3.1.8" + }, + "dependencies": { + "knex": "^0.12.6", + "rekord": "^1.5.1" + } +} diff --git a/src/Rest.js b/src/Rest.js new file mode 100644 index 0000000..e2aba31 --- /dev/null +++ b/src/Rest.js @@ -0,0 +1,195 @@ + +var Rekord = require('rekord'); +var Class = Rekord.Class; + +function Rest(database) +{ + this.database = database; +} + +Class.create( Rest, +{ + + // success ( data[] ) + // failure ( data[], status ) + all: function( options, success, failure ) + { + var db = this.database; + var builder = db.api + .select('*') + .from( db.name ) + ; + + if (Rekord.isFunction(options)) + { + options( builder ); + } + + builder + .then( function(rows) { + success( rows ); + }) + .catch( function(error) { + failure( [], error ); + }) + ; + }, + + // success( data ) + // failure( data, status ) + get: function( model, options, success, failure ) + { + var db = this.database; + var builder = db.api + .select('*') + .from( db.name ) + .where( this.keyOf( model ) ) + ; + + if (Rekord.isFunction(options)) + { + options( builder ); + } + + builder + .then( function(rows) { + success( rows[0] ); + }) + .catch( function(error) { + failure( null, error ); + }) + ; + }, + + // success ( data ) + // failure ( data, status ) + create: function( model, encoded, options, success, failure ) + { + var db = this.database; + var builder = db.api( db.name ) + .returning( db.returning ) + .insert( encoded ) + ; + + if (Rekord.isFunction(options)) + { + options( builder ); + } + + builder + .then( function(rows) { + success( rows[0] ); + }) + .catch( function(error) { + failure( null, error ); + }) + ; + }, + + // success ( data ) + // failure ( data, status ) + update: function( model, encoded, options, success, failure ) + { + var db = this.database; + var builder = db.api( db.name ) + .where( this.keyOf( model ) ) + .update( encoded ) + ; + + if (Rekord.isFunction(options)) + { + options( builder ); + } + + builder + .then( function() { + success( {} ); + }) + .catch( function(error) { + failure( null, error ); + }) + ; + }, + + // success ( data ) + // failure ( data, status ) + remove: function( model, options, success, failure ) + { + var db = this.database; + var builder = db.api( db.name ) + .where( this.keyOf( model ) ) + .delete() + ; + + if (Rekord.isFunction(options)) + { + options( builder ); + } + + builder + .then( function() { + success( {} ); + }) + .catch( function(error) { + failure( null, error ); + }) + ; + }, + + // success ( data[] ) + // failure ( data[], status ) + query: function( url, query, options, success, failure ) + { + var db = this.database; + var select = options && options.select ? options.select : '*'; + + var builder = db.api + .select( select ) + .from( db.name ) + ; + + if (Rekord.isFunction(query)) + { + query( builder ); + } + else if (Rekord.isObject(query)) + { + if (query.page_size) + { + builder.limit( query.page_size ); + + if (query.page_index) + { + builder.offset( query.page_size * query.page_index ); + } + } + } + + builder + .then( function(rows) { + success( rows ); + }) + .catch( function(error) { + failure( [], error ); + }) + ; + }, + + keyOf: function(model) + { + var keyHandler = this.database.keyHandler; + var key = {}; + + keyHandler.copyFields( key, keyHandler.key, model, keyHandler.key ); + + return key; + } + +}); + +function RestFactory(database) +{ + return new Rest( database ); +} + +Rekord.setRest( RestFactory ); diff --git a/src/defaults.js b/src/defaults.js new file mode 100644 index 0000000..d24234c --- /dev/null +++ b/src/defaults.js @@ -0,0 +1,24 @@ + +var Rekord = require('rekord'); + +Rekord.Defaults.returning = '*'; +Rekord.Defaults.cascade = Rekord.Cascade.Rest; +Rekord.Defaults.cache = Rekord.Cache.None; + +Rekord.Relations.hasOne.auto = +Rekord.Relations.belongsTo.auto = +Rekord.Relations.hasMany.auto = +Rekord.Relations.hasManyThrough.auto = + false; + +Rekord.Relations.hasOne.saveCascade = +Rekord.Relations.hasOne.autoCascade = +Rekord.Relations.hasOne.cascade = +Rekord.Relations.belongsTo.autoCascade = +Rekord.Relations.belongsTo.cascade = +Rekord.Relations.hasMany.autoCascade = +Rekord.Relations.hasMany.saveParentCascade = +Rekord.Relations.hasManyThrough.autoCascade = +Rekord.Relations.hasManyThrough.cascadeSave = +Rekord.Relations.hasManyThrough.saveParentCascade = + Rekord.Cascade.Rest; diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 0000000..261b0e2 --- /dev/null +++ b/test/.gitignore @@ -0,0 +1 @@ +mydb.sqlite diff --git a/test/cases/insert.js b/test/cases/insert.js new file mode 100644 index 0000000..37ed6b9 --- /dev/null +++ b/test/cases/insert.js @@ -0,0 +1,24 @@ + +var Rekord = require('rekord'); +var Task = require('../root.js').Task; + +var t0 = new Task({ + name: 't' + Math.random() +}); + +Rekord.Promise + .then(function() { + return t0.$save(); + }) + .then(function() { + return Task.Database.grabModel( t0.id ); + }) + .then(function(t1) { + console.log( t1.name ); + process.exit(); + }) + .catch(function(error) { + console.log( error ); + process.exit(); + }) +; diff --git a/test/cases/list.js b/test/cases/list.js new file mode 100644 index 0000000..914d27c --- /dev/null +++ b/test/cases/list.js @@ -0,0 +1,17 @@ + +var Rekord = require('rekord'); +var Task = require('../root.js').Task; + +Rekord.Promise + .then(function() { + return Task.refresh(); + }) + .then(function() { + console.log( Task.all() ); + process.exit(); + }) + .catch(function(error) { + console.log( error ); + process.exit(); + }) +; diff --git a/test/create.sh b/test/create.sh new file mode 100644 index 0000000..0a07c1f --- /dev/null +++ b/test/create.sh @@ -0,0 +1,2 @@ +#/bin/bash +sqlite3 mydb.sqlite < create.sql diff --git a/test/create.sql b/test/create.sql new file mode 100644 index 0000000..b6eb1bf --- /dev/null +++ b/test/create.sql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS "task" ( + "id" TEXT PRIMARY KEY, + "name" TEXT, + "done" INTEGER +); diff --git a/test/root.js b/test/root.js new file mode 100644 index 0000000..a1e2e43 --- /dev/null +++ b/test/root.js @@ -0,0 +1,26 @@ + +require('../index.js'); + +var Rekord = require('rekord'); + +var knex = require('knex')({ + client: 'sqlite3', + useNullAsDefault: true, + connection: { + filename: "./mydb.sqlite" + } +}); + +var Task = Rekord({ + name: 'task', + api: knex, + fields: ['name', 'done'], + defaults: { + done: false + } +}); + +Rekord.load(); + +exports.Task = Task; +exports.knex = knex;