From 43ee4202d336c73a2402580b3d37636b05e20bb8 Mon Sep 17 00:00:00 2001 From: David Luecke Date: Sun, 16 Dec 2018 20:42:37 -0800 Subject: [PATCH 1/5] Start migration to @feathersjs/adapter-commons --- .gitignore | 2 +- .travis.yml | 4 +- lib/hooks.js | 10 +- lib/index.js | 147 ++++----- package-lock.json | 786 ++++++++++++++++++++------------------------- package.json | 22 +- test/index.test.js | 302 ++++++++--------- 7 files changed, 585 insertions(+), 688 deletions(-) diff --git a/.gitignore b/.gitignore index 2f5fd7a..2df86c6 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,4 @@ node_modules .lock-wscript dist/ -*.sqlite +*.sqlite* diff --git a/.travis.yml b/.travis.yml index 75571ed..0379dac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: node_js node_js: - - 10 - - 6 + - 'node' + - 8 sudo: false install: npm install diff --git a/lib/hooks.js b/lib/hooks.js index 585e040..4134b52 100644 --- a/lib/hooks.js +++ b/lib/hooks.js @@ -1,10 +1,10 @@ const debug = require('debug')('feathers-knex-transaction'); -const RollbackReason = function(error) { +const RollbackReason = function (error) { this.error = error; }; -const start = (options) => { +const start = () => { return hook => new Promise(resolve => { if (!hook.service.Model || typeof hook.service.Model.transaction !== 'function') { return resolve(hook); @@ -36,7 +36,7 @@ const start = (options) => { const end = (options) => { return hook => { if (hook.params.transaction) { - const { promise, trx, id, count } = hook.params.transaction; + const { trx, id, count } = hook.params.transaction; if (count > 0) { hook.params.transaction.count -= 1; @@ -46,7 +46,6 @@ const end = (options) => { hook.params.transaction = undefined; return trx.commit() - .then(() => promise) .then(() => debug('finished transaction %s with success', id)) .then(() => hook); } @@ -57,10 +56,9 @@ const end = (options) => { const rollback = (options) => { return hook => { if (hook.params.transaction) { - const { promise, trx, id } = hook.params.transaction; + const { trx, id } = hook.params.transaction; return trx.rollback(new RollbackReason(hook.error)) .then(() => debug('rolling back transaction %s', id)) - .then(() => promise) .then(() => hook); } return hook; diff --git a/lib/index.js b/lib/index.js index 15995fb..ffbce45 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,5 +1,4 @@ -const Proto = require('uberproto'); -const { filterQuery } = require('@feathersjs/commons'); +const { AdapterService } = require('@feathersjs/adapter-commons'); const isPlainObject = require('is-plain-object'); const errors = require('@feathersjs/errors'); @@ -26,13 +25,9 @@ const OPERATORS = { }; // Create the service. -class Service { +class Service extends AdapterService { constructor (options) { - if (!options) { - throw new Error('Knex options have to be provided'); - } - - if (!options.Model) { + if (!options || !options.Model) { throw new Error('You must provide a Model (the initialized knex object)'); } @@ -40,16 +35,23 @@ class Service { throw new Error('No table name specified.'); } - this.knex = this.Model = options.Model; - this.id = options.id || 'id'; - this.paginate = options.paginate || {}; + const { whitelist = [] } = options; + + super(Object.assign({ + id: 'id', + whitelist: whitelist.concat([ '$like', '$ilike', '$and' ]) + }, options)); + this.table = options.name; this.schema = options.schema; - this.events = options.events || []; + } + + get Model () { + return this.options.Model; } get fullName () { - return (this.schema) ? `${this.schema}.${this.table}` : this.table; + return this.schema ? `${this.schema}.${this.table}` : this.table; } // NOTE (EK): We need this method so that we return a new query @@ -59,17 +61,13 @@ class Service { if (params.transaction) { const { trx, id } = params.transaction; debug('ran %s with transaction %s', fullName, id); - return (schema) ? trx.withSchema(schema).table(table) : trx(table); + return schema ? trx.withSchema(schema).table(table) : trx(table); } - return (schema) ? knex.withSchema(schema).table(table) : knex(table); - } - - extend (obj) { - return Proto.extend(obj, this); + return schema ? knex.withSchema(schema).table(table) : knex(table); } init (opts, cb) { - const k = this.knex; + const k = this.Model; const { table, schema, fullName } = this; return k.schema.hasTable(fullName).then(exists => { @@ -120,10 +118,12 @@ class Service { createQuery (params = {}) { const { schema, table, id } = this; - const { filters, query } = filterQuery(params.query || {}); + const { filters, query } = this.filterQuery(params); let q = this.db(params); - if (schema) { q = q.withSchema(schema).from(`${table} as ${table}`); } + if (schema) { + q = q.withSchema(schema).from(`${table} as ${table}`); + } q = (filters.$select) // $select uses a specific find syntax, so it has to come first. @@ -143,8 +143,8 @@ class Service { return q; } - _find (params, count, getFilter = filterQuery) { - const { filters, query } = getFilter(params.query || {}); + _find (params) { + const { filters, query, paginate } = this.filterQuery(params); const q = params.knex ? params.knex.clone() : this.createQuery(params); // Handle $limit @@ -184,7 +184,7 @@ class Service { }; } - if (count) { + if (paginate && paginate.default) { let countQuery = (params.knex || this.db(params)) .clone() @@ -192,63 +192,44 @@ class Service { .clearOrder() .count(`${this.table}.${this.id} as total`); - if (!params.knex) { this.knexify(countQuery, query); } - - return countQuery.then(count => count[0] ? count[0].total : 0).then(executeQuery).catch(errorHandler); - } - - return executeQuery().catch(errorHandler); - } - - find (params) { - const paginate = (params && typeof params.paginate !== 'undefined') ? params.paginate : this.paginate; - const result = this._find(params, !!paginate.default, - query => filterQuery(query, paginate) - ); + if (!params.knex) { + this.knexify(countQuery, query); + } - if (!paginate.default) { - return result.then(page => page.data); + return countQuery.then(count => count[0] ? count[0].total : 0) + .then(executeQuery) + .catch(errorHandler); } - return result; + return executeQuery().then(page => page.data).catch(errorHandler); } _get (id, params) { - const query = Object.assign({}, params.query); - - query[this.id] = id; - - return this._find(Object.assign({}, params, { query })) - .then(page => { - if (page.data.length !== 1) { - throw new errors.NotFound(`No record found for id '${id}'`); - } - - return page.data[0]; - }).catch(errorHandler); - } - - get (...args) { - return this._get(...args); - } + return this._find(Object.assign({}, params, { + paginate: false, + query: Object.assign({}, params.query, { [this.id]: id }) + })).then(data => { + if (data.length !== 1) { + throw new errors.NotFound(`No record found for id '${id}'`); + } - _create (data, params) { - return this.db(params).insert(data, this.id).then(rows => { - const id = typeof data[this.id] !== 'undefined' ? data[this.id] : rows[0]; - return this._get(id, params); + return data[0]; }).catch(errorHandler); } - create (data, params) { + _create (data, params) { if (Array.isArray(data)) { return Promise.all(data.map(current => this._create(current, params))); } - return this._create(data, params); + return this.db(params).insert(data, this.id).then(rows => { + const id = typeof data[this.id] !== 'undefined' ? data[this.id] : rows[0]; + return this._get(id, params); + }).catch(errorHandler); } - patch (id, raw, params) { - const query = filterQuery(params.query || {}).query; + _patch (id, raw, params) { + const { query } = this.filterQuery(params); const data = Object.assign({}, raw); const mapIds = page => page.data.map(current => current[this.id]); @@ -272,6 +253,7 @@ class Service { // Create a new query that re-queries all ids that // were originally changed const findParams = Object.assign({}, params, { + paginate: false, query: { [this.id]: { $in: idList }, $select: params.query && params.query.$select @@ -279,9 +261,7 @@ class Service { }); return q.update(data).then(() => { - return this._find(findParams).then(page => { - const items = page.data; - + return this._find(findParams).then(items => { if (id !== null) { if (items.length === 1) { return items[0]; @@ -296,14 +276,7 @@ class Service { }).catch(errorHandler); } - update (id, data, params) { - if (Array.isArray(data)) { - return Promise.reject(errors.BadRequest('Not replacing multiple records. Did you mean `patch`?')); - } - - // NOTE (EK): First fetch the old record so - // that we can fill any existing keys that the - // client isn't updating with null; + _update (id, data, params) { return this._get(id, params).then(oldData => { let newObject = {}; @@ -326,18 +299,18 @@ class Service { }).catch(errorHandler); } - remove (id, params) { - params.query = Object.assign({}, params.query); + _remove (id, params) { + const findParams = Object.assign({}, params, { + paginate: false, + query: Object.assign({}, params.query) + }); - // NOTE (EK): First fetch the record so that we can return - // it when we delete it. if (id !== null) { - params.query[this.id] = id; + findParams.query[this.id] = id; } - return this._find(params).then(page => { - const items = page.data; - const { query } = filterQuery(params.query || {}); + return this._find(findParams).then(items => { + const { query } = this.filterQuery(params); const q = this.db(params); // build up the knex query out of the query params @@ -347,9 +320,9 @@ class Service { if (id !== null) { if (items.length === 1) { return items[0]; - } else { - throw new errors.NotFound(`No record found for id '${id}'`); } + + throw new errors.NotFound(`No record found for id '${id}'`); } return items; diff --git a/package-lock.json b/package-lock.json index 223b31e..58f2f45 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,58 +14,51 @@ "regenerator-runtime": "^0.11.1" } }, + "@feathersjs/adapter-commons": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@feathersjs/adapter-commons/-/adapter-commons-1.0.2.tgz", + "integrity": "sha512-nee7PEE/mEx/iofcTALvMO7gj6SC6gzKdH3xorwHMKQi9z82aI3PLvgTgC3+4B0UwCSZ1gthSUJIl8K093P4Ug==", + "requires": { + "@feathersjs/commons": "^4.0.0", + "@feathersjs/errors": "^3.3.5" + } + }, "@feathersjs/commons": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/@feathersjs/commons/-/commons-1.4.4.tgz", - "integrity": "sha512-ZPpzyZA3CPfoa9AuFv3BJUI/ubzaaXixp8T/pqeMFPT6DOaU/6oF7lz1RxwimzfJNna4gy/HByt0EoLSI3BKWg==" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@feathersjs/commons/-/commons-4.0.0.tgz", + "integrity": "sha512-hyCLse4RiNt7WLPQ0KSudjoVnwiRykhYzIZdtDon9i2usPaoYkFw/fEYZrkE5HVB+sUTwphZoZ1oOntRk1MShg==" }, "@feathersjs/errors": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/@feathersjs/errors/-/errors-3.3.4.tgz", - "integrity": "sha512-yA/HXSWgLiK4ngFslCHxcvnt+gek4fUhJcwpix9Z1jpTnCWW5WqtNxUfUqE1Fj8wKq0Y6VPSaQtE+RZcgryDQQ==", + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@feathersjs/errors/-/errors-3.3.5.tgz", + "integrity": "sha512-Nc4SxKJ7xQk5RZ3M68/Oj5c2uB/VrUATd4dLEdSGHf9j+qvajZVmBPjqDPYfY4IeTnYNhvwTmuyCulD0bCL4ZQ==", "requires": { "debug": "^4.0.0" } }, "@feathersjs/express": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@feathersjs/express/-/express-1.2.7.tgz", - "integrity": "sha512-V+Tvg6X+GiANKwyUD6tYRnTjvFBgJhqVC5bqE/Wzd62PvJAn5p5yYZhWadT6b0Jirm2b5YA9kFNcPibb3MfWjA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@feathersjs/express/-/express-1.3.0.tgz", + "integrity": "sha512-IBjjY5x8iGQkZpAGQe7AYlEkhhwPOfx0wDf1Ben0EXwKFWLs+hkux9CJN2yQGRG61k9g8VVc79F4639FWrm3Mw==", "dev": true, "requires": { - "@feathersjs/commons": "^3.0.1", - "@feathersjs/errors": "^3.3.4", + "@feathersjs/commons": "^4.0.0", + "@feathersjs/errors": "^3.3.5", "debug": "^4.0.0", "express": "^4.16.2", "uberproto": "^2.0.0" - }, - "dependencies": { - "@feathersjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@feathersjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-wo2boFwbKqm53h/Wv2F+ggiTxSFOPaCupa6VHujJle/RZrox5On6zbaoO0B1yFZbj1tCJ6kT2IDpFg9StHL0oA==", - "dev": true - } } }, "@feathersjs/feathers": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/@feathersjs/feathers/-/feathers-3.2.3.tgz", - "integrity": "sha512-T51XlcE+HkAG7nfFMoqRU+bLxPhIYGygAiWQ0Fmc5vOsYtCZlj1AGjJWVL8iX7k2HQgFI2mdinWPoFb2rui03A==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@feathersjs/feathers/-/feathers-3.3.0.tgz", + "integrity": "sha512-vi70lwECER0KNZGKZMOg7oPt7OAToRjfpqORc//TJkOR5EOXEH5eFvKvWbZ8wLyuLB3OFlv7iUoufFlMvG19DA==", "dev": true, "requires": { - "@feathersjs/commons": "^3.0.1", + "@feathersjs/commons": "^4.0.0", "debug": "^4.0.0", "events": "^3.0.0", "uberproto": "^2.0.2" - }, - "dependencies": { - "@feathersjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@feathersjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-wo2boFwbKqm53h/Wv2F+ggiTxSFOPaCupa6VHujJle/RZrox5On6zbaoO0B1yFZbj1tCJ6kT2IDpFg9StHL0oA==", - "dev": true - } } }, "abbrev": { @@ -85,49 +78,38 @@ } }, "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.4.tgz", + "integrity": "sha512-VY4i5EKSKkofY2I+6QLTbTTN/UvEQPCo6eiwzzSaSWfpaDhOmStMCMod6wmuPciNq+XS0faCglFu2lHZpdHUtg==", "dev": true }, "acorn-jsx": { - "version": "3.0.1", - "resolved": "http://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", - "dev": true, - "requires": { - "acorn": "^3.0.4" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "http://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", - "dev": true - } - } + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", + "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", + "dev": true }, "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.2.tgz", + "integrity": "sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g==", "dev": true, "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", + "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "ajv-keywords": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", - "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", + "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", "dev": true }, "ansi-escapes": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", + "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", "dev": true }, @@ -203,7 +185,7 @@ }, "array-flatten": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", "dev": true }, @@ -223,33 +205,12 @@ "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", "dev": true }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "requires": { - "array-uniq": "^1.0.1" - } - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "dev": true }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -489,9 +450,9 @@ } }, "bluebird": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.2.tgz", - "integrity": "sha512-dhHTWMI7kMx5whMQntl7Vr9C6BvV10lFXDAasnqnrMYhXVCzzk6IO9Fo2L75jXHT07WrOngL1WDXOp+yYS91Yg==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", + "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==", "dev": true }, "body-parser": { @@ -574,12 +535,6 @@ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", @@ -620,7 +575,7 @@ }, "callsites": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "resolved": "http://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", "dev": true }, @@ -728,12 +683,6 @@ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", "dev": true }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", @@ -793,18 +742,6 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -848,9 +785,9 @@ "dev": true }, "core-js": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.0.tgz", + "integrity": "sha512-kLRC6ncVpuEW/1kwrOXYX6KQASCVtrh1gQr/UiaVgFlf9WE5Vp+lNe5+h3LuMr5PAucWnnEXwH0nQHRH/gpGtw==", "dev": true }, "core-util-is": { @@ -860,12 +797,14 @@ "dev": true }, "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { - "lru-cache": "^4.0.1", + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", "shebang-command": "^1.2.0", "which": "^1.2.9" } @@ -889,7 +828,7 @@ }, "debug-log": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", "dev": true }, @@ -980,32 +919,25 @@ } }, "deglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/deglob/-/deglob-2.1.1.tgz", - "integrity": "sha512-2kjwuGGonL7gWE1XU4Fv79+vVzpoQCl0V+boMwWtOQJV2AGDabCwez++nB1Nli/8BabAfZQ/UuHPlp6AymKdWw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/deglob/-/deglob-3.1.0.tgz", + "integrity": "sha512-al10l5QAYaM/PeuXkAr1Y9AQz0LCtWsnJG23pIgh44hDxHFOj36l6qvhfjnIWBYwZOqM1fXUFV9tkjL7JPdGvw==", "dev": true, "requires": { "find-root": "^1.0.0", "glob": "^7.0.5", - "ignore": "^3.0.9", + "ignore": "^5.0.0", "pkg-config": "^1.1.0", "run-parallel": "^1.1.2", "uniq": "^1.0.1" - } - }, - "del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", - "dev": true, - "requires": { - "globby": "^5.0.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "rimraf": "^2.2.8" + }, + "dependencies": { + "ignore": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.0.4.tgz", + "integrity": "sha512-WLsTMEhsQuXpCiG173+f3aymI43SXa+fB1rSfbzyP4GkPP+ZFVuO0/3sFUGNBtifisPeDcl/uD/Y2NxZ7xFq4g==", + "dev": true + } } }, "delayed-stream": { @@ -1123,6 +1055,12 @@ "is-symbol": "^1.0.2" } }, + "es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", + "dev": true + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1136,48 +1074,49 @@ "dev": true }, "eslint": { - "version": "4.18.2", - "resolved": "http://registry.npmjs.org/eslint/-/eslint-4.18.2.tgz", - "integrity": "sha512-qy4i3wODqKMYfz9LUI8N2qYDkHkoieTbiHpMrYUI/WbjhXJQr7lI4VngixTgaG+yHX+NBCv7nW4hA0ShbvaNKw==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.4.0.tgz", + "integrity": "sha512-UIpL91XGex3qtL6qwyCQJar2j3osKxK9e3ano3OcGEIRM4oWIpCkDg9x95AXEC2wMs7PnxzOkPZ2gq+tsMS9yg==", "dev": true, "requires": { - "ajv": "^5.3.0", - "babel-code-frame": "^6.22.0", + "ajv": "^6.5.0", + "babel-code-frame": "^6.26.0", "chalk": "^2.1.0", - "concat-stream": "^1.6.0", - "cross-spawn": "^5.1.0", + "cross-spawn": "^6.0.5", "debug": "^3.1.0", "doctrine": "^2.1.0", - "eslint-scope": "^3.7.1", + "eslint-scope": "^4.0.0", + "eslint-utils": "^1.3.1", "eslint-visitor-keys": "^1.0.0", - "espree": "^3.5.2", - "esquery": "^1.0.0", + "espree": "^4.0.0", + "esquery": "^1.0.1", "esutils": "^2.0.2", "file-entry-cache": "^2.0.0", "functional-red-black-tree": "^1.0.1", "glob": "^7.1.2", - "globals": "^11.0.1", - "ignore": "^3.3.3", + "globals": "^11.7.0", + "ignore": "^4.0.2", "imurmurhash": "^0.1.4", - "inquirer": "^3.0.6", - "is-resolvable": "^1.0.0", - "js-yaml": "^3.9.1", + "inquirer": "^5.2.0", + "is-resolvable": "^1.1.0", + "js-yaml": "^3.11.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.3.0", - "lodash": "^4.17.4", - "minimatch": "^3.0.2", + "lodash": "^4.17.5", + "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", "optionator": "^0.8.2", "path-is-inside": "^1.0.2", "pluralize": "^7.0.0", "progress": "^2.0.0", + "regexpp": "^2.0.0", "require-uncached": "^1.0.3", - "semver": "^5.3.0", + "semver": "^5.5.0", "strip-ansi": "^4.0.0", - "strip-json-comments": "~2.0.1", - "table": "4.0.2", - "text-table": "~0.2.0" + "strip-json-comments": "^2.0.1", + "table": "^4.0.3", + "text-table": "^0.2.0" }, "dependencies": { "ansi-regex": { @@ -1216,9 +1155,9 @@ } }, "globals": { - "version": "11.8.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.8.0.tgz", - "integrity": "sha512-io6LkyPVuzCHBSQV9fmOwxZkUk6nIaGmxheLDgmuFv89j0fm2aqDbIXKAGfzCMHqz3HLF2Zf8WSG6VqMh2qFmA==", + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.9.0.tgz", + "integrity": "sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg==", "dev": true }, "has-flag": { @@ -1248,21 +1187,21 @@ } }, "eslint-config-semistandard": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/eslint-config-semistandard/-/eslint-config-semistandard-12.0.1.tgz", - "integrity": "sha512-4zaPW5uRFasf2uRZkE19Y+W84KBV3q+oyWYOsgUN+5DQXE5HCsh7ZxeWDXxozk7NPycGm0kXcsJzLe5GZ1jCeg==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-semistandard/-/eslint-config-semistandard-13.0.0.tgz", + "integrity": "sha512-ZuImKnf/9LeZjr6dtRJ0zEdQbjBwXu0PJR3wXJXoQeMooICMrYPyD70O1tIA9Ng+wutgLjB7UXvZOKYPvzHg+w==", "dev": true }, "eslint-config-standard": { - "version": "11.0.0", - "resolved": "http://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-11.0.0.tgz", - "integrity": "sha512-oDdENzpViEe5fwuRCWla7AXQd++/oyIp8zP+iP9jiUPG6NBj3SHgdgtl/kTn00AjeN+1HNvavTKmYbMo+xMOlw==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-12.0.0.tgz", + "integrity": "sha512-COUz8FnXhqFitYj4DTqHzidjIL/t4mumGZto5c7DrBpvWoie+Sn3P4sLEzUGeYhRElWuFEf8K1S1EfvD1vixCQ==", "dev": true }, "eslint-config-standard-jsx": { - "version": "5.0.0", - "resolved": "http://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-5.0.0.tgz", - "integrity": "sha512-rLToPAEqLMPBfWnYTu6xRhm2OWziS2n40QFqJ8jAM8NSVzeVKTa3nclhsU4DpPJQRY60F34Oo1wi/71PN/eITg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-6.0.2.tgz", + "integrity": "sha512-D+YWAoXw+2GIdbMBRAzWwr1ZtvnSf4n4yL0gKGg7ShUOGXkSOLerI17K4F6LdQMJPNMoWYqepzQD/fKY+tXNSg==", "dev": true }, "eslint-import-resolver-node": { @@ -1319,22 +1258,32 @@ } } }, + "eslint-plugin-es": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-1.4.0.tgz", + "integrity": "sha512-XfFmgFdIUDgvaRAlaXUkxrRg5JSADoRC8IkKLc/cISeR3yHVMefFHQZpcyXXEUUPHfy5DwviBcrfqlyqEwlQVw==", + "dev": true, + "requires": { + "eslint-utils": "^1.3.0", + "regexpp": "^2.0.1" + } + }, "eslint-plugin-import": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.8.0.tgz", - "integrity": "sha512-Rf7dfKJxZ16QuTgVv1OYNxkZcsu/hULFnC+e+w0Gzi6jMC3guQoWQgxYxc54IDRinlb6/0v5z/PxxIKmVctN+g==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.14.0.tgz", + "integrity": "sha512-FpuRtniD/AY6sXByma2Wr0TXvXJ4nA/2/04VPlfpmUDPOpOY264x+ILiwnrk/k4RINgDAyFZByxqPUbSQ5YE7g==", "dev": true, "requires": { - "builtin-modules": "^1.1.1", "contains-path": "^0.1.0", "debug": "^2.6.8", "doctrine": "1.5.0", "eslint-import-resolver-node": "^0.3.1", - "eslint-module-utils": "^2.1.1", + "eslint-module-utils": "^2.2.0", "has": "^1.0.1", - "lodash.cond": "^4.3.0", + "lodash": "^4.17.4", "minimatch": "^3.0.3", - "read-pkg-up": "^2.0.0" + "read-pkg-up": "^2.0.0", + "resolve": "^1.6.0" }, "dependencies": { "debug": { @@ -1348,7 +1297,7 @@ }, "doctrine": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "resolved": "http://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", "dev": true, "requires": { @@ -1365,51 +1314,60 @@ } }, "eslint-plugin-node": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-6.0.1.tgz", - "integrity": "sha512-Q/Cc2sW1OAISDS+Ji6lZS2KV4b7ueA/WydVWd1BECTQwVvfQy5JAi3glhINoKzoMnfnuRgNP+ZWKrGAbp3QDxw==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-7.0.1.tgz", + "integrity": "sha512-lfVw3TEqThwq0j2Ba/Ckn2ABdwmL5dkOgAux1rvOk6CO7A6yGyPI2+zIxN6FyNkp1X1X/BSvKOceD6mBWSj4Yw==", "dev": true, "requires": { - "ignore": "^3.3.6", + "eslint-plugin-es": "^1.3.1", + "eslint-utils": "^1.3.1", + "ignore": "^4.0.2", "minimatch": "^3.0.4", - "resolve": "^1.3.3", - "semver": "^5.4.1" + "resolve": "^1.8.1", + "semver": "^5.5.0" } }, "eslint-plugin-promise": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.6.0.tgz", - "integrity": "sha512-YQzM6TLTlApAr7Li8vWKR+K3WghjwKcYzY0d2roWap4SLK+kzuagJX/leTetIDWsFcTFnKNJXWupDCD6aZkP2Q==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.0.1.tgz", + "integrity": "sha512-Si16O0+Hqz1gDHsys6RtFRrW7cCTB6P7p3OJmKp3Y3dxpQE2qwOA7d3xnV+0mBmrPoi0RBnxlCKvqu70te6wjg==", "dev": true }, "eslint-plugin-react": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.6.1.tgz", - "integrity": "sha512-30aMOHWX/DOaaLJVBHz6RMvYM2qy5GH63+y2PLFdIrYe4YLtODFmT3N1YA7ZqUnaBweVbedr4K4cqxOlWAPjIw==", + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.11.1.tgz", + "integrity": "sha512-cVVyMadRyW7qsIUh3FHp3u6QHNhOgVrLQYdQEB1bPWBsgbNCHdFAeNMquBMCcZJu59eNthX053L70l7gRt4SCw==", "dev": true, "requires": { - "doctrine": "^2.0.2", - "has": "^1.0.1", + "array-includes": "^3.0.3", + "doctrine": "^2.1.0", + "has": "^1.0.3", "jsx-ast-utils": "^2.0.1", - "prop-types": "^15.6.0" + "prop-types": "^15.6.2" } }, "eslint-plugin-standard": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz", - "integrity": "sha1-NNDJFbRe3G8BA5PH7vOCOwhWXPI=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.0.0.tgz", + "integrity": "sha512-OwxJkR6TQiYMmt1EsNRMe5qG3GsbjlcOhbGUBY4LtavF9DsLaTcoR+j2Tdjqi23oUwKNUqX7qcn5fPStafMdlA==", "dev": true }, "eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", + "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", "dev": true, "requires": { "esrecurse": "^4.1.0", "estraverse": "^4.1.1" } }, + "eslint-utils": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", + "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", + "dev": true + }, "eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", @@ -1417,13 +1375,14 @@ "dev": true }, "espree": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-4.1.0.tgz", + "integrity": "sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w==", "dev": true, "requires": { - "acorn": "^5.5.0", - "acorn-jsx": "^3.0.0" + "acorn": "^6.0.2", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" } }, "esprima": { @@ -1698,9 +1657,9 @@ "dev": true }, "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", "dev": true }, "fast-json-stable-stringify": { @@ -1739,7 +1698,7 @@ }, "deep-eql": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "resolved": "http://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", "dev": true, "requires": { @@ -1875,9 +1834,9 @@ } }, "fined": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.1.0.tgz", - "integrity": "sha1-s33IRLdqL15wgeiE98CuNE8VNHY=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.1.1.tgz", + "integrity": "sha512-jQp949ZmEbiYHk3gkbdtpJ0G1+kgtLQBNdP5edFP7Fh+WAYceLQz6yO1SBj72Xkg8GVyTB3bBzAYrHJVh5Xd5g==", "dev": true, "requires": { "expand-tilde": "^2.0.2", @@ -1888,20 +1847,20 @@ } }, "flagged-respawn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.0.tgz", - "integrity": "sha1-Tnmumy6zi/hrO7Vr8+ClaqX8q9c=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", "dev": true }, "flat-cache": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", - "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", "dev": true, "requires": { "circular-json": "^0.3.1", - "del": "^2.0.2", "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", "write": "^0.2.1" } }, @@ -1927,25 +1886,14 @@ "dev": true }, "form-data": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "dev": true, "requires": { "asynckit": "^0.4.0", - "combined-stream": "1.0.6", + "combined-stream": "^1.0.6", "mime-types": "^2.1.12" - }, - "dependencies": { - "combined-stream": { - "version": "1.0.6", - "resolved": "http://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - } } }, "forwarded": { @@ -2023,7 +1971,7 @@ }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { @@ -2105,24 +2053,10 @@ "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", "dev": true }, - "globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", "dev": true }, "growl": { @@ -2167,12 +2101,12 @@ "dev": true }, "har-validator": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", - "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "dev": true, "requires": { - "ajv": "^5.3.0", + "ajv": "^6.5.5", "har-schema": "^2.0.0" } }, @@ -2298,9 +2232,9 @@ } }, "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, "ignore-walk": { @@ -2341,22 +2275,21 @@ "dev": true }, "inquirer": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", - "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "version": "5.2.0", + "resolved": "http://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz", + "integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==", "dev": true, "requires": { "ansi-escapes": "^3.0.0", "chalk": "^2.0.0", "cli-cursor": "^2.1.0", "cli-width": "^2.0.0", - "external-editor": "^2.0.4", + "external-editor": "^2.1.0", "figures": "^2.0.0", "lodash": "^4.3.0", "mute-stream": "0.0.7", "run-async": "^2.2.0", - "rx-lite": "^4.0.8", - "rx-lite-aggregates": "^4.0.8", + "rxjs": "^5.5.2", "string-width": "^2.1.0", "strip-ansi": "^4.0.0", "through": "^2.3.6" @@ -2447,7 +2380,7 @@ }, "is-accessor-descriptor": { "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", "dev": true, "requires": { @@ -2494,7 +2427,7 @@ }, "is-data-descriptor": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { @@ -2593,30 +2526,6 @@ } } }, - "is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", - "dev": true - }, - "is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", - "dev": true, - "requires": { - "is-path-inside": "^1.0.0" - } - }, - "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "dev": true, - "requires": { - "path-is-inside": "^1.0.1" - } - }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -2870,7 +2779,7 @@ }, "jsesc": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", "dev": true }, @@ -2887,9 +2796,9 @@ "dev": true }, "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, "json-stable-stringify-without-jsonify": { @@ -2932,9 +2841,9 @@ "dev": true }, "knex": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/knex/-/knex-0.16.0.tgz", - "integrity": "sha512-+TiL02P00GEmdwpKRfgOaRGaI29KeTcvAT7os1jeWMPMnzu8g/C3O4CZ1LXtLo5V1oatUzJcPKBqWATPgS20ng==", + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/knex/-/knex-0.16.2.tgz", + "integrity": "sha512-ZNhwIV8LasmMlEOmZQVCVcGw6CGk2nynmO4uSBkzD0IZveGignUAMdEmrLbrGbK4DhrFRtDGKPCmGHdsKE0bQw==", "dev": true, "requires": { "@babel/polyfill": "^7.0.0", @@ -2964,12 +2873,6 @@ "color-convert": "^1.9.0" } }, - "bluebird": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", - "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==", - "dev": true - }, "chalk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", @@ -3080,12 +2983,6 @@ "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", "dev": true }, - "lodash.cond": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz", - "integrity": "sha1-9HGh2khr5g9quVXRcRVSPdHSVdU=", - "dev": true - }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -3095,16 +2992,6 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, - "lru-cache": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", - "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, "make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", @@ -3131,7 +3018,7 @@ }, "media-typer": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", "dev": true }, @@ -3175,18 +3062,18 @@ "dev": true }, "mime-db": { - "version": "1.36.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", - "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==", + "version": "1.37.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", + "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==", "dev": true }, "mime-types": { - "version": "2.1.20", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", - "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", + "version": "2.1.21", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", + "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", "dev": true, "requires": { - "mime-db": "~1.36.0" + "mime-db": "~1.37.0" } }, "mimic-fn": { @@ -3211,27 +3098,19 @@ "dev": true }, "minipass": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.4.tgz", - "integrity": "sha512-mlouk1OHlaUE8Odt1drMtG1bAJA4ZA6B/ehysgV0LUIrDHdKgo1KorZq3pK0b/7Z7LJIQ12MNM6aC+Tn6lUZ5w==", + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", + "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", "dev": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" - }, - "dependencies": { - "yallist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", - "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", - "dev": true - } } }, "minizlib": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.1.tgz", - "integrity": "sha512-TrfjCjk4jLhcJyGMYymBH6oTXcWjYbUAXTHDbtnWHjZC25h0cdajHuPE1zxb4DVmu8crfh+HwH/WMuyLG0nHBg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", + "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", "dev": true, "requires": { "minipass": "^2.2.1" @@ -3414,6 +3293,12 @@ "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", "dev": true }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, "node-pre-gyp": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz", @@ -3649,13 +3534,13 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, @@ -3742,7 +3627,7 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, @@ -3752,6 +3637,12 @@ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", "dev": true }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", @@ -3808,7 +3699,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, @@ -3927,9 +3818,9 @@ "dev": true }, "progress": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", - "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, "prop-types": { @@ -3952,22 +3843,16 @@ "ipaddr.js": "1.8.0" } }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true - }, "psl": { - "version": "1.1.29", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", - "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==", + "version": "1.1.31", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", + "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==", "dev": true }, "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, "qs": { @@ -4086,6 +3971,12 @@ "safe-regex": "^1.1.0" } }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, "repeat-element": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", @@ -4158,7 +4049,7 @@ }, "require-uncached": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "resolved": "http://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", "dev": true, "requires": { @@ -4237,19 +4128,13 @@ "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", "dev": true }, - "rx-lite": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", - "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", - "dev": true - }, - "rx-lite-aggregates": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", - "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "rxjs": { + "version": "5.5.12", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", + "integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", "dev": true, "requires": { - "rx-lite": "*" + "symbol-observable": "1.0.1" } }, "safe-buffer": { @@ -4260,7 +4145,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { @@ -4280,21 +4165,21 @@ "dev": true }, "semistandard": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/semistandard/-/semistandard-12.0.1.tgz", - "integrity": "sha512-+FBRXBCi8GC1Nivc4ruw2KXER31bE1lrNyESo7prn2Sv9I9+H/Iqpt0NOtlV/GUxq34AgJwJViBUpA3/PUGqOw==", + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/semistandard/-/semistandard-13.0.1.tgz", + "integrity": "sha512-2GkuX4BsoMEYoufJYRz8/ERbYDfgOO3yP29IBaoXtxl202azlkV1MsFyoSFiM6GBUfL7MSUxSy38KfM9oDAE2g==", "dev": true, "requires": { - "eslint": "~4.18.0", - "eslint-config-semistandard": "12.0.1", - "eslint-config-standard": "11.0.0", - "eslint-config-standard-jsx": "5.0.0", - "eslint-plugin-import": "~2.8.0", - "eslint-plugin-node": "~6.0.0", - "eslint-plugin-promise": "~3.6.0", - "eslint-plugin-react": "~7.6.1", - "eslint-plugin-standard": "~3.0.1", - "standard-engine": "~8.0.0" + "eslint": "~5.4.0", + "eslint-config-semistandard": "13.0.0", + "eslint-config-standard": "12.0.0", + "eslint-config-standard-jsx": "6.0.2", + "eslint-plugin-import": "~2.14.0", + "eslint-plugin-node": "~7.0.1", + "eslint-plugin-promise": "~4.0.0", + "eslint-plugin-react": "~7.11.1", + "eslint-plugin-standard": "~4.0.0", + "standard-engine": "~10.0.0" } }, "semver": { @@ -4403,6 +4288,36 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, + "shelljs": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", + "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "shx": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.2.tgz", + "integrity": "sha512-aS0mWtW3T2sHAenrSrip2XGv39O9dXIFUqxAEWHEOS1ePtGIBavdPJY1kE2IHl14V/4iCbUiNDPGdyYTtmhSoA==", + "dev": true, + "requires": { + "es6-object-assign": "^1.0.3", + "minimist": "^1.2.0", + "shelljs": "^0.8.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -4566,9 +4481,9 @@ "dev": true }, "spdx-correct": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.2.tgz", - "integrity": "sha512-q9hedtzyXHr5S0A1vEPoK/7l8NpfkFYTq6iCY+Pno2ZbdZR6WexZFtqeVGkGxW3TEJMN914Z55EnAGMmenlIQQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -4592,9 +4507,9 @@ } }, "spdx-license-ids": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.1.tgz", - "integrity": "sha512-TfOfPcYGBB5sDuPn3deByxPhmfegAhpDYKSOXZQN81Oyrrif8ZCodOLzK3AesELnCx03kikhyDwh0pfvvQvF8w==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.2.tgz", + "integrity": "sha512-qky9CVt0lVIECkEsYbNILVnPvycuEBkXoMFLRWsREkomQLevYhtRKC+R91a5TOAQ3bCMjikRwhyaRqj1VYatYg==", "dev": true }, "split-string": { @@ -4608,14 +4523,14 @@ }, "sprintf-js": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "resolved": "http://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, "sqlite3": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.0.2.tgz", - "integrity": "sha512-51ferIRwYOhzUEtogqOa/y9supADlAht98bF/gbIi6WkzRJX6Yioldxbzj1MV4yV+LgdKD/kkHwFTeFXOG4htA==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.0.4.tgz", + "integrity": "sha512-CO8vZMyUXBPC+E3iXOCc7Tz2pAdq5BWfLcQmOokCOZW5S5sZ/paijiPOCdvzpdP83RroWHYa5xYlVqCxSqpnQg==", "dev": true, "requires": { "nan": "~2.10.0", @@ -4624,9 +4539,9 @@ } }, "sshpk": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.1.tgz", - "integrity": "sha512-mSdgNUaidk+dRU5MhYtN9zebdzF2iG0cNPWy8HG+W8y+fT1JnSkh0fzzpjOa0L7P8i1Rscz38t0h4gPcKz43xA==", + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.2.tgz", + "integrity": "sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==", "dev": true, "requires": { "asn1": "~0.2.3", @@ -4641,12 +4556,12 @@ } }, "standard-engine": { - "version": "8.0.1", - "resolved": "http://registry.npmjs.org/standard-engine/-/standard-engine-8.0.1.tgz", - "integrity": "sha512-LA531C3+nljom/XRvdW/hGPXwmilRkaRkENhO3FAGF1Vtq/WtCXzgmnc5S6vUHHsgv534MRy02C1ikMwZXC+tw==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-10.0.0.tgz", + "integrity": "sha512-91BjmzIRZbFmyOY73R6vaDd/7nw5qDWsfpJW5/N+BCXFgmvreyfrRg7oBSu4ihL0gFGXfnwCImJm6j+sZDQQyw==", "dev": true, "requires": { - "deglob": "^2.1.0", + "deglob": "^3.0.0", "get-stdin": "^6.0.0", "minimist": "^1.1.0", "pkg-conf": "^2.0.0" @@ -4722,7 +4637,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -4759,14 +4674,20 @@ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true }, + "symbol-observable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", + "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=", + "dev": true + }, "table": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", - "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "version": "4.0.3", + "resolved": "http://registry.npmjs.org/table/-/table-4.0.3.tgz", + "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==", "dev": true, "requires": { - "ajv": "^5.2.3", - "ajv-keywords": "^2.1.0", + "ajv": "^6.0.1", + "ajv-keywords": "^3.0.0", "chalk": "^2.1.0", "lodash": "^4.17.4", "slice-ansi": "1.0.0", @@ -4811,26 +4732,18 @@ } }, "tar": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.6.tgz", - "integrity": "sha512-tMkTnh9EdzxyfW+6GK6fCahagXsnYk6kE6S9Gr9pjVdys769+laCTbodXDhPAjzVtEBazRgP0gYqOjnk9dQzLg==", + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", + "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", "dev": true, "requires": { - "chownr": "^1.0.1", + "chownr": "^1.1.1", "fs-minipass": "^1.2.5", - "minipass": "^2.3.3", - "minizlib": "^1.1.0", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", "mkdirp": "^0.5.0", "safe-buffer": "^5.1.2", "yallist": "^3.0.2" - }, - "dependencies": { - "yallist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", - "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", - "dev": true - } } }, "tarn": { @@ -4925,6 +4838,14 @@ "requires": { "psl": "^1.1.24", "punycode": "^1.4.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } } }, "trim-right": { @@ -4973,12 +4894,6 @@ "mime-types": "~2.1.18" } }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, "uberproto": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/uberproto/-/uberproto-2.0.4.tgz", @@ -5097,6 +5012,15 @@ } } }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", @@ -5209,9 +5133,9 @@ "dev": true }, "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", "dev": true } } diff --git a/package.json b/package.json index f351129..d595d23 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "mocha": "mocha --opts mocha.opts", "test": "npm run lint && npm run coverage", "example": "babel-node example/app", - "coverage": "istanbul cover node_modules/mocha/bin/_mocha -- --opts mocha.opts" + "coverage": "shx rm *.sqlite && istanbul cover node_modules/mocha/bin/_mocha -- --opts mocha.opts" }, "semistandard": { "env": [ @@ -51,26 +51,24 @@ "lib": "lib" }, "dependencies": { - "@feathersjs/commons": "^1.4.1", - "@feathersjs/errors": "^3.3.4", + "@feathersjs/adapter-commons": "^1.0.2", + "@feathersjs/commons": "^4.0.0", + "@feathersjs/errors": "^3.3.5", "debug": "^4.1.0", "is-plain-object": "^2.0.4", "uberproto": "^2.0.4" }, - "peerDependencies": { - "knex": "^0.15.2" - }, "devDependencies": { - "@feathersjs/express": "^1.2.7", - "@feathersjs/feathers": "^3.2.3", + "@feathersjs/express": "^1.3.0", + "@feathersjs/feathers": "^3.3.0", "body-parser": "^1.18.3", "chai": "^4.2.0", "chai-as-promised": "^7.1.1", - "feathers-service-tests": "^0.10.2", "istanbul": "^1.1.0-alpha.1", - "knex": "^0.16.0", + "knex": "^0.16.2", "mocha": "^5.2.0", - "semistandard": "^12.0.1", - "sqlite3": "^4.0.2" + "semistandard": "^13.0.1", + "shx": "^0.3.2", + "sqlite3": "^4.0.4" } } diff --git a/test/index.test.js b/test/index.test.js index b2746e4..8a642e7 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -1,13 +1,72 @@ const chai = require('chai'); const chaiAsPromised = require('chai-as-promised'); -const assert = require('assert'); const feathers = require('@feathersjs/feathers'); const knex = require('knex'); -const { base } = require('feathers-service-tests'); +const adapterTests = require('@feathersjs/adapter-commons/tests'); const errors = require('@feathersjs/errors'); const service = require('../lib'); +const testSuite = adapterTests([ + '.options', + '.events', + '._get', + '._find', + '._create', + '._update', + '._patch', + '._remove', + '.get', + '.get + $select', + '.get + id + query', + '.get + NotFound', + '.find', + '.remove', + '.remove + $select', + '.remove + id + query', + '.remove + multi', + '.update', + '.update + $select', + '.update + id + query', + '.update + NotFound', + '.patch', + '.patch + $select', + '.patch + id + query', + '.patch multiple', + '.patch multi query', + '.patch + NotFound', + '.create', + '.create + $select', + '.create multi', + 'internal .find', + 'internal .get', + 'internal .create', + 'internal .update', + 'internal .patch', + 'internal .remove', + '.find + equal', + '.find + equal multiple', + '.find + $sort', + '.find + $sort + string', + '.find + $limit', + '.find + $limit 0', + '.find + $skip', + '.find + $select', + '.find + $or', + '.find + $in', + '.find + $nin', + '.find + $lt', + '.find + $lte', + '.find + $gt', + '.find + $gte', + '.find + $ne', + '.find + $gt + $lt + $sort', + '.find + $or nested + $sort', + '.find + paginate', + '.find + paginate + $limit + $skip', + '.find + paginate + $limit 0', + '.find + paginate + params' +]); chai.use(chaiAsPromised); const { expect } = chai; @@ -63,7 +122,7 @@ function clean () { }); }), db.schema.dropTableIfExists(peopleId.fullName).then(() => { - return peopleId.init({}, (table) => { + return peopleId.init({}, table => { table.increments('customid'); table.string('name'); table.integer('age'); @@ -73,7 +132,7 @@ function clean () { }); }), db.schema.dropTableIfExists(users.fullName).then(() => { - return users.init({}, (table) => { + return users.init({}, table => { table.increments('id'); table.string('name'); table.integer('age'); @@ -114,6 +173,7 @@ describe('Feathers Knex Service', () => { .use('/people', people) .use('people-customid', peopleId) .use('/users', users); + const peopleService = app.service('people'); before(attachSchema); before(clean); @@ -123,7 +183,7 @@ describe('Feathers Knex Service', () => { describe('when missing options', () => { it('throws an error', () => expect(service.bind(null)) - .to.throw('Knex options have to be provided') + .to.throw('You must provide a Model (the initialized knex object)') ); }); @@ -142,19 +202,6 @@ describe('Feathers Knex Service', () => { }); }); - describe('Common functionality', () => { - it('is CommonJS compatible', () => - assert.equal(typeof require('../lib'), 'function') - ); - - base(app, errors, 'people'); - base(app, errors, 'people-customid', 'customid'); - - describe('database schema support', () => { - base(app, errors, 'users'); - }); - }); - describe('custom queries', () => { before(clean); before(() => { @@ -180,43 +227,57 @@ describe('Feathers Knex Service', () => { app.service('people').hooks({}); app.service('users').hooks({}); }); + }); - base(app, errors, 'people'); + describe('$like method', () => { + let charlie; - describe('database schema support', () => { - base(app, errors, 'users'); + beforeEach(async () => { + charlie = await peopleService.create({ + name: 'Charlie Brown', + age: 10 + }); }); - }); - describe('$like method', () => { - beforeEach(() => app.service('/people').create({ - name: 'Charlie Brown', - age: 10 - })); + afterEach(() => peopleService.remove(charlie.id)); - it('$like in query', () => { - return app.service('/people').find({ + it('$like in query', async () => { + const data = await peopleService.find({ query: { name: { $like: '%lie%' } } - }).then(data => { - expect(data[0].name).to.be.equal('Charlie Brown'); }); + + expect(data[0].name).to.be.equal('Charlie Brown'); }); }); describe('adapter specifics', () => { - it('$or works properly (#120)', () => { - app.service('/people').create([{ - name: 'Dave', - age: 23 - }, { - name: 'Dave', - age: 32 - }, { - name: 'Dada', - age: 1 - }]); - - return app.service('/people').find({ + let daves; + + beforeEach(async () => { + daves = await Promise.all([ + peopleService.create({ + name: 'Ageless', + age: null + }), + peopleService.create({ + name: 'Dave', + age: 32 + }), + peopleService.create({ + name: 'Dada', + age: 1 + }) + ]); + }); + + afterEach(async () => Promise.all([ + peopleService.remove(daves[0].id), + peopleService.remove(daves[1].id), + peopleService.remove(daves[2].id) + ]).catch(() => {})); + + it('$or works properly (#120)', async () => { + const data = await peopleService.find({ query: { name: 'Dave', $or: [{ @@ -225,133 +286,73 @@ describe('Feathers Knex Service', () => { age: 32 }] } - }).then(data => { - expect(data.length).to.equal(1); - expect(data[0].name).to.be.equal('Dave'); - expect(data[0].age).to.be.equal(32); - app.service('/people').remove(null); }); + + expect(data.length).to.equal(1); + expect(data[0].name).to.be.equal('Dave'); + expect(data[0].age).to.be.equal(32); }); - it('$and works properly', () => { - app.service('/people').create([{ - name: 'Dave', - age: 23 - }, { - name: 'Dave', - age: 32 - }, { - name: 'Dada', - age: 1 - }]); - - return app.service('/people').find({ + it('$and works properly', async () => { + const data = await peopleService.find({ query: { $and: [{ $or: [ - {name: 'Dave'}, - {name: 'Dada'} + { name: 'Dave' }, + { name: 'Dada' } ] }, { - age: {$lt: 23} + age: { $lt: 23 } }] } - }).then(data => { - expect(data.length).to.equal(1); - expect(data[0].name).to.be.equal('Dada'); - expect(data[0].age).to.be.equal(1); - app.service('/people').remove(null); }); + + expect(data.length).to.equal(1); + expect(data[0].name).to.be.equal('Dada'); + expect(data[0].age).to.be.equal(1); }); - it('where conditions support NULL values properly', () => { - app.service('/people').create([{ - name: 'Dave without age', - age: null - }, { - name: 'Dave', - age: 32 - }, { - name: 'Dada', - age: 1 - }]); - - return app.service('/people').find({ + it('where conditions support NULL values properly', async () => { + const data = await peopleService.find({ query: { age: null } - }).then(data => { - expect(data.length).to.equal(1); - expect(data[0].name).to.be.equal('Dave without age'); - expect(data[0].age).to.be.equal(null); - app.service('/people').remove(null); }); + + expect(data.length).to.equal(1); + expect(data[0].name).to.be.equal('Ageless'); + expect(data[0].age).to.be.equal(null); }); - it('where conditions support NOT NULL case properly', () => { - app.service('/people').create([{ - name: 'Dave without age', - age: null - }, { - name: 'Dave', - age: 32 - }, { - name: 'Dada', - age: 1 - }]); - - return app.service('/people').find({ + it('where conditions support NOT NULL case properly', async () => { + const data = await peopleService.find({ query: { - age: {$ne: null} + age: { $ne: null } } - }).then(data => { - expect(data.length).to.equal(2); - expect(data[0].name).to.not.be.equal('Dave without age'); - expect(data[0].age).to.not.be.equal(null); - expect(data[1].name).to.not.be.equal('Dave without age'); - expect(data[1].age).to.not.be.equal(null); - app.service('/people').remove(null); }); + + expect(data.length).to.equal(2); + expect(data[0].name).to.not.be.equal('Ageless'); + expect(data[0].age).to.not.be.equal(null); + expect(data[1].name).to.not.be.equal('Ageless'); + expect(data[1].age).to.not.be.equal(null); }); - it('where conditions support NULL values within AND conditions', () => { - app.service('/people').create([{ - name: 'Dave', - age: null - }, { - name: 'Dave', - age: 32 - }, { - name: 'Dada', - age: 1 - }]); - - return app.service('/people').find({ + it('where conditions support NULL values within AND conditions', async () => { + const data = await peopleService.find({ query: { age: null, - name: 'Dave' + name: 'Ageless' } - }).then(data => { - expect(data.length).to.equal(1); - expect(data[0].name).to.be.equal('Dave'); - expect(data[0].age).to.be.equal(null); - app.service('/people').remove(null); }); + + expect(data.length).to.equal(1); + expect(data[0].name).to.be.equal('Ageless'); + expect(data[0].age).to.be.equal(null); }); - it('where conditions support NULL values within OR conditions', () => { - app.service('/people').create([{ - name: 'Dave without age', - age: null - }, { - name: 'Dave', - age: 32 - }, { - name: 'Dada', - age: 1 - }]); - - return app.service('/people').find({ + it('where conditions support NULL values within OR conditions', async () => { + const data = await peopleService.find({ query: { $or: [ { @@ -362,14 +363,13 @@ describe('Feathers Knex Service', () => { } ] } - }).then(data => { - expect(data.length).to.equal(2); - expect(data[0].name).not.be.equal('Dave'); - expect(data[0].age).not.be.equal(32); - expect(data[1].name).not.be.equal('Dave'); - expect(data[1].age).not.be.equal(32); - app.service('/people').remove(null); }); + + expect(data.length).to.equal(2); + expect(data[0].name).not.be.equal('Dave'); + expect(data[0].age).not.be.equal(32); + expect(data[1].name).not.be.equal('Dave'); + expect(data[1].age).not.be.equal(32); }); }); @@ -394,8 +394,12 @@ describe('Feathers Knex Service', () => { it('does fail on unsuccessful commit', () => { return expect( - app2.service('/people').create({name: 'Foo'}) + app2.service('/people').create({ name: 'Foo' }) ).to.eventually.be.rejected; }); }); + + // testSuite(app, errors, 'users'); + testSuite(app, errors, 'people'); + // testSuite(app, errors, 'people-customid', 'customid'); }); From de28071ee161f79e94fb828177d0fb509a6696b0 Mon Sep 17 00:00:00 2001 From: David Luecke Date: Thu, 27 Dec 2018 14:06:03 -0800 Subject: [PATCH 2/5] Finalize refactoring to adapter-commons --- lib/hooks.js | 4 +- lib/index.js | 152 +++++++++++++++++++----------------------- package-lock.json | 163 ++++++++++++++++----------------------------- package.json | 5 +- test/index.test.js | 66 +++++------------- 5 files changed, 147 insertions(+), 243 deletions(-) diff --git a/lib/hooks.js b/lib/hooks.js index 4134b52..3ba50ca 100644 --- a/lib/hooks.js +++ b/lib/hooks.js @@ -33,7 +33,7 @@ const start = () => { }); }; -const end = (options) => { +const end = () => { return hook => { if (hook.params.transaction) { const { trx, id, count } = hook.params.transaction; @@ -53,7 +53,7 @@ const end = (options) => { }; }; -const rollback = (options) => { +const rollback = () => { return hook => { if (hook.params.transaction) { const { trx, id } = hook.params.transaction; diff --git a/lib/index.js b/lib/index.js index ffbce45..7859a04 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,3 +1,4 @@ +const { _ } = require('@feathersjs/commons'); const { AdapterService } = require('@feathersjs/adapter-commons'); const isPlainObject = require('is-plain-object'); const errors = require('@feathersjs/errors'); @@ -50,6 +51,10 @@ class Service extends AdapterService { return this.options.Model; } + get knex () { + return this.Model; + } + get fullName () { return this.schema ? `${this.schema}.${this.table}` : this.table; } @@ -112,8 +117,11 @@ class Service extends AdapterService { return query[method].call(query, column, value); } - return operator === '=' ? query.where(column, value) : query.where(column, operator, value); + return operator === '=' ? query.where(column, value) + : query.where(column, operator, value); }); + + return query; } createQuery (params = {}) { @@ -125,9 +133,8 @@ class Service extends AdapterService { q = q.withSchema(schema).from(`${table} as ${table}`); } - q = (filters.$select) - // $select uses a specific find syntax, so it has to come first. - ? q.select(...filters.$select.concat(`${table}.${id}`)) + // $select uses a specific find syntax, so it has to come first. + q = filters.$select ? q.select(...filters.$select.concat(`${table}.${id}`)) : q.select([`${table}.*`]); // build up the knex query out of the query params @@ -162,35 +169,28 @@ class Service extends AdapterService { } } - let executeQuery = total => { - return q.then(data => { - return { - total: parseInt(total, 10), - limit: filters.$limit, - skip: filters.$skip || 0, - data - }; - }); - }; + let executeQuery = total => q.then(data => { + return { + total: parseInt(total, 10), + limit: filters.$limit, + skip: filters.$skip || 0, + data + }; + }); if (filters.$limit === 0) { - executeQuery = total => { - return Promise.resolve({ - total: parseInt(total, 10), - limit: filters.$limit, - skip: filters.$skip || 0, - data: [] - }); - }; + executeQuery = total => Promise.resolve({ + total: parseInt(total, 10), + limit: filters.$limit, + skip: filters.$skip || 0, + data: [] + }); } if (paginate && paginate.default) { - let countQuery = - (params.knex || this.db(params)) - .clone() - .clearSelect() - .clearOrder() - .count(`${this.table}.${this.id} as total`); + let countQuery = (params.knex || this.db(params)) + .clone().clearSelect().clearOrder() + .count(`${this.table}.${this.id} as total`); if (!params.knex) { this.knexify(countQuery, query); @@ -204,11 +204,23 @@ class Service extends AdapterService { return executeQuery().then(page => page.data).catch(errorHandler); } - _get (id, params) { - return this._find(Object.assign({}, params, { + _findOrGet (id, params) { + const findParams = Object.assign({}, params, { paginate: false, - query: Object.assign({}, params.query, { [this.id]: id }) - })).then(data => { + query: Object.assign({}, params.query) + }); + + if (id === null) { + return this._find(findParams); + } + + findParams.query[this.id] = id; + + return this._find(findParams); + } + + _get (id, params) { + return this._findOrGet(id, params).then(data => { if (data.length !== 1) { throw new errors.NotFound(`No record found for id '${id}'`); } @@ -223,41 +235,26 @@ class Service extends AdapterService { } return this.db(params).insert(data, this.id).then(rows => { - const id = typeof data[this.id] !== 'undefined' ? data[this.id] : rows[0]; + const id = data[this.id] !== undefined ? data[this.id] : rows[0]; + return this._get(id, params); }).catch(errorHandler); } _patch (id, raw, params) { - const { query } = this.filterQuery(params); - const data = Object.assign({}, raw); - const mapIds = page => page.data.map(current => current[this.id]); - + // Do not allow to patch the id + const data = _.omit(raw, this.id); // By default we will just query for the one id. For multi patch // we create a list of the ids of all items that will be changed // to re-query them after the update - const ids = id === null ? this._find(params) - .then(mapIds) : Promise.resolve([ id ]); - - if (id !== null) { - query[this.id] = id; - } - - const q = this.db(params); - - this.knexify(q, query); - - delete data[this.id]; - - return ids.then(idList => { - // Create a new query that re-queries all ids that - // were originally changed + return this._findOrGet(id, Object.assign({}, params, { + query: _.extend({}, params.query, { $select: [ this.id ] }) + })).then(results => { + const idList = results.map(current => current[this.id]); + const query = { [this.id]: { $in: idList } }; + const q = this.knexify(this.db(params), query); const findParams = Object.assign({}, params, { - paginate: false, - query: { - [this.id]: { $in: idList }, - $select: params.query && params.query.$select - } + query: Object.assign({}, params.query, query) }); return q.update(data).then(() => { @@ -278,45 +275,32 @@ class Service extends AdapterService { _update (id, data, params) { return this._get(id, params).then(oldData => { - let newObject = {}; - - for (var key of Object.keys(oldData)) { - if (data[key] === undefined) { - newObject[key] = null; - } else { - newObject[key] = data[key]; + const newObject = Object.keys(oldData).reduce((result, key) => { + if (key !== this.id) { // We don't want the id field to be changed + result[key] = data[key] === undefined ? null : data[key]; } - } - // NOTE (EK): Delete id field so we don't update it - delete newObject[this.id]; + return result; + }, {}); - return this.db(params).update(newObject).where(this.id, id).then(() => { - // NOTE (EK): Restore the id field so we can return it to the client - newObject[this.id] = id; - return newObject; - }); + return this.db(params).update(newObject).where(this.id, id).then(() => + this._get(id, params) + ); }).catch(errorHandler); } _remove (id, params) { - const findParams = Object.assign({}, params, { - paginate: false, - query: Object.assign({}, params.query) - }); - - if (id !== null) { - findParams.query[this.id] = id; - } - - return this._find(findParams).then(items => { + return this._findOrGet(id, params).then(items => { const { query } = this.filterQuery(params); const q = this.db(params); + const idList = items.map(current => current[this.id]); + + query[this.id] = { $in: idList }; // build up the knex query out of the query params this.knexify(q, query); - return q.del().then(() => { + return q.del().then((...args) => { if (id !== null) { if (items.length === 1) { return items[0]; diff --git a/package-lock.json b/package-lock.json index 58f2f45..124da01 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,19 +5,27 @@ "requires": true, "dependencies": { "@babel/polyfill": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.0.0.tgz", - "integrity": "sha512-dnrMRkyyr74CRelJwvgnnSUDh2ge2NCTyHVwpOdvRMHtJUyxLtMAfhBN3s64pY41zdw0kgiLPh6S20eb1NcX6Q==", + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.2.5.tgz", + "integrity": "sha512-8Y/t3MWThtMLYr0YNC/Q76tqN1w30+b0uQMeFUYauG2UGTR19zyUtFrAzT23zNtBxPp+LbE5E/nwV/q/r3y6ug==", "dev": true, "requires": { "core-js": "^2.5.7", - "regenerator-runtime": "^0.11.1" + "regenerator-runtime": "^0.12.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", + "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==", + "dev": true + } } }, "@feathersjs/adapter-commons": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@feathersjs/adapter-commons/-/adapter-commons-1.0.2.tgz", - "integrity": "sha512-nee7PEE/mEx/iofcTALvMO7gj6SC6gzKdH3xorwHMKQi9z82aI3PLvgTgC3+4B0UwCSZ1gthSUJIl8K093P4Ug==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@feathersjs/adapter-commons/-/adapter-commons-1.0.6.tgz", + "integrity": "sha512-Qp5h0QP8CpHWBZttCV5vp8C8jrylSd7fqt2WlFwnWL8HLa1CVZOuKw77TaB4u7RPYOljFwp/3OxKDwl/WzVD7g==", "requires": { "@feathersjs/commons": "^4.0.0", "@feathersjs/errors": "^3.3.5" @@ -61,6 +69,12 @@ "uberproto": "^2.0.2" } }, + "@types/bluebird": { + "version": "3.5.25", + "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.25.tgz", + "integrity": "sha512-yfhIBix+AIFTmYGtkC0Bi+XGjSkOINykqKvO/Wqdz/DuXlAKK7HmhLAXdPIGsV4xzKcL3ev/zYc4yLNo+OvGaw==", + "dev": true + }, "abbrev": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", @@ -756,7 +770,7 @@ }, "content-disposition": { "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "resolved": "http://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", "dev": true }, @@ -785,9 +799,9 @@ "dev": true }, "core-js": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.0.tgz", - "integrity": "sha512-kLRC6ncVpuEW/1kwrOXYX6KQASCVtrh1gQr/UiaVgFlf9WE5Vp+lNe5+h3LuMr5PAucWnnEXwH0nQHRH/gpGtw==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.1.tgz", + "integrity": "sha512-L72mmmEayPJBejKIWe2pYtGis5r0tQ5NaJekdhyXgeMQTpJoBsH0NL4ElY2LfSoV15xeQWKQ+XTTOZdyero5Xg==", "dev": true }, "core-util-is": { @@ -819,9 +833,9 @@ } }, "debug": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", - "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "requires": { "ms": "^2.1.1" } @@ -1674,53 +1688,6 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, - "feathers-service-tests": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/feathers-service-tests/-/feathers-service-tests-0.10.2.tgz", - "integrity": "sha1-Pdt/ZoiZqGD5UH8OlU4jY4PlKQQ=", - "dev": true, - "requires": { - "chai": "^3.4.0", - "request": "^2.75.0", - "request-promise": "^4.0.0" - }, - "dependencies": { - "chai": { - "version": "3.5.0", - "resolved": "http://registry.npmjs.org/chai/-/chai-3.5.0.tgz", - "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", - "dev": true, - "requires": { - "assertion-error": "^1.0.1", - "deep-eql": "^0.1.3", - "type-detect": "^1.0.0" - } - }, - "deep-eql": { - "version": "0.1.3", - "resolved": "http://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", - "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", - "dev": true, - "requires": { - "type-detect": "0.1.1" - }, - "dependencies": { - "type-detect": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", - "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", - "dev": true - } - } - }, - "type-detect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", - "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=", - "dev": true - } - } - }, "figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", @@ -2841,12 +2808,13 @@ "dev": true }, "knex": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/knex/-/knex-0.16.2.tgz", - "integrity": "sha512-ZNhwIV8LasmMlEOmZQVCVcGw6CGk2nynmO4uSBkzD0IZveGignUAMdEmrLbrGbK4DhrFRtDGKPCmGHdsKE0bQw==", + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/knex/-/knex-0.16.3.tgz", + "integrity": "sha512-jGTOBW8b7exaBPfCKJSlv5q320IvWw9hEdtnURtbb0k3HusfZrR4UYiEewem8Nl7VqJILoCj99SjCK3W54UNPg==", "dev": true, "requires": { "@babel/polyfill": "^7.0.0", + "@types/bluebird": "^3.5.25", "bluebird": "^3.5.3", "chalk": "2.4.1", "commander": "^2.19.0", @@ -2890,6 +2858,15 @@ "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", "dev": true }, + "debug": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", + "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -4026,27 +4003,6 @@ "uuid": "^3.3.2" } }, - "request-promise": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.2.tgz", - "integrity": "sha1-0epG1lSm7k+O5qT+oQGMIpEZBLQ=", - "dev": true, - "requires": { - "bluebird": "^3.5.0", - "request-promise-core": "1.1.1", - "stealthy-require": "^1.1.0", - "tough-cookie": ">=2.3.3" - } - }, - "request-promise-core": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", - "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", - "dev": true, - "requires": { - "lodash": "^4.13.1" - } - }, "require-uncached": { "version": "1.0.3", "resolved": "http://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", @@ -4058,12 +4014,12 @@ } }, "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.9.0.tgz", + "integrity": "sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ==", "dev": true, "requires": { - "path-parse": "^1.0.5" + "path-parse": "^1.0.6" } }, "resolve-dir": { @@ -4507,9 +4463,9 @@ } }, "spdx-license-ids": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.2.tgz", - "integrity": "sha512-qky9CVt0lVIECkEsYbNILVnPvycuEBkXoMFLRWsREkomQLevYhtRKC+R91a5TOAQ3bCMjikRwhyaRqj1VYatYg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", + "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==", "dev": true }, "split-string": { @@ -4539,9 +4495,9 @@ } }, "sshpk": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.2.tgz", - "integrity": "sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.0.tgz", + "integrity": "sha512-Zhev35/y7hRMcID/upReIvRse+I9SVhyVre/KTJSJQWMz3C3+G+HpO7m1wK/yckEtujKZ7dS4hkVxAnmHaIGVQ==", "dev": true, "requires": { "asn1": "~0.2.3", @@ -4602,12 +4558,6 @@ "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", "dev": true }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true - }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -4670,7 +4620,7 @@ }, "supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "resolved": "http://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true }, @@ -4897,7 +4847,8 @@ "uberproto": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/uberproto/-/uberproto-2.0.4.tgz", - "integrity": "sha512-c/5xjTcztW9XVhrkCycHQRBIAxww5JpDKk/q0zc2tVdQn6ZQvnChWgLvQaWAT1Al5JvRyvloUI15ad41m6dYwg==" + "integrity": "sha512-c/5xjTcztW9XVhrkCycHQRBIAxww5JpDKk/q0zc2tVdQn6ZQvnChWgLvQaWAT1Al5JvRyvloUI15ad41m6dYwg==", + "dev": true }, "uglify-js": { "version": "3.4.9", @@ -5052,9 +5003,9 @@ "dev": true }, "v8flags": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.1.tgz", - "integrity": "sha512-iw/1ViSEaff8NJ3HLyEjawk/8hjJib3E7pvG4pddVXfUg1983s3VGsiClDjhK64MQVDGqc1Q8r18S4VKQZS9EQ==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.2.tgz", + "integrity": "sha512-MtivA7GF24yMPte9Rp/BWGCYQNaUj86zeYxV/x2RRJMKagImbbv3u8iJC57lNhWLPcGLJmHcHmFWkNsplbbLWw==", "dev": true, "requires": { "homedir-polyfill": "^1.0.1" diff --git a/package.json b/package.json index d595d23..b802320 100644 --- a/package.json +++ b/package.json @@ -51,12 +51,11 @@ "lib": "lib" }, "dependencies": { - "@feathersjs/adapter-commons": "^1.0.2", + "@feathersjs/adapter-commons": "^1.0.6", "@feathersjs/commons": "^4.0.0", "@feathersjs/errors": "^3.3.5", "debug": "^4.1.0", - "is-plain-object": "^2.0.4", - "uberproto": "^2.0.4" + "is-plain-object": "^2.0.4" }, "devDependencies": { "@feathersjs/express": "^1.3.0", diff --git a/test/index.test.js b/test/index.test.js index 8a642e7..e255a65 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -149,20 +149,6 @@ function attachSchema () { return db.schema.raw(`attach database '${schemaName}.sqlite' as ${schemaName}`); } -function customQuery () { - return (context) => { - const { params, service } = context; - const query = service.createQuery(params); - - // do something with query here - query.orderBy('name', 'desc'); - // console.log(query.toSQL().toNative()); - - context.params.knex = query; - return context; - }; -} - describe('Feathers Knex Service', () => { const app = feathers() .hooks({ @@ -202,33 +188,6 @@ describe('Feathers Knex Service', () => { }); }); - describe('custom queries', () => { - before(clean); - before(() => { - app.hooks({}); - app.service('people').hooks({ - before: { - find: customQuery() - } - }); - app.service('users').hooks({ - before: { - find: customQuery() - } - }); - }); - after(clean); - after(() => { - app.hooks({ - before: transaction.start(), - after: transaction.end(), - error: transaction.rollback() - }); - app.service('people').hooks({}); - app.service('users').hooks({}); - }); - }); - describe('$like method', () => { let charlie; @@ -374,6 +333,12 @@ describe('Feathers Knex Service', () => { }); describe('hooks', () => { + const people2 = service({ + Model: db, + name: 'people2', + events: [ 'testing' ] + }); + const app2 = feathers() .hooks({ before: transaction.start(), @@ -390,16 +355,21 @@ describe('Feathers Knex Service', () => { ], error: transaction.rollback() }) - .use('/people', people); + .use('/people', people2); + + it('does fail on unsuccessful commit', async () => { + const message = 'Should never get here'; - it('does fail on unsuccessful commit', () => { - return expect( - app2.service('/people').create({ name: 'Foo' }) - ).to.eventually.be.rejected; + try { + await app2.service('/people').create({ name: 'Foo' }); + throw new Error(message); + } catch (error) { + expect(error.message !== message); + } }); }); - // testSuite(app, errors, 'users'); + testSuite(app, errors, 'users'); testSuite(app, errors, 'people'); - // testSuite(app, errors, 'people-customid', 'customid'); + testSuite(app, errors, 'people-customid', 'customid'); }); From bc583f4182108646b84874b918a717112ba4a1b8 Mon Sep 17 00:00:00 2001 From: David Luecke Date: Thu, 27 Dec 2018 14:15:36 -0800 Subject: [PATCH 3/5] Force remove to always work --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b802320..02387b5 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "mocha": "mocha --opts mocha.opts", "test": "npm run lint && npm run coverage", "example": "babel-node example/app", - "coverage": "shx rm *.sqlite && istanbul cover node_modules/mocha/bin/_mocha -- --opts mocha.opts" + "coverage": "shx -rf rm *.sqlite && istanbul cover node_modules/mocha/bin/_mocha -- --opts mocha.opts" }, "semistandard": { "env": [ From 212d817db04cb73a58dc0306cb97b3f9931f56a3 Mon Sep 17 00:00:00 2001 From: David Luecke Date: Thu, 27 Dec 2018 14:23:57 -0800 Subject: [PATCH 4/5] Command typo --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 02387b5..6bb3701 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "mocha": "mocha --opts mocha.opts", "test": "npm run lint && npm run coverage", "example": "babel-node example/app", - "coverage": "shx -rf rm *.sqlite && istanbul cover node_modules/mocha/bin/_mocha -- --opts mocha.opts" + "coverage": "shx rm -rf *.sqlite && istanbul cover node_modules/mocha/bin/_mocha -- --opts mocha.opts" }, "semistandard": { "env": [ From 06fedde3082f20b7a0a7a391cf0dd68fcb2df62e Mon Sep 17 00:00:00 2001 From: David Luecke Date: Fri, 28 Dec 2018 10:57:40 -0800 Subject: [PATCH 5/5] Update error handling and finalize docs --- README.md | 20 ++++++++++++++- lib/error-handler.js | 58 +++++++++++++++++++++----------------------- lib/index.js | 7 ++++-- test/index.test.js | 12 ++++++++- 4 files changed, 62 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 1ca6ea1..4b5cfda 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,8 @@ __Options:__ - `id` (*optional*, default: `'id'`) - The name of the id field property. - `events` (*optional*) - A list of [custom service events](https://docs.feathersjs.com/api/events.html#custom-events) sent by this service - `paginate` (*optional*) - A [pagination object](https://docs.feathersjs.com/api/databases/common.html#pagination) containing a `default` and `max` page size +- `multi` (*optional*) - Allow `create` with arrays and `update` and `remove` with `id` `null` to change multiple items. Can be `true` for all methods or an array of allowed methods (e.g. `[ 'remove', 'create' ]`) +- `whitelist` (*optional*) - A list of additional query parameters to allow (e..g `[ '$regex', '$geoNear' ]`). Default is the supported `operators` ### `adapter.createQuery(query)` @@ -281,8 +283,24 @@ app.service('mesages').hooks({ }); ``` +### Error handling + +As of version 4.0.0 `feathers-knex` only throws [Feathers Errors](https://docs.feathersjs.com/api/errors.html) with the message. On the server, the original error can be retrieved through a secure symbol via `error[require('feathers-knex').ERROR]` + +```js +const { ERROR } = require('feathers-knex'); + +try { + await sequelizeService.doSomething(); +} catch(error) { + // error is a FeathersError with just the message + // Safely retrieve the Knex error + const knexError = error[ERROR]; +} +``` + ## License -Copyright (c) 2016 +Copyright (c) 2019 Licensed under the [MIT license](LICENSE). diff --git a/lib/error-handler.js b/lib/error-handler.js index c46467c..0aefe04 100644 --- a/lib/error-handler.js +++ b/lib/error-handler.js @@ -1,28 +1,25 @@ const errors = require('@feathersjs/errors'); +const ERROR = Symbol('feathers-knex/error'); module.exports = function errorHandler (error) { + const { message } = error; let feathersError = error; - // TODO (EK): Map PG, Oracle, etc. errors - - // NOTE: SQLState values from - // https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-error-sqlstates.html - if (error.sqlState && error.sqlState.length) { // remove SQLSTATE marker (#) and pad/truncate SQLSTATE to 5 chars - let sqlState = ('00000' + error.sqlState.replace('#', '')).slice(-5); + const sqlState = ('00000' + error.sqlState.replace('#', '')).slice(-5); switch (sqlState.slice(0, 2)) { case '02': - feathersError = new errors.NotFound(error); + feathersError = new errors.NotFound(message); break; case '28': - feathersError = new errors.Forbidden(error); + feathersError = new errors.Forbidden(message); break; case '08': case '0A': case '0K': - feathersError = new errors.Unavailable(error); + feathersError = new errors.Unavailable(message); break; case '20': case '21': @@ -33,44 +30,39 @@ module.exports = function errorHandler (error) { case '40': case '42': case '70': - feathersError = new errors.BadRequest(error); + feathersError = new errors.BadRequest(message); break; default: - feathersError = new errors.GeneralError(error); + feathersError = new errors.GeneralError(message); } - } - - // NOTE (EK): Error codes taken from - // https://www.sqlite.org/c3ref/c_abort.html - - if (error.code === 'SQLITE_ERROR') { + } else if (error.code === 'SQLITE_ERROR') { + // NOTE (EK): Error codes taken from + // https://www.sqlite.org/c3ref/c_abort.html switch (error.errno) { case 1: case 8: case 18: case 19: case 20: - feathersError = new errors.BadRequest(error); + feathersError = new errors.BadRequest(message); break; case 2: - feathersError = new errors.Unavailable(error); + feathersError = new errors.Unavailable(message); break; case 3: case 23: - feathersError = new errors.Forbidden(error); + feathersError = new errors.Forbidden(message); break; case 12: - feathersError = new errors.NotFound(error); + feathersError = new errors.NotFound(message); break; default: - feathersError = new errors.GeneralError(error); + feathersError = new errors.GeneralError(message); break; } - } - - // NOTE: Error codes taken from - // https://www.postgresql.org/docs/9.6/static/errcodes-appendix.html - if (typeof error.code === 'string' && error.severity && error.routine) { + } else if (typeof error.code === 'string' && error.severity && error.routine) { + // NOTE: Error codes taken from + // https://www.postgresql.org/docs/9.6/static/errcodes-appendix.html // Omit query information const messages = error.message.split('-'); error.message = messages[messages.length - 1]; @@ -78,21 +70,25 @@ module.exports = function errorHandler (error) { switch (error.code.slice(0, 2)) { case '22': case '23': - feathersError = new errors.BadRequest(error); + feathersError = new errors.BadRequest(message); break; case '28': - feathersError = new errors.Forbidden(error); + feathersError = new errors.Forbidden(message); break; case '3D': case '3F': case '42': - feathersError = new errors.Unprocessable(error); + feathersError = new errors.Unprocessable(message); break; default: - feathersError = new errors.GeneralError(error); + feathersError = new errors.GeneralError(message); break; } + } else if (!(error instanceof errors.FeathersError)) { + feathersError = new errors.GeneralError(message); } + feathersError[ERROR] = error; + throw feathersError; }; diff --git a/lib/index.js b/lib/index.js index 7859a04..8d61986 100644 --- a/lib/index.js +++ b/lib/index.js @@ -319,5 +319,8 @@ module.exports = function init (options) { return new Service(options); }; -module.exports.hooks = hooks; -module.exports.Service = Service; +Object.assign(module.exports, { + hooks, + Service, + ERROR: errorHandler.ERROR +}); diff --git a/test/index.test.js b/test/index.test.js index e255a65..b29ab9c 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -114,7 +114,7 @@ function clean () { db.schema.dropTableIfExists(people.fullName).then(() => { return people.init({}, (table) => { table.increments('id'); - table.string('name'); + table.string('name').notNullable(); table.integer('age'); table.integer('time'); table.boolean('created'); @@ -330,6 +330,16 @@ describe('Feathers Knex Service', () => { expect(data[1].name).not.be.equal('Dave'); expect(data[1].age).not.be.equal(32); }); + + it('attaches the SQL error', async () => { + try { + await peopleService.create({}); + expect(false); + } catch (error) { + expect(error.name).to.equal('GeneralError'); + expect(error[service.ERROR]); + } + }); }); describe('hooks', () => {