js-data-firebase-admin
Version:
Firebase adapter for js-data.
1,311 lines (1,174 loc) • 78.5 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('js-data'), require('firebase-admin')) :
typeof define === 'function' && define.amd ? define(['exports', 'js-data', 'firebase-admin'], factory) :
(factory((global.JSDataFirebase = {}),global.JSData,global['firebase-admin']));
}(this, (function (exports,jsData,firebase) { 'use strict';
firebase = firebase && firebase.hasOwnProperty('default') ? firebase['default'] : firebase;
var defineProperty = function (obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
};
var slicedToArray = function () {
function sliceIterator(arr, i) {
var _arr = [];
var _n = true;
var _d = false;
var _e = undefined;
try {
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
_arr.push(_s.value);
if (i && _arr.length === i) break;
}
} catch (err) {
_d = true;
_e = err;
} finally {
try {
if (!_n && _i["return"]) _i["return"]();
} finally {
if (_d) throw _e;
}
}
return _arr;
}
return function (arr, i) {
if (Array.isArray(arr)) {
return arr;
} else if (Symbol.iterator in Object(arr)) {
return sliceIterator(arr, i);
} else {
throw new TypeError("Invalid attempt to destructure non-iterable instance");
}
};
}();
var noop = function noop() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
var opts = args[args.length - 1];
this.dbg.apply(this, [opts.op].concat(args));
return jsData.utils.resolve();
};
var noop2 = function noop2() {
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
var opts = args[args.length - 2];
this.dbg.apply(this, [opts.op].concat(args));
return jsData.utils.resolve();
};
var unique = function unique(array) {
var seen = {};
var final = [];
array.forEach(function (item) {
if (item in seen) {
return;
}
final.push(item);
seen[item] = 0;
});
return final;
};
var withoutRelations = function withoutRelations(mapper, props, opts) {
opts || (opts = {});
opts.with || (opts.with = []);
var relationFields = mapper.relationFields || [];
var toStrip = relationFields.filter(function (value) {
return opts.with.indexOf(value) === -1;
});
return jsData.utils.omit(props, toStrip);
};
/**
* Response object used when `raw` is `true`. May contain other fields in
* addition to `data`.
*
* @class Response
*/
function Response(data, meta, op) {
meta || (meta = {});
/**
* Response data.
*
* @name Response#data
* @type {*}
*/
this.data = data;
jsData.utils.fillIn(this, meta);
/**
* The operation for which the response was created.
*
* @name Response#op
* @type {string}
*/
this.op = op;
}
var DEFAULTS = {
/**
* Whether to log debugging information.
*
* @name Adapter#debug
* @type {boolean}
* @default false
*/
debug: false,
/**
* Whether to return a more detailed response object.
*
* @name Adapter#raw
* @type {boolean}
* @default false
*/
raw: false
/**
* Abstract class meant to be extended by adapters.
*
* @class Adapter
* @abstract
* @extends Component
* @param {Object} [opts] Configuration opts.
* @param {boolean} [opts.debug=false] Whether to log debugging information.
* @param {boolean} [opts.raw=false] Whether to return a more detailed response
* object.
*/
};function Adapter(opts) {
jsData.utils.classCallCheck(this, Adapter);
jsData.Component.call(this, opts);
opts || (opts = {});
jsData.utils.fillIn(opts, DEFAULTS);
jsData.utils.fillIn(this, opts);
}
jsData.Component.extend({
constructor: Adapter,
/**
* Lifecycle method method called by <a href="#count__anchor">count</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#count__anchor">count</a> to wait for the Promise to resolve before continuing.
*
* If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be the count.
*
* `response` may be modified. You can also re-assign `response` to another value by returning a different value or a Promise that resolves to a different value.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#count__anchor">count</a>.
*
* @name Adapter#afterCount
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#count__anchor">count</a>.
* @param {Object} props The `props` argument passed to <a href="#count__anchor">count</a>.
* @param {Object} opts The `opts` argument passed to <a href="#count__anchor">count</a>.
* @property {string} opts.op `afterCount`
* @param {Object|Response} response Count or {@link Response}, depending on the value of `opts.raw`.
*/
afterCount: noop2,
/**
* Lifecycle method method called by <a href="#create__anchor">create</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#create__anchor">create</a> to wait for the Promise to resolve before continuing.
*
* If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be the created record.
*
* `response` may be modified. You can also re-assign `response` to another value by returning a different value or a Promise that resolves to a different value.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#create__anchor">create</a>.
*
* @name Adapter#afterCreate
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#create__anchor">create</a>.
* @param {Object} props The `props` argument passed to <a href="#create__anchor">create</a>.
* @param {Object} opts The `opts` argument passed to <a href="#create__anchor">create</a>.
* @property {string} opts.op `afterCreate`
* @param {Object|Response} response Created record or {@link Response}, depending on the value of `opts.raw`.
*/
afterCreate: noop2,
/**
* Lifecycle method method called by <a href="#createMany__anchor">createMany</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#createMany__anchor">createMany</a> to wait for the Promise to resolve before continuing.
*
* If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be the created records.
*
* `response` may be modified. You can also re-assign `response` to another value by returning a different value or a Promise that resolves to a different value.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#createMany__anchor">createMany</a>.
*
* @name Adapter#afterCreate
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#createMany__anchor">createMany</a>.
* @param {Object[]} props The `props` argument passed to <a href="#createMany__anchor">createMany</a>.
* @param {Object} opts The `opts` argument passed to <a href="#createMany__anchor">createMany</a>.
* @property {string} opts.op `afterCreateMany`
* @param {Object[]|Response} response Created records or {@link Response}, depending on the value of `opts.raw`.
*/
afterCreateMany: noop2,
/**
* Lifecycle method method called by <a href="#destroy__anchor">destroy</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#destroy__anchor">destroy</a> to wait for the Promise to resolve before continuing.
*
* If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be `undefined`.
*
* `response` may be modified. You can also re-assign `response` to another value by returning a different value or a Promise that resolves to a different value.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#destroy__anchor">destroy</a>.
*
* @name Adapter#afterDestroy
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#destroy__anchor">destroy</a>.
* @param {(string|number)} id The `id` argument passed to <a href="#destroy__anchor">destroy</a>.
* @param {Object} opts The `opts` argument passed to <a href="#destroy__anchor">destroy</a>.
* @property {string} opts.op `afterDestroy`
* @param {undefined|Response} response `undefined` or {@link Response}, depending on the value of `opts.raw`.
*/
afterDestroy: noop2,
/**
* Lifecycle method method called by <a href="#destroyAll__anchor">destroyAll</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#destroyAll__anchor">destroyAll</a> to wait for the Promise to resolve before continuing.
*
* If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be `undefined`.
*
* `response` may be modified. You can also re-assign `response` to another value by returning a different value or a Promise that resolves to a different value.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#destroyAll__anchor">destroyAll</a>.
*
* @name Adapter#afterDestroyAll
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#destroyAll__anchor">destroyAll</a>.
* @param {Object} query The `query` argument passed to <a href="#destroyAll__anchor">destroyAll</a>.
* @param {Object} opts The `opts` argument passed to <a href="#destroyAll__anchor">destroyAll</a>.
* @property {string} opts.op `afterDestroyAll`
* @param {undefined|Response} response `undefined` or {@link Response}, depending on the value of `opts.raw`.
*/
afterDestroyAll: noop2,
/**
* Lifecycle method method called by <a href="#find__anchor">find</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#find__anchor">find</a> to wait for the Promise to resolve before continuing.
*
* If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be the found record, if any.
*
* `response` may be modified. You can also re-assign `response` to another value by returning a different value or a Promise that resolves to a different value.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#find__anchor">find</a>.
*
* @name Adapter#afterFind
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#find__anchor">find</a>.
* @param {(string|number)} id The `id` argument passed to <a href="#find__anchor">find</a>.
* @param {Object} opts The `opts` argument passed to <a href="#find__anchor">find</a>.
* @property {string} opts.op `afterFind`
* @param {Object|Response} response The found record or {@link Response}, depending on the value of `opts.raw`.
*/
afterFind: noop2,
/**
* Lifecycle method method called by <a href="#findAll__anchor">findAll</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#findAll__anchor">findAll</a> to wait for the Promise to resolve before continuing.
*
* If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be the found records, if any.
*
* `response` may be modified. You can also re-assign `response` to another value by returning a different value or a Promise that resolves to a different value.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#findAll__anchor">findAll</a>.
*
* @name Adapter#afterFindAll
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#findAll__anchor">findAll</a>.
* @param {Object} query The `query` argument passed to <a href="#findAll__anchor">findAll</a>.
* @param {Object} opts The `opts` argument passed to <a href="#findAll__anchor">findAll</a>.
* @property {string} opts.op `afterFindAll`
* @param {Object[]|Response} response The found records or {@link Response}, depending on the value of `opts.raw`.
*/
afterFindAll: noop2,
/**
* Lifecycle method method called by <a href="#sum__anchor">sum</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#sum__anchor">sum</a> to wait for the Promise to resolve before continuing.
*
* If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be the sum.
*
* `response` may be modified. You can also re-assign `response` to another value by returning a different value or a Promise that resolves to a different value.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#sum__anchor">sum</a>.
*
* @name Adapter#afterSum
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#sum__anchor">sum</a>.
* @param {string} field The `field` argument passed to <a href="#sum__anchor">sum</a>.
* @param {Object} query The `query` argument passed to <a href="#sum__anchor">sum</a>.
* @param {Object} opts The `opts` argument passed to <a href="#sum__anchor">sum</a>.
* @property {string} opts.op `afterSum`
* @param {Object|Response} response Count or {@link Response}, depending on the value of `opts.raw`.
*/
afterSum: noop2,
/**
* Lifecycle method method called by <a href="#update__anchor">update</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#update__anchor">update</a> to wait for the Promise to resolve before continuing.
*
* If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be the updated record.
*
* `response` may be modified. You can also re-assign `response` to another value by returning a different value or a Promise that resolves to a different value.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#update__anchor">update</a>.
*
* @name Adapter#afterUpdate
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#update__anchor">update</a>.
* @param {(string|number)} id The `id` argument passed to <a href="#update__anchor">update</a>.
* @param {Object} props The `props` argument passed to <a href="#update__anchor">update</a>.
* @param {Object} opts The `opts` argument passed to <a href="#update__anchor">update</a>.
* @property {string} opts.op `afterUpdate`
* @param {Object|Response} response The updated record or {@link Response}, depending on the value of `opts.raw`.
*/
afterUpdate: noop2,
/**
* Lifecycle method method called by <a href="#updateAll__anchor">updateAll</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#updateAll__anchor">updateAll</a> to wait for the Promise to resolve before continuing.
*
* If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be the updated records, if any.
*
* `response` may be modified. You can also re-assign `response` to another value by returning a different value or a Promise that resolves to a different value.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#updateAll__anchor">updateAll</a>.
*
* @name Adapter#afterUpdateAll
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#updateAll__anchor">updateAll</a>.
* @param {Object} props The `props` argument passed to <a href="#updateAll__anchor">updateAll</a>.
* @param {Object} query The `query` argument passed to <a href="#updateAll__anchor">updateAll</a>.
* @param {Object} opts The `opts` argument passed to <a href="#updateAll__anchor">updateAll</a>.
* @property {string} opts.op `afterUpdateAll`
* @param {Object[]|Response} response The updated records or {@link Response}, depending on the value of `opts.raw`.
*/
afterUpdateAll: noop2,
/**
* Lifecycle method method called by <a href="#updateMany__anchor">updateMany</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#updateMany__anchor">updateMany</a> to wait for the Promise to resolve before continuing.
*
* If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be the updated records, if any.
*
* `response` may be modified. You can also re-assign `response` to another value by returning a different value or a Promise that resolves to a different value.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#updateMany__anchor">updateMany</a>.
*
* @name Adapter#afterUpdateMany
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#updateMany__anchor">updateMany</a>.
* @param {Object[]} records The `records` argument passed to <a href="#updateMany__anchor">updateMany</a>.
* @param {Object} opts The `opts` argument passed to <a href="#updateMany__anchor">updateMany</a>.
* @property {string} opts.op `afterUpdateMany`
* @param {Object[]|Response} response The updated records or {@link Response}, depending on the value of `opts.raw`.
*/
afterUpdateMany: noop2,
/**
* Lifecycle method method called by <a href="#count__anchor">count</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#count__anchor">count</a> to wait for the Promise to resolve before continuing.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#count__anchor">count</a>.
*
* @name Adapter#beforeCount
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#count__anchor">count</a>.
* @param {Object} query The `query` argument passed to <a href="#count__anchor">count</a>.
* @param {Object} opts The `opts` argument passed to <a href="#count__anchor">count</a>.
* @property {string} opts.op `beforeCount`
*/
beforeCount: noop,
/**
* Lifecycle method method called by <a href="#create__anchor">create</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#create__anchor">create</a> to wait for the Promise to resolve before continuing.
*
* `props` may be modified. You can also re-assign `props` to another value by returning a different value or a Promise that resolves to a different value.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#create__anchor">create</a>.
*
* @name Adapter#beforeCreate
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#create__anchor">create</a>.
* @param {Object} props The `props` argument passed to <a href="#create__anchor">create</a>.
* @param {Object} opts The `opts` argument passed to <a href="#create__anchor">create</a>.
* @property {string} opts.op `beforeCreate`
*/
beforeCreate: noop,
/**
* Lifecycle method method called by <a href="#createMany__anchor">createMany</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#createMany__anchor">createMany</a> to wait for the Promise to resolve before continuing.
*
* `props` may be modified. You can also re-assign `props` to another value by returning a different value or a Promise that resolves to a different value.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#createMany__anchor">createMany</a>.
*
* @name Adapter#beforeCreateMany
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#createMany__anchor">createMany</a>.
* @param {Object[]} props The `props` argument passed to <a href="#createMany__anchor">createMany</a>.
* @param {Object} opts The `opts` argument passed to <a href="#createMany__anchor">createMany</a>.
* @property {string} opts.op `beforeCreateMany`
*/
beforeCreateMany: noop,
/**
* Lifecycle method method called by <a href="#destroy__anchor">destroy</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#destroy__anchor">destroy</a> to wait for the Promise to resolve before continuing.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#destroy__anchor">destroy</a>.
*
* @name Adapter#beforeDestroy
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#destroy__anchor">destroy</a>.
* @param {(string|number)} id The `id` argument passed to <a href="#destroy__anchor">destroy</a>.
* @param {Object} opts The `opts` argument passed to <a href="#destroy__anchor">destroy</a>.
* @property {string} opts.op `beforeDestroy`
*/
beforeDestroy: noop,
/**
* Lifecycle method method called by <a href="#destroyAll__anchor">destroyAll</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#destroyAll__anchor">destroyAll</a> to wait for the Promise to resolve before continuing.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#destroyAll__anchor">destroyAll</a>.
*
* @name Adapter#beforeDestroyAll
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#destroyAll__anchor">destroyAll</a>.
* @param {Object} query The `query` argument passed to <a href="#destroyAll__anchor">destroyAll</a>.
* @param {Object} opts The `opts` argument passed to <a href="#destroyAll__anchor">destroyAll</a>.
* @property {string} opts.op `beforeDestroyAll`
*/
beforeDestroyAll: noop,
/**
* Lifecycle method method called by <a href="#find__anchor">find</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#find__anchor">find</a> to wait for the Promise to resolve before continuing.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#find__anchor">find</a>.
*
* @name Adapter#beforeFind
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#find__anchor">find</a>.
* @param {(string|number)} id The `id` argument passed to <a href="#find__anchor">find</a>.
* @param {Object} opts The `opts` argument passed to <a href="#find__anchor">find</a>.
* @property {string} opts.op `beforeFind`
*/
beforeFind: noop,
/**
* Lifecycle method method called by <a href="#findAll__anchor">findAll</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#findAll__anchor">findAll</a> to wait for the Promise to resolve before continuing.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#findAll__anchor">findAll</a>.
*
* @name Adapter#beforeFindAll
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#findAll__anchor">findAll</a>.
* @param {Object} query The `query` argument passed to <a href="#findAll__anchor">findAll</a>.
* @param {Object} opts The `opts` argument passed to <a href="#findAll__anchor">findAll</a>.
* @property {string} opts.op `beforeFindAll`
*/
beforeFindAll: noop,
/**
* Lifecycle method method called by <a href="#sum__anchor">sum</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#sum__anchor">sum</a> to wait for the Promise to resolve before continuing.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#sum__anchor">sum</a>.
*
* @name Adapter#beforeSum
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#sum__anchor">sum</a>.
* @param {Object} query The `query` argument passed to <a href="#sum__anchor">sum</a>.
* @param {Object} opts The `opts` argument passed to <a href="#sum__anchor">sum</a>.
* @property {string} opts.op `beforeSum`
*/
beforeSum: noop,
/**
* Lifecycle method method called by <a href="#update__anchor">update</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#update__anchor">update</a> to wait for the Promise to resolve before continuing.
*
* `props` may be modified. You can also re-assign `props` to another value by returning a different value or a Promise that resolves to a different value.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#update__anchor">update</a>.
*
* @name Adapter#beforeUpdate
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#update__anchor">update</a>.
* @param {(string|number)} id The `id` argument passed to <a href="#update__anchor">update</a>.
* @param {Object} props The `props` argument passed to <a href="#update__anchor">update</a>.
* @param {Object} opts The `opts` argument passed to <a href="#update__anchor">update</a>.
* @property {string} opts.op `beforeUpdate`
*/
beforeUpdate: noop,
/**
* Lifecycle method method called by <a href="#updateAll__anchor">updateAll</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#updateAll__anchor">updateAll</a> to wait for the Promise to resolve before continuing.
*
* `props` may be modified. You can also re-assign `props` to another value by returning a different value or a Promise that resolves to a different value.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#updateAll__anchor">updateAll</a>.
*
* @name Adapter#beforeUpdateAll
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#updateAll__anchor">updateAll</a>.
* @param {Object} props The `props` argument passed to <a href="#updateAll__anchor">updateAll</a>.
* @param {Object} query The `query` argument passed to <a href="#updateAll__anchor">updateAll</a>.
* @param {Object} opts The `opts` argument passed to <a href="#updateAll__anchor">updateAll</a>.
* @property {string} opts.op `beforeUpdateAll`
*/
beforeUpdateAll: noop,
/**
* Lifecycle method method called by <a href="#updateMany__anchor">updateMany</a>.
*
* Override this method to add custom behavior for this lifecycle hook.
*
* Returning a Promise causes <a href="#updateMany__anchor">updateMany</a> to wait for the Promise to resolve before continuing.
*
* `props` may be modified. You can also re-assign `props` to another value by returning a different value or a Promise that resolves to a different value.
*
* A thrown error or rejected Promise will bubble up and reject the Promise returned by <a href="#updateMany__anchor">updateMany</a>.
*
* @name Adapter#beforeUpdateMany
* @method
* @param {Object} mapper The `mapper` argument passed to <a href="#updateMany__anchor">updateMany</a>.
* @param {Object[]} props The `props` argument passed to <a href="#updateMany__anchor">updateMany</a>.
* @param {Object} opts The `opts` argument passed to <a href="#updateMany__anchor">updateMany</a>.
* @property {string} opts.op `beforeUpdateMany`
*/
beforeUpdateMany: noop,
/**
* Retrieve the number of records that match the selection query. Called by
* `Mapper#count`.
*
* @name Adapter#count
* @method
* @param {Object} mapper The mapper.
* @param {Object} [query] Selection query.
* @param {Object} [query.where] Filtering criteria.
* @param {string|Array} [query.orderBy] Sorting criteria.
* @param {string|Array} [query.sort] Same as `query.sort`.
* @param {number} [query.limit] Limit results.
* @param {number} [query.skip] Offset results.
* @param {number} [query.offset] Same as `query.skip`.
* @param {Object} [opts] Configuration options.
* @param {boolean} [opts.raw=false] Whether to return a more detailed
* response object.
* @return {Promise}
*/
count: function count(mapper, query, opts) {
var _this = this;
var op = void 0;
query || (query = {});
opts || (opts = {});
// beforeCount lifecycle hook
op = opts.op = 'beforeCount';
return jsData.utils.resolve(this[op](mapper, query, opts)).then(function () {
// Allow for re-assignment from lifecycle hook
op = opts.op = 'count';
_this.dbg(op, mapper, query, opts);
return jsData.utils.resolve(_this._count(mapper, query, opts));
}).then(function (results) {
var _results = slicedToArray(results, 2),
data = _results[0],
result = _results[1];
result || (result = {});
var response = new Response(data, result, op);
response = _this.respond(response, opts);
// afterCount lifecycle hook
op = opts.op = 'afterCount';
return jsData.utils.resolve(_this[op](mapper, query, opts, response)).then(function (_response) {
return _response === undefined ? response : _response;
});
});
},
/**
* Create a new record. Called by `Mapper#create`.
*
* @name Adapter#create
* @method
* @param {Object} mapper The mapper.
* @param {Object} props The record to be created.
* @param {Object} [opts] Configuration options.
* @param {boolean} [opts.raw=false] Whether to return a more detailed
* response object.
* @return {Promise}
*/
create: function create(mapper, props, opts) {
var _this2 = this;
var op = void 0;
props || (props = {});
opts || (opts = {});
// beforeCreate lifecycle hook
op = opts.op = 'beforeCreate';
return jsData.utils.resolve(this[op](mapper, props, opts)).then(function (_props) {
// Allow for re-assignment from lifecycle hook
props = _props === undefined ? props : _props;
props = withoutRelations(mapper, props, opts);
op = opts.op = 'create';
_this2.dbg(op, mapper, props, opts);
return jsData.utils.resolve(_this2._create(mapper, props, opts));
}).then(function (results) {
var _results2 = slicedToArray(results, 2),
data = _results2[0],
result = _results2[1];
result || (result = {});
var response = new Response(data, result, 'create');
response.created = data ? 1 : 0;
response = _this2.respond(response, opts);
// afterCreate lifecycle hook
op = opts.op = 'afterCreate';
return jsData.utils.resolve(_this2[op](mapper, props, opts, response)).then(function (_response) {
return _response === undefined ? response : _response;
});
});
},
/**
* Create multiple records in a single batch. Called by `Mapper#createMany`.
*
* @name Adapter#createMany
* @method
* @param {Object} mapper The mapper.
* @param {Object} props The records to be created.
* @param {Object} [opts] Configuration options.
* @param {boolean} [opts.raw=false] Whether to return a more detailed
* response object.
* @return {Promise}
*/
createMany: function createMany(mapper, props, opts) {
var _this3 = this;
var op = void 0;
props || (props = {});
opts || (opts = {});
// beforeCreateMany lifecycle hook
op = opts.op = 'beforeCreateMany';
return jsData.utils.resolve(this[op](mapper, props, opts)).then(function (_props) {
// Allow for re-assignment from lifecycle hook
props = _props === undefined ? props : _props;
props = props.map(function (record) {
return withoutRelations(mapper, record, opts);
});
op = opts.op = 'createMany';
_this3.dbg(op, mapper, props, opts);
return jsData.utils.resolve(_this3._createMany(mapper, props, opts));
}).then(function (results) {
var _results3 = slicedToArray(results, 2),
data = _results3[0],
result = _results3[1];
data || (data = []);
result || (result = {});
var response = new Response(data, result, 'createMany');
response.created = data.length;
response = _this3.respond(response, opts);
// afterCreateMany lifecycle hook
op = opts.op = 'afterCreateMany';
return jsData.utils.resolve(_this3[op](mapper, props, opts, response)).then(function (_response) {
return _response === undefined ? response : _response;
});
});
},
/**
* Destroy the record with the given primary key. Called by
* `Mapper#destroy`.
*
* @name Adapter#destroy
* @method
* @param {Object} mapper The mapper.
* @param {(string|number)} id Primary key of the record to destroy.
* @param {Object} [opts] Configuration options.
* @param {boolean} [opts.raw=false] Whether to return a more detailed
* response object.
* @return {Promise}
*/
destroy: function destroy(mapper, id, opts) {
var _this4 = this;
var op = void 0;
opts || (opts = {});
// beforeDestroy lifecycle hook
op = opts.op = 'beforeDestroy';
return jsData.utils.resolve(this[op](mapper, id, opts)).then(function () {
op = opts.op = 'destroy';
_this4.dbg(op, mapper, id, opts);
return jsData.utils.resolve(_this4._destroy(mapper, id, opts));
}).then(function (results) {
var _results4 = slicedToArray(results, 2),
data = _results4[0],
result = _results4[1];
result || (result = {});
var response = new Response(data, result, 'destroy');
response = _this4.respond(response, opts);
// afterDestroy lifecycle hook
op = opts.op = 'afterDestroy';
return jsData.utils.resolve(_this4[op](mapper, id, opts, response)).then(function (_response) {
return _response === undefined ? response : _response;
});
});
},
/**
* Destroy the records that match the selection query. Called by
* `Mapper#destroyAll`.
*
* @name Adapter#destroyAll
* @method
* @param {Object} mapper the mapper.
* @param {Object} [query] Selection query.
* @param {Object} [query.where] Filtering criteria.
* @param {string|Array} [query.orderBy] Sorting criteria.
* @param {string|Array} [query.sort] Same as `query.sort`.
* @param {number} [query.limit] Limit results.
* @param {number} [query.skip] Offset results.
* @param {number} [query.offset] Same as `query.skip`.
* @param {Object} [opts] Configuration options.
* @param {boolean} [opts.raw=false] Whether to return a more detailed
* response object.
* @return {Promise}
*/
destroyAll: function destroyAll(mapper, query, opts) {
var _this5 = this;
var op = void 0;
query || (query = {});
opts || (opts = {});
// beforeDestroyAll lifecycle hook
op = opts.op = 'beforeDestroyAll';
return jsData.utils.resolve(this[op](mapper, query, opts)).then(function () {
op = opts.op = 'destroyAll';
_this5.dbg(op, mapper, query, opts);
return jsData.utils.resolve(_this5._destroyAll(mapper, query, opts));
}).then(function (results) {
var _results5 = slicedToArray(results, 2),
data = _results5[0],
result = _results5[1];
result || (result = {});
var response = new Response(data, result, 'destroyAll');
response = _this5.respond(response, opts);
// afterDestroyAll lifecycle hook
op = opts.op = 'afterDestroyAll';
return jsData.utils.resolve(_this5[op](mapper, query, opts, response)).then(function (_response) {
return _response === undefined ? response : _response;
});
});
},
/**
* Load a belongsTo relationship.
*
* Override with care.
*
* @name Adapter#loadBelongsTo
* @method
* @return {Promise}
*/
loadBelongsTo: function loadBelongsTo(mapper, def, records, __opts) {
var _this6 = this;
var relationDef = def.getRelation();
if (jsData.utils.isObject(records) && !jsData.utils.isArray(records)) {
var record = records;
return this.find(relationDef, this.makeBelongsToForeignKey(mapper, def, record), __opts).then(function (relatedItem) {
def.setLocalField(record, relatedItem);
});
} else {
var keys = records.map(function (record) {
return _this6.makeBelongsToForeignKey(mapper, def, record);
}).filter(function (key) {
return key;
});
return this.findAll(relationDef, {
where: defineProperty({}, relationDef.idAttribute, {
'in': keys
})
}, __opts).then(function (relatedItems) {
records.forEach(function (record) {
relatedItems.forEach(function (relatedItem) {
if (relatedItem[relationDef.idAttribute] === record[def.foreignKey]) {
def.setLocalField(record, relatedItem);
}
});
});
});
}
},
/**
* Retrieve the record with the given primary key. Called by `Mapper#find`.
*
* @name Adapter#find
* @method
* @param {Object} mapper The mapper.
* @param {(string|number)} id Primary key of the record to retrieve.
* @param {Object} [opts] Configuration options.
* @param {boolean} [opts.raw=false] Whether to return a more detailed
* response object.
* @param {string[]} [opts.with=[]] Relations to eager load.
* @return {Promise}
*/
find: function find(mapper, id, opts) {
var _this7 = this;
var op = void 0;
opts || (opts = {});
opts.with || (opts.with = []);
// beforeFind lifecycle hook
op = opts.op = 'beforeFind';
return jsData.utils.resolve(this[op](mapper, id, opts)).then(function () {
op = opts.op = 'find';
_this7.dbg(op, mapper, id, opts);
return jsData.utils.resolve(_this7._find(mapper, id, opts));
}).then(function (results) {
return _this7.loadRelationsFor(mapper, results, opts);
}).then(function (_ref) {
var _ref2 = slicedToArray(_ref, 2),
record = _ref2[0],
meta = _ref2[1];
var response = new Response(record, meta, 'find');
response.found = record ? 1 : 0;
response = _this7.respond(response, opts);
// afterFind lifecycle hook
op = opts.op = 'afterFind';
return jsData.utils.resolve(_this7[op](mapper, id, opts, response)).then(function (_response) {
return _response === undefined ? response : _response;
});
});
},
/**
* Retrieve the records that match the selection query.
*
* @name Adapter#findAll
* @method
* @param {Object} mapper The mapper.
* @param {Object} [query] Selection query.
* @param {Object} [query.where] Filtering criteria.
* @param {string|Array} [query.orderBy] Sorting criteria.
* @param {string|Array} [query.sort] Same as `query.sort`.
* @param {number} [query.limit] Limit results.
* @param {number} [query.skip] Offset results.
* @param {number} [query.offset] Same as `query.skip`.
* @param {Object} [opts] Configuration options.
* @param {boolean} [opts.raw=false] Whether to return a more detailed
* response object.
* @param {string[]} [opts.with=[]] Relations to eager load.
* @return {Promise}
*/
findAll: function findAll(mapper, query, opts) {
var _this8 = this;
var op = void 0;
opts || (opts = {});
opts.with || (opts.with = []);
var activeWith = opts._activeWith;
if (jsData.utils.isObject(activeWith)) {
var activeQuery = activeWith.query || {};
if (activeWith.replace) {
query = activeQuery;
} else {
jsData.utils.deepFillIn(query, activeQuery);
}
}
// beforeFindAll lifecycle hook
op = opts.op = 'beforeFindAll';
return jsData.utils.resolve(this[op](mapper, query, opts)).then(function () {
op = opts.op = 'findAll';
_this8.dbg(op, mapper, query, opts);
return jsData.utils.resolve(_this8._findAll(mapper, query, opts));
}).then(function (results) {
return _this8.loadRelationsFor(mapper, results, opts);
}).then(function (_ref3) {
var _ref4 = slicedToArray(_ref3, 2),
records = _ref4[0],
meta = _ref4[1];
var response = new Response(records, meta, 'findAll');
response.found = records.length;
response = _this8.respond(response, opts);
// afterFindAll lifecycle hook
op = opts.op = 'afterFindAll';
return jsData.utils.resolve(_this8[op](mapper, query, opts, response)).then(function (_response) {
return _response === undefined ? response : _response;
});
});
},
loadRelationsFor: function loadRelationsFor(mapper, results, opts) {
var _this9 = this;
var _results6 = slicedToArray(results, 1),
records = _results6[0];
var tasks = [];
if (records) {
jsData.utils.forEachRelation(mapper, opts, function (def, __opts) {
var task = void 0;
if (def.foreignKey && (def.type === 'hasOne' || def.type === 'hasMany')) {
if (def.type === 'hasOne') {
task = _this9.loadHasOne(mapper, def, records, __opts);
} else {
task = _this9.loadHasMany(mapper, def, records, __opts);
}
} else if (def.type === 'hasMany' && def.localKeys) {
task = _this9.loadHasManyLocalKeys(mapper, def, records, __opts);
} else if (def.type === 'hasMany' && def.foreignKeys) {
task = _this9.loadHasManyForeignKeys(mapper, def, records, __opts);
} else if (def.type === 'belongsTo') {
task = _this9.loadBelongsTo(mapper, def, records, __opts);
}
if (task) {
tasks.push(task);
}
});
}
return jsData.utils.Promise.all(tasks).then(function () {
return results;
});
},
/**
* Resolve the value of the specified option based on the given options and
* this adapter's settings. Override with care.
*
* @name Adapter#getOpt
* @method
* @param {string} opt The name of the option.
* @param {Object} [opts] Configuration options.
* @return {*} The value of the specified option.
*/
getOpt: function getOpt(opt, opts) {
opts || (opts = {});
return opts[opt] === undefined ? jsData.utils.plainCopy(this[opt]) : jsData.utils.plainCopy(opts[opt]);
},
/**
* Load a hasMany relationship.
*
* Override with care.
*
* @name Adapter#loadHasMany
* @method
* @return {Promise}
*/
loadHasMany: function loadHasMany(mapper, def, records, __opts) {
var _this10 = this;
var singular = false;
if (jsData.utils.isObject(records) && !jsData.utils.isArray(records)) {
singular = true;
records = [records];
}
var IDs = records.map(function (record) {
return _this10.makeHasManyForeignKey(mapper, def, record);
});
var query = {
where: {}
};
var criteria = query.where[def.foreignKey] = {};
if (singular) {
// more efficient query when we only have one record
criteria['=='] = IDs[0];
} else {
criteria['in'] = IDs.filter(function (id) {
return id;
});
}
return this.findAll(def.getRelation(), query, __opts).then(function (relatedItems) {
records.forEach(function (record) {
var attached = [];
// avoid unneccesary iteration when we only have one record
if (singular) {
attached = relatedItems;
} else {
relatedItems.forEach(function (relatedItem) {
if (jsData.utils.get(relatedItem, def.foreignKey) === record[mapper.idAttribute]) {
attached.push(relatedItem);
}
});
}
def.setLocalField(record, attached);
});
});
},
loadHasManyLocalKeys: function loadHasManyLocalKeys(mapper, def, records, __opts) {
var _this11 = this;
var record = void 0;
var relatedMapper = def.getRelation();
if (jsData.utils.isObject(records) && !jsData.utils.isArray(records)) {
record = records;
}
if (record) {
return this.findAll(relatedMapper, {
where: defineProperty({}, relatedMapper.idAttribute, {
'in': this.makeHasManyLocalKeys(mapper, def, record)
})
}, __opts).then(function (relatedItems) {
def.setLocalField(record, relatedItems);
});
} else {
var localKeys = [];
records.forEach(function (record) {
localKeys = localKeys.concat(_this11.makeHasManyLocalKeys(mapper, def, record));
});
return this.findAll(relatedMapper, {
where: defineProperty({}, relatedMapper.idAttribute, {
'in': unique(localKeys).filter(function (x) {
return x;
})
})
}, __opts).then(function (relatedItems) {
records.forEach(function (item) {
var attached = [];
var itemKeys = jsData.utils.get(item, def.localKeys) || [];
itemKeys = jsData.utils.isArray(itemKeys) ? itemKeys : Object.keys(itemKeys);
relatedItems.forEach(function (relatedItem) {
if (itemKeys && itemKeys.indexOf(relatedItem[relatedMapper.idAttribute]) !== -1) {
attached.push(relatedItem);
}
});
def.setLocalField(item, attached);
});
return relatedItems;
});
}
},
loadHasManyForeignKeys: function loadHasManyForeignKeys(mapper, def, records, __opts) {
var _this12 = this;
var relatedMapper = def.getRelation();
var idAttribute = mapper.idAttribute;
var record = void 0;
if (jsData.utils.isObject(records) && !jsData.utils.isArray(records)) {
record = records;
}
if (record) {
return this.findAll(def.getRelation(), {
where: defineProperty({}, def.foreignKeys, {
'contains': this.makeHasManyForeignKeys(mapper, def, record)
})
}, __opts).then(function (relatedItems) {
def.setLocalField(record, relatedItems);
});
} else {
return this.findAll(relatedMapper, {
where: defineProperty({}, def.foreignKeys, {
'isectNotEmpty': records.map(function (record) {
return _this12.makeHasManyForeignKeys(mapper, def, record);
})
})
}, __opts).then(function (relatedItems) {
var foreignKeysField = def.foreignKeys;
records.forEach(function (record) {
var _relatedItems = [];
var id = jsData.utils.get(record, idAttribute);
relatedItems.forEach(function (relatedItem) {
var foreignKeys = jsData.utils.get(relatedItems, foreignKeysField) || [];
if (foreignKeys.indexOf(id) !== -1) {
_relatedItems.push(relatedItem);
}
});
def.setLocalField(record, _relatedItems);
});
});
}
},
/**
* Load a hasOne relationship.
*
* Override with care.
*
* @name Adapter#loadHasOne
* @method
* @return {Promise}
*/
loadHasOne: function loadHasOne(mapper, def, records, __opts) {
if (jsData.utils.isObject(records) && !jsData.utils.isArray(records)) {
records = [records];
}
return this.loadHasMany(mapper, def, records, __opts).then(function () {
records.forEach(function (record) {
var relatedData = def.getLocalField(record);
if (jsData.utils.isArray(relatedData) && relatedData.length) {
def.setLocalField(record, relatedData[0]);
}
});
});
},
/**
* Return the foreignKey from the given record for the provided relationship.
*
* There may be reasons why you may want to override this method, like when
* the id of the parent doesn't exactly match up to the key on the child.
*
* Override with care.
*
* @name Adapter#makeHasManyForeignKey
* @method
* @return {*}
*/
makeHasManyForeignKey: function makeHasManyForeignKey(mapper, def, record) {
return def.getForeignKey(record);
},
/**
* Return the localKeys from the given record for the provided relationship.
*
* Override with care.
*
* @name Adapter#makeHasManyLocalKeys
* @method
* @return {*}
*/
makeHasManyLocalKeys: function makeHasManyLocalKeys(mapper, def, record) {
var localKeys = [];
var itemKeys = jsData.utils.get(record, def.localKeys) || [];
itemKeys = jsData.utils.isArray(itemKeys) ? itemKeys : Object.keys(itemKeys);
localKeys = localKeys.concat(itemKeys);
return unique(localKeys).filter(function (x) {
return x;
});
},
/**
* Return the foreignKeys from the given record for the provided relationship.
*
* Override with care.
*
* @name Adapter#makeHasManyForeignKeys
* @method
* @retur