(function (global, factory) {
	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
	typeof define === 'function' && define.amd ? define(factory) :
	(global = global || self, global.VuexORM = factory());
}(this, function () { 'use strict';

	function createCommonjsModule(fn, module) {
		return module = { exports: {} }, fn(module, module.exports), module.exports;
	}

	var _global = createCommonjsModule(function (module) {
	// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
	var global = module.exports = typeof window != 'undefined' && window.Math == Math
	  ? window : typeof self != 'undefined' && self.Math == Math ? self
	  // eslint-disable-next-line no-new-func
	  : Function('return this')();
	if (typeof __g == 'number') __g = global; // eslint-disable-line no-undef
	});

	var _core = createCommonjsModule(function (module) {
	var core = module.exports = { version: '2.6.9' };
	if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef
	});
	var _core_1 = _core.version;

	var _isObject = function (it) {
	  return typeof it === 'object' ? it !== null : typeof it === 'function';
	};

	var _anObject = function (it) {
	  if (!_isObject(it)) throw TypeError(it + ' is not an object!');
	  return it;
	};

	var _fails = function (exec) {
	  try {
	    return !!exec();
	  } catch (e) {
	    return true;
	  }
	};

	// Thank's IE8 for his funny defineProperty
	var _descriptors = !_fails(function () {
	  return Object.defineProperty({}, 'a', { get: function () { return 7; } }).a != 7;
	});

	var document = _global.document;
	// typeof document.createElement is 'object' in old IE
	var is = _isObject(document) && _isObject(document.createElement);
	var _domCreate = function (it) {
	  return is ? document.createElement(it) : {};
	};

	var _ie8DomDefine = !_descriptors && !_fails(function () {
	  return Object.defineProperty(_domCreate('div'), 'a', { get: function () { return 7; } }).a != 7;
	});

	// 7.1.1 ToPrimitive(input [, PreferredType])

	// instead of the ES6 spec version, we didn't implement @@toPrimitive case
	// and the second argument - flag - preferred type is a string
	var _toPrimitive = function (it, S) {
	  if (!_isObject(it)) return it;
	  var fn, val;
	  if (S && typeof (fn = it.toString) == 'function' && !_isObject(val = fn.call(it))) return val;
	  if (typeof (fn = it.valueOf) == 'function' && !_isObject(val = fn.call(it))) return val;
	  if (!S && typeof (fn = it.toString) == 'function' && !_isObject(val = fn.call(it))) return val;
	  throw TypeError("Can't convert object to primitive value");
	};

	var dP = Object.defineProperty;

	var f = _descriptors ? Object.defineProperty : function defineProperty(O, P, Attributes) {
	  _anObject(O);
	  P = _toPrimitive(P, true);
	  _anObject(Attributes);
	  if (_ie8DomDefine) try {
	    return dP(O, P, Attributes);
	  } catch (e) { /* empty */ }
	  if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported!');
	  if ('value' in Attributes) O[P] = Attributes.value;
	  return O;
	};

	var _objectDp = {
		f: f
	};

	var _propertyDesc = function (bitmap, value) {
	  return {
	    enumerable: !(bitmap & 1),
	    configurable: !(bitmap & 2),
	    writable: !(bitmap & 4),
	    value: value
	  };
	};

	var _hide = _descriptors ? function (object, key, value) {
	  return _objectDp.f(object, key, _propertyDesc(1, value));
	} : function (object, key, value) {
	  object[key] = value;
	  return object;
	};

	var hasOwnProperty = {}.hasOwnProperty;
	var _has = function (it, key) {
	  return hasOwnProperty.call(it, key);
	};

	var id = 0;
	var px = Math.random();
	var _uid = function (key) {
	  return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36));
	};

	var _shared = createCommonjsModule(function (module) {
	var SHARED = '__core-js_shared__';
	var store = _global[SHARED] || (_global[SHARED] = {});

	(module.exports = function (key, value) {
	  return store[key] || (store[key] = value !== undefined ? value : {});
	})('versions', []).push({
	  version: _core.version,
	  mode:  'global',
	  copyright: '© 2019 Denis Pushkarev (zloirock.ru)'
	});
	});

	var _functionToString = _shared('native-function-to-string', Function.toString);

	var _redefine = createCommonjsModule(function (module) {
	var SRC = _uid('src');

	var TO_STRING = 'toString';
	var TPL = ('' + _functionToString).split(TO_STRING);

	_core.inspectSource = function (it) {
	  return _functionToString.call(it);
	};

	(module.exports = function (O, key, val, safe) {
	  var isFunction = typeof val == 'function';
	  if (isFunction) _has(val, 'name') || _hide(val, 'name', key);
	  if (O[key] === val) return;
	  if (isFunction) _has(val, SRC) || _hide(val, SRC, O[key] ? '' + O[key] : TPL.join(String(key)));
	  if (O === _global) {
	    O[key] = val;
	  } else if (!safe) {
	    delete O[key];
	    _hide(O, key, val);
	  } else if (O[key]) {
	    O[key] = val;
	  } else {
	    _hide(O, key, val);
	  }
	// add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative
	})(Function.prototype, TO_STRING, function toString() {
	  return typeof this == 'function' && this[SRC] || _functionToString.call(this);
	});
	});

	var _aFunction = function (it) {
	  if (typeof it != 'function') throw TypeError(it + ' is not a function!');
	  return it;
	};

	// optional / simple context binding

	var _ctx = function (fn, that, length) {
	  _aFunction(fn);
	  if (that === undefined) return fn;
	  switch (length) {
	    case 1: return function (a) {
	      return fn.call(that, a);
	    };
	    case 2: return function (a, b) {
	      return fn.call(that, a, b);
	    };
	    case 3: return function (a, b, c) {
	      return fn.call(that, a, b, c);
	    };
	  }
	  return function (/* ...args */) {
	    return fn.apply(that, arguments);
	  };
	};

	var PROTOTYPE = 'prototype';

	var $export = function (type, name, source) {
	  var IS_FORCED = type & $export.F;
	  var IS_GLOBAL = type & $export.G;
	  var IS_STATIC = type & $export.S;
	  var IS_PROTO = type & $export.P;
	  var IS_BIND = type & $export.B;
	  var target = IS_GLOBAL ? _global : IS_STATIC ? _global[name] || (_global[name] = {}) : (_global[name] || {})[PROTOTYPE];
	  var exports = IS_GLOBAL ? _core : _core[name] || (_core[name] = {});
	  var expProto = exports[PROTOTYPE] || (exports[PROTOTYPE] = {});
	  var key, own, out, exp;
	  if (IS_GLOBAL) source = name;
	  for (key in source) {
	    // contains in native
	    own = !IS_FORCED && target && target[key] !== undefined;
	    // export native or passed
	    out = (own ? target : source)[key];
	    // bind timers to global for call from export context
	    exp = IS_BIND && own ? _ctx(out, _global) : IS_PROTO && typeof out == 'function' ? _ctx(Function.call, out) : out;
	    // extend global
	    if (target) _redefine(target, key, out, type & $export.U);
	    // export
	    if (exports[key] != out) _hide(exports, key, exp);
	    if (IS_PROTO && expProto[key] != out) expProto[key] = out;
	  }
	};
	_global.core = _core;
	// type bitmap
	$export.F = 1;   // forced
	$export.G = 2;   // global
	$export.S = 4;   // static
	$export.P = 8;   // proto
	$export.B = 16;  // bind
	$export.W = 32;  // wrap
	$export.U = 64;  // safe
	$export.R = 128; // real proto method for `library`
	var _export = $export;

	var toString = {}.toString;

	var _cof = function (it) {
	  return toString.call(it).slice(8, -1);
	};

	// fallback for non-array-like ES3 and non-enumerable old V8 strings

	// eslint-disable-next-line no-prototype-builtins
	var _iobject = Object('z').propertyIsEnumerable(0) ? Object : function (it) {
	  return _cof(it) == 'String' ? it.split('') : Object(it);
	};

	// 7.2.1 RequireObjectCoercible(argument)
	var _defined = function (it) {
	  if (it == undefined) throw TypeError("Can't call method on  " + it);
	  return it;
	};

	// to indexed object, toObject with fallback for non-array-like ES3 strings


	var _toIobject = function (it) {
	  return _iobject(_defined(it));
	};

	// 7.1.4 ToInteger
	var ceil = Math.ceil;
	var floor = Math.floor;
	var _toInteger = function (it) {
	  return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it);
	};

	// 7.1.15 ToLength

	var min = Math.min;
	var _toLength = function (it) {
	  return it > 0 ? min(_toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991
	};

	var max = Math.max;
	var min$1 = Math.min;
	var _toAbsoluteIndex = function (index, length) {
	  index = _toInteger(index);
	  return index < 0 ? max(index + length, 0) : min$1(index, length);
	};

	// false -> Array#indexOf
	// true  -> Array#includes



	var _arrayIncludes = function (IS_INCLUDES) {
	  return function ($this, el, fromIndex) {
	    var O = _toIobject($this);
	    var length = _toLength(O.length);
	    var index = _toAbsoluteIndex(fromIndex, length);
	    var value;
	    // Array#includes uses SameValueZero equality algorithm
	    // eslint-disable-next-line no-self-compare
	    if (IS_INCLUDES && el != el) while (length > index) {
	      value = O[index++];
	      // eslint-disable-next-line no-self-compare
	      if (value != value) return true;
	    // Array#indexOf ignores holes, Array#includes - not
	    } else for (;length > index; index++) if (IS_INCLUDES || index in O) {
	      if (O[index] === el) return IS_INCLUDES || index || 0;
	    } return !IS_INCLUDES && -1;
	  };
	};

	var _wks = createCommonjsModule(function (module) {
	var store = _shared('wks');

	var Symbol = _global.Symbol;
	var USE_SYMBOL = typeof Symbol == 'function';

	var $exports = module.exports = function (name) {
	  return store[name] || (store[name] =
	    USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : _uid)('Symbol.' + name));
	};

	$exports.store = store;
	});

	// 22.1.3.31 Array.prototype[@@unscopables]
	var UNSCOPABLES = _wks('unscopables');
	var ArrayProto = Array.prototype;
	if (ArrayProto[UNSCOPABLES] == undefined) _hide(ArrayProto, UNSCOPABLES, {});
	var _addToUnscopables = function (key) {
	  ArrayProto[UNSCOPABLES][key] = true;
	};

	// https://github.com/tc39/Array.prototype.includes

	var $includes = _arrayIncludes(true);

	_export(_export.P, 'Array', {
	  includes: function includes(el /* , fromIndex = 0 */) {
	    return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);
	  }
	});

	_addToUnscopables('includes');

	var includes = _core.Array.includes;

	var shared = _shared('keys');

	var _sharedKey = function (key) {
	  return shared[key] || (shared[key] = _uid(key));
	};

	var arrayIndexOf = _arrayIncludes(false);
	var IE_PROTO = _sharedKey('IE_PROTO');

	var _objectKeysInternal = function (object, names) {
	  var O = _toIobject(object);
	  var i = 0;
	  var result = [];
	  var key;
	  for (key in O) if (key != IE_PROTO) _has(O, key) && result.push(key);
	  // Don't enum bug & hidden keys
	  while (names.length > i) if (_has(O, key = names[i++])) {
	    ~arrayIndexOf(result, key) || result.push(key);
	  }
	  return result;
	};

	// IE 8- don't enum bug keys
	var _enumBugKeys = (
	  'constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf'
	).split(',');

	// 19.1.2.14 / 15.2.3.14 Object.keys(O)



	var _objectKeys = Object.keys || function keys(O) {
	  return _objectKeysInternal(O, _enumBugKeys);
	};

	var f$1 = Object.getOwnPropertySymbols;

	var _objectGops = {
		f: f$1
	};

	var f$2 = {}.propertyIsEnumerable;

	var _objectPie = {
		f: f$2
	};

	// 7.1.13 ToObject(argument)

	var _toObject = function (it) {
	  return Object(_defined(it));
	};

	// 19.1.2.1 Object.assign(target, source, ...)






	var $assign = Object.assign;

	// should work with symbols and should have deterministic property order (V8 bug)
	var _objectAssign = !$assign || _fails(function () {
	  var A = {};
	  var B = {};
	  // eslint-disable-next-line no-undef
	  var S = Symbol();
	  var K = 'abcdefghijklmnopqrst';
	  A[S] = 7;
	  K.split('').forEach(function (k) { B[k] = k; });
	  return $assign({}, A)[S] != 7 || Object.keys($assign({}, B)).join('') != K;
	}) ? function assign(target, source) { // eslint-disable-line no-unused-vars
	  var T = _toObject(target);
	  var aLen = arguments.length;
	  var index = 1;
	  var getSymbols = _objectGops.f;
	  var isEnum = _objectPie.f;
	  while (aLen > index) {
	    var S = _iobject(arguments[index++]);
	    var keys = getSymbols ? _objectKeys(S).concat(getSymbols(S)) : _objectKeys(S);
	    var length = keys.length;
	    var j = 0;
	    var key;
	    while (length > j) {
	      key = keys[j++];
	      if (!_descriptors || isEnum.call(S, key)) T[key] = S[key];
	    }
	  } return T;
	} : $assign;

	// 19.1.3.1 Object.assign(target, source)


	_export(_export.S + _export.F, 'Object', { assign: _objectAssign });

	var assign = _core.Object.assign;

	var isEnum = _objectPie.f;
	var _objectToArray = function (isEntries) {
	  return function (it) {
	    var O = _toIobject(it);
	    var keys = _objectKeys(O);
	    var length = keys.length;
	    var i = 0;
	    var result = [];
	    var key;
	    while (length > i) {
	      key = keys[i++];
	      if (!_descriptors || isEnum.call(O, key)) {
	        result.push(isEntries ? [key, O[key]] : O[key]);
	      }
	    }
	    return result;
	  };
	};

	// https://github.com/tc39/proposal-object-values-entries

	var $entries = _objectToArray(true);

	_export(_export.S, 'Object', {
	  entries: function entries(it) {
	    return $entries(it);
	  }
	});

	var entries = _core.Object.entries;

	// https://github.com/tc39/proposal-object-values-entries

	var $values = _objectToArray(false);

	_export(_export.S, 'Object', {
	  values: function values(it) {
	    return $values(it);
	  }
	});

	var values = _core.Object.values;

	// 7.2.8 IsRegExp(argument)


	var MATCH = _wks('match');
	var _isRegexp = function (it) {
	  var isRegExp;
	  return _isObject(it) && ((isRegExp = it[MATCH]) !== undefined ? !!isRegExp : _cof(it) == 'RegExp');
	};

	// helper for String#{startsWith, endsWith, includes}



	var _stringContext = function (that, searchString, NAME) {
	  if (_isRegexp(searchString)) throw TypeError('String#' + NAME + " doesn't accept regex!");
	  return String(_defined(that));
	};

	var MATCH$1 = _wks('match');
	var _failsIsRegexp = function (KEY) {
	  var re = /./;
	  try {
	    '/./'[KEY](re);
	  } catch (e) {
	    try {
	      re[MATCH$1] = false;
	      return !'/./'[KEY](re);
	    } catch (f) { /* empty */ }
	  } return true;
	};

	var STARTS_WITH = 'startsWith';
	var $startsWith = ''[STARTS_WITH];

	_export(_export.P + _export.F * _failsIsRegexp(STARTS_WITH), 'String', {
	  startsWith: function startsWith(searchString /* , position = 0 */) {
	    var that = _stringContext(this, searchString, STARTS_WITH);
	    var index = _toLength(Math.min(arguments.length > 1 ? arguments[1] : undefined, that.length));
	    var search = String(searchString);
	    return $startsWith
	      ? $startsWith.call(that, search, index)
	      : that.slice(index, index + search.length) === search;
	  }
	});

	var startsWith = _core.String.startsWith;

	var Container = /** @class */ (function () {
	    function Container() {
	    }
	    /**
	     * Register the database.
	     */
	    Container.register = function (database) {
	        this.database = database;
	    };
	    return Container;
	}());

	var install = (function (database, options) {
	    if (options === void 0) { options = {}; }
	    var namespace = options.namespace || 'entities';
	    return function (store) {
	        Container.register(database);
	        database.start(store, namespace);
	    };
	});

	/*! *****************************************************************************
	Copyright (c) Microsoft Corporation. All rights reserved.
	Licensed under the Apache License, Version 2.0 (the "License"); you may not use
	this file except in compliance with the License. You may obtain a copy of the
	License at http://www.apache.org/licenses/LICENSE-2.0

	THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
	KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
	WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
	MERCHANTABLITY OR NON-INFRINGEMENT.

	See the Apache Version 2.0 License for specific language governing permissions
	and limitations under the License.
	***************************************************************************** */
	/* global Reflect, Promise */

	var extendStatics = function(d, b) {
	    extendStatics = Object.setPrototypeOf ||
	        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
	        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
	    return extendStatics(d, b);
	};

	function __extends(d, b) {
	    extendStatics(d, b);
	    function __() { this.constructor = d; }
	    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
	}

	var __assign = function() {
	    __assign = Object.assign || function __assign(t) {
	        for (var s, i = 1, n = arguments.length; i < n; i++) {
	            s = arguments[i];
	            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
	        }
	        return t;
	    };
	    return __assign.apply(this, arguments);
	};

	function __awaiter(thisArg, _arguments, P, generator) {
	    return new (P || (P = Promise))(function (resolve, reject) {
	        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
	        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
	        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
	        step((generator = generator.apply(thisArg, _arguments || [])).next());
	    });
	}

	function __generator(thisArg, body) {
	    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
	    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
	    function verb(n) { return function (v) { return step([n, v]); }; }
	    function step(op) {
	        if (f) throw new TypeError("Generator is already executing.");
	        while (_) try {
	            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
	            if (y = 0, t) op = [op[0] & 2, t.value];
	            switch (op[0]) {
	                case 0: case 1: t = op; break;
	                case 4: _.label++; return { value: op[1], done: false };
	                case 5: _.label++; y = op[1]; op = [0]; continue;
	                case 7: op = _.ops.pop(); _.trys.pop(); continue;
	                default:
	                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
	                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
	                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
	                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
	                    if (t[2]) _.ops.pop();
	                    _.trys.pop(); continue;
	            }
	            op = body.call(thisArg, _);
	        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
	        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
	    }
	}

	function __spreadArrays() {
	    for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
	    for (var r = Array(s), k = 0, i = 0; i < il; i++)
	        for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
	            r[k] = a[j];
	    return r;
	}

	/**
	 * Check if the given array or object is empty.
	 */
	function isEmpty(data) {
	    if (Array.isArray(data)) {
	        return data.length === 0;
	    }
	    return Object.keys(data).length === 0;
	}
	/**
	 * Iterates over own enumerable string keyed properties of an object and
	 * invokes `iteratee` for each property.
	 */
	function forOwn(object, iteratee) {
	    Object.keys(object).forEach(function (key) { return iteratee(object[key], key, object); });
	}
	/**
	 * Creates an object with the same keys as object and values generated by
	 * running each own enumerable string keyed property of object thru
	 * iteratee. The iteratee is invoked with three arguments:
	 * (value, key, object).
	 */
	function mapValues(object, iteratee) {
	    var newObject = Object.assign({}, object);
	    return Object.keys(object).reduce(function (records, key) {
	        records[key] = iteratee(object[key], key, object);
	        return records;
	    }, newObject);
	}
	/**
	 * Creates an object composed of the object properties predicate returns
	 * truthy for. The predicate is invoked with two arguments: (value, key).
	 */
	function pickBy(object, predicate) {
	    return Object.keys(object).reduce(function (records, key) {
	        var value = object[key];
	        if (predicate(value, key)) {
	            records[key] = value;
	        }
	        return records;
	    }, {});
	}
	/**
	 * Creates an array of elements, sorted in specified order by the results
	 * of running each element in a collection thru each iteratee.
	 */
	function orderBy(collection, keys, directions) {
	    var index = -1;
	    var result = collection.map(function (value) {
	        var criteria = keys.map(function (key) { return value[key]; });
	        return { criteria: criteria, index: ++index, value: value };
	    });
	    return baseSortBy(result, function (object, other) {
	        return compareMultiple(object, other, directions);
	    });
	}
	/**
	 * Creates an object composed of keys generated from the results of running
	 * each element of collection thru iteratee.
	 */
	function groupBy(collection, iteratee) {
	    return collection.reduce(function (records, record) {
	        var key = iteratee(record);
	        if (records[key] === undefined) {
	            records[key] = [];
	        }
	        records[key].push(record);
	        return records;
	    }, {});
	}
	/**
	 * The base implementation of `_.sortBy` which uses `comparer` to define the
	 * sort order of `array` and replaces criteria objects with their
	 * corresponding values.
	 */
	function baseSortBy(array, comparer) {
	    var length = array.length;
	    array.sort(comparer);
	    while (length--) {
	        array[length] = array[length].value;
	    }
	    return array;
	}
	/**
	 * Used by `orderBy` to compare multiple properties of a value to another
	 * and stable sort them.
	 *
	 * If `orders` is unspecified, all values are sorted in ascending order.
	 * Otherwise, specify an order of "desc" for descending or "asc" for
	 * ascending sort order of corresponding values.
	 */
	function compareMultiple(object, other, orders) {
	    var objCriteria = object.criteria;
	    var othCriteria = other.criteria;
	    var length = objCriteria.length;
	    var ordersLength = orders.length;
	    var index = -1;
	    while (++index < length) {
	        var result = compareAscending(objCriteria[index], othCriteria[index]);
	        if (result) {
	            if (index >= ordersLength) {
	                return result;
	            }
	            var order = orders[index];
	            return result * (order === 'desc' ? -1 : 1);
	        }
	    }
	    return object.index - other.index;
	}
	/**
	 * Compares values to sort them in ascending order.
	 */
	function compareAscending(value, other) {
	    if (value !== other) {
	        if (value > other) {
	            return 1;
	        }
	        if (value < other) {
	            return -1;
	        }
	    }
	    return 0;
	}
	var Utils = {
	    isEmpty: isEmpty,
	    forOwn: forOwn,
	    groupBy: groupBy,
	    mapValues: mapValues,
	    orderBy: orderBy,
	    pickBy: pickBy
	};

	var Attribute = /** @class */ (function () {
	    /**
	     * Create a new attribute instance.
	     */
	    function Attribute(model) {
	        this.model = model;
	    }
	    return Attribute;
	}());

	var Type = /** @class */ (function (_super) {
	    __extends(Type, _super);
	    /**
	     * Create a new type instance.
	     */
	    function Type(model, value, mutator) {
	        var _this = _super.call(this, model) /* istanbul ignore next */ || this;
	        /**
	         * Whether if the attribute can accept `null` as a value.
	         */
	        _this.isNullable = false;
	        _this.value = value;
	        _this.mutator = mutator;
	        return _this;
	    }
	    /**
	     * Set `isNullable` to be `true`.
	     */
	    Type.prototype.nullable = function () {
	        this.isNullable = true;
	        return this;
	    };
	    /**
	     * Mutate the given value by mutator.
	     */
	    Type.prototype.mutate = function (value, key) {
	        var mutator = this.mutator || this.model.mutators()[key];
	        return mutator ? mutator(value) : value;
	    };
	    return Type;
	}(Attribute));

	var Attr = /** @class */ (function (_super) {
	    __extends(Attr, _super);
	    /**
	     * Create a new attr instance.
	     */
	    function Attr(model, value, mutator) {
	        var _this = _super.call(this, model, value, mutator) /* istanbul ignore next */ || this;
	        _this.value = value;
	        return _this;
	    }
	    /**
	     * Make value to be set to model property. This method is used when
	     * instantiating a model or creating a plain object from a model.
	     */
	    Attr.prototype.make = function (value, _parent, key) {
	        value = value !== undefined ? value : this.value;
	        // Default Value might be a function (taking no parameter)
	        var localValue = value;
	        if (typeof value === 'function') {
	            localValue = value();
	        }
	        return this.mutate(localValue, key);
	    };
	    return Attr;
	}(Type));

	var Increment = /** @class */ (function (_super) {
	    __extends(Increment, _super);
	    /**
	     * Create a new increment instance.
	     */
	    function Increment(model) {
	        /* istanbul ignore next */
	        return _super.call(this, model, null) || this;
	    }
	    /**
	     * Convert given value to the appropriate value for the attribute.
	     */
	    Increment.prototype.make = function (value, _parent, _key) {
	        return typeof value === 'number' ? value : null;
	    };
	    return Increment;
	}(Type));

	var String$1 = /** @class */ (function (_super) {
	    __extends(String, _super);
	    /**
	     * Create a new string instance.
	     */
	    function String(model, value, mutator) {
	        /* istanbul ignore next */
	        return _super.call(this, model, value, mutator) || this;
	    }
	    /**
	     * Convert given value to the appropriate value for the attribute.
	     */
	    String.prototype.make = function (value, _parent, key) {
	        return this.mutate(this.fix(value), key);
	    };
	    /**
	     * Convert given value to the string.
	     */
	    String.prototype.fix = function (value) {
	        if (value === undefined) {
	            return this.value;
	        }
	        if (typeof value === 'string') {
	            return value;
	        }
	        if (value === null && this.isNullable) {
	            return value;
	        }
	        return value + '';
	    };
	    return String;
	}(Type));

	var Number = /** @class */ (function (_super) {
	    __extends(Number, _super);
	    /**
	     * Create a new number instance.
	     */
	    function Number(model, value, mutator) {
	        /* istanbul ignore next */
	        return _super.call(this, model, value, mutator) || this;
	    }
	    /**
	     * Convert given value to the appropriate value for the attribute.
	     */
	    Number.prototype.make = function (value, _parent, key) {
	        return this.mutate(this.fix(value), key);
	    };
	    /**
	     * Transform given data to the number.
	     */
	    Number.prototype.fix = function (value) {
	        if (value === undefined) {
	            return this.value;
	        }
	        if (typeof value === 'number') {
	            return value;
	        }
	        if (typeof value === 'string') {
	            return parseFloat(value);
	        }
	        if (typeof value === 'boolean') {
	            return value ? 1 : 0;
	        }
	        if (value === null && this.isNullable) {
	            return value;
	        }
	        return 0;
	    };
	    return Number;
	}(Type));

	var Boolean = /** @class */ (function (_super) {
	    __extends(Boolean, _super);
	    /**
	     * Create a new number instance.
	     */
	    function Boolean(model, value, mutator) {
	        /* istanbul ignore next */
	        return _super.call(this, model, value, mutator) || this;
	    }
	    /**
	     * Convert given value to the appropriate value for the attribute.
	     */
	    Boolean.prototype.make = function (value, _parent, key) {
	        return this.mutate(this.fix(value), key);
	    };
	    /**
	     * Transform given data to the boolean.
	     */
	    Boolean.prototype.fix = function (value) {
	        if (value === undefined) {
	            return this.value;
	        }
	        if (typeof value === 'boolean') {
	            return value;
	        }
	        if (typeof value === 'string') {
	            if (value.length === 0) {
	                return false;
	            }
	            var int = parseInt(value, 0);
	            return isNaN(int) ? true : !!int;
	        }
	        if (typeof value === 'number') {
	            return !!value;
	        }
	        if (value === null && this.isNullable) {
	            return value;
	        }
	        return false;
	    };
	    return Boolean;
	}(Type));

	var Relation = /** @class */ (function (_super) {
	    __extends(Relation, _super);
	    function Relation() {
	        return _super !== null && _super.apply(this, arguments) || this;
	    }
	    /**
	     * Get relation query instance with constraint attached.
	     */
	    Relation.prototype.getRelation = function (query, name, constraints) {
	        var relation = query.newQuery(name);
	        constraints.forEach(function (constraint) { constraint(relation); });
	        return relation;
	    };
	    /**
	     * Get specified keys from the given collection.
	     */
	    Relation.prototype.getKeys = function (collection, key) {
	        return collection.reduce(function (models, model) {
	            if (model[key] === null || model[key] === undefined) {
	                return models;
	            }
	            models.push(model[key]);
	            return models;
	        }, []);
	    };
	    /**
	     * Create a new indexed map for the single relation by specified key.
	     */
	    Relation.prototype.mapSingleRelations = function (collection, key) {
	        return collection.reduce(function (records, record) {
	            var id = record[key];
	            records[id] = record;
	            return records;
	        }, {});
	    };
	    /**
	     * Create a new indexed map for the many relation by specified key.
	     */
	    Relation.prototype.mapManyRelations = function (collection, key) {
	        return collection.reduce(function (records, record) {
	            var id = record[key];
	            if (!records[id]) {
	                records[id] = [];
	            }
	            records[id].push(record);
	            return records;
	        }, {});
	    };
	    /**
	     * Check if the given value is a single relation, which is the Object.
	     */
	    Relation.prototype.isOneRelation = function (record) {
	        if (!Array.isArray(record) && record !== null && typeof record === 'object') {
	            return true;
	        }
	        return false;
	    };
	    /**
	     * Check if the given value is a single relation, which is the Object.
	     */
	    Relation.prototype.isManyRelation = function (records) {
	        if (!Array.isArray(records)) {
	            return false;
	        }
	        if (records.length < 1) {
	            return false;
	        }
	        return true;
	    };
	    /**
	     * Convert given records to the collection.
	     */
	    Relation.prototype.makeManyRelation = function (records, model) {
	        var _this = this;
	        if (!this.isManyRelation(records)) {
	            return [];
	        }
	        return records.filter(function (record) {
	            return _this.isOneRelation(record);
	        }).map(function (record) {
	            return new model(record);
	        });
	    };
	    return Relation;
	}(Attribute));

	var HasOne = /** @class */ (function (_super) {
	    __extends(HasOne, _super);
	    /**
	     * Create a new has one instance.
	     */
	    function HasOne(model, related, foreignKey, localKey) {
	        var _this = _super.call(this, model) /* istanbul ignore next */ || this;
	        _this.related = _this.model.relation(related);
	        _this.foreignKey = foreignKey;
	        _this.localKey = localKey;
	        return _this;
	    }
	    /**
	     * Define the normalizr schema for the relationship.
	     */
	    HasOne.prototype.define = function (schema) {
	        return schema.one(this.related);
	    };
	    /**
	     * Attach the relational key to the related data. For example,
	     * when User has one Phone, it will attach value to the
	     * `user_id` field of Phone record.
	     */
	    HasOne.prototype.attach = function (key, record, data) {
	        // Check if the record has local key set. If not, set the local key to be
	        // the id value. This happens if the user defines the custom local key
	        // and didn't include it in the data being normalized.
	        if (!record[this.localKey]) {
	            record[this.localKey] = record.$id;
	        }
	        // Finally, set the foreign key of the related record if it exists to be the local
	        // key of this record.
	        var related = data[this.related.entity] && data[this.related.entity][key];
	        if (related) {
	            related[this.foreignKey] = record[this.localKey];
	        }
	    };
	    /**
	     * Make value to be set to model property. This method is used when
	     * instantiating a model or creating a plain object from a model.
	     */
	    HasOne.prototype.make = function (value, _parent, _key) {
	        if (!this.isOneRelation(value)) {
	            return null;
	        }
	        return new this.related(value);
	    };
	    /**
	     * Load the has one relationship for the collection.
	     */
	    HasOne.prototype.load = function (query, collection, name, constraints) {
	        var relation = this.getRelation(query, this.related.entity, constraints);
	        this.addEagerConstraints(relation, collection);
	        this.match(collection, relation.get(), name);
	    };
	    /**
	     * Set the constraints for an eager load of the relation.
	     */
	    HasOne.prototype.addEagerConstraints = function (relation, collection) {
	        relation.whereFk(this.foreignKey, this.getKeys(collection, this.localKey));
	    };
	    /**
	     * Match the eagerly loaded results to their parents.
	     */
	    HasOne.prototype.match = function (collection, relations, name) {
	        var _this = this;
	        var dictionary = this.buildDictionary(relations);
	        collection.forEach(function (model) {
	            var id = model[_this.localKey];
	            var relation = dictionary[id];
	            model[name] = relation || null;
	        });
	    };
	    /**
	     * Build model dictionary keyed by the relation's foreign key.
	     */
	    HasOne.prototype.buildDictionary = function (relations) {
	        var _this = this;
	        return relations.reduce(function (dictionary, relation) {
	            var key = relation[_this.foreignKey];
	            dictionary[key] = relation;
	            return dictionary;
	        }, {});
	    };
	    return HasOne;
	}(Relation));

	var BelongsTo = /** @class */ (function (_super) {
	    __extends(BelongsTo, _super);
	    /**
	     * Create a new belongs to instance.
	     */
	    function BelongsTo(model, parent, foreignKey, ownerKey) {
	        var _this = _super.call(this, model) /* istanbul ignore next */ || this;
	        _this.parent = _this.model.relation(parent);
	        _this.foreignKey = foreignKey;
	        _this.ownerKey = ownerKey;
	        return _this;
	    }
	    /**
	     * Define the normalizr schema for the relationship.
	     */
	    BelongsTo.prototype.define = function (schema) {
	        return schema.one(this.parent);
	    };
	    /**
	     * Attach the relational key to the given data. For example, when Post
	     * belongs to User, it will attach value to the `user_id` field of
	     * Post record.
	     */
	    BelongsTo.prototype.attach = function (key, record, data) {
	        // See if the record has the foreign key, if yes, it means the user has
	        // provided the key explicitly so do nothing and return.
	        if (record[this.foreignKey] !== undefined) {
	            return;
	        }
	        // If there is no foreign key, let's set it here.
	        record[this.foreignKey] = data[this.parent.entity] && data[this.parent.entity][key]
	            ? data[this.parent.entity][key][this.ownerKey]
	            : key;
	    };
	    /**
	     * Convert given value to the appropriate value for the attribute.
	     */
	    BelongsTo.prototype.make = function (value, _parent, _key) {
	        if (!this.isOneRelation(value)) {
	            return null;
	        }
	        return new this.parent(value);
	    };
	    /**
	     * Load the belongs to relationship for the collection.
	     */
	    BelongsTo.prototype.load = function (query, collection, name, constraints) {
	        var relation = this.getRelation(query, this.parent.entity, constraints);
	        this.addEagerConstraints(relation, collection);
	        this.match(collection, relation.get(), name);
	    };
	    /**
	     * Set the constraints for an eager load of the relation.
	     */
	    BelongsTo.prototype.addEagerConstraints = function (relation, collection) {
	        relation.whereFk(this.ownerKey, this.getKeys(collection, this.foreignKey));
	    };
	    /**
	     * Match the eagerly loaded results to their parents.
	     */
	    BelongsTo.prototype.match = function (collection, relations, name) {
	        var _this = this;
	        var dictionary = this.buildDictionary(relations);
	        collection.forEach(function (model) {
	            var id = model[_this.foreignKey];
	            var relation = id !== null ? dictionary[id] : null;
	            model[name] = relation || null;
	        });
	    };
	    /**
	     * Build model dictionary keyed by the relation's foreign key.
	     */
	    BelongsTo.prototype.buildDictionary = function (relations) {
	        var _this = this;
	        return relations.reduce(function (dictionary, relation) {
	            var key = relation[_this.ownerKey];
	            dictionary[key] = relation;
	            return dictionary;
	        }, {});
	    };
	    return BelongsTo;
	}(Relation));

	var HasMany = /** @class */ (function (_super) {
	    __extends(HasMany, _super);
	    /**
	     * Create a new has many instance.
	     */
	    function HasMany(model, related, foreignKey, localKey) {
	        var _this = _super.call(this, model) /* istanbul ignore next */ || this;
	        _this.related = _this.model.relation(related);
	        _this.foreignKey = foreignKey;
	        _this.localKey = localKey;
	        return _this;
	    }
	    /**
	     * Define the normalizr schema for the relationship.
	     */
	    HasMany.prototype.define = function (schema) {
	        return schema.many(this.related);
	    };
	    /**
	     * Attach the relational key to the given data.
	     */
	    HasMany.prototype.attach = function (key, record, data) {
	        var _this = this;
	        key.forEach(function (index) {
	            var related = data[_this.related.entity];
	            if (!related || !related[index] || related[index][_this.foreignKey] !== undefined) {
	                return;
	            }
	            related[index][_this.foreignKey] = record[_this.localKey];
	        });
	    };
	    /**
	     * Convert given value to the appropriate value for the attribute.
	     */
	    HasMany.prototype.make = function (value, _parent, _key) {
	        return this.makeManyRelation(value, this.related);
	    };
	    /**
	     * Load the has many relationship for the collection.
	     */
	    HasMany.prototype.load = function (query, collection, name, constraints) {
	        var relation = this.getRelation(query, this.related.entity, constraints);
	        this.addEagerConstraints(relation, collection);
	        this.match(collection, relation.get(), name);
	    };
	    /**
	     * Set the constraints for an eager load of the relation.
	     */
	    HasMany.prototype.addEagerConstraints = function (relation, collection) {
	        relation.whereFk(this.foreignKey, this.getKeys(collection, this.localKey));
	    };
	    /**
	     * Match the eagerly loaded results to their parents.
	     */
	    HasMany.prototype.match = function (collection, relations, name) {
	        var _this = this;
	        var dictionary = this.buildDictionary(relations);
	        collection.forEach(function (model) {
	            var id = model[_this.localKey];
	            var relation = dictionary[id];
	            model[name] = relation || [];
	        });
	    };
	    /**
	     * Build model dictionary keyed by the relation's foreign key.
	     */
	    HasMany.prototype.buildDictionary = function (relations) {
	        var _this = this;
	        return relations.reduce(function (dictionary, relation) {
	            var key = relation[_this.foreignKey];
	            if (!dictionary[key]) {
	                dictionary[key] = [];
	            }
	            dictionary[key].push(relation);
	            return dictionary;
	        }, {});
	    };
	    return HasMany;
	}(Relation));

	var HasManyBy = /** @class */ (function (_super) {
	    __extends(HasManyBy, _super);
	    /**
	     * Create a new has many by instance.
	     */
	    function HasManyBy(model, parent, foreignKey, ownerKey) {
	        var _this = _super.call(this, model) /* istanbul ignore next */ || this;
	        _this.parent = _this.model.relation(parent);
	        _this.foreignKey = foreignKey;
	        _this.ownerKey = ownerKey;
	        return _this;
	    }
	    /**
	     * Define the normalizr schema for the relationship.
	     */
	    HasManyBy.prototype.define = function (schema) {
	        return schema.many(this.parent);
	    };
	    /**
	     * Attach the relational key to the given data.
	     */
	    HasManyBy.prototype.attach = function (key, record, _data) {
	        if (key.length === 0) {
	            return;
	        }
	        record[this.foreignKey] = key;
	    };
	    /**
	     * Convert given value to the appropriate value for the attribute.
	     */
	    HasManyBy.prototype.make = function (value, _parent, _key) {
	        return this.makeManyRelation(value, this.parent);
	    };
	    /**
	     * Load the has many by relationship for the collection.
	     */
	    HasManyBy.prototype.load = function (query, collection, name, constraints) {
	        var _this = this;
	        var relatedQuery = this.getRelation(query, this.parent.entity, constraints);
	        this.addConstraintForHasManyBy(relatedQuery, collection);
	        var relations = this.mapSingleRelations(relatedQuery.get(), this.ownerKey);
	        collection.forEach(function (item) {
	            var related = _this.getRelatedRecords(relations, item[_this.foreignKey]);
	            item[name] = related;
	        });
	    };
	    /**
	     * Set the constraints for an eager load of the relation.
	     */
	    HasManyBy.prototype.addConstraintForHasManyBy = function (query, collection) {
	        var _this = this;
	        var keys = collection.reduce(function (keys, item) {
	            return keys.concat(item[_this.foreignKey]);
	        }, []);
	        query.where(this.ownerKey, keys);
	    };
	    /**
	     * Get related records.
	     */
	    HasManyBy.prototype.getRelatedRecords = function (records, keys) {
	        return keys.reduce(function (items, id) {
	            var related = records[id];
	            related && items.push(related);
	            return items;
	        }, []);
	    };
	    return HasManyBy;
	}(Relation));

	var HasManyThrough = /** @class */ (function (_super) {
	    __extends(HasManyThrough, _super);
	    /**
	     * Create a new has many through instance.
	     */
	    function HasManyThrough(model, related, through, firstKey, secondKey, localKey, secondLocalKey) {
	        var _this = _super.call(this, model) /* istanbul ignore next */ || this;
	        _this.related = _this.model.relation(related);
	        _this.through = _this.model.relation(through);
	        _this.firstKey = firstKey;
	        _this.secondKey = secondKey;
	        _this.localKey = localKey;
	        _this.secondLocalKey = secondLocalKey;
	        return _this;
	    }
	    /**
	     * Define the normalizr schema for the relationship.
	     */
	    HasManyThrough.prototype.define = function (schema) {
	        return schema.many(this.related);
	    };
	    /**
	     * Attach the relational key to the given data. Since has many through
	     * relationship doesn't have any foreign key, it would do nothing.
	     */
	    HasManyThrough.prototype.attach = function (_key, _record, _data) {
	        return;
	    };
	    /**
	     * Convert given value to the appropriate value for the attribute.
	     */
	    HasManyThrough.prototype.make = function (value, _parent, _key) {
	        return this.makeManyRelation(value, this.related);
	    };
	    /**
	     * Load the has many through relationship for the collection.
	     */
	    HasManyThrough.prototype.load = function (query, collection, name, constraints) {
	        var _this = this;
	        var relatedQuery = this.getRelation(query, this.related.entity, constraints);
	        var throughQuery = query.newQuery(this.through.entity);
	        this.addEagerConstraintForThrough(throughQuery, collection);
	        var throughs = throughQuery.get();
	        this.addEagerConstraintForRelated(relatedQuery, throughs);
	        var relateds = this.mapThroughRelations(throughs, relatedQuery);
	        collection.forEach(function (item) {
	            var related = relateds[item[_this.localKey]];
	            item[name] = related || [];
	        });
	    };
	    /**
	     * Set the constraints for the through relation.
	     */
	    HasManyThrough.prototype.addEagerConstraintForThrough = function (query, collection) {
	        query.where(this.firstKey, this.getKeys(collection, this.localKey));
	    };
	    /**
	     * Set the constraints for the related relation.
	     */
	    HasManyThrough.prototype.addEagerConstraintForRelated = function (query, collection) {
	        query.where(this.secondKey, this.getKeys(collection, this.secondLocalKey));
	    };
	    /**
	     * Create a new indexed map for the through relation.
	     */
	    HasManyThrough.prototype.mapThroughRelations = function (throughs, relatedQuery) {
	        var _this = this;
	        var relateds = this.mapManyRelations(relatedQuery.get(), this.secondKey);
	        return throughs.reduce(function (records, record) {
	            var id = record[_this.firstKey];
	            if (!records[id]) {
	                records[id] = [];
	            }
	            var related = relateds[record[_this.secondLocalKey]];
	            if (related === undefined) {
	                return records;
	            }
	            records[id] = records[id].concat(related);
	            return records;
	        }, {});
	    };
	    return HasManyThrough;
	}(Relation));

	var BelongsToMany = /** @class */ (function (_super) {
	    __extends(BelongsToMany, _super);
	    /**
	     * Create a new belongs to instance.
	     */
	    function BelongsToMany(model, related, pivot, foreignPivotKey, relatedPivotKey, parentKey, relatedKey) {
	        var _this = _super.call(this, model) /* istanbul ignore next */ || this;
	        _this.related = _this.model.relation(related);
	        _this.pivot = _this.model.relation(pivot);
	        _this.foreignPivotKey = foreignPivotKey;
	        _this.relatedPivotKey = relatedPivotKey;
	        _this.parentKey = parentKey;
	        _this.relatedKey = relatedKey;
	        return _this;
	    }
	    /**
	     * Define the normalizr schema for the relationship.
	     */
	    BelongsToMany.prototype.define = function (schema) {
	        return schema.many(this.related);
	    };
	    /**
	     * Attach the relational key to the given data. Since belongs to many
	     * relationship doesn't have any foreign key, it would do nothing.
	     */
	    BelongsToMany.prototype.attach = function (_key, _record, _data) {
	        return;
	    };
	    /**
	     * Convert given value to the appropriate value for the attribute.
	     */
	    BelongsToMany.prototype.make = function (value, _parent, _key) {
	        return this.makeManyRelation(value, this.related);
	    };
	    /**
	     * Load the belongs to relationship for the record.
	     */
	    BelongsToMany.prototype.load = function (query, collection, name, constraints) {
	        var _this = this;
	        var relatedQuery = this.getRelation(query, this.related.entity, constraints);
	        var pivotQuery = query.newQuery(this.pivot.entity);
	        this.addEagerConstraintForPivot(pivotQuery, collection);
	        var pivots = pivotQuery.get();
	        this.addEagerConstraintForRelated(relatedQuery, pivots);
	        var relateds = this.mapPivotRelations(pivots, relatedQuery);
	        collection.forEach(function (item) {
	            var related = relateds[item[_this.parentKey]];
	            item[name] = related || [];
	        });
	    };
	    /**
	     * Set the constraints for the pivot relation.
	     */
	    BelongsToMany.prototype.addEagerConstraintForPivot = function (query, collection) {
	        query.whereFk(this.foreignPivotKey, this.getKeys(collection, this.parentKey));
	    };
	    /**
	     * Set the constraints for the related relation.
	     */
	    BelongsToMany.prototype.addEagerConstraintForRelated = function (query, collection) {
	        query.whereFk(this.relatedKey, this.getKeys(collection, this.relatedPivotKey));
	    };
	    /**
	     * Create a new indexed map for the pivot relation.
	     */
	    BelongsToMany.prototype.mapPivotRelations = function (pivots, relatedQuery) {
	        var _this = this;
	        var relateds = this.mapManyRelations(relatedQuery.get(), this.relatedKey);
	        return pivots.reduce(function (records, record) {
	            var id = record[_this.foreignPivotKey];
	            if (!records[id]) {
	                records[id] = [];
	            }
	            var related = relateds[record[_this.relatedPivotKey]];
	            if (related) {
	                records[id] = records[id].concat(related);
	            }
	            return records;
	        }, {});
	    };
	    /**
	     * Create pivot records for the given records if needed.
	     */
	    BelongsToMany.prototype.createPivots = function (parent, data, key) {
	        var _this = this;
	        if (this.pivot.primaryKey instanceof Array === false)
	            return data;
	        Utils.forOwn(data[parent.entity], function (record) {
	            var related = record[key];
	            if (related === undefined || related.length === 0) {
	                return;
	            }
	            _this.createPivotRecord(data, record, related);
	        });
	        return data;
	    };
	    /**
	     * Create a pivot record.
	     */
	    BelongsToMany.prototype.createPivotRecord = function (data, record, related) {
	        var _this = this;
	        related.forEach(function (id) {
	            var _a, _b;
	            var parentId = record[_this.parentKey];
	            var relatedId = data[_this.related.entity][id][_this.relatedKey];
	            var pivotKey = relatedId + "_" + parentId;
	            var pivotRecord = data[_this.pivot.entity] ? data[_this.pivot.entity][pivotKey] : {};
	            data[_this.pivot.entity] = __assign(__assign({}, data[_this.pivot.entity]), (_a = {}, _a[pivotKey] = __assign(__assign({}, pivotRecord), (_b = { $id: pivotKey }, _b[_this.foreignPivotKey] = parentId, _b[_this.relatedPivotKey] = relatedId, _b)), _a));
	        });
	    };
	    return BelongsToMany;
	}(Relation));

	var MorphTo = /** @class */ (function (_super) {
	    __extends(MorphTo, _super);
	    /**
	     * Create a new morph to instance.
	     */
	    function MorphTo(model, id, type) {
	        var _this = _super.call(this, model) /* istanbul ignore next */ || this;
	        _this.id = id;
	        _this.type = type;
	        return _this;
	    }
	    /**
	     * Define the normalizr schema for the relationship.
	     */
	    MorphTo.prototype.define = function (schema) {
	        var _this = this;
	        return schema.union(function (_value, parentValue) { return parentValue[_this.type]; });
	    };
	    /**
	     * Attach the relational key to the given record. Since morph to
	     * relationship doesn't have any foreign key, it would do nothing.
	     */
	    MorphTo.prototype.attach = function (_key, _record, _data) {
	        return;
	    };
	    /**
	     * Convert given value to the appropriate value for the attribute.
	     */
	    MorphTo.prototype.make = function (value, parent, _key) {
	        if (!this.isOneRelation(value)) {
	            return null;
	        }
	        var related = parent[this.type];
	        var model = this.model.relation(related);
	        return model ? new model(value) : null;
	    };
	    /**
	     * Load the morph to relationship for the collection.
	     */
	    MorphTo.prototype.load = function (query, collection, name, constraints) {
	        var _this = this;
	        var types = this.getTypes(collection);
	        var relateds = types.reduce(function (relateds, type) {
	            var relatedQuery = _this.getRelation(query, type, constraints);
	            relateds[type] = _this.mapSingleRelations(relatedQuery.get(), '$id');
	            return relateds;
	        }, {});
	        collection.forEach(function (item) {
	            var id = item[_this.id];
	            var type = item[_this.type];
	            var related = relateds[type][id];
	            item[name] = related || null;
	        });
	    };
	    /**
	     * Get all types from the collection.
	     */
	    MorphTo.prototype.getTypes = function (collection) {
	        var _this = this;
	        return collection.reduce(function (types, item) {
	            var type = item[_this.type];
	            !types.includes(type) && types.push(type);
	            return types;
	        }, []);
	    };
	    return MorphTo;
	}(Relation));

	var MorphOne = /** @class */ (function (_super) {
	    __extends(MorphOne, _super);
	    /**
	     * Create a new belongs to instance.
	     */
	    function MorphOne(model, related, id, type, localKey) {
	        var _this = _super.call(this, model) /* istanbul ignore next */ || this;
	        _this.related = _this.model.relation(related);
	        _this.id = id;
	        _this.type = type;
	        _this.localKey = localKey;
	        return _this;
	    }
	    /**
	     * Define the normalizr schema for the relationship.
	     */
	    MorphOne.prototype.define = function (schema) {
	        return schema.one(this.related);
	    };
	    /**
	     * Attach the relational key to the given data.
	     */
	    MorphOne.prototype.attach = function (key, record, data) {
	        var relatedRecord = data[this.related.entity][key];
	        relatedRecord[this.id] = relatedRecord[this.id] || record.$id;
	        relatedRecord[this.type] = relatedRecord[this.type] || this.model.entity;
	    };
	    /**
	     * Convert given value to the appropriate value for the attribute.
	     */
	    MorphOne.prototype.make = function (value, _parent, _key) {
	        if (!this.isOneRelation(value)) {
	            return null;
	        }
	        return new this.related(value);
	    };
	    /**
	     * Load the morph many relationship for the record.
	     */
	    MorphOne.prototype.load = function (query, collection, name, constraints) {
	        var _this = this;
	        var relatedQuery = this.getRelation(query, this.related.entity, constraints);
	        this.addEagerConstraintForMorphOne(relatedQuery, collection, query.entity);
	        var relations = this.mapSingleRelations(relatedQuery.get(), this.id);
	        collection.forEach(function (item) {
	            var related = relations[item[_this.localKey]];
	            item[name] = related || null;
	        });
	    };
	    /**
	     * Set the constraints for an eager load of the relation.
	     */
	    MorphOne.prototype.addEagerConstraintForMorphOne = function (query, collection, type) {
	        query.whereFk(this.type, type).whereFk(this.id, this.getKeys(collection, this.localKey));
	    };
	    return MorphOne;
	}(Relation));

	var MorphMany = /** @class */ (function (_super) {
	    __extends(MorphMany, _super);
	    /**
	     * Create a new belongs to instance.
	     */
	    function MorphMany(model, related, id, type, localKey) {
	        var _this = _super.call(this, model) /* istanbul ignore next */ || this;
	        _this.related = _this.model.relation(related);
	        _this.id = id;
	        _this.type = type;
	        _this.localKey = localKey;
	        return _this;
	    }
	    /**
	     * Define the normalizr schema for the relationship.
	     */
	    MorphMany.prototype.define = function (schema) {
	        return schema.many(this.related);
	    };
	    /**
	     * Attach the relational key to the given data.
	     */
	    MorphMany.prototype.attach = function (key, record, data) {
	        var _this = this;
	        var relatedItems = data[this.related.entity];
	        key.forEach(function (id) {
	            var relatedItem = relatedItems[id];
	            relatedItem[_this.id] = relatedItem[_this.id] || record.$id;
	            relatedItem[_this.type] = relatedItem[_this.type] || _this.model.entity;
	        });
	    };
	    /**
	     * Convert given value to the appropriate value for the attribute.
	     */
	    MorphMany.prototype.make = function (value, _parent, _key) {
	        return this.makeManyRelation(value, this.related);
	    };
	    /**
	     * Load the morph many relationship for the record.
	     */
	    MorphMany.prototype.load = function (query, collection, name, constraints) {
	        var _this = this;
	        var relatedQuery = this.getRelation(query, this.related.entity, constraints);
	        this.addEagerConstraintForMorphMany(relatedQuery, collection, query.entity);
	        var relations = this.mapManyRelations(relatedQuery.get(), this.id);
	        collection.forEach(function (item) {
	            var related = relations[item[_this.localKey]];
	            item[name] = related || [];
	        });
	    };
	    /**
	     * Set the constraints for an eager load of the relation.
	     */
	    MorphMany.prototype.addEagerConstraintForMorphMany = function (query, collection, type) {
	        query.whereFk(this.type, type).whereFk(this.id, this.getKeys(collection, this.localKey));
	    };
	    return MorphMany;
	}(Relation));

	var MorphToMany = /** @class */ (function (_super) {
	    __extends(MorphToMany, _super);
	    /**
	     * Create a new belongs to instance.
	     */
	    function MorphToMany(model, related, pivot, relatedId, id, type, parentKey, relatedKey) {
	        var _this = _super.call(this, model) /* istanbul ignore next */ || this;
	        _this.related = _this.model.relation(related);
	        _this.pivot = _this.model.relation(pivot);
	        _this.relatedId = relatedId;
	        _this.id = id;
	        _this.type = type;
	        _this.parentKey = parentKey;
	        _this.relatedKey = relatedKey;
	        return _this;
	    }
	    /**
	     * Define the normalizr schema for the relationship.
	     */
	    MorphToMany.prototype.define = function (schema) {
	        return schema.many(this.related);
	    };
	    /**
	     * Attach the relational key to the given record. Since morph to many
	     * relationship doesn't have any foreign key, it would do nothing.
	     */
	    MorphToMany.prototype.attach = function (_key, _record, _data) {
	        return;
	    };
	    /**
	     * Convert given value to the appropriate value for the attribute.
	     */
	    MorphToMany.prototype.make = function (value, _parent, _key) {
	        return this.makeManyRelation(value, this.related);
	    };
	    /**
	     * Load the morph to many relationship for the collection.
	     */
	    MorphToMany.prototype.load = function (query, collection, name, constraints) {
	        var _this = this;
	        var relatedQuery = this.getRelation(query, this.related.entity, constraints);
	        var pivotQuery = query.newQuery(this.pivot.entity);
	        this.addEagerConstraintForPivot(pivotQuery, collection, query.entity);
	        var pivots = pivotQuery.get();
	        this.addEagerConstraintForRelated(relatedQuery, pivots);
	        var relateds = this.mapPivotRelations(pivots, relatedQuery);
	        collection.forEach(function (item) {
	            var related = relateds[item[_this.parentKey]];
	            item[name] = related || [];
	        });
	    };
	    /**
	     * Set the constraints for the pivot relation.
	     */
	    MorphToMany.prototype.addEagerConstraintForPivot = function (query, collection, type) {
	        query.whereFk(this.type, type).whereFk(this.id, this.getKeys(collection, this.parentKey));
	    };
	    /**
	     * Set the constraints for the related relation.
	     */
	    MorphToMany.prototype.addEagerConstraintForRelated = function (query, collection) {
	        query.whereFk(this.relatedKey, this.getKeys(collection, this.relatedId));
	    };
	    /**
	     * Create a new indexed map for the pivot relation.
	     */
	    MorphToMany.prototype.mapPivotRelations = function (pivots, relatedQuery) {
	        var _this = this;
	        var relateds = this.mapManyRelations(relatedQuery.get(), this.relatedKey);
	        return pivots.reduce(function (records, record) {
	            var id = record[_this.id];
	            if (!records[id]) {
	                records[id] = [];
	            }
	            var related = relateds[record[_this.relatedId]];
	            records[id] = records[id].concat(related);
	            return records;
	        }, {});
	    };
	    /**
	     * Create pivot records for the given records if needed.
	     */
	    MorphToMany.prototype.createPivots = function (parent, data, key) {
	        var _this = this;
	        Utils.forOwn(data[parent.entity], function (record) {
	            var relatedIds = parent.query().newQuery(_this.pivot.entity)
	                .where(_this.id, record[_this.parentKey])
	                .where(_this.type, parent.entity)
	                .get()
	                .map(function (pivotRecord) { return pivotRecord[_this.parentKey]; });
	            var relateds = (record[key] || []).filter(function (relatedId) { return !relatedIds.includes(relatedId); });
	            if (!Array.isArray(relateds) || relateds.length === 0) {
	                return;
	            }
	            _this.createPivotRecord(parent, data, record, relateds);
	        });
	        return data;
	    };
	    /**
	     * Create a pivot record.
	     */
	    MorphToMany.prototype.createPivotRecord = function (parent, data, record, related) {
	        var _this = this;
	        related.forEach(function (id) {
	            var _a, _b;
	            var parentId = record[_this.parentKey];
	            var relatedId = data[_this.related.entity][id][_this.relatedKey];
	            var pivotKey = parentId + "_" + id + "_" + parent.entity;
	            data[_this.pivot.entity] = __assign(__assign({}, data[_this.pivot.entity]), (_a = {}, _a[pivotKey] = (_b = {
	                    $id: pivotKey
	                },
	                _b[_this.relatedId] = relatedId,
	                _b[_this.id] = parentId,
	                _b[_this.type] = parent.entity,
	                _b), _a));
	        });
	    };
	    return MorphToMany;
	}(Relation));

	var MorphedByMany = /** @class */ (function (_super) {
	    __extends(MorphedByMany, _super);
	    /**
	     * Create a new belongs to instance.
	     */
	    function MorphedByMany(model, related, pivot, relatedId, id, type, parentKey, relatedKey) {
	        var _this = _super.call(this, model) /* istanbul ignore next */ || this;
	        _this.related = _this.model.relation(related);
	        _this.pivot = _this.model.relation(pivot);
	        _this.relatedId = relatedId;
	        _this.id = id;
	        _this.type = type;
	        _this.parentKey = parentKey;
	        _this.relatedKey = relatedKey;
	        return _this;
	    }
	    /**
	     * Define the normalizr schema for the relationship.
	     */
	    MorphedByMany.prototype.define = function (schema) {
	        return schema.many(this.related);
	    };
	    /**
	     * Attach the relational key to the given data. Since morphed by many
	     * relationship doesn't have any foreign key, it would do nothing.
	     */
	    MorphedByMany.prototype.attach = function (_key, _record, _data) {
	        return;
	    };
	    /**
	     * Make value to be set to model property. This method is used when
	     * instantiating a model or creating a plain object from a model.
	     */
	    MorphedByMany.prototype.make = function (value, _parent, _key) {
	        return this.makeManyRelation(value, this.related);
	    };
	    /**
	     * Load the morph many relationship for the record.
	     */
	    MorphedByMany.prototype.load = function (query, collection, name, constraints) {
	        var _this = this;
	        var relatedQuery = this.getRelation(query, this.related.entity, constraints);
	        var pivotQuery = query.newQuery(this.pivot.entity);
	        this.addEagerConstraintForPivot(pivotQuery, collection, this.related.entity);
	        var pivots = pivotQuery.get();
	        this.addEagerConstraintForRelated(relatedQuery, pivots);
	        var relateds = this.mapPivotRelations(pivots, relatedQuery);
	        collection.forEach(function (item) {
	            var related = relateds[item[_this.parentKey]];
	            item[name] = related || [];
	        });
	    };
	    /**
	     * Set the constraints for the pivot relation.
	     */
	    MorphedByMany.prototype.addEagerConstraintForPivot = function (query, collection, type) {
	        query.whereFk(this.type, type).whereFk(this.relatedId, this.getKeys(collection, this.parentKey));
	    };
	    /**
	     * Set the constraints for the related relation.
	     */
	    MorphedByMany.prototype.addEagerConstraintForRelated = function (query, collection) {
	        query.whereFk(this.relatedKey, this.getKeys(collection, this.id));
	    };
	    /**
	     * Create a new indexed map for the pivot relation.
	     */
	    MorphedByMany.prototype.mapPivotRelations = function (pivots, relatedQuery) {
	        var _this = this;
	        var relateds = this.mapManyRelations(relatedQuery.get(), this.relatedKey);
	        return pivots.reduce(function (records, record) {
	            var id = record[_this.relatedId];
	            if (!records[id]) {
	                records[id] = [];
	            }
	            var related = relateds[record[_this.id]];
	            records[id] = records[id].concat(related);
	            return records;
	        }, {});
	    };
	    /**
	     * Create pivot records for the given records if needed.
	     */
	    MorphedByMany.prototype.createPivots = function (parent, data, key) {
	        var _this = this;
	        Utils.forOwn(data[parent.entity], function (record) {
	            var related = record[key];
	            if (!Array.isArray(related)) {
	                return;
	            }
	            _this.createPivotRecord(data, record, related);
	        });
	        return data;
	    };
	    /**
	     * Create a pivot record.
	     */
	    MorphedByMany.prototype.createPivotRecord = function (data, record, related) {
	        var _this = this;
	        related.forEach(function (id) {
	            var _a, _b;
	            var parentId = record[_this.parentKey];
	            var pivotKey = id + "_" + parentId + "_" + _this.related.entity;
	            data[_this.pivot.entity] = __assign(__assign({}, data[_this.pivot.entity]), (_a = {}, _a[pivotKey] = (_b = {
	                    $id: pivotKey
	                },
	                _b[_this.relatedId] = parentId,
	                _b[_this.id] = id,
	                _b[_this.type] = _this.related.entity,
	                _b), _a));
	        });
	    };
	    return MorphedByMany;
	}(Relation));

	var Serializer = /** @class */ (function () {
	    function Serializer() {
	    }
	    /**
	     * Serialize given model fields value to json.
	     */
	    Serializer.serialize = function (model) {
	        var _this = this;
	        var fields = model.$fields();
	        return Object.keys(fields).reduce(function (record, key) {
	            var value = model[key];
	            record[key] = _this.serializeValue(value);
	            return record;
	        }, {});
	    };
	    /**
	     * Serialize given value.
	     */
	    Serializer.serializeValue = function (value) {
	        if (value instanceof Model) {
	            return this.serializeItem(value);
	        }
	        if (Array.isArray(value)) {
	            return this.serializeCollection(value);
	        }
	        return value;
	    };
	    /**
	     * Serialize an item into json.
	     */
	    Serializer.serializeItem = function (item) {
	        return item.$toJson();
	    };
	    /**
	     * Serialize a collection into json.
	     */
	    Serializer.serializeCollection = function (collection) {
	        return collection.map(function (item) {
	            if (item instanceof Model) {
	                return item.$toJson();
	            }
	            return item;
	        });
	    };
	    return Serializer;
	}());

	var Model = /** @class */ (function () {
	    /**
	     * Create a new model instance.
	     */
	    function Model(record) {
	        /**
	         * The index ID for the model.
	         */
	        this.$id = null;
	        this.$fill(record);
	    }
	    /**
	     * The definition of the fields of the model and its relations.
	     */
	    Model.fields = function () {
	        return {};
	    };
	    /**
	     * Create an attr attribute.
	     */
	    Model.attr = function (value, mutator) {
	        return new Attr(this, value, mutator);
	    };
	    /**
	     * Create a string attribute.
	     */
	    Model.string = function (value, mutator) {
	        return new String$1(this, value, mutator);
	    };
	    /**
	     * Create a number attribute.
	     */
	    Model.number = function (value, mutator) {
	        return new Number(this, value, mutator);
	    };
	    /**
	     * Create a boolean attribute.
	     */
	    Model.boolean = function (value, mutator) {
	        return new Boolean(this, value, mutator);
	    };
	    /**
	     * Create an increment attribute.
	     */
	    Model.increment = function () {
	        return new Increment(this);
	    };
	    /**
	     * Create a has one relationship.
	     */
	    Model.hasOne = function (related, foreignKey, localKey) {
	        return new HasOne(this, related, foreignKey, this.localKey(localKey));
	    };
	    /**
	     * Create a belongs to relationship.
	     */
	    Model.belongsTo = function (parent, foreignKey, ownerKey) {
	        return new BelongsTo(this, parent, foreignKey, this.relation(parent).localKey(ownerKey));
	    };
	    /**
	     * Create a has many relationship.
	     */
	    Model.hasMany = function (related, foreignKey, localKey) {
	        return new HasMany(this, related, foreignKey, this.localKey(localKey));
	    };
	    /**
	     * Create a has many by relationship.
	     */
	    Model.hasManyBy = function (parent, foreignKey, ownerKey) {
	        return new HasManyBy(this, parent, foreignKey, this.relation(parent).localKey(ownerKey));
	    };
	    /**
	     * Create a has many through relationship.
	     */
	    Model.hasManyThrough = function (related, through, firstKey, secondKey, localKey, secondLocalKey) {
	        return new HasManyThrough(this, related, through, firstKey, secondKey, this.localKey(localKey), this.relation(through).localKey(secondLocalKey));
	    };
	    /**
	     * Create a belongs to many relationship.
	     */
	    Model.belongsToMany = function (related, pivot, foreignPivotKey, relatedPivotKey, parentKey, relatedKey) {
	        return new BelongsToMany(this, related, pivot, foreignPivotKey, relatedPivotKey, this.localKey(parentKey), this.relation(related).localKey(relatedKey));
	    };
	    /**
	     * Create a morph to relationship.
	     */
	    Model.morphTo = function (id, type) {
	        return new MorphTo(this, id, type);
	    };
	    /**
	     * Create a morph one relationship.
	     */
	    Model.morphOne = function (related, id, type, localKey) {
	        return new MorphOne(this, related, id, type, this.localKey(localKey));
	    };
	    /**
	     * Create a morph many relationship.
	     */
	    Model.morphMany = function (related, id, type, localKey) {
	        return new MorphMany(this, related, id, type, this.localKey(localKey));
	    };
	    /**
	     * Create a morph to many relationship.
	     */
	    Model.morphToMany = function (related, pivot, relatedId, id, type, parentKey, relatedKey) {
	        return new MorphToMany(this, related, pivot, relatedId, id, type, this.localKey(parentKey), this.relation(related).localKey(relatedKey));
	    };
	    /**
	     * Create a morphed by many relationship.
	     */
	    Model.morphedByMany = function (related, pivot, relatedId, id, type, parentKey, relatedKey) {
	        return new MorphedByMany(this, related, pivot, relatedId, id, type, this.localKey(parentKey), this.relation(related).localKey(relatedKey));
	    };
	    /**
	     * Mutators to mutate matching fields when instantiating the model.
	     */
	    Model.mutators = function () {
	        return {};
	    };
	    /**
	     * Types mapping used to dispatch entities based on their discriminator field
	     */
	    Model.types = function () {
	        return {};
	    };
	    /**
	     * Get the database instance from the container.
	     */
	    Model.database = function () {
	        return Container.database;
	    };
	    /**
	     * Get the store instance from the container.
	     */
	    Model.store = function () {
	        return this.database().store;
	    };
	    /**
	     * Create a namespaced method name for Vuex Module from the given
	     * method name.
	     */
	    Model.namespace = function (method) {
	        return this.database().namespace + "/" + this.entity + "/" + method;
	    };
	    /**
	     * Call Vuex Getters.
	     */
	    Model.getters = function (method) {
	        return this.store().getters[this.namespace(method)];
	    };
	    /**
	     * Dispatch Vuex Action.
	     */
	    Model.dispatch = function (method, payload) {
	        return this.store().dispatch(this.namespace(method), payload);
	    };
	    /**
	     * Commit Vuex Mutation.
	     */
	    Model.commit = function (callback) {
	        this.store().commit(this.database().namespace + "/$mutate", {
	            entity: this.entity,
	            callback: callback
	        });
	    };
	    /**
	     * Get the Model schema definition from the cache.
	     */
	    Model.getFields = function () {
	        if (!this.cachedFields) {
	            this.cachedFields = {};
	        }
	        if (this.cachedFields[this.entity]) {
	            return this.cachedFields[this.entity];
	        }
	        this.cachedFields[this.entity] = this.fields();
	        return this.cachedFields[this.entity];
	    };
	    /**
	     * Get all records.
	     */
	    Model.all = function () {
	        return this.getters('all')();
	    };
	    /**
	     * Find a record.
	     */
	    Model.find = function (id) {
	        return this.getters('find')(id);
	    };
	    /**
	     * Get the record of the given array of ids.
	     */
	    Model.findIn = function (idList) {
	        return this.getters('findIn')(idList);
	    };
	    /**
	     * Get query instance.
	     */
	    Model.query = function () {
	        return this.getters('query')();
	    };
	    /**
	     * Create new data with all fields filled by default values.
	     */
	    Model.new = function () {
	        return this.dispatch('new');
	    };
	    /**
	     * Save given data to the store by replacing all existing records in the
	     * store. If you want to save data without replacing existing records,
	     * use the `insert` method instead.
	     */
	    Model.create = function (payload) {
	        return this.dispatch('create', payload);
	    };
	    /**
	     * Insert records.
	     */
	    Model.insert = function (payload) {
	        return this.dispatch('insert', payload);
	    };
	    /**
	     * Update records.
	     */
	    Model.update = function (payload) {
	        return this.dispatch('update', payload);
	    };
	    /**
	     * Insert or update records.
	     */
	    Model.insertOrUpdate = function (payload) {
	        return this.dispatch('insertOrUpdate', payload);
	    };
	    Model.delete = function (payload) {
	        return this.dispatch('delete', payload);
	    };
	    /**
	     * Delete all records from the store.
	     */
	    Model.deleteAll = function () {
	        return this.dispatch('deleteAll');
	    };
	    /**
	     * Get the index ID value from the given record. An index ID is a value that
	     * used as a key for records within the Vuex Store.
	     *
	     * Most of the time, it's same as the value for the Model's primary key. If
	     * the Model has a composite primary key, each value corresponding to those
	     * primary key will be joined together with `_` and become a single string
	     * value such as `1_2`.
	     *
	     * If the primary key is not present at the given record, it returns `null`.
	     * For the composite primary key, every key must exist at a given record,
	     * or it will return `null`.
	     */
	    Model.getIndexIdFromRecord = function (record) {
	        var _this = this;
	        var key = this.primaryKey;
	        if (typeof key === 'string') {
	            return this.getIndexIdFromValue(record[key]);
	        }
	        var ids = [];
	        var isCompositeKeyValid = key.every(function (k) {
	            var id = _this.getIndexIdFromValue(record[k]);
	            id && ids.push(id);
	            return id;
	        });
	        return isCompositeKeyValid ? ids.join('_') : null;
	    };
	    /**
	     * Get correct index ID from the given value. This method will cast the
	     * number to the string, and returns `null` for anything which is not
	     * a string or a number.
	     */
	    Model.getIndexIdFromValue = function (value) {
	        if (typeof value === 'string' && value !== '') {
	            return value;
	        }
	        if (typeof value === 'number') {
	            return value;
	        }
	        return null;
	    };
	    /**
	     * Get local key to pass to the attributes.
	     */
	    Model.localKey = function (key) {
	        if (key) {
	            return key;
	        }
	        return typeof this.primaryKey === 'string' ? this.primaryKey : 'id';
	    };
	    /**
	     * Get the model object that matches the given record type. The method is for
	     * getting the correct model object when the model has any inheritance
	     * children model.
	     *
	     * For example, if a User Model have `static types()` declared, and if you
	     * pass record with `{ type: 'admin' }`, then the method will likely to
	     * return SuperUser class.
	     */
	    Model.getModelFromRecord = function (record) {
	        // If the given record is already a model instance, return the
	        // model object.
	        if (record instanceof Model) {
	            return record.$self();
	        }
	        // Else, get the corresponding model for the type value if there's any.
	        return this.getTypeModel(record[this.typeKey]);
	    };
	    /**
	     * Get a model from the container.
	     */
	    Model.relation = function (model) {
	        if (typeof model !== 'string') {
	            return model;
	        }
	        return this.database().model(model);
	    };
	    /**
	     * Get the attribute class for the given attribute name.
	     */
	    Model.getAttributeClass = function (name) {
	        switch (name) {
	            case 'increment': return Increment;
	            default:
	                throw Error("The attribute name \"" + name + "\" doesn't exist.");
	        }
	    };
	    /**
	     * Get all of the fields that matches the given attribute name.
	     */
	    Model.getFieldsByAttribute = function (name) {
	        var attr = this.getAttributeClass(name);
	        var fields = this.getFields();
	        return Object.keys(fields).reduce(function (newFields, key) {
	            var field = fields[key];
	            if (field instanceof attr) {
	                newFields[key] = field;
	            }
	            return newFields;
	        }, {});
	    };
	    /**
	     * Get all `increment` fields from the schema.
	     */
	    Model.getIncrementFields = function () {
	        return this.getFieldsByAttribute('increment');
	    };
	    /**
	     * Check if fields contains the `increment` field type.
	     */
	    Model.hasIncrementFields = function () {
	        return Object.keys(this.getIncrementFields()).length > 0;
	    };
	    /**
	     * Get all `belongsToMany` fields from the schema.
	     */
	    Model.pivotFields = function () {
	        var fields = [];
	        Utils.forOwn(this.getFields(), function (field, key) {
	            var _a;
	            if (field instanceof BelongsToMany || field instanceof MorphToMany || field instanceof MorphedByMany) {
	                fields.push((_a = {}, _a[key] = field, _a));
	            }
	        });
	        return fields;
	    };
	    /**
	     * Check if fields contains the `belongsToMany` field type.
	     */
	    Model.hasPivotFields = function () {
	        return this.pivotFields().length > 0;
	    };
	    /**
	     * Check if the current model has a type definition
	     */
	    Model.hasTypes = function () {
	        return Object.keys(this.types()).length > 0;
	    };
	    /**
	     * Get the model corresponding to the given type name. If it can't be found,
	     * it'll return `null`.
	     */
	    Model.getTypeModel = function (name) {
	        return this.types()[name] || null;
	    };
	    /**
	     * Given a Model, this returns the corresponding key in the InheritanceTypes mapping
	     */
	    Model.getTypeKeyValueFromModel = function (model) {
	        var modelToCheck = model || this;
	        var types = this.types();
	        for (var type in types) {
	            if (types[type] === modelToCheck) {
	                return type;
	            }
	        }
	        return null;
	    };
	    /**
	     * Tries to find a Relation field in all types defined in the InheritanceTypes mapping
	     */
	    Model.findRelationInSubTypes = function (relationName) {
	        var types = this.types();
	        for (var type in types) {
	            var fields = types[type].getFields();
	            for (var fieldName in fields) {
	                if (fieldName === relationName && fields[fieldName] instanceof Relation) {
	                    return fields[fieldName];
	                }
	            }
	        }
	        return null;
	    };
	    /**
	     * Fill any missing fields in the given record with the default value defined
	     * in the model schema.
	     */
	    Model.hydrate = function (record) {
	        return (new this(record)).$toJson();
	    };
	    /**
	     * Get the constructor of this model.
	     */
	    Model.prototype.$self = function () {
	        return this.constructor;
	    };
	    /**
	     * Get the primary key for the model.
	     */
	    Model.prototype.$primaryKey = function () {
	        return this.$self().primaryKey;
	    };
	    /**
	     * The definition of the fields of the model and its relations.
	     */
	    Model.prototype.$fields = function () {
	        return this.$self().getFields();
	    };
	    /**
	     * Get the store instance from the container.
	     */
	    Model.prototype.$store = function () {
	        return this.$self().store();
	    };
	    /**
	     * Create a namespaced method name for Vuex Module from the given
	     * method name.
	     */
	    Model.prototype.$namespace = function (method) {
	        return this.$self().namespace(method);
	    };
	    /**
	     * Call Vuex Getetrs.
	     */
	    Model.prototype.$getters = function (method) {
	        return this.$self().getters(method);
	    };
	    /**
	     * Dispatch Vuex Action.
	     */
	    Model.prototype.$dispatch = function (method, payload) {
	        return __awaiter(this, void 0, void 0, function () {
	            return __generator(this, function (_a) {
	                return [2 /*return*/, this.$self().dispatch(method, payload)];
	            });
	        });
	    };
	    /**
	     * Get all records.
	     */
	    Model.prototype.$all = function () {
	        return this.$getters('all')();
	    };
	    /**
	     * Find a record.
	     */
	    Model.prototype.$find = function (id) {
	        return this.$getters('find')(id);
	    };
	    /**
	     * Find record of the given array of ids.
	     */
	    Model.prototype.$findIn = function (idList) {
	        return this.$getters('findIn')(idList);
	    };
	    /**
	     * Get query instance.
	     */
	    Model.prototype.$query = function () {
	        return this.$getters('query')();
	    };
	    /**
	     * Create records.
	     */
	    Model.prototype.$create = function (payload) {
	        return __awaiter(this, void 0, void 0, function () {
	            return __generator(this, function (_a) {
	                return [2 /*return*/, this.$dispatch('create', payload)];
	            });
	        });
	    };
	    /**
	     * Create records.
	     */
	    Model.prototype.$insert = function (payload) {
	        return __awaiter(this, void 0, void 0, function () {
	            return __generator(this, function (_a) {
	                return [2 /*return*/, this.$dispatch('insert', payload)];
	            });
	        });
	    };
	    /**
	     * Update records.
	     */
	    Model.prototype.$update = function (payload) {
	        return __awaiter(this, void 0, void 0, function () {
	            return __generator(this, function (_a) {
	                if (Array.isArray(payload)) {
	                    return [2 /*return*/, this.$dispatch('update', payload)];
	                }
	                if (payload.where !== undefined) {
	                    return [2 /*return*/, this.$dispatch('update', payload)];
	                }
	                if (this.$self().getIndexIdFromRecord(payload) === null) {
	                    return [2 /*return*/, this.$dispatch('update', { where: this.$id, data: payload })];
	                }
	                return [2 /*return*/, this.$dispatch('update', payload)];
	            });
	        });
	    };
	    /**
	     * Insert or update records.
	     */
	    Model.prototype.$insertOrUpdate = function (payload) {
	        return __awaiter(this, void 0, void 0, function () {
	            return __generator(this, function (_a) {
	                return [2 /*return*/, this.$dispatch('insertOrUpdate', payload)];
	            });
	        });
	    };
	    /**
	     * Save record.
	     */
	    Model.prototype.$save = function () {
	        return __awaiter(this, void 0, void 0, function () {
	            var fields, record, records;
	            var _this = this;
	            return __generator(this, function (_a) {
	                switch (_a.label) {
	                    case 0:
	                        fields = this.$self().getFields();
	                        record = Object.keys(fields).reduce(function (record, key) {
	                            if (fields[key] instanceof Type) {
	                                record[key] = _this[key];
	                            }
	                            return record;
	                        }, {});
	                        return [4 /*yield*/, this.$dispatch('insertOrUpdate', { data: record })];
	                    case 1:
	                        records = _a.sent();
	                        this.$fill(records[this.$self().entity][0]);
	                        return [2 /*return*/, this];
	                }
	            });
	        });
	    };
	    /**
	     * Delete records that matches the given condition.
	     */
	    Model.prototype.$delete = function () {
	        return __awaiter(this, void 0, void 0, function () {
	            var primaryKey;
	            var _this = this;
	            return __generator(this, function (_a) {
	                primaryKey = this.$primaryKey();
	                if (!Array.isArray(primaryKey)) {
	                    return [2 /*return*/, this.$dispatch('delete', this[primaryKey])];
	                }
	                return [2 /*return*/, this.$dispatch('delete', function (model) {
	                        return primaryKey.every(function (id) { return model[id] === _this[id]; });
	                    })];
	            });
	        });
	    };
	    /**
	     * Delete all records.
	     */
	    Model.prototype.$deleteAll = function () {
	        return __awaiter(this, void 0, void 0, function () {
	            return __generator(this, function (_a) {
	                return [2 /*return*/, this.$dispatch('deleteAll')];
	            });
	        });
	    };
	    /**
	     * Fill the model instance with the given record. If no record were passed,
	     * or if the record has any missing fields, each value of the fields will
	     * be filled with its default value defined at model fields definition.
	     */
	    Model.prototype.$fill = function (record) {
	        var _this = this;
	        var data = record || {};
	        var fields = this.$fields();
	        Object.keys(fields).forEach(function (key) {
	            var field = fields[key];
	            var value = data[key];
	            _this[key] = field.make(value, data, key);
	        });
	        if (data.$id !== undefined) {
	            this.$id = data.$id;
	        }
	    };
	    /**
	     * Serialize field values into json.
	     */
	    Model.prototype.$toJson = function () {
	        return Serializer.serialize(this);
	    };
	    /**
	     * This method is used by Nuxt server-side rendering. It will prevent
	     * `non-POJO` warning when using Vuex ORM with Nuxt universal mode.
	     * The method is not meant to be used publicly by a user.
	     *
	     * See https://github.com/vuex-orm/vuex-orm/issues/255 for more detail.
	     */
	    Model.prototype.toJSON = function () {
	        var _this = this;
	        return Object.keys(this).reduce(function (json, key) {
	            var value = _this[key];
	            if (value instanceof Model) {
	                json[key] = value.toJSON();
	                return json;
	            }
	            if (Array.isArray(value)) {
	                json[key] = value.map(function (v) { return v instanceof Model ? v.toJSON() : v; });
	                return json;
	            }
	            json[key] = value;
	            return json;
	        }, {});
	    };
	    /**
	     * The primary key to be used for the model.
	     */
	    Model.primaryKey = 'id';
	    /**
	     * The discriminator key to be used for the model when inheritance is used
	     */
	    Model.typeKey = 'type';
	    /**
	     * Vuex Store state definition.
	     */
	    Model.state = {};
	    return Model;
	}());

	function _defineProperties(target, props) {
	  for (var i = 0; i < props.length; i++) {
	    var descriptor = props[i];
	    descriptor.enumerable = descriptor.enumerable || false;
	    descriptor.configurable = true;
	    if ("value" in descriptor) descriptor.writable = true;
	    Object.defineProperty(target, descriptor.key, descriptor);
	  }
	}

	function _createClass(Constructor, protoProps, staticProps) {
	  if (protoProps) _defineProperties(Constructor.prototype, protoProps);
	  if (staticProps) _defineProperties(Constructor, staticProps);
	  return Constructor;
	}

	function _defineProperty(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;
	}

	function _objectSpread(target) {
	  for (var i = 1; i < arguments.length; i++) {
	    var source = arguments[i] != null ? arguments[i] : {};
	    var ownKeys = Object.keys(source);

	    if (typeof Object.getOwnPropertySymbols === 'function') {
	      ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
	        return Object.getOwnPropertyDescriptor(source, sym).enumerable;
	      }));
	    }

	    ownKeys.forEach(function (key) {
	      _defineProperty(target, key, source[key]);
	    });
	  }

	  return target;
	}

	function _inheritsLoose(subClass, superClass) {
	  subClass.prototype = Object.create(superClass.prototype);
	  subClass.prototype.constructor = subClass;
	  subClass.__proto__ = superClass;
	}

	/**
	 * Helpers to enable Immutable compatibility *without* bringing in
	 * the 'immutable' package as a dependency.
	 */

	/**
	 * Check if an object is immutable by checking if it has a key specific
	 * to the immutable library.
	 *
	 * @param  {any} object
	 * @return {bool}
	 */
	function isImmutable(object) {
	  return !!(object && typeof object.hasOwnProperty === 'function' && (object.hasOwnProperty('__ownerID') || // Immutable.Map
	  object._map && object._map.hasOwnProperty('__ownerID'))); // Immutable.Record
	}
	/**
	 * Denormalize an immutable entity.
	 *
	 * @param  {Schema} schema
	 * @param  {Immutable.Map|Immutable.Record} input
	 * @param  {function} unvisit
	 * @param  {function} getDenormalizedEntity
	 * @return {Immutable.Map|Immutable.Record}
	 */

	function denormalizeImmutable(schema, input, unvisit) {
	  return Object.keys(schema).reduce(function (object, key) {
	    // Immutable maps cast keys to strings on write so we need to ensure
	    // we're accessing them using string keys.
	    var stringKey = "" + key;

	    if (object.has(stringKey)) {
	      return object.set(stringKey, unvisit(object.get(stringKey), schema[stringKey]));
	    } else {
	      return object;
	    }
	  }, input);
	}

	var getDefaultGetId = function getDefaultGetId(idAttribute) {
	  return function (input) {
	    return isImmutable(input) ? input.get(idAttribute) : input[idAttribute];
	  };
	};

	var EntitySchema =
	/*#__PURE__*/
	function () {
	  function EntitySchema(key, definition, options) {
	    if (definition === void 0) {
	      definition = {};
	    }

	    if (options === void 0) {
	      options = {};
	    }

	    if (!key || typeof key !== 'string') {
	      throw new Error("Expected a string key for Entity, but found " + key + ".");
	    }

	    var _options = options,
	        _options$idAttribute = _options.idAttribute,
	        idAttribute = _options$idAttribute === void 0 ? 'id' : _options$idAttribute,
	        _options$mergeStrateg = _options.mergeStrategy,
	        mergeStrategy = _options$mergeStrateg === void 0 ? function (entityA, entityB) {
	      return _objectSpread({}, entityA, entityB);
	    } : _options$mergeStrateg,
	        _options$processStrat = _options.processStrategy,
	        processStrategy = _options$processStrat === void 0 ? function (input) {
	      return _objectSpread({}, input);
	    } : _options$processStrat;
	    this._key = key;
	    this._getId = typeof idAttribute === 'function' ? idAttribute : getDefaultGetId(idAttribute);
	    this._idAttribute = idAttribute;
	    this._mergeStrategy = mergeStrategy;
	    this._processStrategy = processStrategy;
	    this.define(definition);
	  }

	  var _proto = EntitySchema.prototype;

	  _proto.define = function define(definition) {
	    this.schema = Object.keys(definition).reduce(function (entitySchema, key) {
	      var _objectSpread2;

	      var schema = definition[key];
	      return _objectSpread({}, entitySchema, (_objectSpread2 = {}, _objectSpread2[key] = schema, _objectSpread2));
	    }, this.schema || {});
	  };

	  _proto.getId = function getId(input, parent, key) {
	    return this._getId(input, parent, key);
	  };

	  _proto.merge = function merge(entityA, entityB) {
	    return this._mergeStrategy(entityA, entityB);
	  };

	  _proto.normalize = function normalize(input, parent, key, visit, addEntity, visitedEntities) {
	    var _this = this;

	    if (visitedEntities.some(function (entity) {
	      return entity === input;
	    })) {
	      return this.getId(input, parent, key);
	    }

	    visitedEntities.push(input);

	    var processedEntity = this._processStrategy(input, parent, key);

	    Object.keys(this.schema).forEach(function (key) {
	      if (processedEntity.hasOwnProperty(key) && typeof processedEntity[key] === 'object') {
	        var schema = _this.schema[key];
	        processedEntity[key] = visit(processedEntity[key], processedEntity, key, schema, addEntity, visitedEntities);
	      }
	    });
	    addEntity(this, processedEntity, input, parent, key);
	    return this.getId(input, parent, key);
	  };

	  _proto.denormalize = function denormalize(entity, unvisit) {
	    var _this2 = this;

	    if (isImmutable(entity)) {
	      return denormalizeImmutable(this.schema, entity, unvisit);
	    }

	    Object.keys(this.schema).forEach(function (key) {
	      if (entity.hasOwnProperty(key)) {
	        var schema = _this2.schema[key];
	        entity[key] = unvisit(entity[key], schema);
	      }
	    });
	    return entity;
	  };

	  _createClass(EntitySchema, [{
	    key: "key",
	    get: function get() {
	      return this._key;
	    }
	  }, {
	    key: "idAttribute",
	    get: function get() {
	      return this._idAttribute;
	    }
	  }]);

	  return EntitySchema;
	}();

	var PolymorphicSchema =
	/*#__PURE__*/
	function () {
	  function PolymorphicSchema(definition, schemaAttribute) {
	    if (schemaAttribute) {
	      this._schemaAttribute = typeof schemaAttribute === 'string' ? function (input) {
	        return input[schemaAttribute];
	      } : schemaAttribute;
	    }

	    this.define(definition);
	  }

	  var _proto = PolymorphicSchema.prototype;

	  _proto.define = function define(definition) {
	    this.schema = definition;
	  };

	  _proto.getSchemaAttribute = function getSchemaAttribute(input, parent, key) {
	    return !this.isSingleSchema && this._schemaAttribute(input, parent, key);
	  };

	  _proto.inferSchema = function inferSchema(input, parent, key) {
	    if (this.isSingleSchema) {
	      return this.schema;
	    }

	    var attr = this.getSchemaAttribute(input, parent, key);
	    return this.schema[attr];
	  };

	  _proto.normalizeValue = function normalizeValue(value, parent, key, visit, addEntity, visitedEntities) {
	    var schema = this.inferSchema(value, parent, key);

	    if (!schema) {
	      return value;
	    }

	    var normalizedValue = visit(value, parent, key, schema, addEntity, visitedEntities);
	    return this.isSingleSchema || normalizedValue === undefined || normalizedValue === null ? normalizedValue : {
	      id: normalizedValue,
	      schema: this.getSchemaAttribute(value, parent, key)
	    };
	  };

	  _proto.denormalizeValue = function denormalizeValue(value, unvisit) {
	    var schemaKey = isImmutable(value) ? value.get('schema') : value.schema;

	    if (!this.isSingleSchema && !schemaKey) {
	      return value;
	    }

	    var id = isImmutable(value) ? value.get('id') : value.id;
	    var schema = this.isSingleSchema ? this.schema : this.schema[schemaKey];
	    return unvisit(id || value, schema);
	  };

	  _createClass(PolymorphicSchema, [{
	    key: "isSingleSchema",
	    get: function get() {
	      return !this._schemaAttribute;
	    }
	  }]);

	  return PolymorphicSchema;
	}();

	var UnionSchema =
	/*#__PURE__*/
	function (_PolymorphicSchema) {
	  _inheritsLoose(UnionSchema, _PolymorphicSchema);

	  function UnionSchema(definition, schemaAttribute) {
	    if (!schemaAttribute) {
	      throw new Error('Expected option "schemaAttribute" not found on UnionSchema.');
	    }

	    return _PolymorphicSchema.call(this, definition, schemaAttribute) || this;
	  }

	  var _proto = UnionSchema.prototype;

	  _proto.normalize = function normalize(input, parent, key, visit, addEntity, visitedEntities) {
	    return this.normalizeValue(input, parent, key, visit, addEntity, visitedEntities);
	  };

	  _proto.denormalize = function denormalize(input, unvisit) {
	    return this.denormalizeValue(input, unvisit);
	  };

	  return UnionSchema;
	}(PolymorphicSchema);

	var ValuesSchema =
	/*#__PURE__*/
	function (_PolymorphicSchema) {
	  _inheritsLoose(ValuesSchema, _PolymorphicSchema);

	  function ValuesSchema() {
	    return _PolymorphicSchema.apply(this, arguments) || this;
	  }

	  var _proto = ValuesSchema.prototype;

	  _proto.normalize = function normalize(input, parent, key, visit, addEntity, visitedEntities) {
	    var _this = this;

	    return Object.keys(input).reduce(function (output, key, index) {
	      var _objectSpread2;

	      var value = input[key];
	      return value !== undefined && value !== null ? _objectSpread({}, output, (_objectSpread2 = {}, _objectSpread2[key] = _this.normalizeValue(value, input, key, visit, addEntity, visitedEntities), _objectSpread2)) : output;
	    }, {});
	  };

	  _proto.denormalize = function denormalize(input, unvisit) {
	    var _this2 = this;

	    return Object.keys(input).reduce(function (output, key) {
	      var _objectSpread3;

	      var entityOrId = input[key];
	      return _objectSpread({}, output, (_objectSpread3 = {}, _objectSpread3[key] = _this2.denormalizeValue(entityOrId, unvisit), _objectSpread3));
	    }, {});
	  };

	  return ValuesSchema;
	}(PolymorphicSchema);

	var validateSchema = function validateSchema(definition) {
	  var isArray = Array.isArray(definition);

	  if (isArray && definition.length > 1) {
	    throw new Error("Expected schema definition to be a single schema, but found " + definition.length + ".");
	  }

	  return definition[0];
	};

	var getValues = function getValues(input) {
	  return Array.isArray(input) ? input : Object.keys(input).map(function (key) {
	    return input[key];
	  });
	};

	var normalize = function normalize(schema, input, parent, key, visit, addEntity, visitedEntities) {
	  schema = validateSchema(schema);
	  var values = getValues(input); // Special case: Arrays pass *their* parent on to their children, since there
	  // is not any special information that can be gathered from themselves directly

	  return values.map(function (value, index) {
	    return visit(value, parent, key, schema, addEntity, visitedEntities);
	  });
	};

	var ArraySchema =
	/*#__PURE__*/
	function (_PolymorphicSchema) {
	  _inheritsLoose(ArraySchema, _PolymorphicSchema);

	  function ArraySchema() {
	    return _PolymorphicSchema.apply(this, arguments) || this;
	  }

	  var _proto = ArraySchema.prototype;

	  _proto.normalize = function normalize(input, parent, key, visit, addEntity, visitedEntities) {
	    var _this = this;

	    var values = getValues(input);
	    return values.map(function (value, index) {
	      return _this.normalizeValue(value, parent, key, visit, addEntity, visitedEntities);
	    }).filter(function (value) {
	      return value !== undefined && value !== null;
	    });
	  };

	  _proto.denormalize = function denormalize(input, unvisit) {
	    var _this2 = this;

	    return input && input.map ? input.map(function (value) {
	      return _this2.denormalizeValue(value, unvisit);
	    }) : input;
	  };

	  return ArraySchema;
	}(PolymorphicSchema);

	var _normalize = function normalize(schema, input, parent, key, visit, addEntity, visitedEntities) {
	  var object = _objectSpread({}, input);

	  Object.keys(schema).forEach(function (key) {
	    var localSchema = schema[key];
	    var value = visit(input[key], input, key, localSchema, addEntity, visitedEntities);

	    if (value === undefined || value === null) {
	      delete object[key];
	    } else {
	      object[key] = value;
	    }
	  });
	  return object;
	};

	var _denormalize = function denormalize(schema, input, unvisit) {
	  if (isImmutable(input)) {
	    return denormalizeImmutable(schema, input, unvisit);
	  }

	  var object = _objectSpread({}, input);

	  Object.keys(schema).forEach(function (key) {
	    if (object[key] != null) {
	      object[key] = unvisit(object[key], schema[key]);
	    }
	  });
	  return object;
	};

	var ObjectSchema =
	/*#__PURE__*/
	function () {
	  function ObjectSchema(definition) {
	    this.define(definition);
	  }

	  var _proto = ObjectSchema.prototype;

	  _proto.define = function define(definition) {
	    this.schema = Object.keys(definition).reduce(function (entitySchema, key) {
	      var _objectSpread2;

	      var schema = definition[key];
	      return _objectSpread({}, entitySchema, (_objectSpread2 = {}, _objectSpread2[key] = schema, _objectSpread2));
	    }, this.schema || {});
	  };

	  _proto.normalize = function normalize() {
	    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
	      args[_key] = arguments[_key];
	    }

	    return _normalize.apply(void 0, [this.schema].concat(args));
	  };

	  _proto.denormalize = function denormalize() {
	    for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
	      args[_key2] = arguments[_key2];
	    }

	    return _denormalize.apply(void 0, [this.schema].concat(args));
	  };

	  return ObjectSchema;
	}();

	var visit = function visit(value, parent, key, schema, addEntity, visitedEntities) {
	  if (typeof value !== 'object' || !value) {
	    return value;
	  }

	  if (typeof schema === 'object' && (!schema.normalize || typeof schema.normalize !== 'function')) {
	    var method = Array.isArray(schema) ? normalize : _normalize;
	    return method(schema, value, parent, key, visit, addEntity, visitedEntities);
	  }

	  return schema.normalize(value, parent, key, visit, addEntity, visitedEntities);
	};

	var addEntities = function addEntities(entities) {
	  return function (schema, processedEntity, value, parent, key) {
	    var schemaKey = schema.key;
	    var id = schema.getId(value, parent, key);

	    if (!(schemaKey in entities)) {
	      entities[schemaKey] = {};
	    }

	    var existingEntity = entities[schemaKey][id];

	    if (existingEntity) {
	      entities[schemaKey][id] = schema.merge(existingEntity, processedEntity);
	    } else {
	      entities[schemaKey][id] = processedEntity;
	    }
	  };
	};

	var schema = {
	  Array: ArraySchema,
	  Entity: EntitySchema,
	  Object: ObjectSchema,
	  Union: UnionSchema,
	  Values: ValuesSchema
	};
	var normalize$1 = function normalize(input, schema) {
	  if (!input || typeof input !== 'object') {
	    throw new Error("Unexpected input given to normalize. Expected type to be \"object\", found \"" + typeof input + "\".");
	  }

	  var entities = {};
	  var addEntity = addEntities(entities);
	  var visitedEntities = [];
	  var result = visit(input, input, null, schema, addEntity, visitedEntities);
	  return {
	    entities: entities,
	    result: result
	  };
	};

	var Normalizer = /** @class */ (function () {
	    function Normalizer() {
	    }
	    /**
	     * Normalize the data given data.
	     */
	    Normalizer.process = function (query, record) {
	        if (Utils.isEmpty(record)) {
	            return {};
	        }
	        var entity = query.database().schemas[query.model.entity];
	        var schema = Array.isArray(record) ? [entity] : entity;
	        return normalize$1(record, schema).entities;
	    };
	    return Normalizer;
	}());

	var PivotCreator = /** @class */ (function () {
	    function PivotCreator() {
	    }
	    /**
	     * Create an intermediate entity if the data contains any entities that
	     * require it for example `belongsTo` or `morphMany`.
	     */
	    PivotCreator.process = function (query, data) {
	        Object.keys(data).forEach(function (entity) {
	            var model = query.getModel(entity);
	            if (model.hasPivotFields()) {
	                Utils.forOwn(model.pivotFields(), function (field) {
	                    Utils.forOwn(field, function (attr, key) { attr.createPivots(model, data, key); });
	                });
	            }
	        });
	        return data;
	    };
	    return PivotCreator;
	}());

	var Incrementer = /** @class */ (function () {
	    function Incrementer() {
	    }
	    /**
	     * Increment all fields that have increment attribute.
	     */
	    Incrementer.process = function (query, data) {
	        var _this = this;
	        return Utils.mapValues(data, function (records, entity) {
	            var newQuery = query.newQuery(entity);
	            // If the entity doesn't have increment attribute, do nothing and
	            // just return immediately.
	            if (!newQuery.model.hasIncrementFields()) {
	                return records;
	            }
	            _this.processRecordsByFields(records, newQuery);
	            return records;
	        });
	    };
	    /**
	     * Process all of the increment fields.
	     */
	    Incrementer.processRecordsByFields = function (records, query) {
	        var _this = this;
	        var fields = query.model.getIncrementFields();
	        Utils.forOwn(fields, function (_attr, key) {
	            _this.processRecords(records, query, key);
	        });
	    };
	    /**
	     * Process all records and increment all field that is defined as increment.
	     */
	    Incrementer.processRecords = function (records, query, key) {
	        var max = this.max(records, query, key);
	        Utils.forOwn(records, function (record) {
	            if (typeof record[key] !== 'number') {
	                record[key] = ++max;
	            }
	        });
	    };
	    /**
	     * Get the max value of the specified field with given data combined
	     * with existing records.
	     */
	    Incrementer.max = function (records, query, field) {
	        var maxInState = query.max(field);
	        var maxInRecord = Math.max.apply(Math, Object.keys(records).map(function (key) {
	            var record = records[key];
	            var id = record[field];
	            return typeof id === 'number' ? id : 0;
	        }));
	        return Math.max(maxInRecord, maxInState);
	    };
	    return Incrementer;
	}());

	var Attacher = /** @class */ (function () {
	    function Attacher() {
	    }
	    /**
	     * Attach missing relational key to the records.
	     */
	    Attacher.process = function (query, data) {
	        Utils.forOwn(data, function (entity, name) {
	            var fields = query.getModel(name).fields();
	            Utils.forOwn(entity, function (record) {
	                Utils.forOwn(record, function (value, key) {
	                    var field = fields[key];
	                    if (field instanceof Relation) {
	                        value !== null && field.attach(value, record, data);
	                    }
	                });
	            });
	        });
	        return data;
	    };
	    return Attacher;
	}());

	var IdFixer = /** @class */ (function () {
	    function IdFixer() {
	    }
	    /**
	     * Fix all of the "no key" records with appropriate id value if it can.
	     */
	    IdFixer.process = function (query, data) {
	        var _this = this;
	        return Utils.mapValues(data, function (records, entity) {
	            var newQuery = query.newQuery(entity);
	            return _this.processRecords(records, newQuery);
	        });
	    };
	    /**
	     * Process records to Fix all of the "no key" records with
	     * appropriate id value if it can.
	     */
	    IdFixer.processRecords = function (records, query) {
	        return Object.keys(records).reduce(function (newRecords, id) {
	            var record = records[id];
	            var newId = query.model.getIndexIdFromRecord(record);
	            var newStringId = String(newId);
	            if (newId === null || id === newStringId) {
	                newRecords[id] = record;
	                return newRecords;
	            }
	            newRecords[newStringId] = __assign(__assign({}, record), { $id: newId });
	            return newRecords;
	        }, {});
	    };
	    return IdFixer;
	}());

	var Processor = /** @class */ (function () {
	    function Processor() {
	    }
	    /**
	     * Normalize the given data.
	     */
	    Processor.normalize = function (query, record) {
	        // First, let's normalize the data.
	        var data = Normalizer.process(query, record);
	        // Next, increment any field that defined with `increment` attribute.
	        data = Incrementer.process(query, data);
	        // Then, attach any missing foreign keys. For example, if a User has many
	        // Post nested but without foreign key such as `user_id`, we can attach
	        // the `user_id` value to the Post entities.
	        data = Attacher.process(query, data);
	        // Now we'll create any missing pivot entities for relationships such as
	        // `belongsTo` or `morphMany`.
	        data = PivotCreator.process(query, data);
	        // There might be new pivot entities now which weren't there before, and
	        // it might contain increment field so we must increment those filed
	        // again here.
	        //
	        // Improvements: This double incrementing process can be improved. Since
	        // currently, we're looping whole records twice. If we could remember the
	        // entities which were already incremented at an earlier stage, we could
	        // only process the newly created entities.
	        data = Incrementer.process(query, data);
	        // Finally, let's fix key id for the entities since the id value might
	        // have changed due to the incrementing process.
	        data = IdFixer.process(query, data);
	        // And we'll return the result as a normalized data.
	        return data;
	    };
	    return Processor;
	}());

	var WhereFilter = /** @class */ (function () {
	    function WhereFilter() {
	    }
	    /**
	     * Filter the given data by registered where clause.
	     */
	    WhereFilter.filter = function (query, records) {
	        var _this = this;
	        if (query.wheres.length === 0) {
	            return records;
	        }
	        return records.filter(function (record) { return _this.check(query, record); });
	    };
	    /**
	     * Checks if given Record matches the registered where clause.
	     */
	    WhereFilter.check = function (query, record) {
	        var whereTypes = Utils.groupBy(query.wheres, function (where) { return where.boolean; });
	        var comparator = this.getComparator(query, record);
	        var results = [];
	        whereTypes.and && results.push(whereTypes.and.every(comparator));
	        whereTypes.or && results.push(whereTypes.or.some(comparator));
	        return results.indexOf(true) !== -1;
	    };
	    /**
	     * Get comparator for the where clause.
	     */
	    WhereFilter.getComparator = function (query, record) {
	        var _this = this;
	        return function (where) {
	            // Function with Record and Query as argument.
	            if (typeof where.field === 'function') {
	                var newQuery = new Query(query.rootState, query.entity);
	                var result = _this.executeWhereClosure(newQuery, record, where.field);
	                if (typeof result === 'boolean') {
	                    return result;
	                }
	                // If closure returns undefined, we need to execute the local query.
	                var matchingRecords = newQuery.get();
	                // And check if current record is part of the result.
	                return !Utils.isEmpty(matchingRecords.filter(function (rec) {
	                    return rec['$id'] === record['$id'];
	                }));
	            }
	            // Function with Record value as argument.
	            if (typeof where.value === 'function') {
	                return where.value(record[where.field]);
	            }
	            // Check if field value is in given where Array.
	            if (Array.isArray(where.value)) {
	                return where.value.indexOf(record[where.field]) !== -1;
	            }
	            // Simple equal check.
	            return record[where.field] === where.value;
	        };
	    };
	    /**
	     * Execute where closure.
	     */
	    WhereFilter.executeWhereClosure = function (query, record, closure) {
	        if (closure.length !== 3) {
	            return closure(record, query);
	        }
	        var model = new query.model(record);
	        return closure(record, query, model);
	    };
	    return WhereFilter;
	}());

	var OrderByFilter = /** @class */ (function () {
	    function OrderByFilter() {
	    }
	    /**
	     * Sort the given data by registered orders.
	     */
	    OrderByFilter.filter = function (query, records) {
	        if (query.orders.length === 0) {
	            return records;
	        }
	        var keys = query.orders.map(function (order) { return order.field; });
	        var directions = query.orders.map(function (order) { return order.direction; });
	        return Utils.orderBy(records, keys, directions);
	    };
	    return OrderByFilter;
	}());

	var LimitFilter = /** @class */ (function () {
	    function LimitFilter() {
	    }
	    /**
	     * Limit the given records by the lmilt and offset.
	     */
	    LimitFilter.filter = function (query, records) {
	        return records.slice(query.offsetNumber, query.offsetNumber + query.limitNumber);
	    };
	    return LimitFilter;
	}());

	var Filter = /** @class */ (function () {
	    function Filter() {
	    }
	    /**
	     * Filter the given data by registered where clause.
	     */
	    Filter.where = function (query, records) {
	        return WhereFilter.filter(query, records);
	    };
	    /**
	     * Sort the given data by registered orders.
	     */
	    Filter.orderBy = function (query, records) {
	        return OrderByFilter.filter(query, records);
	    };
	    /**
	     * Limit the given records by the lmilt and offset.
	     */
	    Filter.limit = function (query, records) {
	        return LimitFilter.filter(query, records);
	    };
	    return Filter;
	}());

	var Loader = /** @class */ (function () {
	    function Loader() {
	    }
	    /**
	     * Set the relationships that should be eager loaded with the query.
	     */
	    Loader.with = function (query, name, constraint) {
	        var _this = this;
	        // If the name of the relation is `*`, we'll load all relationships.
	        if (name === '*') {
	            this.withAll(query);
	            return;
	        }
	        // If we passed an array, we dispatch the bits to with queries
	        if (name instanceof Array) {
	            name.forEach(function (relationName) { return _this.with(query, relationName, constraint); });
	        }
	        else {
	            // Else parse relations and set appropriate constraints.
	            this.parseWithRelations(query, name.split('.'), constraint);
	        }
	    };
	    /**
	     * Set all relationships to be eager loaded with the query.
	     */
	    Loader.withAll = function (query, constraint) {
	        if (constraint === void 0) { constraint = function () { return null; }; }
	        var fields = query.model.getFields();
	        for (var field in fields) {
	            fields[field] instanceof Relation && this.with(query, field, constraint);
	        }
	    };
	    /**
	     * Set relationships to be recursively eager loaded with the query.
	     */
	    Loader.withAllRecursive = function (query, depth) {
	        this.withAll(query, function (relatedQuery) {
	            depth > 0 && relatedQuery.withAllRecursive(depth - 1);
	        });
	    };
	    /**
	     * Set eager load relation and constraint.
	     */
	    Loader.setEagerLoad = function (query, name, constraint) {
	        if (constraint === void 0) { constraint = null; }
	        if (!query.load[name]) {
	            query.load[name] = [];
	        }
	        constraint && query.load[name].push(constraint);
	    };
	    /**
	     * Parse a list of relations into individuals.
	     */
	    Loader.parseWithRelations = function (query, relations, constraint) {
	        var _this = this;
	        // First we'll get the very first relationship from teh whole relations.
	        var relation = relations[0];
	        // If the first relation has "or" syntax which is `|` for example
	        // `posts|videos`, set each of them as separate eager load.
	        relation.split('|').forEach(function (name) {
	            // If there's only one relationship in relations array, that means
	            // there's no nested relationship. So we'll set the given
	            // constraint to the relationship loading.
	            if (relations.length === 1) {
	                _this.setEagerLoad(query, name, constraint);
	                return;
	            }
	            // Else we'll skip adding constraint because the constraint has to be
	            // applied to the nested relationship. We'll let `addNestedWiths`
	            // method to handle that later.
	            _this.setEagerLoad(query, name);
	        });
	        // If the given relations only contains a single name, which means it
	        // doesn't have any nested relations such as `posts.comments`, we
	        // don't need go farther so return here.
	        if (relations.length === 1) {
	            return;
	        }
	        // Finally, we shift the first relation from the array and handle lest
	        // of relations as a nested relation.
	        relations.shift();
	        this.addNestedWiths(query, relation, relations, constraint);
	    };
	    /**
	     * Parse the nested relationships in a relation.
	     */
	    Loader.addNestedWiths = function (query, name, children, constraint) {
	        this.setEagerLoad(query, name, function (nestedQuery) {
	            nestedQuery.with(children.join('.'), constraint);
	        });
	    };
	    /**
	     * Eager load the relationships for the given collection.
	     */
	    Loader.eagerLoadRelations = function (query, collection) {
	        var fields = query.model.getFields();
	        for (var name_1 in query.load) {
	            var constraints = query.load[name_1];
	            var relation = fields[name_1];
	            if (relation instanceof Relation) {
	                relation.load(query, collection, name_1, constraints);
	                continue;
	            }
	            // If no relation was found on the query, it might be run on the
	            // base entity of a hierarchy. In this case, we try looking up
	            // the relation on the derived entities
	            if (query.model.hasTypes()) {
	                var candidateRelation = query.model.findRelationInSubTypes(name_1);
	                if (candidateRelation !== null) {
	                    candidateRelation.load(query, collection, name_1, constraints);
	                }
	            }
	        }
	    };
	    return Loader;
	}());

	var Rollcaller = /** @class */ (function () {
	    function Rollcaller() {
	    }
	    /**
	     * Set where constraint based on relationship existence.
	     */
	    Rollcaller.has = function (query, relation, operator, count) {
	        this.setHas(query, relation, 'exists', operator, count);
	    };
	    /**
	     * Set where constraint based on relationship absence.
	     */
	    Rollcaller.hasNot = function (query, relation, operator, count) {
	        this.setHas(query, relation, 'doesntExist', operator, count);
	    };
	    /**
	     * Add where has condition.
	     */
	    Rollcaller.whereHas = function (query, relation, constraint) {
	        this.setHas(query, relation, 'exists', undefined, undefined, constraint);
	    };
	    /**
	     * Add where has not condition.
	     */
	    Rollcaller.whereHasNot = function (query, relation, constraint) {
	        this.setHas(query, relation, 'doesntExist', undefined, undefined, constraint);
	    };
	    /**
	     * Set `has` condition.
	     */
	    Rollcaller.setHas = function (query, relation, type, operator, count, constraint) {
	        if (operator === void 0) { operator = '>='; }
	        if (count === void 0) { count = 1; }
	        if (constraint === void 0) { constraint = null; }
	        if (typeof operator === 'number') {
	            query.have.push({ relation: relation, type: type, operator: '>=', count: operator, constraint: constraint });
	            return;
	        }
	        query.have.push({ relation: relation, type: type, operator: operator, count: count, constraint: constraint });
	    };
	    /**
	     * Convert `has` conditions to where clause. It will check any relationship
	     * existence, or absence for the records then set ids of the records that
	     * matched the condition to `where` clause.
	     *
	     * This way, when the query gets executed, only those records that matched
	     * the `has` condition get retrieved. In the future, once relationship index
	     * mapping is implemented, we can simply do all checks inside the where
	     * filter since we can treat `has` condition as usual `where` condition.
	     *
	     * For now, since we must fetch any relationship by eager loading them, due
	     * to performance concern, we'll apply `has` conditions this way to gain
	     * maximum performance.
	     */
	    Rollcaller.applyConstraints = function (query) {
	        if (query.have.length === 0) {
	            return;
	        }
	        var newQuery = query.newQuery();
	        this.addHasWhereConstraints(query, newQuery);
	        this.addHasConstraints(query, newQuery.get());
	    };
	    /**
	     * Add has constraints to the given query. It's going to set all relationship
	     * as `with` alongside with its closure constraints.
	     */
	    Rollcaller.addHasWhereConstraints = function (query, newQuery) {
	        query.have.forEach(function (constraint) {
	            newQuery.with(constraint.relation, constraint.constraint);
	        });
	    };
	    /**
	     * Add has constraints as where clause.
	     */
	    Rollcaller.addHasConstraints = function (query, collection) {
	        var comparators = this.getComparators(query);
	        var ids = [];
	        collection.forEach(function (model) {
	            if (comparators.every(function (comparator) { return comparator(model); })) {
	                ids.push(model.$id);
	            }
	        });
	        query.whereIdIn(ids);
	    };
	    /**
	     * Get comparators for the has clause.
	     */
	    Rollcaller.getComparators = function (query) {
	        var _this = this;
	        return query.have.map(function (constraint) { return _this.getComparator(constraint); });
	    };
	    /**
	     * Get a comparator for the has clause.
	     */
	    Rollcaller.getComparator = function (constraint) {
	        var _this = this;
	        var compare = this.getCountComparator(constraint.operator);
	        return function (model) {
	            var count = _this.getRelationshipCount(model[constraint.relation]);
	            var result = compare(count, constraint.count);
	            return constraint.type === 'exists' ? result : !result;
	        };
	    };
	    /**
	     * Get count of the relationship.
	     */
	    Rollcaller.getRelationshipCount = function (relation) {
	        if (Array.isArray(relation)) {
	            return relation.length;
	        }
	        return relation ? 1 : 0;
	    };
	    /**
	     * Get comparator function for the `has` clause.
	     */
	    Rollcaller.getCountComparator = function (operator) {
	        switch (operator) {
	            case '=':
	                return function (x, y) { return x === y; };
	            case '>':
	                return function (x, y) { return x > y; };
	            case '>=':
	                return function (x, y) { return x >= y; };
	            case '<':
	                return function (x, y) { return x > 0 && x < y; };
	            case '<=':
	                return function (x, y) { return x > 0 && x <= y; };
	            default:
	                return function (x, y) { return x === y; };
	        }
	    };
	    return Rollcaller;
	}());

	var Query = /** @class */ (function () {
	    /**
	     * Create a new Query instance.
	     */
	    function Query(state, entity) {
	        /**
	         * Primary key ids to filter records by. It is used for filtering records
	         * direct key lookup when a user is trying to fetch records by its
	         * primary key.
	         *
	         * It should not be used if there is a logic which prevents index usage, for
	         * example, an "or" condition which already requires a full scan of records.
	         */
	        this.idFilter = null;
	        /**
	         * Whether to use `idFilter` key lookup. True if there is a logic which
	         * prevents index usage, for example, an "or" condition which already
	         * requires full scan.
	         */
	        this.cancelIdFilter = false;
	        /**
	         * Primary key ids to filter joined records. It is used for filtering
	         * records direct key lookup. It should not be cancelled, because it
	         * is free from the effects of normal where methods.
	         */
	        this.joinedIdFilter = null;
	        /**
	         * The where constraints for the query.
	         */
	        this.wheres = [];
	        /**
	         * The has constraints for the query.
	         */
	        this.have = [];
	        /**
	         * The orders of the query result.
	         */
	        this.orders = [];
	        /**
	         * Number of results to skip.
	         */
	        this.offsetNumber = 0;
	        /**
	         * Maximum number of records to return.
	         *
	         * We use polyfill of `Number.MAX_SAFE_INTEGER` for IE11 here.
	         */
	        this.limitNumber = Math.pow(2, 53) - 1;
	        /**
	         * The relationships that should be eager loaded with the result.
	         */
	        this.load = {};
	        /**
	         * This flag lets us know if current Query instance applies to
	         * a base class or not (in order to know when to filter out some
	         * records)
	         */
	        this.appliedOnBase = true;
	        // All entitites with same base class are stored in the same state
	        var baseModel = this.getBase(entity);
	        this.state = state[baseModel.entity];
	        this.appliedOnBase = baseModel.entity === entity;
	        this.rootState = state;
	        this.entity = entity;
	        this.model = this.getModel(entity);
	        this.module = this.getModule(entity);
	    }
	    /**
	     * Get the database from the container.
	     */
	    Query.database = function () {
	        return Container.database;
	    };
	    /**
	     * Get model of given name from the container.
	     */
	    Query.getModel = function (name) {
	        return this.database().model(name);
	    };
	    /**
	     * Get base model of given name from the container.
	     */
	    Query.getBase = function (name) {
	        return this.database().baseModel(name);
	    };
	    /**
	     * Get all models from the container.
	     */
	    Query.getModels = function () {
	        return this.database().models();
	    };
	    /**
	     * Get module of given name from the container.
	     */
	    Query.getModule = function (name) {
	        return this.database().module(name);
	    };
	    /**
	     * Get all modules from the container.
	     */
	    Query.getModules = function () {
	        return this.database().modules();
	    };
	    /**
	     * Delete all records from the store.
	     */
	    Query.deleteAll = function (state) {
	        var _this = this;
	        var models = this.getModels();
	        Object.keys(models).forEach(function (name) {
	            state[name] && (new _this(state, name)).deleteAll();
	        });
	    };
	    /**
	     * Register a global hook. It will return ID for the hook that users may use
	     * it to unregister hooks.
	     */
	    Query.on = function (on, callback, once) {
	        if (once === void 0) { once = false; }
	        var id = ++this.lastHookId;
	        if (!this.hooks[on]) {
	            this.hooks[on] = [];
	        }
	        this.hooks[on].push({ id: id, callback: callback, once: once });
	        return id;
	    };
	    /**
	     * Unregister global hook with the given id.
	     */
	    Query.off = function (id) {
	        var _this = this;
	        return Object.keys(this.hooks).some(function (on) {
	            var hooks = _this.hooks[on];
	            var index = hooks.findIndex(function (h) { return h.id === id; });
	            if (index === -1) {
	                return false;
	            }
	            hooks.splice(index, 1);
	            return true;
	        });
	    };
	    /**
	     * Get query class.
	     */
	    Query.prototype.self = function () {
	        return this.constructor;
	    };
	    /**
	     * Create a new query instance.
	     */
	    Query.prototype.newQuery = function (entity) {
	        entity = entity || this.entity;
	        return (new Query(this.rootState, entity));
	    };
	    /**
	     * Get the database from the container.
	     */
	    Query.prototype.database = function () {
	        return this.self().database();
	    };
	    /**
	     * Get model of given name from the container.
	     */
	    Query.prototype.getModel = function (name) {
	        var entity = name || this.entity;
	        return this.self().getModel(entity);
	    };
	    /**
	     * Get all models from the container.
	     */
	    Query.prototype.getModels = function () {
	        return this.self().getModels();
	    };
	    /**
	     * Get base model of given name from the container.
	     */
	    Query.prototype.getBase = function (name) {
	        return this.self().getBase(name);
	    };
	    /**
	     * Get module of given name from the container.
	     */
	    Query.prototype.getModule = function (name) {
	        var entity = name || this.entity;
	        return this.self().getModule(entity);
	    };
	    /**
	     * Get all modules from the container.
	     */
	    Query.prototype.getModules = function () {
	        return this.self().getModules();
	    };
	    /**
	     * Returns all record of the query chain result. This method is alias
	     * of the `get` method.
	     */
	    Query.prototype.all = function () {
	        return this.get();
	    };
	    /**
	     * Get the record of the given id.
	     */
	    Query.prototype.find = function (id) {
	        return this.item(this.state.data[id]); // TODO: Delete "as ..." when model type coverage reaches 100%.
	    };
	    /**
	     * Get the record of the given array of ids.
	     */
	    Query.prototype.findIn = function (idList) {
	        var _this = this;
	        return idList.map(function (id) { return _this.state.data[id]; }).filter(function (item) { return item; }); // TODO: Delete "as ..." when model type coverage reaches 100%.
	    };
	    /**
	     * Returns all record of the query chain result.
	     */
	    Query.prototype.get = function () {
	        var records = this.select();
	        return this.collect(records); // TODO: Delete "as ..." when model type coverage reaches 100%.
	    };
	    /**
	     * Returns the first record of the query chain result.
	     */
	    Query.prototype.first = function () {
	        var records = this.select();
	        return this.item(records[0]); // TODO: Delete "as ..." when model type coverage reaches 100%.
	    };
	    /**
	     * Returns the last single record of the query chain result.
	     */
	    Query.prototype.last = function () {
	        var records = this.select();
	        return this.item(records[records.length - 1]); // TODO: Delete "as ..." when model type coverage reaches 100%.
	    };
	    /**
	     * Add a and where clause to the query.
	     */
	    Query.prototype.where = function (field, value) {
	        if (this.isIdfilterable(field)) {
	            this.setIdFilter(value);
	        }
	        this.wheres.push({ field: field, value: value, boolean: 'and' });
	        return this;
	    };
	    /**
	     * Add a or where clause to the query.
	     */
	    Query.prototype.orWhere = function (field, value) {
	        // Cacncel id filter usage, since "or" needs full scan.
	        this.cancelIdFilter = true;
	        this.wheres.push({ field: field, value: value, boolean: 'or' });
	        return this;
	    };
	    /**
	     * Filter records by their primary key.
	     */
	    Query.prototype.whereId = function (value) {
	        return this.where(this.model.primaryKey, value);
	    };
	    /**
	     * Filter records by their primary keys.
	     */
	    Query.prototype.whereIdIn = function (values) {
	        return this.where(this.model.primaryKey, values);
	    };
	    /**
	     * Fast comparison for foreign keys. If the foreign key is the primary key,
	     * it uses object lookup, fallback normal where otherwise.
	     *
	     * Why separate `whereFk` instead of just `where`? Additional logic needed
	     * for the distinction between where and orWhere in normal queries, but
	     * Fk lookups are always "and" type.
	     */
	    Query.prototype.whereFk = function (field, value) {
	        var values = Array.isArray(value) ? value : [value];
	        // If lookup filed is the primary key. Initialize or get intersection,
	        // because boolean and could have a condition such as
	        // `whereId(1).whereId(2).get()`.
	        if (field === this.model.primaryKey) {
	            this.setJoinedIdFilter(values);
	            return this;
	        }
	        // Else fallback to normal where.
	        this.where(field, values);
	        return this;
	    };
	    /**
	     * Check whether the given field and value combination is filterable through
	     * primary key direct look up.
	     */
	    Query.prototype.isIdfilterable = function (field) {
	        return field === this.model.primaryKey && !this.cancelIdFilter;
	    };
	    /**
	     * Set id filter for the given where condition.
	     */
	    Query.prototype.setIdFilter = function (value) {
	        var _this = this;
	        var values = Array.isArray(value) ? value : [value];
	        // Initialize or get intersection, because boolean and could have a
	        // condition such as `whereIdIn([1,2,3]).whereIdIn([1,2]).get()`.
	        if (this.idFilter === null) {
	            this.idFilter = new Set(values);
	            return;
	        }
	        this.idFilter = new Set(values.filter(function (v) { return _this.idFilter.has(v); }));
	    };
	    /**
	     * Set joined id filter for the given where condition.
	     */
	    Query.prototype.setJoinedIdFilter = function (values) {
	        var _this = this;
	        // Initialize or get intersection, because boolean and could have a
	        // condition such as `whereId(1).whereId(2).get()`.
	        if (this.joinedIdFilter === null) {
	            this.joinedIdFilter = new Set(values);
	            return;
	        }
	        this.joinedIdFilter = new Set(values.filter(function (v) { return _this.joinedIdFilter.has(v); }));
	    };
	    /**
	     * Add an order to the query.
	     */
	    Query.prototype.orderBy = function (field, direction) {
	        if (direction === void 0) { direction = 'asc'; }
	        this.orders.push({ field: field, direction: direction });
	        return this;
	    };
	    /**
	     * Add an offset to the query.
	     */
	    Query.prototype.offset = function (offset) {
	        this.offsetNumber = offset;
	        return this;
	    };
	    /**
	     * Add limit to the query.
	     */
	    Query.prototype.limit = function (limit) {
	        this.limitNumber = limit;
	        return this;
	    };
	    /**
	     * Set the relationships that should be loaded.
	     */
	    Query.prototype.with = function (name, constraint) {
	        if (constraint === void 0) { constraint = null; }
	        Loader.with(this, name, constraint);
	        return this;
	    };
	    /**
	     * Query all relations.
	     */
	    Query.prototype.withAll = function () {
	        Loader.withAll(this);
	        return this;
	    };
	    /**
	     * Query all relations recursively.
	     */
	    Query.prototype.withAllRecursive = function (depth) {
	        if (depth === void 0) { depth = 3; }
	        Loader.withAllRecursive(this, depth);
	        return this;
	    };
	    /**
	     * Set where constraint based on relationship existence.
	     */
	    Query.prototype.has = function (relation, operator, count) {
	        Rollcaller.has(this, relation, operator, count);
	        return this;
	    };
	    /**
	     * Set where constraint based on relationship absence.
	     */
	    Query.prototype.hasNot = function (relation, operator, count) {
	        Rollcaller.hasNot(this, relation, operator, count);
	        return this;
	    };
	    /**
	     * Add where has condition.
	     */
	    Query.prototype.whereHas = function (relation, constraint) {
	        Rollcaller.whereHas(this, relation, constraint);
	        return this;
	    };
	    /**
	     * Add where has not condition.
	     */
	    Query.prototype.whereHasNot = function (relation, constraint) {
	        Rollcaller.whereHasNot(this, relation, constraint);
	        return this;
	    };
	    /**
	     * Get all records from the state and convert them into the array. It will
	     * check if the record is an instance of Model and if not, it will
	     * instantiate before returning them.
	     *
	     * This is needed to support SSR, that when the state is hydrated at server
	     * side, it will be converted to the plain record at the client side.
	     */
	    Query.prototype.records = function () {
	        var _this = this;
	        this.finalizeIdFilter();
	        return this.getIdsToLookup()
	            .map(function (id) {
	            var model = _this.state.data[id];
	            // Getting the typed instance
	            var hydrated = model instanceof Model ? model : _this.hydrate(model);
	            // And ignoring if needed
	            if (!_this.appliedOnBase && !(hydrated instanceof _this.model)) {
	                return null;
	            }
	            return hydrated;
	        })
	            .filter(function (record) {
	            return record !== null;
	        });
	    };
	    /**
	     * Check whether if id filters should on select. If not, clear out id filter.
	     */
	    Query.prototype.finalizeIdFilter = function () {
	        if (!this.cancelIdFilter || this.idFilter === null) {
	            return;
	        }
	        this.where(this.model.primaryKey, Array.from(this.idFilter.values()));
	        this.idFilter = null;
	    };
	    /**
	     * Get a list of id that should be used to lookup when fetching records
	     * from the state.
	     */
	    Query.prototype.getIdsToLookup = function () {
	        var _this = this;
	        // If both id filter and joined id filter are set, intersect them.
	        if (this.idFilter && this.joinedIdFilter) {
	            return Array.from(this.idFilter.values()).filter(function (id) {
	                return _this.joinedIdFilter.has(id);
	            });
	        }
	        // If only either one is set, return which one is set.
	        if (this.idFilter || this.joinedIdFilter) {
	            return Array.from((this.idFilter || this.joinedIdFilter).values());
	        }
	        // If none is set, return all keys.
	        return Object.keys(this.state.data);
	    };
	    /**
	     * Process the query and filter data.
	     */
	    Query.prototype.select = function () {
	        // At first, well apply any `has` condition to the query.
	        Rollcaller.applyConstraints(this);
	        // Next, get all record as an array and then start filtering it through.
	        var records = this.records();
	        // Process `beforeSelect` hook.
	        records = this.executeRetrieveHook('beforeSelect', records);
	        // Let's filter the records at first by the where clauses.
	        records = this.filterWhere(records);
	        // Process `afterWhere` hook.
	        records = this.executeRetrieveHook('afterWhere', records);
	        // Next, lets sort the data.
	        records = this.filterOrderBy(records);
	        // Process `afterOrderBy` hook.
	        records = this.executeRetrieveHook('afterOrderBy', records);
	        // Finally, slice the record by limit and offset.
	        records = this.filterLimit(records);
	        // Process `afterLimit` hook.
	        records = this.executeRetrieveHook('afterLimit', records);
	        return records; // TODO: Delete "as ..." when model type coverage reaches 100%.
	    };
	    /**
	     * Filter the given data by registered where clause.
	     */
	    Query.prototype.filterWhere = function (records) {
	        return Filter.where(this, records);
	    };
	    /**
	     * Sort the given data by registered orders.
	     */
	    Query.prototype.filterOrderBy = function (records) {
	        return Filter.orderBy(this, records);
	    };
	    /**
	     * Limit the given records by the lmilt and offset.
	     */
	    Query.prototype.filterLimit = function (records) {
	        return Filter.limit(this, records);
	    };
	    /**
	     * Get the count of the retrieved data.
	     */
	    Query.prototype.count = function () {
	        return this.get().length;
	    };
	    /**
	     * Get the max value of the specified filed.
	     */
	    Query.prototype.max = function (field) {
	        var numbers = this.get().reduce(function (numbers, item) {
	            if (typeof item[field] === 'number') {
	                numbers.push(item[field]);
	            }
	            return numbers;
	        }, []);
	        return numbers.length === 0 ? 0 : Math.max.apply(Math, numbers);
	    };
	    /**
	     * Get the min value of the specified filed.
	     */
	    Query.prototype.min = function (field) {
	        var numbers = this.get().reduce(function (numbers, item) {
	            if (typeof item[field] === 'number') {
	                numbers.push(item[field]);
	            }
	            return numbers;
	        }, []);
	        return numbers.length === 0 ? 0 : Math.min.apply(Math, numbers);
	    };
	    /**
	     * Get the sum value of the specified filed.
	     */
	    Query.prototype.sum = function (field) {
	        return this.get().reduce(function (sum, item) {
	            if (typeof item[field] === 'number') {
	                sum += item[field];
	            }
	            return sum;
	        }, 0);
	    };
	    /**
	     * Create a item from given record.
	     */
	    Query.prototype.item = function (item) {
	        if (!item) {
	            return null;
	        }
	        if (Object.keys(this.load).length > 0) {
	            var model = this.model.getModelFromRecord(item);
	            item = new model(item);
	            Loader.eagerLoadRelations(this, [item]);
	        }
	        return item;
	    };
	    /**
	     * Create a collection (array) from given records.
	     */
	    Query.prototype.collect = function (collection) {
	        var _this = this;
	        if (collection.length < 1) {
	            return [];
	        }
	        if (Object.keys(this.load).length > 0) {
	            collection = collection.map(function (item) {
	                var model = _this.model.getModelFromRecord(item);
	                return new model(item);
	            });
	            Loader.eagerLoadRelations(this, collection);
	        }
	        return collection;
	    };
	    /**
	     * Filter all data in the store by the given predicate.
	     */
	    Query.prototype.filterData = function (predicate) {
	        var _this = this;
	        this.state.data = Object.keys(this.state.data).reduce(function (models, id) {
	            var model = _this.state.data[id];
	            if (predicate(model)) {
	                models[id] = model;
	            }
	            return models;
	        }, {});
	    };
	    /**
	     * Create new data with all fields filled by default values.
	     */
	    Query.prototype.new = function () {
	        var record = (new this.model()).$toJson();
	        var result = this.insert(record, {});
	        return result[this.entity][0];
	    };
	    /**
	     * Save given data to the store by replacing all existing records in the
	     * store. If you want to save data without replacing existing records,
	     * use the `insert` method instead.
	     */
	    Query.prototype.create = function (data, options) {
	        return this.persist(data, 'create', options); // TODO: Delete "as ..." when model type coverage reaches 100%.
	    };
	    /**
	     * Create records to the state.
	     */
	    Query.prototype.createMany = function (records) {
	        var _this = this;
	        var instances = this.hydrateMany(records);
	        var createCallback = function () {
	            _this.emptyState();
	            _this.state.data = __assign(__assign({}, _this.state.data), instances);
	        };
	        this.commitCreateOnRecords(instances, createCallback);
	        return this.map(instances); // TODO: Delete "as ..." when model type coverage reaches 100%.
	    };
	    /**
	     * Insert given data to the state. Unlike `create`, this method will not
	     * remove existing data within the state, but it will update the data
	     * with the same primary key.
	     */
	    Query.prototype.insert = function (data, options) {
	        return this.persist(data, 'insert', options); // TODO: Delete "as ..." when model type coverage reaches 100%.
	    };
	    /**
	     * Insert list of records in the state.
	     */
	    Query.prototype.insertMany = function (records) {
	        var _this = this;
	        var instances = this.hydrateMany(records);
	        this.commitCreateOnRecords(instances, function () {
	            _this.state.data = __assign(__assign({}, _this.state.data), instances);
	        });
	        return this.map(instances); // TODO: Delete "as ..." when model type coverage reaches 100%.
	    };
	    /**
	     * Commit given models to the store by `create` method.
	     */
	    Query.prototype.commitCreateOnRecords = function (models, callback) {
	        this.executeBeforeCreateHookOnModels(models);
	        callback();
	        this.executeAfterCreateHookOnModels(models);
	    };
	    /**
	     * Update data in the state.
	     */
	    Query.prototype.update = function (data, condition, options) {
	        // If the data is array, simply normalize the data and update them.
	        if (Array.isArray(data)) {
	            return this.persist(data, 'update', options);
	        }
	        // OK, the data is not an array. Now let's check `data` to see what we can
	        // do if it's a closure.
	        if (typeof data === 'function') {
	            // If the data is closure, but if there's no condition, we wouldn't know
	            // what record to update so raise an error and abort.
	            if (!condition) {
	                throw new Error('You must specify `where` to update records by specifying `data` as a closure.');
	            }
	            // If the condition is a closure, then update records by the closure.
	            if (typeof condition === 'function') {
	                return this.updateByCondition(data, condition);
	            }
	            // Else the condition is either String or Number, so let's
	            // update the record by ID.
	            return this.updateById(data, condition);
	        }
	        // Now the data is not a closure, and it's not an array, so it should be an object.
	        // If the condition is closure, we can't normalize the data so let's update
	        // records using the closure.
	        if (typeof condition === 'function') {
	            return this.updateByCondition(data, condition);
	        }
	        // If there's no condition, let's normalize the data and update them.
	        if (!condition) {
	            return this.persist(data, 'update', options);
	        }
	        // Now since the condition is either String or Number, let's check if the
	        // model's primary key is not a composite key. If yes, we can't set the
	        // condition as ID value for the record so throw an error and abort.
	        if (Array.isArray(this.model.primaryKey)) {
	            throw new Error("\n        You can't specify `where` value as `string` or `number` when you\n        have a composite key defined in your model. Please include composite\n        keys to the `data` fields.\n      ");
	        }
	        // Finally, let's add condition as the primary key of the object and
	        // then normalize them to update the records.
	        return this.updateById(data, condition);
	    };
	    /**
	     * Update all records.
	     */
	    Query.prototype.updateMany = function (records) {
	        var instances = this.combine(records);
	        return this.commitUpdate(instances); // TODO: Delete "as ..." when model type coverage reaches 100%.
	    };
	    /**
	     * Update the state by id.
	     */
	    Query.prototype.updateById = function (data, id) {
	        var _a;
	        id = typeof id === 'number' ? id.toString() : id;
	        var instance = this.state.data[id];
	        if (!instance) {
	            return null;
	        }
	        var instances = (_a = {},
	            _a[id] = this.processUpdate(data, instance),
	            _a);
	        this.commitUpdate(instances);
	        return instances[id];
	    };
	    /**
	     * Update the state by condition.
	     */
	    Query.prototype.updateByCondition = function (data, condition) {
	        var _this = this;
	        var instances = Object.keys(this.state.data).reduce(function (instances, id) {
	            var instance = _this.state.data[id];
	            if (!condition(instance)) {
	                return instances;
	            }
	            instances[id] = _this.processUpdate(data, instance);
	            return instances;
	        }, {});
	        return this.commitUpdate(instances);
	    };
	    /**
	     * Update the given record with given data.
	     */
	    Query.prototype.processUpdate = function (data, instance) {
	        if (typeof data === 'function') {
	            data(instance);
	            return instance;
	        }
	        // When the updated instance is not the base model, we tell te hydrate what model to use
	        if (instance.constructor !== this.model && instance instanceof Model) {
	            return this.hydrate(__assign(__assign({}, instance), data), instance.constructor);
	        }
	        return this.hydrate(__assign(__assign({}, instance), data));
	    };
	    /**
	     * Commit `update` to the state.
	     */
	    Query.prototype.commitUpdate = function (instances) {
	        var _this = this;
	        instances = this.updateIndexes(instances);
	        this.commitUpdateOnRecords(instances, function () {
	            _this.state.data = __assign(__assign({}, _this.state.data), instances);
	        });
	        return this.map(instances);
	    };
	    /**
	     * Commit given models to the store by `update` method.
	     */
	    Query.prototype.commitUpdateOnRecords = function (models, callback) {
	        this.executeBeforeUpdateHookOnModels(models);
	        callback();
	        this.executeAfterUpdateHookOnModels(models);
	    };
	    /**
	     * Update the key of the instances. This is needed when a user updates
	     * record's primary key. We must then update the index key to
	     * correspond with new id value.
	     */
	    Query.prototype.updateIndexes = function (instances) {
	        var _this = this;
	        return Object.keys(instances).reduce(function (instances, key) {
	            var instance = instances[key];
	            var id = String(_this.model.getIndexIdFromRecord(instance));
	            if (key !== id) {
	                instance.$id = id;
	                instances[id] = instance;
	                delete instances[key];
	            }
	            return instances;
	        }, instances);
	    };
	    /**
	     * Insert or update given data to the state. Unlike `insert`, this method
	     * will not replace existing data within the state, but it will update only
	     * the submitted data with the same primary key.
	     */
	    Query.prototype.insertOrUpdate = function (data, options) {
	        return this.persist(data, 'insertOrUpdate', options); // TODO: Delete "as ..." when model type coverage reaches 100%.
	    };
	    /**
	     * Insert or update the records.
	     */
	    Query.prototype.insertOrUpdateMany = function (records) {
	        var _this = this;
	        var toBeInserted = {};
	        var toBeUpdated = {};
	        Object.keys(records).forEach(function (id) {
	            var record = records[id];
	            if (_this.state.data[id]) {
	                toBeUpdated[id] = record;
	                return;
	            }
	            toBeInserted[id] = record;
	        });
	        return __spreadArrays(this.insertMany(toBeInserted), this.updateMany(toBeUpdated));
	    };
	    /**
	     * Persist data into the state.
	     */
	    Query.prototype.persist = function (data, method, options) {
	        var _this = this;
	        data = this.normalize(data);
	        if (Utils.isEmpty(data)) {
	            if (method === 'create') {
	                this.emptyState();
	            }
	            return {};
	        }
	        return Object.keys(data).reduce(function (collection, entity) {
	            var query = _this.newQuery(entity);
	            var persistMethod = _this.getPersistMethod(entity, method, options);
	            var records = query[persistMethod + "Many"](data[entity]);
	            if (records.length > 0) {
	                collection[entity] = records;
	            }
	            return collection;
	        }, {});
	    };
	    /**
	     * Get method for the persist.
	     */
	    Query.prototype.getPersistMethod = function (entity, method, options) {
	        if (options.create && options.create.includes(entity)) {
	            return 'create';
	        }
	        if (options.insert && options.insert.includes(entity)) {
	            return 'insert';
	        }
	        if (options.update && options.update.includes(entity)) {
	            return 'update';
	        }
	        if (options.insertOrUpdate && options.insertOrUpdate.includes(entity)) {
	            return 'insertOrUpdate';
	        }
	        return method;
	    };
	    Query.prototype.delete = function (condition) {
	        if (typeof condition === 'function') {
	            return this.deleteByCondition(condition);
	        }
	        return this.deleteById(condition);
	    };
	    /**
	     * Delete all records from the store. Even when deleting all records, we'll
	     * iterate over all records to ensure that before and after hook will be
	     * called for each existing records.
	     */
	    Query.prototype.deleteAll = function () {
	        var _this = this;
	        // If the target entity is the base entity and not inherited entity, we can
	        // just delete all records.
	        if (this.appliedOnBase) {
	            return this.deleteByCondition(function () { return true; });
	        }
	        // Otherwise, we should filter out any derived entities from being deleted
	        // so we'll add such filter here.
	        return this.deleteByCondition(function (model) { return model instanceof _this.model; });
	    };
	    /**
	     * Delete a record from the store by given id.
	     */
	    Query.prototype.deleteById = function (id) {
	        var item = this.whereId(id).first();
	        if (!item) {
	            return null;
	        }
	        return this.deleteByCondition(function (model) { return model.$id === item.$id; })[0];
	    };
	    /**
	     * Perform the actual delete query to the store.
	     */
	    Query.prototype.deleteByCondition = function (condition) {
	        var _this = this;
	        var deleted = [];
	        this.filterData(function (model) {
	            if (!condition(model)) {
	                return true;
	            }
	            if (_this.executeBeforeDeleteHook(model) === false) {
	                return true;
	            }
	            deleted.push(model);
	            _this.executeAfterDeleteHook(model);
	            return false;
	        });
	        return deleted;
	    };
	    /**
	     * Normalize the given data.
	     */
	    Query.prototype.normalize = function (data) {
	        return Processor.normalize(this, data);
	    };
	    /**
	     * Convert given record to the model instance.
	     */
	    Query.prototype.hydrate = function (record, forceModel) {
	        if (forceModel !== undefined) {
	            return new forceModel(record);
	        }
	        var model = this.model;
	        if (record) {
	            // If the record has the right typeKey attribute set, and Model has type mapping
	            // we hydrate it as the corresponding model
	            var newModel = model.getModelFromRecord(record);
	            if (typeof newModel === 'function') {
	                return new newModel(record);
	            }
	            // If we know that we're hydrating an entity which is not a base one,
	            // we can set it's typeKey attribute as a "bonus"
	            if (!this.appliedOnBase) {
	                var typeValue = model.getTypeKeyValueFromModel();
	                record[model.typeKey] = typeValue;
	            }
	        }
	        return new model(record);
	    };
	    /**
	     * Convert all given records to model instances.
	     */
	    Query.prototype.hydrateMany = function (records) {
	        var _this = this;
	        return Object.keys(records).reduce(function (instances, id) {
	            var record = records[id];
	            instances[id] = _this.hydrate(record);
	            return instances;
	        }, {});
	    };
	    /**
	     * Convert given records to instances by merging existing record. If there's
	     * no existing record, that record will not be included in the result.
	     */
	    Query.prototype.combine = function (records) {
	        var _this = this;
	        return Object.keys(records).reduce(function (instances, id) {
	            var instance = _this.state.data[id];
	            if (!instance) {
	                return instances;
	            }
	            var record = records[id];
	            if (instance.constructor !== _this.model && instance instanceof Model) {
	                instances[id] = _this.hydrate(__assign(__assign({}, instance), record), instance.constructor);
	                return instances;
	            }
	            instances[id] = _this.hydrate(__assign(__assign({}, instance), record));
	            return instances;
	        }, {});
	    };
	    /**
	     * Convert all given instances to collections.
	     */
	    Query.prototype.map = function (instances) {
	        return Object.keys(instances).map(function (id) { return instances[id]; });
	    };
	    /**
	     * Clears the current state from any data related to current model:
	     * - everything if not in a inheritance scheme
	     * - only derived instances if applied to a derived entity
	     */
	    Query.prototype.emptyState = function () {
	        if (this.appliedOnBase) {
	            this.state.data = {};
	            return;
	        }
	        for (var id in this.state.data) {
	            if (this.state.data[id] instanceof this.model) {
	                delete this.state.data[id];
	            }
	        }
	    };
	    /**
	     * Execute retrieve hook for the given method.
	     */
	    Query.prototype.executeRetrieveHook = function (on, models) {
	        var collection = models;
	        collection = this.executeLocalRetrieveHook(on, collection);
	        collection = this.executeGlobalRetrieveHook(on, collection);
	        return collection;
	    };
	    /**
	     * Execute local retrieve hook for the given method.
	     */
	    Query.prototype.executeLocalRetrieveHook = function (on, models) {
	        var hook = this.model[on];
	        return hook ? hook(models, this.model.entity) : models;
	    };
	    /**
	     * Execute global retrieve hook for the given method.
	     */
	    Query.prototype.executeGlobalRetrieveHook = function (on, models) {
	        var _this = this;
	        var hooks = this.self().hooks[on];
	        if (!hooks) {
	            return models;
	        }
	        var result = hooks.reduce(function (collection, hook) {
	            return hook.callback.call(_this, collection, _this.model.entity);
	        }, models);
	        this.cleanGlobalHooksOn(on);
	        return result;
	    };
	    /**
	     * Execute before create hook to the given model.
	     */
	    Query.prototype.executeBeforeCreateHook = function (model) {
	        if (this.executeLocalBeforeCreateHook(model) === false) {
	            return false;
	        }
	        if (this.executeGlobalBeforeCreateHook(model) === false) {
	            return false;
	        }
	    };
	    /**
	     * Execute before create hook to the goven models.
	     */
	    Query.prototype.executeBeforeCreateHookOnModels = function (models) {
	        var _this = this;
	        Object.keys(models).forEach(function (id) {
	            var model = models[id];
	            if (_this.executeBeforeCreateHook(model) === false) {
	                delete models[id];
	            }
	        });
	    };
	    /**
	     * Execute local before create hook to the given model.
	     */
	    Query.prototype.executeLocalBeforeCreateHook = function (model) {
	        var hook = this.model['beforeCreate'];
	        return hook && hook(model, this.entity);
	    };
	    /**
	     * Execute global before create hook to the given model.
	     */
	    Query.prototype.executeGlobalBeforeCreateHook = function (model) {
	        var _this = this;
	        return this.executeGlobalBeforeMutationHooks('beforeCreate', function (hook) {
	            return hook(model, _this.entity);
	        });
	    };
	    /**
	     * Execute after create hook to the given model.
	     */
	    Query.prototype.executeAfterCreateHook = function (model) {
	        this.executeLocalAfterCreateHook(model);
	        this.executeGlobalAfterCreateHook(model);
	    };
	    /**
	     * Execute after create hook to the goven models.
	     */
	    Query.prototype.executeAfterCreateHookOnModels = function (models) {
	        var _this = this;
	        Object.keys(models).forEach(function (id) {
	            var model = models[id];
	            _this.executeAfterCreateHook(model);
	        });
	    };
	    /**
	     * Execute local after create hook to the given model.
	     */
	    Query.prototype.executeLocalAfterCreateHook = function (model) {
	        var hook = this.model['afterCreate'];
	        return hook && hook(model, this.entity);
	    };
	    /**
	     * Execute global after create hook to the given model.
	     */
	    Query.prototype.executeGlobalAfterCreateHook = function (model) {
	        var _this = this;
	        this.executeGlobalAfterMutationHooks('afterCreate', function (hook) {
	            hook(model, _this.entity);
	        });
	    };
	    /**
	     * Execute before update hook to the given model.
	     */
	    Query.prototype.executeBeforeUpdateHook = function (model) {
	        if (this.executeLocalBeforeUpdateHook(model) === false) {
	            return false;
	        }
	        if (this.executeGlobalBeforeUpdateHook(model) === false) {
	            return false;
	        }
	    };
	    /**
	     * Execute before update hook to the goven models.
	     */
	    Query.prototype.executeBeforeUpdateHookOnModels = function (models) {
	        var _this = this;
	        Object.keys(models).forEach(function (id) {
	            var model = models[id];
	            if (_this.executeBeforeUpdateHook(model) === false) {
	                delete models[id];
	            }
	        });
	    };
	    /**
	     * Execute local before update hook to the given model.
	     */
	    Query.prototype.executeLocalBeforeUpdateHook = function (model) {
	        var hook = this.model['beforeUpdate'];
	        return hook && hook(model, this.entity);
	    };
	    /**
	     * Execute global before update hook to the given model.
	     */
	    Query.prototype.executeGlobalBeforeUpdateHook = function (model) {
	        var _this = this;
	        return this.executeGlobalBeforeMutationHooks('beforeUpdate', function (hook) {
	            return hook(model, _this.entity);
	        });
	    };
	    /**
	     * Execute after update hook to the given model.
	     */
	    Query.prototype.executeAfterUpdateHook = function (model) {
	        this.executeLocalAfterUpdateHook(model);
	        this.executeGlobalAfterUpdateHook(model);
	    };
	    /**
	     * Execute local after update hook to the given model.
	     */
	    Query.prototype.executeLocalAfterUpdateHook = function (model) {
	        var hook = this.model['afterUpdate'];
	        return hook && hook(model, this.entity);
	    };
	    /**
	     * Execute global after create hook to the given model.
	     */
	    Query.prototype.executeGlobalAfterUpdateHook = function (model) {
	        var _this = this;
	        this.executeGlobalAfterMutationHooks('afterUpdate', function (hook) {
	            hook(model, _this.entity);
	        });
	    };
	    /**
	     * Execute after update hook to the goven models.
	     */
	    Query.prototype.executeAfterUpdateHookOnModels = function (models) {
	        var _this = this;
	        Object.keys(models).forEach(function (id) {
	            var model = models[id];
	            _this.executeAfterUpdateHook(model);
	        });
	    };
	    /**
	     * Execute before delete hook to the given model.
	     */
	    Query.prototype.executeBeforeDeleteHook = function (model) {
	        if (this.executeLocalBeforeDeleteHook(model) === false) {
	            return false;
	        }
	        if (this.executeGlobalBeforeDeleteHook(model) === false) {
	            return false;
	        }
	    };
	    /**
	     * Execute local before delete hook to the given model.
	     */
	    Query.prototype.executeLocalBeforeDeleteHook = function (model) {
	        var hook = this.model['beforeDelete'];
	        return hook && hook(model, this.entity);
	    };
	    /**
	     * Execute global before delete hook to the given model.
	     */
	    Query.prototype.executeGlobalBeforeDeleteHook = function (model) {
	        var _this = this;
	        return this.executeGlobalBeforeMutationHooks('beforeDelete', function (hook) {
	            return hook(model, _this.entity);
	        });
	    };
	    /**
	     * Execute after delete hook to the given model.
	     */
	    Query.prototype.executeAfterDeleteHook = function (model) {
	        this.executeLocalAfterDeleteHook(model);
	        this.executeGlobalAfterDeleteHook(model);
	    };
	    /**
	     * Execute local after delete hook to the given model.
	     */
	    Query.prototype.executeLocalAfterDeleteHook = function (model) {
	        var hook = this.model['afterDelete'];
	        return hook && hook(model, this.entity);
	    };
	    /**
	     * Execute global after delete hook to the given model.
	     */
	    Query.prototype.executeGlobalAfterDeleteHook = function (model) {
	        var _this = this;
	        this.executeGlobalAfterMutationHooks('afterDelete', function (hook) {
	            hook(model, _this.entity);
	        });
	    };
	    /**
	     * Execute global before mutation hook on the given method.
	     */
	    Query.prototype.executeGlobalBeforeMutationHooks = function (on, callback) {
	        var hooks = this.self().hooks[on];
	        if (!Array.isArray(hooks) || hooks.length <= 0) {
	            return;
	        }
	        var result = hooks.some(function (hook) {
	            return callback(hook.callback) === false ? false : true;
	        });
	        this.cleanGlobalHooksOn(on);
	        return result === false ? false : undefined;
	    };
	    /**
	     * Execute global after mutation hook on the given method.
	     */
	    Query.prototype.executeGlobalAfterMutationHooks = function (on, callback) {
	        var hooks = this.self().hooks[on];
	        if (!Array.isArray(hooks)) {
	            return;
	        }
	        hooks.forEach(function (hook) { callback(hook.callback); });
	        this.cleanGlobalHooksOn(on);
	    };
	    /**
	     * Remove all callback defined as "once" from the global hooks.
	     */
	    Query.prototype.cleanGlobalHooksOn = function (on) {
	        var hooks = this.self().hooks[on];
	        this.self().hooks[on] = hooks.filter(function (hook) { return !hook.once; });
	    };
	    /**
	     * The global lifecycle hook registries.
	     */
	    Query.hooks = {};
	    /**
	     * The counter to generate the UID for global hooks.
	     */
	    Query.lastHookId = 0;
	    return Query;
	}());

	var Getters = {
	    /**
	     * Create a new Query instance.
	     */
	    query: function (state, _getters, _rootState, rootGetters) { return function () {
	        return rootGetters[state.$connection + "/query"](state.$name);
	    }; },
	    /**
	     * Get all data of given entity.
	     */
	    all: function (state, _getters, _rootState, rootGetters) { return function () {
	        return rootGetters[state.$connection + "/all"](state.$name);
	    }; },
	    /**
	     * Find a data of the given entity by given id.
	     */
	    find: function (state, _getters, _rootState, rootGetters) { return function (id) {
	        return rootGetters[state.$connection + "/find"](state.$name, id);
	    }; },
	    /**
	     * Find array of data of the given entity by given ids.
	     */
	    findIn: function (state, _getters, _rootState, rootGetters) { return function (idList) {
	        return rootGetters[state.$connection + "/findIn"](state.$name, idList);
	    }; }
	};

	function destroy(context, payload) {
	    return __awaiter(this, void 0, void 0, function () {
	        var state, entity, where;
	        return __generator(this, function (_a) {
	            state = context.state;
	            entity = state.$name;
	            where = payload;
	            return [2 /*return*/, context.dispatch(state.$connection + "/delete", { entity: entity, where: where }, { root: true })];
	        });
	    });
	}
	/**
	 * Delete all data from the store.
	 */
	function deleteAll(context) {
	    return __awaiter(this, void 0, void 0, function () {
	        var state, entity;
	        return __generator(this, function (_a) {
	            state = context.state;
	            entity = state.$name;
	            return [2 /*return*/, context.dispatch(state.$connection + "/deleteAll", { entity: entity }, { root: true })];
	        });
	    });
	}
	var Actions = {
	    /**
	     * Create new data with all fields filled by default values.
	     */
	    new: function (context) {
	        var state = context.state;
	        var entity = state.$name;
	        return context.dispatch(state.$connection + "/new", { entity: entity }, { root: true });
	    },
	    /**
	     * Save given data to the store by replacing all existing records in the
	     * store. If you want to save data without replacing existing records,
	     * use the `insert` method instead.
	     */
	    create: function (context, payload) {
	        var state = context.state;
	        var entity = state.$name;
	        return context.dispatch(state.$connection + "/create", __assign(__assign({}, payload), { entity: entity }), { root: true });
	    },
	    /**
	     * Insert given data to the state. Unlike `create`, this method will not
	     * remove existing data within the state, but it will update the data
	     * with the same primary key.
	     */
	    insert: function (context, payload) {
	        var state = context.state;
	        var entity = state.$name;
	        return context.dispatch(state.$connection + "/insert", __assign(__assign({}, payload), { entity: entity }), { root: true });
	    },
	    /**
	     * Update data in the store.
	     */
	    update: function (context, payload) {
	        var state = context.state;
	        var entity = state.$name;
	        // If the payload is an array, then the payload should be an array of
	        // data so let's pass the whole payload as data.
	        if (Array.isArray(payload)) {
	            return context.dispatch(state.$connection + "/update", { entity: entity, data: payload }, { root: true });
	        }
	        // If the payload doesn't have `data` property, we'll assume that
	        // the user has passed the object as the payload so let's define
	        // the whole payload as a data.
	        if (payload.data === undefined) {
	            return context.dispatch(state.$connection + "/update", { entity: entity, data: payload }, { root: true });
	        }
	        // Else destructure the payload and let root action handle it.
	        return context.dispatch(state.$connection + "/update", __assign({ entity: entity }, payload), { root: true });
	    },
	    /**
	     * Insert or update given data to the state. Unlike `insert`, this method
	     * will not replace existing data within the state, but it will update only
	     * the submitted data with the same primary key.
	     */
	    insertOrUpdate: function (context, payload) {
	        var state = context.state;
	        var entity = state.$name;
	        return context.dispatch(state.$connection + "/insertOrUpdate", __assign({ entity: entity }, payload), { root: true });
	    },
	    delete: destroy,
	    deleteAll: deleteAll
	};

	var RootGetters = {
	    /**
	     * Create a new Query instance.
	     */
	    query: function (state) { return function (entity) {
	        return new Query(state, entity);
	    }; },
	    /**
	     * Get all data of given entity.
	     */
	    all: function (state) { return function (entity) {
	        return (new Query(state, entity)).all();
	    }; },
	    /**
	     * Find a data of the given entity by given id.
	     */
	    find: function (state) { return function (entity, id) {
	        return (new Query(state, entity)).find(id);
	    }; },
	    /**
	     * Find a data of the given entity by given id.
	     */
	    findIn: function (state) { return function (entity, idList) {
	        return (new Query(state, entity)).findIn(idList);
	    }; }
	};

	function destroy$1(context, payload) {
	    return __awaiter(this, void 0, void 0, function () {
	        var result;
	        return __generator(this, function (_a) {
	            result = { data: {} };
	            context.commit('delete', __assign(__assign({}, payload), { result: result }));
	            return [2 /*return*/, result.data];
	        });
	    });
	}
	/**
	 * Delete all data from the store.
	 */
	function deleteAll$1(context, payload) {
	    return __awaiter(this, void 0, void 0, function () {
	        return __generator(this, function (_a) {
	            if (payload && payload.entity) {
	                context.commit('deleteAll', { entity: payload.entity });
	                return [2 /*return*/];
	            }
	            context.commit('deleteAll');
	            return [2 /*return*/];
	        });
	    });
	}
	var RootActions = {
	    /**
	     * Create new data with all fields filled by default values.
	     */
	    new: function (context, payload) {
	        var result = { data: {} };
	        context.commit('new', __assign(__assign({}, payload), { result: result }));
	        return result.data;
	    },
	    /**
	     * Save given data to the store by replacing all existing records in the
	     * store. If you want to save data without replacing existing records,
	     * use the `insert` method instead.
	     */
	    create: function (context, payload) {
	        return __awaiter(this, void 0, void 0, function () {
	            var result;
	            return __generator(this, function (_a) {
	                result = { data: {} };
	                context.commit('create', __assign(__assign({}, payload), { result: result }));
	                return [2 /*return*/, result.data];
	            });
	        });
	    },
	    /**
	     * Insert given data to the state. Unlike `create`, this method will not
	     * remove existing data within the state, but it will update the data
	     * with the same primary key.
	     */
	    insert: function (context, payload) {
	        return __awaiter(this, void 0, void 0, function () {
	            var result;
	            return __generator(this, function (_a) {
	                result = { data: {} };
	                context.commit('insert', __assign(__assign({}, payload), { result: result }));
	                return [2 /*return*/, result.data];
	            });
	        });
	    },
	    /**
	     * Update data in the store.
	     */
	    update: function (context, payload) {
	        return __awaiter(this, void 0, void 0, function () {
	            var result;
	            return __generator(this, function (_a) {
	                result = { data: {} };
	                context.commit('update', __assign(__assign({}, payload), { result: result }));
	                return [2 /*return*/, result.data];
	            });
	        });
	    },
	    /**
	     * Insert or update given data to the state. Unlike `insert`, this method
	     * will not replace existing data within the state, but it will update only
	     * the submitted data with the same primary key.
	     */
	    insertOrUpdate: function (context, payload) {
	        return __awaiter(this, void 0, void 0, function () {
	            var result;
	            return __generator(this, function (_a) {
	                result = { data: {} };
	                context.commit('insertOrUpdate', __assign(__assign({}, payload), { result: result }));
	                return [2 /*return*/, result.data];
	            });
	        });
	    },
	    delete: destroy$1,
	    deleteAll: deleteAll$1
	};

	var OptionsBuilder = /** @class */ (function () {
	    function OptionsBuilder() {
	    }
	    /**
	     * Get persist options from the given payload.
	     */
	    OptionsBuilder.createPersistOptions = function (payload) {
	        return {
	            create: payload.create,
	            insert: payload.insert,
	            update: payload.update,
	            insertOrUpdate: payload.insertOrUpdate
	        };
	    };
	    return OptionsBuilder;
	}());

	/**
	 * Delete records from the store. The actual name for this mutation is
	 * `delete`, but named `destroy` here because `delete` can't be declared at
	 * this scope level.
	 */
	function destroy$2(state, payload) {
	    var entity = payload.entity;
	    var where = payload.where;
	    var result = payload.result;
	    result.data = (new Query(state, entity)).delete(where);
	}
	/**
	 * Delete all data from the store.
	 */
	function deleteAll$2(state, payload) {
	    if (payload && payload.entity) {
	        (new Query(state, payload.entity)).deleteAll();
	        return;
	    }
	    Query.deleteAll(state);
	}
	var RootMutations = {
	    /**
	     * Execute generic mutation. This method is used by `Model.commit` method so
	     * that user can commit any state changes easily through models.
	     */
	    $mutate: function (state, payload) {
	        payload.callback(state[payload.entity]);
	    },
	    /**
	     * Create new data with all fields filled by default values.
	     */
	    new: function (state, payload) {
	        var entity = payload.entity;
	        var result = payload.result;
	        result.data = (new Query(state, entity)).new();
	    },
	    /**
	     * Save given data to the store by replacing all existing records in the
	     * store. If you want to save data without replacing existing records,
	     * use the `insert` method instead.
	     */
	    create: function (state, payload) {
	        var entity = payload.entity;
	        var data = payload.data;
	        var options = OptionsBuilder.createPersistOptions(payload);
	        var result = payload.result;
	        result.data = (new Query(state, entity)).create(data, options);
	    },
	    /**
	     * Insert given data to the state. Unlike `create`, this method will not
	     * remove existing data within the state, but it will update the data
	     * with the same primary key.
	     */
	    insert: function (state, payload) {
	        var entity = payload.entity;
	        var data = payload.data;
	        var options = OptionsBuilder.createPersistOptions(payload);
	        var result = payload.result;
	        result.data = (new Query(state, entity)).insert(data, options);
	    },
	    /**
	     * Update data in the store.
	     */
	    update: function (state, payload) {
	        var entity = payload.entity;
	        var data = payload.data;
	        var where = payload.where || null;
	        var options = OptionsBuilder.createPersistOptions(payload);
	        var result = payload.result;
	        result.data = (new Query(state, entity)).update(data, where, options);
	    },
	    /**
	     * Insert or update given data to the state. Unlike `insert`, this method
	     * will not replace existing data within the state, but it will update only
	     * the submitted data with the same primary key.
	     */
	    insertOrUpdate: function (state, payload) {
	        var entity = payload.entity;
	        var data = payload.data;
	        var options = OptionsBuilder.createPersistOptions(payload);
	        var result = payload.result;
	        result.data = (new Query(state, entity)).insertOrUpdate(data, options);
	    },
	    delete: destroy$2,
	    deleteAll: deleteAll$2
	};

	function use (plugin, options) {
	    if (options === void 0) { options = {}; }
	    var components = {
	        Model: Model,
	        Query: Query,
	        Attribute: Attribute,
	        Type: Type,
	        Attr: Attr,
	        String: String$1,
	        Number: Number,
	        Boolean: Boolean,
	        Increment: Increment,
	        Relation: Relation,
	        HasOne: HasOne,
	        BelongsTo: BelongsTo,
	        HasMany: HasMany,
	        HasManyBy: HasManyBy,
	        BelongsToMany: BelongsToMany,
	        HasManyThrough: HasManyThrough,
	        MorphTo: MorphTo,
	        MorphOne: MorphOne,
	        MorphMany: MorphMany,
	        MorphToMany: MorphToMany,
	        MorphedByMany: MorphedByMany,
	        Getters: Getters,
	        Actions: Actions,
	        RootGetters: RootGetters,
	        RootActions: RootActions,
	        RootMutations: RootMutations
	    };
	    plugin.install(components, options);
	}

	/* istanbul ignore next */
	var NoKey = /** @class */ (function () {
	    function NoKey() {
	    }
	    /**
	     * Set new unique id value.
	     */
	    NoKey.set = function () {
	        this.value = "" + this.prefix + this.count;
	    };
	    /**
	     * Get the current unique id value.
	     */
	    NoKey.get = function () {
	        return this.value;
	    };
	    /**
	     * Increment the count, then set the new unique id value.
	     */
	    NoKey.increment = function () {
	        this.count++;
	        this.set();
	        return this.get();
	    };
	    /**
	     * Count to create a unique id for the record that missing its primary key.
	     */
	    NoKey.count = 0;
	    /**
	     * Prefix string to be used for undefined primary key value.
	     */
	    NoKey.prefix = '_no_key_';
	    /**
	     * The current unique id value. This is the combination of
	     * the `prefix` and the `count`.
	     */
	    NoKey.value = '';
	    return NoKey;
	}());

	var IdAttribute = /** @class */ (function () {
	    function IdAttribute() {
	    }
	    /**
	     * Create the id attribute.
	     */
	    IdAttribute.create = function (model) {
	        return function (value, _parent, _key) {
	            var id = model.getIndexIdFromRecord(value);
	            return id === null ? NoKey.get() : id;
	        };
	    };
	    return IdAttribute;
	}());

	var ProcessStrategy = /** @class */ (function () {
	    function ProcessStrategy() {
	    }
	    /**
	     * Create the process strategy.
	     */
	    ProcessStrategy.create = function (model) {
	        return function (value, _parentValue, _key) {
	            var id = model.getIndexIdFromRecord(value);
	            return __assign(__assign({}, value), { $id: id === null ? NoKey.increment() : id });
	        };
	    };
	    return ProcessStrategy;
	}());

	var Schema = /** @class */ (function () {
	    /**
	     * Create a new schema instance.
	     */
	    function Schema(model) {
	        var _this = this;
	        /**
	         * List of generated schemas.
	         */
	        this.schemas = {};
	        this.model = model;
	        var models = model.database().models();
	        Object.keys(models).forEach(function (name) { _this.one(models[name]); });
	    }
	    /**
	     * Create a schema for the given model.
	     */
	    Schema.create = function (model) {
	        return (new this(model)).one();
	    };
	    /**
	     * Create a single schema for the given model.
	     */
	    Schema.prototype.one = function (model) {
	        model = model || this.model;
	        if (this.schemas[model.entity]) {
	            return this.schemas[model.entity];
	        }
	        var schema$1 = new schema.Entity(model.entity, {}, {
	            idAttribute: IdAttribute.create(model),
	            processStrategy: ProcessStrategy.create(model)
	        });
	        this.schemas[model.entity] = schema$1;
	        var definition = this.definition(model);
	        schema$1.define(definition);
	        return schema$1;
	    };
	    /**
	     * Create an array schema for the given model.
	     */
	    Schema.prototype.many = function (model) {
	        return new schema.Array(this.one(model));
	    };
	    /**
	     * Create an union schema for the given model.
	     */
	    Schema.prototype.union = function (callback) {
	        return new schema.Union(this.schemas, callback);
	    };
	    /**
	     * Create a dfinition for the given model.
	     */
	    Schema.prototype.definition = function (model) {
	        var _this = this;
	        var fields = model.getFields();
	        return Object.keys(fields).reduce(function (definition, key) {
	            var field = fields[key];
	            if (field instanceof Relation) {
	                definition[key] = field.define(_this);
	            }
	            return definition;
	        }, {});
	    };
	    return Schema;
	}());

	var Builder = /** @class */ (function () {
	    function Builder() {
	    }
	    /**
	     * Create module from the given modules.
	     */
	    Builder.create = function (namespace, models, modules) {
	        var tree = {
	            namespaced: true,
	            state: { $name: namespace },
	            getters: RootGetters,
	            actions: RootActions,
	            mutations: RootMutations,
	            modules: {}
	        };
	        return this.createModules(tree, namespace, models, modules);
	    };
	    /**
	     * Creates module tree to be registered under top level module
	     * from the given entities.
	     */
	    Builder.createModules = function (tree, namespace, models, modules) {
	        var _this = this;
	        Object.keys(modules).forEach(function (name) {
	            var model = models[name];
	            var module = modules[name];
	            tree.modules[name] = { namespaced: true };
	            tree.modules[name].state = _this.createState(namespace, name, model, module);
	            tree.getters[name] = function (_state, getters, _rootState, _rootGetters) { return function () {
	                return getters.query(name);
	            }; };
	            tree.modules[name].getters = __assign(__assign({}, Getters), module.getters);
	            tree.modules[name].actions = __assign(__assign({}, Actions), module.actions);
	            tree.modules[name].mutations = module.mutations || {};
	        });
	        return tree;
	    };
	    /**
	     * Get new state to be registered to the modules.
	     */
	    Builder.createState = function (namespace, name, model, module) {
	        var modelState = typeof model.state === 'function' ? model.state() : model.state;
	        var moduleState = typeof module.state === 'function' ? module.state() : module.state;
	        return __assign(__assign(__assign({}, modelState), moduleState), { $connection: namespace, $name: name, data: {} });
	    };
	    return Builder;
	}());

	var Database = /** @class */ (function () {
	    function Database() {
	        /**
	         * The list of entities registered to the Vuex Store. It contains models and
	         * modules with its name.
	         */
	        this.entities = [];
	        /**
	         * The database schema definition. This schema is going to be used when
	         * normalizing the data before persisting them to the Vuex Store.
	         */
	        this.schemas = {};
	    }
	    /**
	     * Initialize the database before a user can start using it.
	     */
	    Database.prototype.start = function (store, namespace) {
	        this.store = store;
	        this.namespace = namespace;
	        this.registerModules();
	        this.createSchema();
	    };
	    /**
	     * Register a model and a module to Database.
	     */
	    Database.prototype.register = function (model, module) {
	        if (module === void 0) { module = {}; }
	        this.checkModelTypeMappingCapability(model);
	        this.entities.push({
	            name: model.entity,
	            base: model.baseEntity || model.entity,
	            model: model,
	            module: module
	        });
	    };
	    /**
	     * Get the model of the given name from the entities list.
	     */
	    Database.prototype.model = function (name) {
	        return this.models()[name];
	    };
	    /**
	     * Get the base model of the given name from the entities list.
	     */
	    Database.prototype.baseModel = function (name) {
	        return this.baseModels()[name];
	    };
	    /**
	     * Get all models from the entities list.
	     */
	    Database.prototype.models = function () {
	        return this.entities.reduce(function (models, entity) {
	            models[entity.name] = entity.model;
	            return models;
	        }, {});
	    };
	    /**
	     * Get all base models from the entities list.
	     */
	    Database.prototype.baseModels = function () {
	        var _this = this;
	        return this.entities.reduce(function (models, entity) {
	            models[entity.name] = _this.model(entity.base);
	            return models;
	        }, {});
	    };
	    /**
	     * Get the module of the given name from the entities list.
	     */
	    Database.prototype.module = function (name) {
	        return this.modules()[name];
	    };
	    /**
	     * Get all modules from the entities list.
	     */
	    Database.prototype.modules = function () {
	        return this.entities.reduce(function (modules, entity) {
	            modules[entity.name] = entity.module;
	            return modules;
	        }, {});
	    };
	    /**
	     * Create the Vuex Module from the registered entities.
	     */
	    Database.prototype.registerModules = function () {
	        var modules = Builder.create(this.namespace, this.models(), this.modules());
	        this.store.registerModule(this.namespace, modules);
	    };
	    /**
	     * Create the schema definition from registered entities list and set it to
	     * the `schema` property. This schema will be used by the normalizer
	     * to normalize data before persisting them to the Vuex Store.
	     */
	    Database.prototype.createSchema = function () {
	        var _this = this;
	        this.entities.forEach(function (entity) {
	            _this.schemas[entity.name] = Schema.create(entity.model);
	        });
	    };
	    /**
	     * Warn user if the given model is a type of an inherited model that is being
	     * defined without overwriting `Model.types()` because the user will not be
	     * able to use the type mapping feature in this case.
	     */
	    Database.prototype.checkModelTypeMappingCapability = function (model) {
	        // We'll not be logging any warning if it's on a production environment,
	        // so let's return here if it is.
	        /* istanbul ignore next */
	        if (process.env.NODE_ENV === 'production') {
	            return;
	        }
	        // If the model doesn't have `baseEntity` property set, we'll assume it is
	        // not an inherited model so we can stop here.
	        if (!model.baseEntity) {
	            return;
	        }
	        // Now it seems like the model is indeed an inherited model. Let's check if
	        // it has `types()` method declared, or we'll warn the user that it's not
	        // possible to use type mapping feature.
	        var baseModel = this.model(model.baseEntity);
	        if (baseModel && baseModel.types === Model.types) {
	            console.warn("Model " + model.name + " extends " + baseModel.name + " which doesn't overwrite Model.types(). You will not be able to use type mapping.");
	        }
	    };
	    return Database;
	}());

	var index_cjs = {
	    install: install,
	    use: use,
	    Database: Database,
	    Model: Model,
	    Query: Query,
	    Attribute: Attribute,
	    Type: Type,
	    Attr: Attr,
	    String: String$1,
	    Number: Number,
	    Boolean: Boolean,
	    Increment: Increment,
	    Relation: Relation,
	    HasOne: HasOne,
	    BelongsTo: BelongsTo,
	    HasMany: HasMany,
	    HasManyBy: HasManyBy,
	    BelongsToMany: BelongsToMany,
	    HasManyThrough: HasManyThrough,
	    MorphTo: MorphTo,
	    MorphOne: MorphOne,
	    MorphMany: MorphMany,
	    MorphToMany: MorphToMany,
	    MorphedByMany: MorphedByMany,
	    Getters: Getters,
	    Actions: Actions,
	    RootGetters: RootGetters,
	    RootActions: RootActions,
	    RootMutations: RootMutations
	};

	return index_cjs;

}));
