diff --git a/.gitignore b/.gitignore index ce8a8aa..5dd003a 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,4 @@ typings/ .vscode key.json config.js -.nyc_output/ -dist/*.js -dist/*.map \ No newline at end of file +.nyc_output/ \ No newline at end of file diff --git a/dist/js-data-firebase.js b/dist/js-data-firebase.js new file mode 100644 index 0000000..c8c8ccd --- /dev/null +++ b/dist/js-data-firebase.js @@ -0,0 +1,2246 @@ +/*! +* js-data-firebase +* @version 3.0.0 - Homepage +* @author Jason Dobry +* @copyright (c) 2014-2016 Jason Dobry +* @license MIT +* +* @overview firebase adapter for js-data. +*/ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('js-data'), require('firebase')) : + typeof define === 'function' && define.amd ? define(['exports', 'js-data', 'firebase'], factory) : + (factory((global.JSDataFirebase = {}),global.JSData,global.firebase)); +}(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 count. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes count 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 count. + * + * @name Adapter#afterCount + * @method + * @param {Object} mapper The `mapper` argument passed to count. + * @param {Object} props The `props` argument passed to count. + * @param {Object} opts The `opts` argument passed to count. + * @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 create. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes create 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 create. + * + * @name Adapter#afterCreate + * @method + * @param {Object} mapper The `mapper` argument passed to create. + * @param {Object} props The `props` argument passed to create. + * @param {Object} opts The `opts` argument passed to create. + * @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 createMany. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes createMany 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 createMany. + * + * @name Adapter#afterCreate + * @method + * @param {Object} mapper The `mapper` argument passed to createMany. + * @param {Object[]} props The `props` argument passed to createMany. + * @param {Object} opts The `opts` argument passed to createMany. + * @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 destroy. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes destroy 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 destroy. + * + * @name Adapter#afterDestroy + * @method + * @param {Object} mapper The `mapper` argument passed to destroy. + * @param {(string|number)} id The `id` argument passed to destroy. + * @param {Object} opts The `opts` argument passed to destroy. + * @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 destroyAll. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes destroyAll 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 destroyAll. + * + * @name Adapter#afterDestroyAll + * @method + * @param {Object} mapper The `mapper` argument passed to destroyAll. + * @param {Object} query The `query` argument passed to destroyAll. + * @param {Object} opts The `opts` argument passed to destroyAll. + * @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 find. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes find 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 find. + * + * @name Adapter#afterFind + * @method + * @param {Object} mapper The `mapper` argument passed to find. + * @param {(string|number)} id The `id` argument passed to find. + * @param {Object} opts The `opts` argument passed to find. + * @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 findAll. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes findAll 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 findAll. + * + * @name Adapter#afterFindAll + * @method + * @param {Object} mapper The `mapper` argument passed to findAll. + * @param {Object} query The `query` argument passed to findAll. + * @param {Object} opts The `opts` argument passed to findAll. + * @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 sum. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes sum 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 sum. + * + * @name Adapter#afterSum + * @method + * @param {Object} mapper The `mapper` argument passed to sum. + * @param {string} field The `field` argument passed to sum. + * @param {Object} query The `query` argument passed to sum. + * @param {Object} opts The `opts` argument passed to sum. + * @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 update. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes update 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 update. + * + * @name Adapter#afterUpdate + * @method + * @param {Object} mapper The `mapper` argument passed to update. + * @param {(string|number)} id The `id` argument passed to update. + * @param {Object} props The `props` argument passed to update. + * @param {Object} opts The `opts` argument passed to update. + * @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 updateAll. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes updateAll 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 updateAll. + * + * @name Adapter#afterUpdateAll + * @method + * @param {Object} mapper The `mapper` argument passed to updateAll. + * @param {Object} props The `props` argument passed to updateAll. + * @param {Object} query The `query` argument passed to updateAll. + * @param {Object} opts The `opts` argument passed to updateAll. + * @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 updateMany. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes updateMany 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 updateMany. + * + * @name Adapter#afterUpdateMany + * @method + * @param {Object} mapper The `mapper` argument passed to updateMany. + * @param {Object[]} records The `records` argument passed to updateMany. + * @param {Object} opts The `opts` argument passed to updateMany. + * @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 count. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes count to wait for the Promise to resolve before continuing. + * + * A thrown error or rejected Promise will bubble up and reject the Promise returned by count. + * + * @name Adapter#beforeCount + * @method + * @param {Object} mapper The `mapper` argument passed to count. + * @param {Object} query The `query` argument passed to count. + * @param {Object} opts The `opts` argument passed to count. + * @property {string} opts.op `beforeCount` + */ + beforeCount: noop, + + /** + * Lifecycle method method called by create. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes create 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 create. + * + * @name Adapter#beforeCreate + * @method + * @param {Object} mapper The `mapper` argument passed to create. + * @param {Object} props The `props` argument passed to create. + * @param {Object} opts The `opts` argument passed to create. + * @property {string} opts.op `beforeCreate` + */ + beforeCreate: noop, + + /** + * Lifecycle method method called by createMany. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes createMany 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 createMany. + * + * @name Adapter#beforeCreateMany + * @method + * @param {Object} mapper The `mapper` argument passed to createMany. + * @param {Object[]} props The `props` argument passed to createMany. + * @param {Object} opts The `opts` argument passed to createMany. + * @property {string} opts.op `beforeCreateMany` + */ + beforeCreateMany: noop, + + /** + * Lifecycle method method called by destroy. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes destroy to wait for the Promise to resolve before continuing. + * + * A thrown error or rejected Promise will bubble up and reject the Promise returned by destroy. + * + * @name Adapter#beforeDestroy + * @method + * @param {Object} mapper The `mapper` argument passed to destroy. + * @param {(string|number)} id The `id` argument passed to destroy. + * @param {Object} opts The `opts` argument passed to destroy. + * @property {string} opts.op `beforeDestroy` + */ + beforeDestroy: noop, + + /** + * Lifecycle method method called by destroyAll. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes destroyAll to wait for the Promise to resolve before continuing. + * + * A thrown error or rejected Promise will bubble up and reject the Promise returned by destroyAll. + * + * @name Adapter#beforeDestroyAll + * @method + * @param {Object} mapper The `mapper` argument passed to destroyAll. + * @param {Object} query The `query` argument passed to destroyAll. + * @param {Object} opts The `opts` argument passed to destroyAll. + * @property {string} opts.op `beforeDestroyAll` + */ + beforeDestroyAll: noop, + + /** + * Lifecycle method method called by find. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes find to wait for the Promise to resolve before continuing. + * + * A thrown error or rejected Promise will bubble up and reject the Promise returned by find. + * + * @name Adapter#beforeFind + * @method + * @param {Object} mapper The `mapper` argument passed to find. + * @param {(string|number)} id The `id` argument passed to find. + * @param {Object} opts The `opts` argument passed to find. + * @property {string} opts.op `beforeFind` + */ + beforeFind: noop, + + /** + * Lifecycle method method called by findAll. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes findAll to wait for the Promise to resolve before continuing. + * + * A thrown error or rejected Promise will bubble up and reject the Promise returned by findAll. + * + * @name Adapter#beforeFindAll + * @method + * @param {Object} mapper The `mapper` argument passed to findAll. + * @param {Object} query The `query` argument passed to findAll. + * @param {Object} opts The `opts` argument passed to findAll. + * @property {string} opts.op `beforeFindAll` + */ + beforeFindAll: noop, + + /** + * Lifecycle method method called by sum. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes sum to wait for the Promise to resolve before continuing. + * + * A thrown error or rejected Promise will bubble up and reject the Promise returned by sum. + * + * @name Adapter#beforeSum + * @method + * @param {Object} mapper The `mapper` argument passed to sum. + * @param {Object} query The `query` argument passed to sum. + * @param {Object} opts The `opts` argument passed to sum. + * @property {string} opts.op `beforeSum` + */ + beforeSum: noop, + + /** + * Lifecycle method method called by update. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes update 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 update. + * + * @name Adapter#beforeUpdate + * @method + * @param {Object} mapper The `mapper` argument passed to update. + * @param {(string|number)} id The `id` argument passed to update. + * @param {Object} props The `props` argument passed to update. + * @param {Object} opts The `opts` argument passed to update. + * @property {string} opts.op `beforeUpdate` + */ + beforeUpdate: noop, + + /** + * Lifecycle method method called by updateAll. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes updateAll 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 updateAll. + * + * @name Adapter#beforeUpdateAll + * @method + * @param {Object} mapper The `mapper` argument passed to updateAll. + * @param {Object} props The `props` argument passed to updateAll. + * @param {Object} query The `query` argument passed to updateAll. + * @param {Object} opts The `opts` argument passed to updateAll. + * @property {string} opts.op `beforeUpdateAll` + */ + beforeUpdateAll: noop, + + /** + * Lifecycle method method called by updateMany. + * + * Override this method to add custom behavior for this lifecycle hook. + * + * Returning a Promise causes updateMany 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 updateMany. + * + * @name Adapter#beforeUpdateMany + * @method + * @param {Object} mapper The `mapper` argument passed to updateMany. + * @param {Object[]} props The `props` argument passed to updateMany. + * @param {Object} opts The `opts` argument passed to updateMany. + * @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 + * @return {*} + */ + makeHasManyForeignKeys: function makeHasManyForeignKeys(mapper, def, record) { + return jsData.utils.get(record, mapper.idAttribute); + }, + + + /** + * Return the foreignKey from the given record for the provided relationship. + * + * Override with care. + * + * @name Adapter#makeBelongsToForeignKey + * @method + * @return {*} + */ + makeBelongsToForeignKey: function makeBelongsToForeignKey(mapper, def, record) { + return def.getForeignKey(record); + }, + + + /** + * Retrieve sum of the specified field of the records that match the selection + * query. Called by `Mapper#sum`. + * + * @name Adapter#sum + * @method + * @param {Object} mapper The mapper. + * @param {string} field By to sum. + * @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} + */ + sum: function sum(mapper, field, query, opts) { + var _this13 = this; + + var op = void 0; + if (!jsData.utils.isString(field)) { + throw new Error('field must be a string!'); + } + query || (query = {}); + opts || (opts = {}); + + // beforeSum lifecycle hook + op = opts.op = 'beforeSum'; + return jsData.utils.resolve(this[op](mapper, field, query, opts)).then(function () { + // Allow for re-assignment from lifecycle hook + op = opts.op = 'sum'; + _this13.dbg(op, mapper, field, query, opts); + return jsData.utils.resolve(_this13._sum(mapper, field, query, opts)); + }).then(function (results) { + var _results7 = slicedToArray(results, 2), + data = _results7[0], + result = _results7[1]; + + result || (result = {}); + var response = new Response(data, result, op); + response = _this13.respond(response, opts); + + // afterSum lifecycle hook + op = opts.op = 'afterSum'; + return jsData.utils.resolve(_this13[op](mapper, field, query, opts, response)).then(function (_response) { + return _response === undefined ? response : _response; + }); + }); + }, + + + /** + * @name Adapter#respond + * @method + * @param {Object} response Response object. + * @param {Object} opts Configuration options. + * return {Object} If `opts.raw == true` then return `response`, else return + * `response.data`. + */ + respond: function respond(response, opts) { + return this.getOpt('raw', opts) ? response : response.data; + }, + + + /** + * Apply the given update to the record with the specified primary key. Called + * by `Mapper#update`. + * + * @name Adapter#update + * @method + * @param {Object} mapper The mapper. + * @param {(string|number)} id The primary key of the record to be updated. + * @param {Object} props The update to apply to the record. + * @param {Object} [opts] Configuration options. + * @param {boolean} [opts.raw=false] Whether to return a more detailed + * response object. + * @return {Promise} + */ + update: function update(mapper, id, props, opts) { + var _this14 = this; + + props || (props = {}); + opts || (opts = {}); + var op = void 0; + + // beforeUpdate lifecycle hook + op = opts.op = 'beforeUpdate'; + return jsData.utils.resolve(this[op](mapper, id, 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 = 'update'; + _this14.dbg(op, mapper, id, props, opts); + return jsData.utils.resolve(_this14._update(mapper, id, props, opts)); + }).then(function (results) { + var _results8 = slicedToArray(results, 2), + data = _results8[0], + result = _results8[1]; + + result || (result = {}); + var response = new Response(data, result, 'update'); + response.updated = data ? 1 : 0; + response = _this14.respond(response, opts); + + // afterUpdate lifecycle hook + op = opts.op = 'afterUpdate'; + return jsData.utils.resolve(_this14[op](mapper, id, props, opts, response)).then(function (_response) { + return _response === undefined ? response : _response; + }); + }); + }, + + + /** + * Apply the given update to all records that match the selection query. + * Called by `Mapper#updateAll`. + * + * @name Adapter#updateAll + * @method + * @param {Object} mapper The mapper. + * @param {Object} props The update to apply to the selected records. + * @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} + */ + updateAll: function updateAll(mapper, props, query, opts) { + var _this15 = this; + + props || (props = {}); + query || (query = {}); + opts || (opts = {}); + var op = void 0; + + // beforeUpdateAll lifecycle hook + op = opts.op = 'beforeUpdateAll'; + return jsData.utils.resolve(this[op](mapper, props, query, opts)).then(function (_props) { + // Allow for re-assignment from lifecycle hook + props = _props === undefined ? props : _props; + props = withoutRelations(mapper, props, opts); + op = opts.op = 'updateAll'; + _this15.dbg(op, mapper, props, query, opts); + return jsData.utils.resolve(_this15._updateAll(mapper, props, query, opts)); + }).then(function (results) { + var _results9 = slicedToArray(results, 2), + data = _results9[0], + result = _results9[1]; + + data || (data = []); + result || (result = {}); + var response = new Response(data, result, 'updateAll'); + response.updated = data.length; + response = _this15.respond(response, opts); + + // afterUpdateAll lifecycle hook + op = opts.op = 'afterUpdateAll'; + return jsData.utils.resolve(_this15[op](mapper, props, query, opts, response)).then(function (_response) { + return _response === undefined ? response : _response; + }); + }); + }, + + + /** + * Update the given records in a single batch. Called by `Mapper#updateMany`. + * + * @name Adapter#updateMany + * @method + * @param {Object} mapper The mapper. + * @param {Object[]} records The records to update. + * @param {Object} [opts] Configuration options. + * @param {boolean} [opts.raw=false] Whether to return a more detailed + * response object. + * @return {Promise} + */ + updateMany: function updateMany(mapper, records, opts) { + var _this16 = this; + + records || (records = []); + opts || (opts = {}); + var op = void 0; + var idAttribute = mapper.idAttribute; + + records = records.filter(function (record) { + return jsData.utils.get(record, idAttribute); + }); + + // beforeUpdateMany lifecycle hook + op = opts.op = 'beforeUpdateMany'; + return jsData.utils.resolve(this[op](mapper, records, opts)).then(function (_records) { + // Allow for re-assignment from lifecycle hook + records = _records === undefined ? records : _records; + records = records.map(function (record) { + return withoutRelations(mapper, record, opts); + }); + op = opts.op = 'updateMany'; + _this16.dbg(op, mapper, records, opts); + return jsData.utils.resolve(_this16._updateMany(mapper, records, opts)); + }).then(function (results) { + var _results10 = slicedToArray(results, 2), + data = _results10[0], + result = _results10[1]; + + data || (data = []); + result || (result = {}); + var response = new Response(data, result, 'updateMany'); + response.updated = data.length; + response = _this16.respond(response, opts); + + // afterUpdateMany lifecycle hook + op = opts.op = 'afterUpdateMany'; + return jsData.utils.resolve(_this16[op](mapper, records, opts, response)).then(function (_response) { + return _response === undefined ? response : _response; + }); + }); + } +}); + +/** + * Create a subclass of this Adapter: + * + * @example Adapter.extend + * // Normally you would do: import {Adapter} from 'js-data' + * const JSData = require('js-data@3.0.0-beta.10') + * const {Adapter} = JSData + * console.log('Using JSData v' + JSData.version.full) + * + * // Extend the class using ES2015 class syntax. + * class CustomAdapterClass extends Adapter { + * foo () { return 'bar' } + * static beep () { return 'boop' } + * } + * const customAdapter = new CustomAdapterClass() + * console.log(customAdapter.foo()) + * console.log(CustomAdapterClass.beep()) + * + * // Extend the class using alternate method. + * const OtherAdapterClass = Adapter.extend({ + * foo () { return 'bar' } + * }, { + * beep () { return 'boop' } + * }) + * const otherAdapter = new OtherAdapterClass() + * console.log(otherAdapter.foo()) + * console.log(OtherAdapterClass.beep()) + * + * // Extend the class, providing a custom constructor. + * function AnotherAdapterClass () { + * Adapter.call(this) + * this.created_at = new Date().getTime() + * } + * Adapter.extend({ + * constructor: AnotherAdapterClass, + * foo () { return 'bar' } + * }, { + * beep () { return 'boop' } + * }) + * const anotherAdapter = new AnotherAdapterClass() + * console.log(anotherAdapter.created_at) + * console.log(anotherAdapter.foo()) + * console.log(AnotherAdapterClass.beep()) + * + * @method Adapter.extend + * @param {Object} [props={}] Properties to add to the prototype of the + * subclass. + * @param {Object} [props.constructor] Provide a custom constructor function + * to be used as the subclass itself. + * @param {Object} [classProps={}] Static properties to add to the subclass. + * @returns {Constructor} Subclass of this Adapter class. + */ + +var queue = []; +var taskInProcess = false; + +function enqueue(task) { + queue.push(task); +} + +function dequeue() { + if (queue.length && !taskInProcess) { + taskInProcess = true; + queue[0](); + } +} + +function queueTask(task) { + if (!queue.length) { + enqueue(task); + dequeue(); + } else { + enqueue(task); + } +} + +function createTask(fn) { + return new jsData.utils.Promise(fn).then(function (result) { + taskInProcess = false; + queue.shift(); + setTimeout(dequeue, 0); + return result; + }, function (err) { + taskInProcess = false; + queue.shift(); + setTimeout(dequeue, 0); + return jsData.utils.reject(err); + }); +} + +var __super__ = Adapter.prototype; + +/** + * FirebaseAdapter class. + * + * @example Browser + * import {DataStore} from 'js-data' + * import firebase from 'firebase' + * import {FirebaseAdapter} from 'js-data-firebase' + * const store = new DataStore() + * firebase.initializeApp({ + * apiKey: 'your-api-key', + * databaseURL: 'your-database-url' + * }) + * const adapter = new FirebaseAdapter({ db: firebase.database() }) + * store.registerAdapter('firebase', adapter, { 'default': true }) + * + * @example Node.js + * import {Container} from 'js-data' + * import firebase from 'firebase' + * import {FirebaseAdapter} from 'js-data-firebase' + * const store = new Container() + * firebase.initializeApp({ + * databaseURL: 'your-database-url', + * serviceAccount: 'path/to/keyfile' + * }) + * const adapter = new FirebaseAdapter({ db: firebase.database() }) + * store.registerAdapter('firebase', adapter, { 'default': true }) + * + * @class FirebaseAdapter + * @param {Object} [opts] Configuration opts. + * @param {Object} [opts.db] See {@link FirebaseAdapter#db} + * @param {boolean} [opts.debug=false] See {@link Adapter#debug}. + * @param {boolean} [opts.raw=false] See {@link Adapter#raw}. + */ +function FirebaseAdapter(opts) { + jsData.utils.classCallCheck(this, FirebaseAdapter); + opts || (opts = {}); + Adapter.call(this, opts); + + /** + * The database instance used by this adapter. + * + * @name FirebaseAdapter#db + * @type {Object} + * @default firebase.database() + */ + if (opts.db) { + this.db = opts.db || firebase.database(); + } +} + +// Setup prototype inheritance from Adapter +FirebaseAdapter.prototype = Object.create(Adapter.prototype, { + constructor: { + value: FirebaseAdapter, + enumerable: false, + writable: true, + configurable: true + } +}); + +Object.defineProperty(FirebaseAdapter, '__super__', { + configurable: true, + value: Adapter +}); + +/** + * Alternative to ES6 class syntax for extending `FirebaseAdapter`. + * + * @example Using the ES2015 class syntax. + * class MyFirebaseAdapter extends FirebaseAdapter {...} + * const adapter = new MyFirebaseAdapter() + * + * @example Using {@link FirebaseAdapter.extend}. + * var instanceProps = {...} + * var classProps = {...} + * + * var MyFirebaseAdapter = FirebaseAdapter.extend(instanceProps, classProps) + * var adapter = new MyFirebaseAdapter() + * + * @method FirebaseAdapter.extend + * @static + * @param {Object} [instanceProps] Properties that will be added to the + * prototype of the subclass. + * @param {Object} [classProps] Properties that will be added as static + * properties to the subclass itself. + * @return {Constructor} Subclass of `FirebaseAdapter`. + */ +FirebaseAdapter.extend = jsData.utils.extend; + +jsData.utils.addHiddenPropsToTarget(FirebaseAdapter.prototype, { + /** + * Retrieve the number of records that match the selection query. Internal + * method used by Adapter#count. + * + * @name FirebaseAdapter#_count + * @method + * @private + * @param {Object} mapper The mapper. + * @param {Object} query Selection query. + * @param {Object} [opts] Configuration options. + * @return {Promise} + */ + _count: function _count(mapper, query, opts) { + query || (query = {}); + opts || (opts = {}); + return this._findAll(mapper, query, opts).then(function (result) { + result[0] = result[0].length; + return result; + }); + }, + + + /** + * Create a new record. Internal method used by Adapter#create. + * + * @name FirebaseAdapter#_create + * @method + * @private + * @param {Object} mapper The mapper. + * @param {Object} props The record to be created. + * @param {Object} [opts] Configuration options. + * @return {Promise} + */ + _create: function _create(mapper, props, opts) { + props || (props = {}); + opts || (opts = {}); + return this._upsert(mapper, props, opts); + }, + _upsert: function _upsert(mapper, props, opts) { + var _this = this; + + var _props = jsData.utils.plainCopy(props); + opts || (opts = {}); + + var id = jsData.utils.get(_props, mapper.idAttribute); + var collectionRef = this.getRef(mapper, opts); + + var itemRef = void 0; + + if (jsData.utils.isSorN(id)) { + itemRef = collectionRef.child(id); + } else { + itemRef = collectionRef.push(); + jsData.utils.set(_props, mapper.idAttribute, itemRef.key); + } + + return itemRef.set(_props).then(function () { + return _this._once(itemRef); + }).then(function (record) { + if (!record) { + throw new Error('Not Found'); + } + return [record, { ref: itemRef }]; + }); + }, + _upsertBatch: function _upsertBatch(mapper, records, opts) { + var _this2 = this; + + opts || (opts = {}); + + var idAttribute = mapper.idAttribute; + var refValueCollection = []; + var collectionRef = this.getRef(mapper, opts); + + // generate path for each + records.forEach(function (record) { + var id = jsData.utils.get(record, idAttribute); + var _props = jsData.utils.plainCopy(record); + var itemRef = void 0; + + if (jsData.utils.isSorN(id)) { + itemRef = collectionRef.child(id); + } else { + itemRef = collectionRef.push(); + jsData.utils.set(_props, idAttribute, itemRef.key); + } + refValueCollection.push({ ref: itemRef, props: _props }); + }); + + return this._atomicUpdate(mapper, refValueCollection, opts).then(function () { + // since UDFs and timestamps can alter values on write, let's get the latest values + return jsData.utils.Promise.all(refValueCollection.map(function (item) { + return _this2._once(item.ref); + })); + }).then(function (records) { + // just return the updated records and not the refs? + return [records, { ref: refValueCollection.map(function (item) { + return item.ref; + }) }]; + }); + }, + _once: function _once(ref) { + return ref.once('value').then(function (dataSnapshot) { + if (!dataSnapshot.exists()) { + return null; + } + return dataSnapshot.val(); + }); + }, + _atomicUpdate: function _atomicUpdate(mapper, refValueCollection, opts) { + var _this3 = this; + + // collection of refs and the new value to set at that ref + // do a deep-path update off the database + // see https://www.firebase.com/blog/2015-09-24-atomic-writes-and-more.html + var atomicUpdate = {}; + refValueCollection.forEach(function (item) { + atomicUpdate[item.ref.toString().replace(_this3.getRef(mapper, opts).toString(), '')] = item.props; + }); + return this.getRef(mapper, opts).update(atomicUpdate); + }, + + + /** + * Create multiple records in a single batch. Internal method used by + * Adapter#createMany. + * + * @name FirebaseAdapter#_createMany + * @method + * @private + * @param {Object} mapper The mapper. + * @param {Object} records The records to be created. + * @param {Object} [opts] Configuration options. + * @return {Promise} + */ + _createMany: function _createMany(mapper, records, opts) { + opts || (opts = {}); + return this._upsertBatch(mapper, records, opts); + }, + + + /** + * Destroy the record with the given primary key. Internal method used by + * Adapter#destroy. + * + * @name FirebaseAdapter#_destroy + * @method + * @private + * @param {Object} mapper The mapper. + * @param {(string|number)} id Primary key of the record to destroy. + * @param {Object} [opts] Configuration options. + * @return {Promise} + */ + _destroy: function _destroy(mapper, id, opts) { + opts || (opts = {}); + var ref = this.getRef(mapper, opts).child(id); + return ref.remove().then(function () { + return [undefined, { ref: ref }]; + }); + }, + + + /** + * Destroy the records that match the selection query. Internal method used by + * Adapter#destroyAll. + * + * @name FirebaseAdapter#_destroyAll + * @method + * @private + * @param {Object} mapper the mapper. + * @param {Object} [query] Selection query. + * @param {Object} [opts] Configuration options. + * @return {Promise} + */ + _destroyAll: function _destroyAll(mapper, query, opts) { + var _this4 = this; + + query || (query = {}); + opts || (opts = {}); + + return this._findAll(mapper, query).then(function (results) { + var _results = slicedToArray(results, 1), + records = _results[0]; + + var idAttribute = mapper.idAttribute; + return jsData.utils.Promise.all(records.map(function (record) { + return _this4._destroy(mapper, jsData.utils.get(record, idAttribute), opts); + })); + }).then(function () { + return [undefined, {}]; + }); + }, + + + /** + * Retrieve the record with the given primary key. Internal method used by + * Adapter#find. + * + * @name FirebaseAdapter#_find + * @method + * @private + * @param {Object} mapper The mapper. + * @param {(string|number)} id Primary key of the record to retrieve. + * @param {Object} [opts] Configuration options. + * @return {Promise} + */ + _find: function _find(mapper, id, opts) { + opts || (opts = {}); + var itemRef = this.getRef(mapper, opts).child(id); + return this._once(itemRef).then(function (record) { + if (!record) { + record = undefined; + } + return [record, { ref: itemRef }]; + }); + }, + + /** + * Retrieve the records that match the selection query. Internal method used + * by Adapter#findAll. + * + * @name FirebaseAdapter#_findAll + * @method + * @private + * @param {Object} mapper The mapper. + * @param {Object} query Selection query. + * @param {Object} [opts] Configuration options. + * @return {Promise} + */ + _findAll: function _findAll(mapper, query, opts) { + query || (query = {}); + opts || (opts = {}); + + var collectionRef = this.getRef(mapper, opts); + + return collectionRef.once('value').then(function (dataSnapshot) { + var data = dataSnapshot.val(); + if (!data) { + return [[], { ref: collectionRef }]; + } + var records = []; + jsData.utils.forOwn(data, function (value, key) { + records.push(value); + }); + var _query = new jsData.Query({ + index: { + getAll: function getAll() { + return records; + } + } + }); + return [_query.filter(query).run(), { ref: collectionRef }]; + }); + }, + + + /** + * Retrieve the number of records that match the selection query. Internal + * method used by Adapter#sum. + * + * @name FirebaseAdapter#_sum + * @method + * @private + * @param {Object} mapper The mapper. + * @param {string} field The field to sum. + * @param {Object} query Selection query. + * @param {Object} [opts] Configuration options. + * @return {Promise} + */ + _sum: function _sum(mapper, field, query, opts) { + return this._findAll(mapper, query, opts).then(function (result) { + result[0] = result[0].reduce(function (sum, record) { + return sum + (jsData.utils.get(record, field) || 0); + }, 0); + return result; + }); + }, + + + /** + * Apply the given update to the record with the specified primary key. + * Internal method used by Adapter#update. + * + * @name FirebaseAdapter#_update + * @method + * @private + * @param {Object} mapper The mapper. + * @param {(string|number)} id The primary key of the record to be updated. + * @param {Object} props The update to apply to the record. + * @param {Object} [opts] Configuration options. + * @return {Promise} + */ + _update: function _update(mapper, id, props, opts) { + var _this5 = this; + + props || (props = {}); + opts || (opts = {}); + + var itemRef = this.getRef(mapper, opts).child(id); + return this._once(itemRef).then(function (currentVal) { + if (!currentVal) { + throw new Error('Not Found'); + } + jsData.utils.deepMixIn(currentVal, props); + return itemRef.set(currentVal); + }).then(function () { + return _this5._once(itemRef); + }).then(function (record) { + if (!record) { + throw new Error('Not Found'); + } + return [record, { ref: itemRef }]; + }); + }, + + + /** + * Apply the given update to all records that match the selection query. + * Internal method used by Adapter#updateAll. + * + * @name FirebaseAdapter#_updateAll + * @method + * @private + * @param {Object} mapper The mapper. + * @param {Object} props The update to apply to the selected records. + * @param {Object} [query] Selection query. + * @param {Object} [opts] Configuration options. + * @return {Promise} + */ + _updateAll: function _updateAll(mapper, props, query, opts) { + var _this6 = this; + + opts || (opts = {}); + props || (props = {}); + query || (query = {}); + + return this._findAll(mapper, query, opts).then(function (results) { + var _results2 = slicedToArray(results, 1), + records = _results2[0]; + + records.forEach(function (record) { + return jsData.utils.deepMixIn(record, props); + }); + return _this6._upsertBatch(mapper, records, opts); + }); + }, + + + /** + * Update the given records in a single batch. Internal method used by + * Adapter#updateMany. + * + * @name FirebaseAdapter#updateMany + * @method + * @private + * @param {Object} mapper The mapper. + * @param {Object[]} records The records to update. + * @param {Object} [opts] Configuration options. + * @return {Promise} + */ + _updateMany: function _updateMany(mapper, records, opts) { + opts || (opts = {}); + return this._upsertBatch(mapper, records, opts); + }, + getRef: function getRef(mapper, opts) { + opts = opts || {}; + return this.db.ref().child(opts.endpoint || mapper.endpoint || mapper.name); + }, + create: function create(mapper, props, opts) { + var _this7 = this; + + return createTask(function (success, failure) { + queueTask(function () { + __super__.create.call(_this7, mapper, props, opts).then(success, failure); + }); + }); + }, + createMany: function createMany(mapper, props, opts) { + var _this8 = this; + + return createTask(function (success, failure) { + queueTask(function () { + __super__.createMany.call(_this8, mapper, props, opts).then(success, failure); + }); + }); + }, + destroy: function destroy(mapper, id, opts) { + var _this9 = this; + + return createTask(function (success, failure) { + queueTask(function () { + __super__.destroy.call(_this9, mapper, id, opts).then(success, failure); + }); + }); + }, + destroyAll: function destroyAll(mapper, query, opts) { + var _this10 = this; + + return createTask(function (success, failure) { + queueTask(function () { + __super__.destroyAll.call(_this10, mapper, query, opts).then(success, failure); + }); + }); + }, + update: function update(mapper, id, props, opts) { + var _this11 = this; + + return createTask(function (success, failure) { + queueTask(function () { + __super__.update.call(_this11, mapper, id, props, opts).then(success, failure); + }); + }); + }, + updateAll: function updateAll(mapper, props, query, opts) { + var _this12 = this; + + return createTask(function (success, failure) { + queueTask(function () { + __super__.updateAll.call(_this12, mapper, props, query, opts).then(success, failure); + }); + }); + }, + updateMany: function updateMany(mapper, records, opts) { + var _this13 = this; + + return createTask(function (success, failure) { + queueTask(function () { + __super__.updateMany.call(_this13, mapper, records, opts).then(success, failure); + }); + }); + } +}); + +/** + * Details of the current version of the `js-data-firebase` module. + * + * @name FirebaseAdapter.version + * @type {Object} + * @property {string} version.full The full semver value. + * @property {number} version.major The major version number. + * @property {number} version.minor The minor version number. + * @property {number} version.patch The patch version number. + * @property {(string|boolean)} version.alpha The alpha version value, + * otherwise `false` if the current version is not alpha. + * @property {(string|boolean)} version.beta The beta version value, + * otherwise `false` if the current version is not beta. + */ + +var version = { + full: '3.0.0', + major: 3, + minor: 0, + patch: 0 +}; + +/** + * {@link FirebaseAdapter} class. + * + * @name module:js-data-firebase.FirebaseAdapter + * @see FirebaseAdapter + */ + +/** + * Registered as `js-data-firebase` in NPM and Bower. + * + * @example Script tag + * var FirebaseAdapter = window.JSDataFirebase.FirebaseAdapter + * var adapter = new FirebaseAdapter() + * + * @example CommonJS + * var FirebaseAdapter = require('js-data-firebase').FirebaseAdapter + * var adapter = new FirebaseAdapter() + * + * @example ES2015 Modules + * import {FirebaseAdapter} from 'js-data-firebase' + * const adapter = new FirebaseAdapter() + * + * @example AMD + * define('myApp', ['js-data-firebase'], function (JSDataFirebase) { + * var FirebaseAdapter = JSDataFirebase.FirebaseAdapter + * var adapter = new FirebaseAdapter() + * + * // ... + * }) + * + * @module js-data-firebase + */ + +exports.FirebaseAdapter = FirebaseAdapter; +exports.version = version; + +Object.defineProperty(exports, '__esModule', { value: true }); + +}))); +//# sourceMappingURL=js-data-firebase.js.map diff --git a/dist/js-data-firebase.js.map b/dist/js-data-firebase.js.map new file mode 100644 index 0000000..a5e5c74 --- /dev/null +++ b/dist/js-data-firebase.js.map @@ -0,0 +1 @@ +{"version":3,"file":"js-data-firebase.js","sources":["../node_modules/js-data-adapter/src/index.js","../src/index.js"],"sourcesContent":["import { Component, utils } from 'js-data'\n\nexport const noop = function (...args) {\n const opts = args[args.length - 1]\n this.dbg(opts.op, ...args)\n return utils.resolve()\n}\n\nexport const noop2 = function (...args) {\n const opts = args[args.length - 2]\n this.dbg(opts.op, ...args)\n return utils.resolve()\n}\n\nexport const unique = function (array) {\n const seen = {}\n const final = []\n array.forEach(function (item) {\n if (item in seen) {\n return\n }\n final.push(item)\n seen[item] = 0\n })\n return final\n}\n\nexport const withoutRelations = function (mapper, props, opts) {\n opts || (opts = {})\n opts.with || (opts.with = [])\n const relationFields = mapper.relationFields || []\n const toStrip = relationFields.filter((value) => opts.with.indexOf(value) === -1)\n return utils.omit(props, toStrip)\n}\n\nexport const reserved = [\n 'orderBy',\n 'sort',\n 'limit',\n 'offset',\n 'skip',\n 'where'\n]\n\n/**\n * Response object used when `raw` is `true`. May contain other fields in\n * addition to `data`.\n *\n * @class Response\n */\nexport function Response (data, meta, op) {\n meta || (meta = {})\n\n /**\n * Response data.\n *\n * @name Response#data\n * @type {*}\n */\n this.data = data\n\n utils.fillIn(this, meta)\n\n /**\n * The operation for which the response was created.\n *\n * @name Response#op\n * @type {string}\n */\n this.op = op\n}\n\nconst DEFAULTS = {\n /**\n * Whether to log debugging information.\n *\n * @name Adapter#debug\n * @type {boolean}\n * @default false\n */\n debug: false,\n\n /**\n * Whether to return a more detailed response object.\n *\n * @name Adapter#raw\n * @type {boolean}\n * @default false\n */\n raw: false\n}\n\n/**\n * Abstract class meant to be extended by adapters.\n *\n * @class Adapter\n * @abstract\n * @extends Component\n * @param {Object} [opts] Configuration opts.\n * @param {boolean} [opts.debug=false] Whether to log debugging information.\n * @param {boolean} [opts.raw=false] Whether to return a more detailed response\n * object.\n */\nexport function Adapter (opts) {\n utils.classCallCheck(this, Adapter)\n Component.call(this, opts)\n opts || (opts = {})\n utils.fillIn(opts, DEFAULTS)\n utils.fillIn(this, opts)\n}\n\nComponent.extend({\n constructor: Adapter,\n\n /**\n * Lifecycle method method called by count.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes count to wait for the Promise to resolve before continuing.\n *\n * If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be the count.\n *\n * `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.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by count.\n *\n * @name Adapter#afterCount\n * @method\n * @param {Object} mapper The `mapper` argument passed to count.\n * @param {Object} props The `props` argument passed to count.\n * @param {Object} opts The `opts` argument passed to count.\n * @property {string} opts.op `afterCount`\n * @param {Object|Response} response Count or {@link Response}, depending on the value of `opts.raw`.\n */\n afterCount: noop2,\n\n /**\n * Lifecycle method method called by create.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes create to wait for the Promise to resolve before continuing.\n *\n * If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be the created record.\n *\n * `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.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by create.\n *\n * @name Adapter#afterCreate\n * @method\n * @param {Object} mapper The `mapper` argument passed to create.\n * @param {Object} props The `props` argument passed to create.\n * @param {Object} opts The `opts` argument passed to create.\n * @property {string} opts.op `afterCreate`\n * @param {Object|Response} response Created record or {@link Response}, depending on the value of `opts.raw`.\n */\n afterCreate: noop2,\n\n /**\n * Lifecycle method method called by createMany.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes createMany to wait for the Promise to resolve before continuing.\n *\n * If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be the created records.\n *\n * `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.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by createMany.\n *\n * @name Adapter#afterCreate\n * @method\n * @param {Object} mapper The `mapper` argument passed to createMany.\n * @param {Object[]} props The `props` argument passed to createMany.\n * @param {Object} opts The `opts` argument passed to createMany.\n * @property {string} opts.op `afterCreateMany`\n * @param {Object[]|Response} response Created records or {@link Response}, depending on the value of `opts.raw`.\n */\n afterCreateMany: noop2,\n\n /**\n * Lifecycle method method called by destroy.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes destroy to wait for the Promise to resolve before continuing.\n *\n * If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be `undefined`.\n *\n * `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.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by destroy.\n *\n * @name Adapter#afterDestroy\n * @method\n * @param {Object} mapper The `mapper` argument passed to destroy.\n * @param {(string|number)} id The `id` argument passed to destroy.\n * @param {Object} opts The `opts` argument passed to destroy.\n * @property {string} opts.op `afterDestroy`\n * @param {undefined|Response} response `undefined` or {@link Response}, depending on the value of `opts.raw`.\n */\n afterDestroy: noop2,\n\n /**\n * Lifecycle method method called by destroyAll.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes destroyAll to wait for the Promise to resolve before continuing.\n *\n * If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be `undefined`.\n *\n * `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.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by destroyAll.\n *\n * @name Adapter#afterDestroyAll\n * @method\n * @param {Object} mapper The `mapper` argument passed to destroyAll.\n * @param {Object} query The `query` argument passed to destroyAll.\n * @param {Object} opts The `opts` argument passed to destroyAll.\n * @property {string} opts.op `afterDestroyAll`\n * @param {undefined|Response} response `undefined` or {@link Response}, depending on the value of `opts.raw`.\n */\n afterDestroyAll: noop2,\n\n /**\n * Lifecycle method method called by find.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes find to wait for the Promise to resolve before continuing.\n *\n * If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be the found record, if any.\n *\n * `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.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by find.\n *\n * @name Adapter#afterFind\n * @method\n * @param {Object} mapper The `mapper` argument passed to find.\n * @param {(string|number)} id The `id` argument passed to find.\n * @param {Object} opts The `opts` argument passed to find.\n * @property {string} opts.op `afterFind`\n * @param {Object|Response} response The found record or {@link Response}, depending on the value of `opts.raw`.\n */\n afterFind: noop2,\n\n /**\n * Lifecycle method method called by findAll.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes findAll to wait for the Promise to resolve before continuing.\n *\n * If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be the found records, if any.\n *\n * `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.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by findAll.\n *\n * @name Adapter#afterFindAll\n * @method\n * @param {Object} mapper The `mapper` argument passed to findAll.\n * @param {Object} query The `query` argument passed to findAll.\n * @param {Object} opts The `opts` argument passed to findAll.\n * @property {string} opts.op `afterFindAll`\n * @param {Object[]|Response} response The found records or {@link Response}, depending on the value of `opts.raw`.\n */\n afterFindAll: noop2,\n\n /**\n * Lifecycle method method called by sum.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes sum to wait for the Promise to resolve before continuing.\n *\n * If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be the sum.\n *\n * `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.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by sum.\n *\n * @name Adapter#afterSum\n * @method\n * @param {Object} mapper The `mapper` argument passed to sum.\n * @param {string} field The `field` argument passed to sum.\n * @param {Object} query The `query` argument passed to sum.\n * @param {Object} opts The `opts` argument passed to sum.\n * @property {string} opts.op `afterSum`\n * @param {Object|Response} response Count or {@link Response}, depending on the value of `opts.raw`.\n */\n afterSum: noop2,\n\n /**\n * Lifecycle method method called by update.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes update to wait for the Promise to resolve before continuing.\n *\n * If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be the updated record.\n *\n * `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.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by update.\n *\n * @name Adapter#afterUpdate\n * @method\n * @param {Object} mapper The `mapper` argument passed to update.\n * @param {(string|number)} id The `id` argument passed to update.\n * @param {Object} props The `props` argument passed to update.\n * @param {Object} opts The `opts` argument passed to update.\n * @property {string} opts.op `afterUpdate`\n * @param {Object|Response} response The updated record or {@link Response}, depending on the value of `opts.raw`.\n */\n afterUpdate: noop2,\n\n /**\n * Lifecycle method method called by updateAll.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes updateAll to wait for the Promise to resolve before continuing.\n *\n * If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be the updated records, if any.\n *\n * `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.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by updateAll.\n *\n * @name Adapter#afterUpdateAll\n * @method\n * @param {Object} mapper The `mapper` argument passed to updateAll.\n * @param {Object} props The `props` argument passed to updateAll.\n * @param {Object} query The `query` argument passed to updateAll.\n * @param {Object} opts The `opts` argument passed to updateAll.\n * @property {string} opts.op `afterUpdateAll`\n * @param {Object[]|Response} response The updated records or {@link Response}, depending on the value of `opts.raw`.\n */\n afterUpdateAll: noop2,\n\n /**\n * Lifecycle method method called by updateMany.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes updateMany to wait for the Promise to resolve before continuing.\n *\n * If `opts.raw` is `true` then `response` will be a detailed response object, otherwise `response` will be the updated records, if any.\n *\n * `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.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by updateMany.\n *\n * @name Adapter#afterUpdateMany\n * @method\n * @param {Object} mapper The `mapper` argument passed to updateMany.\n * @param {Object[]} records The `records` argument passed to updateMany.\n * @param {Object} opts The `opts` argument passed to updateMany.\n * @property {string} opts.op `afterUpdateMany`\n * @param {Object[]|Response} response The updated records or {@link Response}, depending on the value of `opts.raw`.\n */\n afterUpdateMany: noop2,\n\n /**\n * Lifecycle method method called by count.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes count to wait for the Promise to resolve before continuing.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by count.\n *\n * @name Adapter#beforeCount\n * @method\n * @param {Object} mapper The `mapper` argument passed to count.\n * @param {Object} query The `query` argument passed to count.\n * @param {Object} opts The `opts` argument passed to count.\n * @property {string} opts.op `beforeCount`\n */\n beforeCount: noop,\n\n /**\n * Lifecycle method method called by create.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes create to wait for the Promise to resolve before continuing.\n *\n * `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.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by create.\n *\n * @name Adapter#beforeCreate\n * @method\n * @param {Object} mapper The `mapper` argument passed to create.\n * @param {Object} props The `props` argument passed to create.\n * @param {Object} opts The `opts` argument passed to create.\n * @property {string} opts.op `beforeCreate`\n */\n beforeCreate: noop,\n\n /**\n * Lifecycle method method called by createMany.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes createMany to wait for the Promise to resolve before continuing.\n *\n * `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.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by createMany.\n *\n * @name Adapter#beforeCreateMany\n * @method\n * @param {Object} mapper The `mapper` argument passed to createMany.\n * @param {Object[]} props The `props` argument passed to createMany.\n * @param {Object} opts The `opts` argument passed to createMany.\n * @property {string} opts.op `beforeCreateMany`\n */\n beforeCreateMany: noop,\n\n /**\n * Lifecycle method method called by destroy.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes destroy to wait for the Promise to resolve before continuing.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by destroy.\n *\n * @name Adapter#beforeDestroy\n * @method\n * @param {Object} mapper The `mapper` argument passed to destroy.\n * @param {(string|number)} id The `id` argument passed to destroy.\n * @param {Object} opts The `opts` argument passed to destroy.\n * @property {string} opts.op `beforeDestroy`\n */\n beforeDestroy: noop,\n\n /**\n * Lifecycle method method called by destroyAll.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes destroyAll to wait for the Promise to resolve before continuing.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by destroyAll.\n *\n * @name Adapter#beforeDestroyAll\n * @method\n * @param {Object} mapper The `mapper` argument passed to destroyAll.\n * @param {Object} query The `query` argument passed to destroyAll.\n * @param {Object} opts The `opts` argument passed to destroyAll.\n * @property {string} opts.op `beforeDestroyAll`\n */\n beforeDestroyAll: noop,\n\n /**\n * Lifecycle method method called by find.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes find to wait for the Promise to resolve before continuing.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by find.\n *\n * @name Adapter#beforeFind\n * @method\n * @param {Object} mapper The `mapper` argument passed to find.\n * @param {(string|number)} id The `id` argument passed to find.\n * @param {Object} opts The `opts` argument passed to find.\n * @property {string} opts.op `beforeFind`\n */\n beforeFind: noop,\n\n /**\n * Lifecycle method method called by findAll.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes findAll to wait for the Promise to resolve before continuing.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by findAll.\n *\n * @name Adapter#beforeFindAll\n * @method\n * @param {Object} mapper The `mapper` argument passed to findAll.\n * @param {Object} query The `query` argument passed to findAll.\n * @param {Object} opts The `opts` argument passed to findAll.\n * @property {string} opts.op `beforeFindAll`\n */\n beforeFindAll: noop,\n\n /**\n * Lifecycle method method called by sum.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes sum to wait for the Promise to resolve before continuing.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by sum.\n *\n * @name Adapter#beforeSum\n * @method\n * @param {Object} mapper The `mapper` argument passed to sum.\n * @param {Object} query The `query` argument passed to sum.\n * @param {Object} opts The `opts` argument passed to sum.\n * @property {string} opts.op `beforeSum`\n */\n beforeSum: noop,\n\n /**\n * Lifecycle method method called by update.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes update to wait for the Promise to resolve before continuing.\n *\n * `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.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by update.\n *\n * @name Adapter#beforeUpdate\n * @method\n * @param {Object} mapper The `mapper` argument passed to update.\n * @param {(string|number)} id The `id` argument passed to update.\n * @param {Object} props The `props` argument passed to update.\n * @param {Object} opts The `opts` argument passed to update.\n * @property {string} opts.op `beforeUpdate`\n */\n beforeUpdate: noop,\n\n /**\n * Lifecycle method method called by updateAll.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes updateAll to wait for the Promise to resolve before continuing.\n *\n * `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.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by updateAll.\n *\n * @name Adapter#beforeUpdateAll\n * @method\n * @param {Object} mapper The `mapper` argument passed to updateAll.\n * @param {Object} props The `props` argument passed to updateAll.\n * @param {Object} query The `query` argument passed to updateAll.\n * @param {Object} opts The `opts` argument passed to updateAll.\n * @property {string} opts.op `beforeUpdateAll`\n */\n beforeUpdateAll: noop,\n\n /**\n * Lifecycle method method called by updateMany.\n *\n * Override this method to add custom behavior for this lifecycle hook.\n *\n * Returning a Promise causes updateMany to wait for the Promise to resolve before continuing.\n *\n * `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.\n *\n * A thrown error or rejected Promise will bubble up and reject the Promise returned by updateMany.\n *\n * @name Adapter#beforeUpdateMany\n * @method\n * @param {Object} mapper The `mapper` argument passed to updateMany.\n * @param {Object[]} props The `props` argument passed to updateMany.\n * @param {Object} opts The `opts` argument passed to updateMany.\n * @property {string} opts.op `beforeUpdateMany`\n */\n beforeUpdateMany: noop,\n\n /**\n * Retrieve the number of records that match the selection query. Called by\n * `Mapper#count`.\n *\n * @name Adapter#count\n * @method\n * @param {Object} mapper The mapper.\n * @param {Object} [query] Selection query.\n * @param {Object} [query.where] Filtering criteria.\n * @param {string|Array} [query.orderBy] Sorting criteria.\n * @param {string|Array} [query.sort] Same as `query.sort`.\n * @param {number} [query.limit] Limit results.\n * @param {number} [query.skip] Offset results.\n * @param {number} [query.offset] Same as `query.skip`.\n * @param {Object} [opts] Configuration options.\n * @param {boolean} [opts.raw=false] Whether to return a more detailed\n * response object.\n * @return {Promise}\n */\n count (mapper, query, opts) {\n let op\n query || (query = {})\n opts || (opts = {})\n\n // beforeCount lifecycle hook\n op = opts.op = 'beforeCount'\n return utils.resolve(this[op](mapper, query, opts))\n .then(() => {\n // Allow for re-assignment from lifecycle hook\n op = opts.op = 'count'\n this.dbg(op, mapper, query, opts)\n return utils.resolve(this._count(mapper, query, opts))\n })\n .then((results) => {\n let [data, result] = results\n result || (result = {})\n let response = new Response(data, result, op)\n response = this.respond(response, opts)\n\n // afterCount lifecycle hook\n op = opts.op = 'afterCount'\n return utils.resolve(this[op](mapper, query, opts, response))\n .then((_response) => _response === undefined ? response : _response)\n })\n },\n\n /**\n * Create a new record. Called by `Mapper#create`.\n *\n * @name Adapter#create\n * @method\n * @param {Object} mapper The mapper.\n * @param {Object} props The record to be created.\n * @param {Object} [opts] Configuration options.\n * @param {boolean} [opts.raw=false] Whether to return a more detailed\n * response object.\n * @return {Promise}\n */\n create (mapper, props, opts) {\n let op\n props || (props = {})\n opts || (opts = {})\n\n // beforeCreate lifecycle hook\n op = opts.op = 'beforeCreate'\n return utils.resolve(this[op](mapper, props, opts))\n .then((_props) => {\n // Allow for re-assignment from lifecycle hook\n props = _props === undefined ? props : _props\n props = withoutRelations(mapper, props, opts)\n op = opts.op = 'create'\n this.dbg(op, mapper, props, opts)\n return utils.resolve(this._create(mapper, props, opts))\n })\n .then((results) => {\n let [data, result] = results\n result || (result = {})\n let response = new Response(data, result, 'create')\n response.created = data ? 1 : 0\n response = this.respond(response, opts)\n\n // afterCreate lifecycle hook\n op = opts.op = 'afterCreate'\n return utils.resolve(this[op](mapper, props, opts, response))\n .then((_response) => _response === undefined ? response : _response)\n })\n },\n\n /**\n * Create multiple records in a single batch. Called by `Mapper#createMany`.\n *\n * @name Adapter#createMany\n * @method\n * @param {Object} mapper The mapper.\n * @param {Object} props The records to be created.\n * @param {Object} [opts] Configuration options.\n * @param {boolean} [opts.raw=false] Whether to return a more detailed\n * response object.\n * @return {Promise}\n */\n createMany (mapper, props, opts) {\n let op\n props || (props = {})\n opts || (opts = {})\n\n // beforeCreateMany lifecycle hook\n op = opts.op = 'beforeCreateMany'\n return utils.resolve(this[op](mapper, props, opts))\n .then((_props) => {\n // Allow for re-assignment from lifecycle hook\n props = _props === undefined ? props : _props\n props = props.map((record) => withoutRelations(mapper, record, opts))\n op = opts.op = 'createMany'\n this.dbg(op, mapper, props, opts)\n return utils.resolve(this._createMany(mapper, props, opts))\n })\n .then((results) => {\n let [data, result] = results\n data || (data = [])\n result || (result = {})\n let response = new Response(data, result, 'createMany')\n response.created = data.length\n response = this.respond(response, opts)\n\n // afterCreateMany lifecycle hook\n op = opts.op = 'afterCreateMany'\n return utils.resolve(this[op](mapper, props, opts, response))\n .then((_response) => _response === undefined ? response : _response)\n })\n },\n\n /**\n * Destroy the record with the given primary key. Called by\n * `Mapper#destroy`.\n *\n * @name Adapter#destroy\n * @method\n * @param {Object} mapper The mapper.\n * @param {(string|number)} id Primary key of the record to destroy.\n * @param {Object} [opts] Configuration options.\n * @param {boolean} [opts.raw=false] Whether to return a more detailed\n * response object.\n * @return {Promise}\n */\n destroy (mapper, id, opts) {\n let op\n opts || (opts = {})\n\n // beforeDestroy lifecycle hook\n op = opts.op = 'beforeDestroy'\n return utils.resolve(this[op](mapper, id, opts))\n .then(() => {\n op = opts.op = 'destroy'\n this.dbg(op, mapper, id, opts)\n return utils.resolve(this._destroy(mapper, id, opts))\n })\n .then((results) => {\n let [data, result] = results\n result || (result = {})\n let response = new Response(data, result, 'destroy')\n response = this.respond(response, opts)\n\n // afterDestroy lifecycle hook\n op = opts.op = 'afterDestroy'\n return utils.resolve(this[op](mapper, id, opts, response))\n .then((_response) => _response === undefined ? response : _response)\n })\n },\n\n /**\n * Destroy the records that match the selection query. Called by\n * `Mapper#destroyAll`.\n *\n * @name Adapter#destroyAll\n * @method\n * @param {Object} mapper the mapper.\n * @param {Object} [query] Selection query.\n * @param {Object} [query.where] Filtering criteria.\n * @param {string|Array} [query.orderBy] Sorting criteria.\n * @param {string|Array} [query.sort] Same as `query.sort`.\n * @param {number} [query.limit] Limit results.\n * @param {number} [query.skip] Offset results.\n * @param {number} [query.offset] Same as `query.skip`.\n * @param {Object} [opts] Configuration options.\n * @param {boolean} [opts.raw=false] Whether to return a more detailed\n * response object.\n * @return {Promise}\n */\n destroyAll (mapper, query, opts) {\n let op\n query || (query = {})\n opts || (opts = {})\n\n // beforeDestroyAll lifecycle hook\n op = opts.op = 'beforeDestroyAll'\n return utils.resolve(this[op](mapper, query, opts))\n .then(() => {\n op = opts.op = 'destroyAll'\n this.dbg(op, mapper, query, opts)\n return utils.resolve(this._destroyAll(mapper, query, opts))\n })\n .then((results) => {\n let [data, result] = results\n result || (result = {})\n let response = new Response(data, result, 'destroyAll')\n response = this.respond(response, opts)\n\n // afterDestroyAll lifecycle hook\n op = opts.op = 'afterDestroyAll'\n return utils.resolve(this[op](mapper, query, opts, response))\n .then((_response) => _response === undefined ? response : _response)\n })\n },\n\n /**\n * Load a belongsTo relationship.\n *\n * Override with care.\n *\n * @name Adapter#loadBelongsTo\n * @method\n * @return {Promise}\n */\n loadBelongsTo (mapper, def, records, __opts) {\n const relationDef = def.getRelation()\n\n if (utils.isObject(records) && !utils.isArray(records)) {\n const record = records\n return this.find(relationDef, this.makeBelongsToForeignKey(mapper, def, record), __opts)\n .then((relatedItem) => {\n def.setLocalField(record, relatedItem)\n })\n } else {\n const keys = records\n .map((record) => this.makeBelongsToForeignKey(mapper, def, record))\n .filter((key) => key)\n return this.findAll(relationDef, {\n where: {\n [relationDef.idAttribute]: {\n 'in': keys\n }\n }\n }, __opts).then((relatedItems) => {\n records.forEach((record) => {\n relatedItems.forEach((relatedItem) => {\n if (relatedItem[relationDef.idAttribute] === record[def.foreignKey]) {\n def.setLocalField(record, relatedItem)\n }\n })\n })\n })\n }\n },\n\n /**\n * Retrieve the record with the given primary key. Called by `Mapper#find`.\n *\n * @name Adapter#find\n * @method\n * @param {Object} mapper The mapper.\n * @param {(string|number)} id Primary key of the record to retrieve.\n * @param {Object} [opts] Configuration options.\n * @param {boolean} [opts.raw=false] Whether to return a more detailed\n * response object.\n * @param {string[]} [opts.with=[]] Relations to eager load.\n * @return {Promise}\n */\n find (mapper, id, opts) {\n let op\n opts || (opts = {})\n opts.with || (opts.with = [])\n\n // beforeFind lifecycle hook\n op = opts.op = 'beforeFind'\n return utils.resolve(this[op](mapper, id, opts))\n .then(() => {\n op = opts.op = 'find'\n this.dbg(op, mapper, id, opts)\n return utils.resolve(this._find(mapper, id, opts))\n })\n .then((results) => this.loadRelationsFor(mapper, results, opts))\n .then(([record, meta]) => {\n let response = new Response(record, meta, 'find')\n response.found = record ? 1 : 0\n response = this.respond(response, opts)\n\n // afterFind lifecycle hook\n op = opts.op = 'afterFind'\n return utils.resolve(this[op](mapper, id, opts, response))\n .then((_response) => _response === undefined ? response : _response)\n })\n },\n\n /**\n * Retrieve the records that match the selection query.\n *\n * @name Adapter#findAll\n * @method\n * @param {Object} mapper The mapper.\n * @param {Object} [query] Selection query.\n * @param {Object} [query.where] Filtering criteria.\n * @param {string|Array} [query.orderBy] Sorting criteria.\n * @param {string|Array} [query.sort] Same as `query.sort`.\n * @param {number} [query.limit] Limit results.\n * @param {number} [query.skip] Offset results.\n * @param {number} [query.offset] Same as `query.skip`.\n * @param {Object} [opts] Configuration options.\n * @param {boolean} [opts.raw=false] Whether to return a more detailed\n * response object.\n * @param {string[]} [opts.with=[]] Relations to eager load.\n * @return {Promise}\n */\n findAll (mapper, query, opts) {\n let op\n opts || (opts = {})\n opts.with || (opts.with = [])\n\n const activeWith = opts._activeWith\n\n if (utils.isObject(activeWith)) {\n const activeQuery = activeWith.query || {}\n if (activeWith.replace) {\n query = activeQuery\n } else {\n utils.deepFillIn(query, activeQuery)\n }\n }\n\n // beforeFindAll lifecycle hook\n op = opts.op = 'beforeFindAll'\n return utils.resolve(this[op](mapper, query, opts))\n .then(() => {\n op = opts.op = 'findAll'\n this.dbg(op, mapper, query, opts)\n return utils.resolve(this._findAll(mapper, query, opts))\n })\n .then((results) => this.loadRelationsFor(mapper, results, opts))\n .then(([records, meta]) => {\n let response = new Response(records, meta, 'findAll')\n response.found = records.length\n response = this.respond(response, opts)\n\n // afterFindAll lifecycle hook\n op = opts.op = 'afterFindAll'\n return utils.resolve(this[op](mapper, query, opts, response))\n .then((_response) => _response === undefined ? response : _response)\n })\n },\n\n loadRelationsFor (mapper, results, opts) {\n const [records] = results\n const tasks = []\n\n if (records) {\n utils.forEachRelation(mapper, opts, (def, __opts) => {\n let task\n if (def.foreignKey && (def.type === 'hasOne' || def.type === 'hasMany')) {\n if (def.type === 'hasOne') {\n task = this.loadHasOne(mapper, def, records, __opts)\n } else {\n task = this.loadHasMany(mapper, def, records, __opts)\n }\n } else if (def.type === 'hasMany' && def.localKeys) {\n task = this.loadHasManyLocalKeys(mapper, def, records, __opts)\n } else if (def.type === 'hasMany' && def.foreignKeys) {\n task = this.loadHasManyForeignKeys(mapper, def, records, __opts)\n } else if (def.type === 'belongsTo') {\n task = this.loadBelongsTo(mapper, def, records, __opts)\n }\n if (task) {\n tasks.push(task)\n }\n })\n }\n\n return utils.Promise.all(tasks)\n .then(() => results)\n },\n\n /**\n * Resolve the value of the specified option based on the given options and\n * this adapter's settings. Override with care.\n *\n * @name Adapter#getOpt\n * @method\n * @param {string} opt The name of the option.\n * @param {Object} [opts] Configuration options.\n * @return {*} The value of the specified option.\n */\n getOpt (opt, opts) {\n opts || (opts = {})\n return opts[opt] === undefined ? utils.plainCopy(this[opt]) : utils.plainCopy(opts[opt])\n },\n\n /**\n * Load a hasMany relationship.\n *\n * Override with care.\n *\n * @name Adapter#loadHasMany\n * @method\n * @return {Promise}\n */\n loadHasMany (mapper, def, records, __opts) {\n let singular = false\n\n if (utils.isObject(records) && !utils.isArray(records)) {\n singular = true\n records = [records]\n }\n const IDs = records.map((record) => this.makeHasManyForeignKey(mapper, def, record))\n const query = {\n where: {}\n }\n const criteria = query.where[def.foreignKey] = {}\n if (singular) {\n // more efficient query when we only have one record\n criteria['=='] = IDs[0]\n } else {\n criteria['in'] = IDs.filter((id) => id)\n }\n return this.findAll(def.getRelation(), query, __opts).then((relatedItems) => {\n records.forEach((record) => {\n let attached = []\n // avoid unneccesary iteration when we only have one record\n if (singular) {\n attached = relatedItems\n } else {\n relatedItems.forEach((relatedItem) => {\n if (utils.get(relatedItem, def.foreignKey) === record[mapper.idAttribute]) {\n attached.push(relatedItem)\n }\n })\n }\n def.setLocalField(record, attached)\n })\n })\n },\n\n loadHasManyLocalKeys (mapper, def, records, __opts) {\n let record\n const relatedMapper = def.getRelation()\n\n if (utils.isObject(records) && !utils.isArray(records)) {\n record = records\n }\n\n if (record) {\n return this.findAll(relatedMapper, {\n where: {\n [relatedMapper.idAttribute]: {\n 'in': this.makeHasManyLocalKeys(mapper, def, record)\n }\n }\n }, __opts).then((relatedItems) => {\n def.setLocalField(record, relatedItems)\n })\n } else {\n let localKeys = []\n records.forEach((record) => {\n localKeys = localKeys.concat(this.makeHasManyLocalKeys(mapper, def, record))\n })\n return this.findAll(relatedMapper, {\n where: {\n [relatedMapper.idAttribute]: {\n 'in': unique(localKeys).filter((x) => x)\n }\n }\n }, __opts).then((relatedItems) => {\n records.forEach((item) => {\n let attached = []\n let itemKeys = utils.get(item, def.localKeys) || []\n itemKeys = utils.isArray(itemKeys) ? itemKeys : Object.keys(itemKeys)\n relatedItems.forEach((relatedItem) => {\n if (itemKeys && itemKeys.indexOf(relatedItem[relatedMapper.idAttribute]) !== -1) {\n attached.push(relatedItem)\n }\n })\n def.setLocalField(item, attached)\n })\n return relatedItems\n })\n }\n },\n\n loadHasManyForeignKeys (mapper, def, records, __opts) {\n const relatedMapper = def.getRelation()\n const idAttribute = mapper.idAttribute\n let record\n\n if (utils.isObject(records) && !utils.isArray(records)) {\n record = records\n }\n\n if (record) {\n return this.findAll(def.getRelation(), {\n where: {\n [def.foreignKeys]: {\n 'contains': this.makeHasManyForeignKeys(mapper, def, record)\n }\n }\n }, __opts).then((relatedItems) => {\n def.setLocalField(record, relatedItems)\n })\n } else {\n return this.findAll(relatedMapper, {\n where: {\n [def.foreignKeys]: {\n 'isectNotEmpty': records.map((record) => this.makeHasManyForeignKeys(mapper, def, record))\n }\n }\n }, __opts).then((relatedItems) => {\n const foreignKeysField = def.foreignKeys\n records.forEach((record) => {\n const _relatedItems = []\n const id = utils.get(record, idAttribute)\n relatedItems.forEach((relatedItem) => {\n const foreignKeys = utils.get(relatedItems, foreignKeysField) || []\n if (foreignKeys.indexOf(id) !== -1) {\n _relatedItems.push(relatedItem)\n }\n })\n def.setLocalField(record, _relatedItems)\n })\n })\n }\n },\n\n /**\n * Load a hasOne relationship.\n *\n * Override with care.\n *\n * @name Adapter#loadHasOne\n * @method\n * @return {Promise}\n */\n loadHasOne (mapper, def, records, __opts) {\n if (utils.isObject(records) && !utils.isArray(records)) {\n records = [records]\n }\n return this.loadHasMany(mapper, def, records, __opts).then(() => {\n records.forEach((record) => {\n const relatedData = def.getLocalField(record)\n if (utils.isArray(relatedData) && relatedData.length) {\n def.setLocalField(record, relatedData[0])\n }\n })\n })\n },\n\n /**\n * Return the foreignKey from the given record for the provided relationship.\n *\n * There may be reasons why you may want to override this method, like when\n * the id of the parent doesn't exactly match up to the key on the child.\n *\n * Override with care.\n *\n * @name Adapter#makeHasManyForeignKey\n * @method\n * @return {*}\n */\n makeHasManyForeignKey (mapper, def, record) {\n return def.getForeignKey(record)\n },\n\n /**\n * Return the localKeys from the given record for the provided relationship.\n *\n * Override with care.\n *\n * @name Adapter#makeHasManyLocalKeys\n * @method\n * @return {*}\n */\n makeHasManyLocalKeys (mapper, def, record) {\n let localKeys = []\n let itemKeys = utils.get(record, def.localKeys) || []\n itemKeys = utils.isArray(itemKeys) ? itemKeys : Object.keys(itemKeys)\n localKeys = localKeys.concat(itemKeys)\n return unique(localKeys).filter((x) => x)\n },\n\n /**\n * Return the foreignKeys from the given record for the provided relationship.\n *\n * Override with care.\n *\n * @name Adapter#makeHasManyForeignKeys\n * @method\n * @return {*}\n */\n makeHasManyForeignKeys (mapper, def, record) {\n return utils.get(record, mapper.idAttribute)\n },\n\n /**\n * Return the foreignKey from the given record for the provided relationship.\n *\n * Override with care.\n *\n * @name Adapter#makeBelongsToForeignKey\n * @method\n * @return {*}\n */\n makeBelongsToForeignKey (mapper, def, record) {\n return def.getForeignKey(record)\n },\n\n /**\n * Retrieve sum of the specified field of the records that match the selection\n * query. Called by `Mapper#sum`.\n *\n * @name Adapter#sum\n * @method\n * @param {Object} mapper The mapper.\n * @param {string} field By to sum.\n * @param {Object} [query] Selection query.\n * @param {Object} [query.where] Filtering criteria.\n * @param {string|Array} [query.orderBy] Sorting criteria.\n * @param {string|Array} [query.sort] Same as `query.sort`.\n * @param {number} [query.limit] Limit results.\n * @param {number} [query.skip] Offset results.\n * @param {number} [query.offset] Same as `query.skip`.\n * @param {Object} [opts] Configuration options.\n * @param {boolean} [opts.raw=false] Whether to return a more detailed\n * response object.\n * @return {Promise}\n */\n sum (mapper, field, query, opts) {\n let op\n if (!utils.isString(field)) {\n throw new Error('field must be a string!')\n }\n query || (query = {})\n opts || (opts = {})\n\n // beforeSum lifecycle hook\n op = opts.op = 'beforeSum'\n return utils.resolve(this[op](mapper, field, query, opts))\n .then(() => {\n // Allow for re-assignment from lifecycle hook\n op = opts.op = 'sum'\n this.dbg(op, mapper, field, query, opts)\n return utils.resolve(this._sum(mapper, field, query, opts))\n })\n .then((results) => {\n let [data, result] = results\n result || (result = {})\n let response = new Response(data, result, op)\n response = this.respond(response, opts)\n\n // afterSum lifecycle hook\n op = opts.op = 'afterSum'\n return utils.resolve(this[op](mapper, field, query, opts, response))\n .then((_response) => _response === undefined ? response : _response)\n })\n },\n\n /**\n * @name Adapter#respond\n * @method\n * @param {Object} response Response object.\n * @param {Object} opts Configuration options.\n * return {Object} If `opts.raw == true` then return `response`, else return\n * `response.data`.\n */\n respond (response, opts) {\n return this.getOpt('raw', opts) ? response : response.data\n },\n\n /**\n * Apply the given update to the record with the specified primary key. Called\n * by `Mapper#update`.\n *\n * @name Adapter#update\n * @method\n * @param {Object} mapper The mapper.\n * @param {(string|number)} id The primary key of the record to be updated.\n * @param {Object} props The update to apply to the record.\n * @param {Object} [opts] Configuration options.\n * @param {boolean} [opts.raw=false] Whether to return a more detailed\n * response object.\n * @return {Promise}\n */\n update (mapper, id, props, opts) {\n props || (props = {})\n opts || (opts = {})\n let op\n\n // beforeUpdate lifecycle hook\n op = opts.op = 'beforeUpdate'\n return utils.resolve(this[op](mapper, id, props, opts))\n .then((_props) => {\n // Allow for re-assignment from lifecycle hook\n props = _props === undefined ? props : _props\n props = withoutRelations(mapper, props, opts)\n op = opts.op = 'update'\n this.dbg(op, mapper, id, props, opts)\n return utils.resolve(this._update(mapper, id, props, opts))\n })\n .then((results) => {\n let [data, result] = results\n result || (result = {})\n let response = new Response(data, result, 'update')\n response.updated = data ? 1 : 0\n response = this.respond(response, opts)\n\n // afterUpdate lifecycle hook\n op = opts.op = 'afterUpdate'\n return utils.resolve(this[op](mapper, id, props, opts, response))\n .then((_response) => _response === undefined ? response : _response)\n })\n },\n\n /**\n * Apply the given update to all records that match the selection query.\n * Called by `Mapper#updateAll`.\n *\n * @name Adapter#updateAll\n * @method\n * @param {Object} mapper The mapper.\n * @param {Object} props The update to apply to the selected records.\n * @param {Object} [query] Selection query.\n * @param {Object} [query.where] Filtering criteria.\n * @param {string|Array} [query.orderBy] Sorting criteria.\n * @param {string|Array} [query.sort] Same as `query.sort`.\n * @param {number} [query.limit] Limit results.\n * @param {number} [query.skip] Offset results.\n * @param {number} [query.offset] Same as `query.skip`.\n * @param {Object} [opts] Configuration options.\n * @param {boolean} [opts.raw=false] Whether to return a more detailed\n * response object.\n * @return {Promise}\n */\n updateAll (mapper, props, query, opts) {\n props || (props = {})\n query || (query = {})\n opts || (opts = {})\n let op\n\n // beforeUpdateAll lifecycle hook\n op = opts.op = 'beforeUpdateAll'\n return utils.resolve(this[op](mapper, props, query, opts))\n .then((_props) => {\n // Allow for re-assignment from lifecycle hook\n props = _props === undefined ? props : _props\n props = withoutRelations(mapper, props, opts)\n op = opts.op = 'updateAll'\n this.dbg(op, mapper, props, query, opts)\n return utils.resolve(this._updateAll(mapper, props, query, opts))\n })\n .then((results) => {\n let [data, result] = results\n data || (data = [])\n result || (result = {})\n let response = new Response(data, result, 'updateAll')\n response.updated = data.length\n response = this.respond(response, opts)\n\n // afterUpdateAll lifecycle hook\n op = opts.op = 'afterUpdateAll'\n return utils.resolve(this[op](mapper, props, query, opts, response))\n .then((_response) => _response === undefined ? response : _response)\n })\n },\n\n /**\n * Update the given records in a single batch. Called by `Mapper#updateMany`.\n *\n * @name Adapter#updateMany\n * @method\n * @param {Object} mapper The mapper.\n * @param {Object[]} records The records to update.\n * @param {Object} [opts] Configuration options.\n * @param {boolean} [opts.raw=false] Whether to return a more detailed\n * response object.\n * @return {Promise}\n */\n updateMany (mapper, records, opts) {\n records || (records = [])\n opts || (opts = {})\n let op\n const idAttribute = mapper.idAttribute\n\n records = records.filter((record) => utils.get(record, idAttribute))\n\n // beforeUpdateMany lifecycle hook\n op = opts.op = 'beforeUpdateMany'\n return utils.resolve(this[op](mapper, records, opts))\n .then((_records) => {\n // Allow for re-assignment from lifecycle hook\n records = _records === undefined ? records : _records\n records = records.map((record) => withoutRelations(mapper, record, opts))\n op = opts.op = 'updateMany'\n this.dbg(op, mapper, records, opts)\n return utils.resolve(this._updateMany(mapper, records, opts))\n })\n .then((results) => {\n let [data, result] = results\n data || (data = [])\n result || (result = {})\n let response = new Response(data, result, 'updateMany')\n response.updated = data.length\n response = this.respond(response, opts)\n\n // afterUpdateMany lifecycle hook\n op = opts.op = 'afterUpdateMany'\n return utils.resolve(this[op](mapper, records, opts, response))\n .then((_response) => _response === undefined ? response : _response)\n })\n }\n})\n\n/**\n * Create a subclass of this Adapter:\n *\n * @example Adapter.extend\n * // Normally you would do: import {Adapter} from 'js-data'\n * const JSData = require('js-data@3.0.0-beta.10')\n * const {Adapter} = JSData\n * console.log('Using JSData v' + JSData.version.full)\n *\n * // Extend the class using ES2015 class syntax.\n * class CustomAdapterClass extends Adapter {\n * foo () { return 'bar' }\n * static beep () { return 'boop' }\n * }\n * const customAdapter = new CustomAdapterClass()\n * console.log(customAdapter.foo())\n * console.log(CustomAdapterClass.beep())\n *\n * // Extend the class using alternate method.\n * const OtherAdapterClass = Adapter.extend({\n * foo () { return 'bar' }\n * }, {\n * beep () { return 'boop' }\n * })\n * const otherAdapter = new OtherAdapterClass()\n * console.log(otherAdapter.foo())\n * console.log(OtherAdapterClass.beep())\n *\n * // Extend the class, providing a custom constructor.\n * function AnotherAdapterClass () {\n * Adapter.call(this)\n * this.created_at = new Date().getTime()\n * }\n * Adapter.extend({\n * constructor: AnotherAdapterClass,\n * foo () { return 'bar' }\n * }, {\n * beep () { return 'boop' }\n * })\n * const anotherAdapter = new AnotherAdapterClass()\n * console.log(anotherAdapter.created_at)\n * console.log(anotherAdapter.foo())\n * console.log(AnotherAdapterClass.beep())\n *\n * @method Adapter.extend\n * @param {Object} [props={}] Properties to add to the prototype of the\n * subclass.\n * @param {Object} [props.constructor] Provide a custom constructor function\n * to be used as the subclass itself.\n * @param {Object} [classProps={}] Static properties to add to the subclass.\n * @returns {Constructor} Subclass of this Adapter class.\n */\n","import {Query, utils} from 'js-data'\nimport {Adapter} from '../node_modules/js-data-adapter/src/index'\nimport firebase from 'firebase'\n\nfunction isValidString (value) {\n return (value != null && value !== '')\n}\n\nfunction join (items, separator) {\n separator || (separator = '')\n return items.filter(isValidString).join(separator)\n}\n\nfunction makePath (...args) { // eslint-disable-line no-unused-vars\n let result = join(args, '/')\n return result.replace(/([^:/]|^)\\/{2,}/g, '$1/')\n}\n\nlet queue = []\nlet taskInProcess = false\n\nfunction enqueue (task) {\n queue.push(task)\n}\n\nfunction dequeue () {\n if (queue.length && !taskInProcess) {\n taskInProcess = true\n queue[0]()\n }\n}\n\nfunction queueTask (task) {\n if (!queue.length) {\n enqueue(task)\n dequeue()\n } else {\n enqueue(task)\n }\n}\n\nfunction createTask (fn) {\n return new utils.Promise(fn).then((result) => {\n taskInProcess = false\n queue.shift()\n setTimeout(dequeue, 0)\n return result\n }, (err) => {\n taskInProcess = false\n queue.shift()\n setTimeout(dequeue, 0)\n return utils.reject(err)\n })\n}\n\nconst __super__ = Adapter.prototype\n\n/**\n * FirebaseAdapter class.\n *\n * @example Browser\n * import {DataStore} from 'js-data'\n * import firebase from 'firebase'\n * import {FirebaseAdapter} from 'js-data-firebase'\n * const store = new DataStore()\n * firebase.initializeApp({\n * apiKey: 'your-api-key',\n * databaseURL: 'your-database-url'\n * })\n * const adapter = new FirebaseAdapter({ db: firebase.database() })\n * store.registerAdapter('firebase', adapter, { 'default': true })\n *\n * @example Node.js\n * import {Container} from 'js-data'\n * import firebase from 'firebase'\n * import {FirebaseAdapter} from 'js-data-firebase'\n * const store = new Container()\n * firebase.initializeApp({\n * databaseURL: 'your-database-url',\n * serviceAccount: 'path/to/keyfile'\n * })\n * const adapter = new FirebaseAdapter({ db: firebase.database() })\n * store.registerAdapter('firebase', adapter, { 'default': true })\n *\n * @class FirebaseAdapter\n * @param {Object} [opts] Configuration opts.\n * @param {Object} [opts.db] See {@link FirebaseAdapter#db}\n * @param {boolean} [opts.debug=false] See {@link Adapter#debug}.\n * @param {boolean} [opts.raw=false] See {@link Adapter#raw}.\n */\nexport function FirebaseAdapter (opts) {\n utils.classCallCheck(this, FirebaseAdapter)\n opts || (opts = {})\n Adapter.call(this, opts)\n\n /**\n * The database instance used by this adapter.\n *\n * @name FirebaseAdapter#db\n * @type {Object}\n * @default firebase.database()\n */\n if (opts.db) {\n this.db = opts.db || firebase.database()\n }\n}\n\n// Setup prototype inheritance from Adapter\nFirebaseAdapter.prototype = Object.create(Adapter.prototype, {\n constructor: {\n value: FirebaseAdapter,\n enumerable: false,\n writable: true,\n configurable: true\n }\n})\n\nObject.defineProperty(FirebaseAdapter, '__super__', {\n configurable: true,\n value: Adapter\n})\n\n/**\n * Alternative to ES6 class syntax for extending `FirebaseAdapter`.\n *\n * @example Using the ES2015 class syntax.\n * class MyFirebaseAdapter extends FirebaseAdapter {...}\n * const adapter = new MyFirebaseAdapter()\n *\n * @example Using {@link FirebaseAdapter.extend}.\n * var instanceProps = {...}\n * var classProps = {...}\n *\n * var MyFirebaseAdapter = FirebaseAdapter.extend(instanceProps, classProps)\n * var adapter = new MyFirebaseAdapter()\n *\n * @method FirebaseAdapter.extend\n * @static\n * @param {Object} [instanceProps] Properties that will be added to the\n * prototype of the subclass.\n * @param {Object} [classProps] Properties that will be added as static\n * properties to the subclass itself.\n * @return {Constructor} Subclass of `FirebaseAdapter`.\n */\nFirebaseAdapter.extend = utils.extend\n\nutils.addHiddenPropsToTarget(FirebaseAdapter.prototype, {\n /**\n * Retrieve the number of records that match the selection query. Internal\n * method used by Adapter#count.\n *\n * @name FirebaseAdapter#_count\n * @method\n * @private\n * @param {Object} mapper The mapper.\n * @param {Object} query Selection query.\n * @param {Object} [opts] Configuration options.\n * @return {Promise}\n */\n _count (mapper, query, opts) {\n query || (query = {})\n opts || (opts = {})\n return this._findAll(mapper, query, opts).then((result) => {\n result[0] = result[0].length\n return result\n })\n },\n\n /**\n * Create a new record. Internal method used by Adapter#create.\n *\n * @name FirebaseAdapter#_create\n * @method\n * @private\n * @param {Object} mapper The mapper.\n * @param {Object} props The record to be created.\n * @param {Object} [opts] Configuration options.\n * @return {Promise}\n */\n _create (mapper, props, opts) {\n props || (props = {})\n opts || (opts = {})\n return this._upsert(mapper, props, opts)\n },\n\n _upsert (mapper, props, opts) {\n const _props = utils.plainCopy(props)\n opts || (opts = {})\n\n const id = utils.get(_props, mapper.idAttribute)\n const collectionRef = this.getRef(mapper, opts)\n\n let itemRef\n\n if (utils.isSorN(id)) {\n itemRef = collectionRef.child(id)\n } else {\n itemRef = collectionRef.push()\n utils.set(_props, mapper.idAttribute, itemRef.key)\n }\n\n return itemRef.set(_props)\n .then(() => this._once(itemRef))\n .then((record) => {\n if (!record) {\n throw new Error('Not Found')\n }\n return [record, { ref: itemRef }]\n })\n },\n\n _upsertBatch (mapper, records, opts) {\n opts || (opts = {})\n\n const idAttribute = mapper.idAttribute\n const refValueCollection = []\n const collectionRef = this.getRef(mapper, opts)\n\n // generate path for each\n records.forEach((record) => {\n const id = utils.get(record, idAttribute)\n let _props = utils.plainCopy(record)\n let itemRef\n\n if (utils.isSorN(id)) {\n itemRef = collectionRef.child(id)\n } else {\n itemRef = collectionRef.push()\n utils.set(_props, idAttribute, itemRef.key)\n }\n refValueCollection.push({ ref: itemRef, props: _props })\n })\n\n return this._atomicUpdate(mapper, refValueCollection, opts)\n .then(() => {\n // since UDFs and timestamps can alter values on write, let's get the latest values\n return utils.Promise.all(refValueCollection.map((item) => this._once(item.ref)))\n })\n .then((records) => {\n // just return the updated records and not the refs?\n return [records, { ref: refValueCollection.map((item) => item.ref) }]\n })\n },\n\n _once (ref) {\n return ref.once('value').then((dataSnapshot) => {\n if (!dataSnapshot.exists()) {\n return null\n }\n return dataSnapshot.val()\n })\n },\n\n _atomicUpdate (mapper, refValueCollection, opts) { // collection of refs and the new value to set at that ref\n // do a deep-path update off the database\n // see https://www.firebase.com/blog/2015-09-24-atomic-writes-and-more.html\n let atomicUpdate = {}\n refValueCollection.forEach((item) => {\n atomicUpdate[item.ref.toString().replace(this.getRef(mapper, opts).toString(), '')] = item.props\n })\n return this.getRef(mapper, opts).update(atomicUpdate)\n },\n\n /**\n * Create multiple records in a single batch. Internal method used by\n * Adapter#createMany.\n *\n * @name FirebaseAdapter#_createMany\n * @method\n * @private\n * @param {Object} mapper The mapper.\n * @param {Object} records The records to be created.\n * @param {Object} [opts] Configuration options.\n * @return {Promise}\n */\n _createMany (mapper, records, opts) {\n opts || (opts = {})\n return this._upsertBatch(mapper, records, opts)\n },\n\n /**\n * Destroy the record with the given primary key. Internal method used by\n * Adapter#destroy.\n *\n * @name FirebaseAdapter#_destroy\n * @method\n * @private\n * @param {Object} mapper The mapper.\n * @param {(string|number)} id Primary key of the record to destroy.\n * @param {Object} [opts] Configuration options.\n * @return {Promise}\n */\n _destroy (mapper, id, opts) {\n opts || (opts = {})\n const ref = this.getRef(mapper, opts).child(id)\n return ref.remove().then(() => [undefined, { ref }])\n },\n\n /**\n * Destroy the records that match the selection query. Internal method used by\n * Adapter#destroyAll.\n *\n * @name FirebaseAdapter#_destroyAll\n * @method\n * @private\n * @param {Object} mapper the mapper.\n * @param {Object} [query] Selection query.\n * @param {Object} [opts] Configuration options.\n * @return {Promise}\n */\n _destroyAll (mapper, query, opts) {\n query || (query = {})\n opts || (opts = {})\n\n return this._findAll(mapper, query)\n .then((results) => {\n const [records] = results\n const idAttribute = mapper.idAttribute\n return utils.Promise.all(records.map((record) => {\n return this._destroy(mapper, utils.get(record, idAttribute), opts)\n }))\n })\n .then(() => [undefined, {}])\n },\n\n /**\n * Retrieve the record with the given primary key. Internal method used by\n * Adapter#find.\n *\n * @name FirebaseAdapter#_find\n * @method\n * @private\n * @param {Object} mapper The mapper.\n * @param {(string|number)} id Primary key of the record to retrieve.\n * @param {Object} [opts] Configuration options.\n * @return {Promise}\n */\n _find (mapper, id, opts) {\n opts || (opts = {})\n const itemRef = this.getRef(mapper, opts).child(id)\n return this._once(itemRef).then((record) => {\n if (!record) {\n record = undefined;\n }\n return [record, { ref: itemRef }]\n })\n },\n /**\n * Retrieve the records that match the selection query. Internal method used\n * by Adapter#findAll.\n *\n * @name FirebaseAdapter#_findAll\n * @method\n * @private\n * @param {Object} mapper The mapper.\n * @param {Object} query Selection query.\n * @param {Object} [opts] Configuration options.\n * @return {Promise}\n */\n _findAll (mapper, query, opts) {\n query || (query = {})\n opts || (opts = {})\n\n const collectionRef = this.getRef(mapper, opts)\n\n return collectionRef.once('value').then((dataSnapshot) => {\n const data = dataSnapshot.val()\n if (!data) {\n return [[], { ref: collectionRef }]\n }\n const records = []\n utils.forOwn(data, (value, key) => {\n records.push(value)\n })\n const _query = new Query({\n index: {\n getAll () {\n return records\n }\n }\n })\n return [_query.filter(query).run(), { ref: collectionRef }]\n })\n },\n\n /**\n * Retrieve the number of records that match the selection query. Internal\n * method used by Adapter#sum.\n *\n * @name FirebaseAdapter#_sum\n * @method\n * @private\n * @param {Object} mapper The mapper.\n * @param {string} field The field to sum.\n * @param {Object} query Selection query.\n * @param {Object} [opts] Configuration options.\n * @return {Promise}\n */\n _sum (mapper, field, query, opts) {\n return this._findAll(mapper, query, opts).then((result) => {\n result[0] = result[0].reduce((sum, record) => sum + (utils.get(record, field) || 0), 0)\n return result\n })\n },\n\n /**\n * Apply the given update to the record with the specified primary key.\n * Internal method used by Adapter#update.\n *\n * @name FirebaseAdapter#_update\n * @method\n * @private\n * @param {Object} mapper The mapper.\n * @param {(string|number)} id The primary key of the record to be updated.\n * @param {Object} props The update to apply to the record.\n * @param {Object} [opts] Configuration options.\n * @return {Promise}\n */\n _update (mapper, id, props, opts) {\n props || (props = {})\n opts || (opts = {})\n\n const itemRef = this.getRef(mapper, opts).child(id)\n return this._once(itemRef)\n .then((currentVal) => {\n if (!currentVal) {\n throw new Error('Not Found')\n }\n utils.deepMixIn(currentVal, props)\n return itemRef.set(currentVal)\n })\n .then(() => this._once(itemRef))\n .then((record) => {\n if (!record) {\n throw new Error('Not Found')\n }\n return [record, { ref: itemRef }]\n })\n },\n\n /**\n * Apply the given update to all records that match the selection query.\n * Internal method used by Adapter#updateAll.\n *\n * @name FirebaseAdapter#_updateAll\n * @method\n * @private\n * @param {Object} mapper The mapper.\n * @param {Object} props The update to apply to the selected records.\n * @param {Object} [query] Selection query.\n * @param {Object} [opts] Configuration options.\n * @return {Promise}\n */\n _updateAll (mapper, props, query, opts) {\n opts || (opts = {})\n props || (props = {})\n query || (query = {})\n\n return this._findAll(mapper, query, opts).then((results) => {\n const [records] = results\n records.forEach((record) => utils.deepMixIn(record, props))\n return this._upsertBatch(mapper, records, opts)\n })\n },\n\n /**\n * Update the given records in a single batch. Internal method used by\n * Adapter#updateMany.\n *\n * @name FirebaseAdapter#updateMany\n * @method\n * @private\n * @param {Object} mapper The mapper.\n * @param {Object[]} records The records to update.\n * @param {Object} [opts] Configuration options.\n * @return {Promise}\n */\n _updateMany (mapper, records, opts) {\n opts || (opts = {})\n return this._upsertBatch(mapper, records, opts)\n },\n\n getRef (mapper, opts) {\n opts = opts || {}\n return this.db.ref().child(opts.endpoint || mapper.endpoint || mapper.name)\n },\n\n create (mapper, props, opts) {\n return createTask((success, failure) => {\n queueTask(() => {\n __super__.create.call(this, mapper, props, opts).then(success, failure)\n })\n })\n },\n\n createMany (mapper, props, opts) {\n return createTask((success, failure) => {\n queueTask(() => {\n __super__.createMany.call(this, mapper, props, opts).then(success, failure)\n })\n })\n },\n\n destroy (mapper, id, opts) {\n return createTask((success, failure) => {\n queueTask(() => {\n __super__.destroy.call(this, mapper, id, opts).then(success, failure)\n })\n })\n },\n\n destroyAll (mapper, query, opts) {\n return createTask((success, failure) => {\n queueTask(() => {\n __super__.destroyAll.call(this, mapper, query, opts).then(success, failure)\n })\n })\n },\n\n update (mapper, id, props, opts) {\n return createTask((success, failure) => {\n queueTask(() => {\n __super__.update.call(this, mapper, id, props, opts).then(success, failure)\n })\n })\n },\n\n updateAll (mapper, props, query, opts) {\n return createTask((success, failure) => {\n queueTask(() => {\n __super__.updateAll.call(this, mapper, props, query, opts).then(success, failure)\n })\n })\n },\n\n updateMany (mapper, records, opts) {\n return createTask((success, failure) => {\n queueTask(() => {\n __super__.updateMany.call(this, mapper, records, opts).then(success, failure)\n })\n })\n }\n})\n\n/**\n * Details of the current version of the `js-data-firebase` module.\n *\n * @name FirebaseAdapter.version\n * @type {Object}\n * @property {string} version.full The full semver value.\n * @property {number} version.major The major version number.\n * @property {number} version.minor The minor version number.\n * @property {number} version.patch The patch version number.\n * @property {(string|boolean)} version.alpha The alpha version value,\n * otherwise `false` if the current version is not alpha.\n * @property {(string|boolean)} version.beta The beta version value,\n * otherwise `false` if the current version is not beta.\n */\n\nexport const version = '<%= version %>'\n\n/**\n * {@link FirebaseAdapter} class.\n *\n * @name module:js-data-firebase.FirebaseAdapter\n * @see FirebaseAdapter\n */\n\n/**\n * Registered as `js-data-firebase` in NPM and Bower.\n *\n * @example Script tag\n * var FirebaseAdapter = window.JSDataFirebase.FirebaseAdapter\n * var adapter = new FirebaseAdapter()\n *\n * @example CommonJS\n * var FirebaseAdapter = require('js-data-firebase').FirebaseAdapter\n * var adapter = new FirebaseAdapter()\n *\n * @example ES2015 Modules\n * import {FirebaseAdapter} from 'js-data-firebase'\n * const adapter = new FirebaseAdapter()\n *\n * @example AMD\n * define('myApp', ['js-data-firebase'], function (JSDataFirebase) {\n * var FirebaseAdapter = JSDataFirebase.FirebaseAdapter\n * var adapter = new FirebaseAdapter()\n *\n * // ...\n * })\n *\n * @module js-data-firebase\n */\n"],"names":["noop","args","opts","length","dbg","op","utils","resolve","noop2","unique","array","seen","final","forEach","item","push","withoutRelations","mapper","props","with","relationFields","toStrip","filter","value","indexOf","omit","Response","data","meta","fillIn","DEFAULTS","Adapter","classCallCheck","call","Component","extend","query","then","_count","results","result","response","respond","_response","undefined","_props","_create","created","map","record","_createMany","id","_destroy","_destroyAll","def","records","__opts","relationDef","getRelation","isObject","isArray","find","makeBelongsToForeignKey","relatedItem","setLocalField","keys","key","findAll","idAttribute","relatedItems","foreignKey","_find","loadRelationsFor","found","activeWith","_activeWith","activeQuery","replace","deepFillIn","_findAll","tasks","forEachRelation","task","type","loadHasOne","loadHasMany","localKeys","loadHasManyLocalKeys","foreignKeys","loadHasManyForeignKeys","loadBelongsTo","Promise","all","opt","plainCopy","singular","IDs","makeHasManyForeignKey","criteria","where","attached","get","relatedMapper","makeHasManyLocalKeys","concat","x","itemKeys","Object","makeHasManyForeignKeys","foreignKeysField","_relatedItems","relatedData","getLocalField","getForeignKey","field","isString","Error","_sum","getOpt","_update","updated","_updateAll","_records","_updateMany","queue","taskInProcess","enqueue","dequeue","queueTask","createTask","fn","shift","err","reject","__super__","prototype","FirebaseAdapter","db","firebase","database","create","defineProperty","addHiddenPropsToTarget","_upsert","collectionRef","getRef","itemRef","isSorN","child","set","_once","ref","refValueCollection","_atomicUpdate","once","dataSnapshot","exists","val","atomicUpdate","toString","update","_upsertBatch","remove","forOwn","_query","Query","run","reduce","sum","currentVal","deepMixIn","endpoint","name","success","failure","createMany","destroy","destroyAll","updateAll","updateMany","version"],"mappings":"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"} \ No newline at end of file diff --git a/dist/js-data-firebase.min.js b/dist/js-data-firebase.min.js new file mode 100644 index 0000000..c890a02 --- /dev/null +++ b/dist/js-data-firebase.min.js @@ -0,0 +1,11 @@ +/*! +* js-data-firebase +* @version 3.0.0 - Homepage +* @author Jason Dobry +* @copyright (c) 2014-2016 Jason Dobry +* @license MIT +* +* @overview firebase adapter for js-data. +*/ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("js-data"),require("firebase")):"function"==typeof define&&define.amd?define(["exports","js-data","firebase"],t):t(e.JSDataFirebase={},e.JSData,e.firebase)}(this,function(e,t,n){"use strict";function Response(e,n,r){n||(n={}),this.data=e,t.utils.fillIn(this,n),this.op=r}function Adapter(e){t.utils.classCallCheck(this,Adapter),t.Component.call(this,e),e||(e={}),t.utils.fillIn(e,l),t.utils.fillIn(this,e)}function enqueue(e){f.push(e)}function dequeue(){f.length&&!c&&(c=!0,f[0]())}function queueTask(e){f.length?enqueue(e):(enqueue(e),dequeue())}function createTask(e){return new t.utils.Promise(e).then(function(e){return c=!1,f.shift(),setTimeout(dequeue,0),e},function(e){return c=!1,f.shift(),setTimeout(dequeue,0),t.utils.reject(e)})}function FirebaseAdapter(e){t.utils.classCallCheck(this,FirebaseAdapter),e||(e={}),Adapter.call(this,e),e.db&&(this.db=e.db||n.database())}n=n&&n.hasOwnProperty("default")?n.default:n;var r=function(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e},i=function(){function sliceIterator(e,t){var n=[],r=!0,i=!1,o=void 0;try{for(var u,a=e[Symbol.iterator]();!(r=(u=a.next()).done)&&(n.push(u.value),!t||n.length!==t);r=!0);}catch(e){i=!0,o=e}finally{try{!r&&a.return&&a.return()}finally{if(i)throw o}}return n}return function(e,t){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return sliceIterator(e,t);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),o=function noop(){for(var e=arguments.length,n=Array(e),r=0;r