From 809c4560357d1b37f886831258da3b4819ee3684 Mon Sep 17 00:00:00 2001 From: TeamworkGuy2 Date: Sat, 12 Jun 2021 20:28:57 +0000 Subject: [PATCH] 0.29.0 - Update to TypeScript 4.3 --- CHANGELOG.md | 8 +- package.json | 12 +- test/CompileManualBrowserBundleTest.js | 2 +- test/CompileManualBrowserBundleTest.ts | 2 +- test/tmp/bundle.js | 2653 ------------------------ test/tmp/bundle.js.map | 27 - test/tmp/index.html | 7 - 7 files changed, 15 insertions(+), 2696 deletions(-) delete mode 100644 test/tmp/bundle.js delete mode 100644 test/tmp/bundle.js.map delete mode 100644 test/tmp/index.html diff --git a/CHANGELOG.md b/CHANGELOG.md index 74f6dc1..7e03d5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,13 @@ This project does its best to adhere to [Semantic Versioning](http://semver.org/ -------- -### [0.28.0](N/A) - 2021-03-16 +### [0.29.0](N/A) - 2021-06-12 +#### Change +* Update to TypeScript 4.3 + + +-------- +### [0.28.0](https://github.com/TeamworkGuy2/lokijs-collections/commit/90f58f598ae74a828517809282b1a1a2d40502eb) - 2021-03-16 #### Change * Remove `Q` dependency (still used as a devDependency) * Update dependencies for `Q` dependency removal diff --git a/package.json b/package.json index 559fec3..6d7f5d0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lokijs-collections", - "version": "0.28.0", + "version": "0.29.0", "description": "TypeScript in-memory data collections based off LokiJS with data models, constraints (like primary keys and non-null fields), and collection change tracking", "author": "TeamworkGuy2", "homepage": "https://github.com/TeamworkGuy2/lokijs-collections", @@ -10,10 +10,10 @@ "url": "https://github.com/TeamworkGuy2/lokijs-collections.git" }, "dependencies": { - "@twg2/ts-twg-ast-codegen": "~0.24.4", - "ts-event-handlers-lite": "~0.4.1", - "ts-mortar": "~0.20.0", - "ts-promises": "~0.7.0" + "@twg2/ts-twg-ast-codegen": "~0.25.0", + "ts-event-handlers-lite": "~0.5.0", + "ts-mortar": "~0.21.0", + "ts-promises": "~0.8.0" }, "devDependencies": { "@types/browser-pack": "~6.0.4", @@ -31,7 +31,7 @@ "module-deps": "^6.2.0", "q": "~1.5.1", "ts-bundlify": "*", - "typescript": "~4.0.2" + "typescript": "~4.3.2" }, "scripts": { "test": "node node_modules/mocha/bin/_mocha -u tdd --recursive ./test/**/*Test.js", diff --git a/test/CompileManualBrowserBundleTest.js b/test/CompileManualBrowserBundleTest.js index a2f7f33..ae34064 100644 --- a/test/CompileManualBrowserBundleTest.js +++ b/test/CompileManualBrowserBundleTest.js @@ -12,7 +12,7 @@ var BundleBuilder = require("ts-bundlify/bundlers/BundleBuilder"); var TsBrowserify = require("ts-bundlify/bundlers/browser/TsBrowserify"); var asr = chai.assert; suite("CompileManualBrowserBundle", function CompileManualBrowserBundleTest() { - var doCleanup = false; + var doCleanup = true; test("bundleLokijsCollections", function bundleLokijsCollectionsTest(done) { this.timeout(3000); TsBrowserify.builtins = { diff --git a/test/CompileManualBrowserBundleTest.ts b/test/CompileManualBrowserBundleTest.ts index 9dd713a..06981f7 100644 --- a/test/CompileManualBrowserBundleTest.ts +++ b/test/CompileManualBrowserBundleTest.ts @@ -13,7 +13,7 @@ import TsBrowserify = require("ts-bundlify/bundlers/browser/TsBrowserify"); var asr = chai.assert; suite("CompileManualBrowserBundle", function CompileManualBrowserBundleTest() { - var doCleanup = false; + var doCleanup = true; test("bundleLokijsCollections", function bundleLokijsCollectionsTest(done) { diff --git a/test/tmp/bundle.js b/test/tmp/bundle.js deleted file mode 100644 index 64c6753..0000000 --- a/test/tmp/bundle.js +++ /dev/null @@ -1,2653 +0,0 @@ -(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i 0) { - Array.prototype.push.apply(src, toAdd); - } - return src; - } - Arrays.addAll = addAll; - /** Transform and add the elements from one array to another - * @param src the array to add elements to - * @param toAdd the elements to transform and add - * @param transformer a function to transform the 'toAdd' values before adding them to 'src' - */ - function addAllTransform(src, toAdd, transformer) { - for (var i = 0, size = toAdd.length; i < size; i++) { - src.push(transformer(toAdd[i])); - } - return src; - } - Arrays.addAllTransform = addAllTransform; - /** Given an array or an object, return the array, or a new array containing the object as it's only element - * @param data the object or array - * @param copyToNewAry optional (default: false) if the data is an array, copy the items into a new array - */ - function asArray(data, copyToNewAry) { - if (Array.isArray(data)) { - return copyToNewAry ? data.slice() : data; - } - else { - return [data]; - } - } - Arrays.asArray = asArray; - /** Check if an array is not null and has any items - * @param ary the array to check - * @returns true if the array is not null and has a length greater than 0 - */ - function hasAny(ary) { - return ary != null && ary.length > 0; - } - Arrays.hasAny = hasAny; - /** Given an array or an object, return true if it is an object or an array containing one element, false if the array is empty or contains more than 1 element - * @param data the object or array - */ - function isOneItem(data) { - return Array.isArray(data) ? data.length === 1 : true; - } - Arrays.isOneItem = isOneItem; - /** Given an array or an object, return the object or the first element if the array contains 1 element, else return null if the array is empty or contains more than 1 element - * @param data the object or array - */ - function getIfOneItem(data) { - return Array.isArray(data) ? (data.length === 1 ? data[0] : null) : data; - } - Arrays.getIfOneItem = getIfOneItem; - /** Perform a binary search of a property in an array of values and return the index. - * For example: Arrays.binarySearch([{key: 3}, {key: 10}, {key: 14}, {key: 15}], "key", 14) - * returns: 2 indicating that the 3rd array element matches - * - * For example: Arrays.binarySearch([{key: 3}, {key: 10}, {key: 14}, {key: 15}], "id", 13) - * returns: -3 indicating that no matching element was found, - * but if a matching element did exist in the array, it would be at index 3 - */ - function binarySearch(ary, comparatorPropName, searchValue) { - var low = 0; - var high = ary.length - 1; - while (low <= high) { - var mid = Math.floor((low + high) / 2); - var midVal = ary[mid]; - var compare = midVal[comparatorPropName] - searchValue; - if (compare < 0) { - low = mid + 1; - } - else if (compare > 0) { - high = mid - 1; - } - else { - return mid; - } - } - return -(low + 1); - } - Arrays.binarySearch = binarySearch; - /** Remove all values from an array - */ - function clear(ary) { - if (ary != null) { - ary.length = 0; - } - } - Arrays.clear = clear; - /** Returns a new array containing the elements from 'ary1' followed by the elements from 'ary2' - */ - function concat(ary1, ary2) { - if (ary1 != null && ary2 != null) { - return ary1.concat(ary2); - } - else { - return (ary1 != null ? ary1.slice() : (ary2 != null ? ary2.slice() : [])); - } - } - Arrays.concat = concat; - /** Check whether all of the values in the second array are contained in the first array - * @param ary the array of values - * @param searchFor the values to search for - * @returns true if all of 'searchFor' values are contained in 'ary' - */ - function containsAll(ary, searchFor) { - if (ary == null || searchFor == null) { - return false; - } - for (var i = 0, size = searchFor.length; i < size; i++) { - if (ary.indexOf(searchFor[i]) < 0) { - return false; - } - } - return true; - } - Arrays.containsAll = containsAll; - /** Check whether any of the values in the second array are contained in the first array - * @param ary the array of values - * @param searchFor the values to search for - * @returns true if any of 'searchFor' values are contained in 'ary' - */ - function containsAny(ary, searchFor) { - if (ary == null || searchFor == null) { - return false; - } - for (var i = 0, size = searchFor.length; i < size; i++) { - if (ary.indexOf(searchFor[i]) > -1) { - return true; - } - } - return false; - } - Arrays.containsAny = containsAny; - /** Count the number of elements in an array that match a filter - * @param ary the array of values - * @param filter the filter to use on 'ary' - * @returns the number of 'ary' elements that return a truthy value when passed through the 'filter' function - */ - function count(ary, filter) { - var res = 0; - for (var i = 0, size = ary.length; i < size; i++) { - if (filter(ary[i], i, ary)) { - res++; - } - } - return res; - } - Arrays.count = count; - /** Get the difference between two arrays. Also known as the symmetric difference (https://en.wikipedia.org/wiki/Symmetric_difference). - * NOTE: duplicate values in either array are considered unique. If there are two of the same values in 'ary1', then 'ary2' must contain two of those values to cancel out both of the values from 'ary1'. - * For example: Arrays.diff([1, 2, 3], [2, 4]) - * returns: [4, 1, 3] - * which represents the differences between 'ary1' and 'ary2' (note: the returned array order is undefined) - * - * @param ary1 the first array to compare - * @param ary2 the second array to compare - * @returns of values that exist in only one of the input arrays - * @see diff() - */ - function diff(ary1, ary2, equal) { - var diffRes = (equal != null ? diffPartsCustomEquality(ary1, ary2, equal) : diffParts(ary1, ary2)); - var looseDiff = Array.prototype.concat.apply(diffRes.added, diffRes.removed); - return looseDiff; - } - Arrays.diff = diff; - /** Return the difference between two arrays as elements added and removed from the first array. - * Items which only exist in 'ary1' are called 'removed'. - * Items which only exist in 'ary2' are called 'added'. - * NOTE: duplicate values in either array are considered unique. If there are two of the same values in 'ary1', then 'ary2' must contain two of those values to cancel out both of the values from 'ary1'. - * - * For example: Arrays.diffParts([1, 2, 3], [2, 4]) - * returns: { added: [4], removed: [1, 3]}, - * which are the values to add and remove from 'ary1' to convert it to 'ary2' - * - * @param ary1 the master/original array to base differences on - * @param ary2 the branch/new array to find differences in - * @returns with 'added' and 'removed' arrays of values from 'ary1' and 'ary2' - * @see looseDiff() - */ - function diffParts(ary1, ary2) { - if (ary1 == null || ary2 == null || !Array.isArray(ary1) || !Array.isArray(ary2)) { - if (ary1 == null && ary2 == null) { - return { added: [], removed: [] }; - } - // else, incorrect arguments - if ((ary1 != null && !Array.isArray(ary1)) || (ary2 != null && !Array.isArray(ary2)) || ary1 === undefined || ary2 === undefined) { - throw new Error("incorrect usage ([" + ary1 + "], [" + ary2 + "]), expected (Array ary1, Array ary2)"); - } - // if one array is null and the other is not, the difference is just the non-null array's values - if (ary1 == null && ary2 != null) { - return { - added: ary2.slice(), - removed: [] - }; - } - else /*if (ary1 != null && ary2 == null)*/ { - return { - added: [], - removed: ary1.slice() - }; - } - } - var added = []; - var removed = []; - var ary2Used = []; - var ary1Size = ary1.length; - var ary2Size = ary2.length; - // keep track of each element in 'ary2' that does not exist in 'ary1' - for (var i = 0; i < ary1Size; i++) { - var elem1 = ary1[i]; - var matchingIdx2 = -1; - for (var ii = 0; ii < ary2Size; ii++) { - if (ary2Used[ii] !== true && elem1 === ary2[ii]) { - matchingIdx2 = ii; - break; - } - } - // items that only exist in 'ary1' are 'removed' - if (matchingIdx2 === -1) { - removed.push(ary1[i]); - } - else { - ary2Used[matchingIdx2] = true; - } - } - // items that only exist in 'ary2' are 'added' - for (var ii = 0; ii < ary2Size; ii++) { - if (!ary2Used[ii]) { - added.push(ary2[ii]); - } - } - return { - added: added, - removed: removed - }; - } - Arrays.diffParts = diffParts; - /** Return the difference between two arrays as elements added and removed from the first array. - * Items which only exist in 'ary1' are called 'removed'. - * Items which only exist in 'ary2' are called 'added'. - * NOTE: duplicate values in either array are considered unique. If there are two of the same values in 'ary1', then 'ary2' must contain two of those values to cancel out both of the values from 'ary1'. - * - * For example: Arrays.diffParts([1, 2, 3], [2, 4]) - * returns: { added: [4], removed: [1, 3]}, - * which are the values to add and remove from 'ary1' to convert it to 'ary2' - * - * @param ary1 the master/original array to base differences on - * @param ary2 the branch/new array to find differences in - * @returns with 'added' and 'removed' arrays of values from 'ary1' and 'ary2' - * @see looseDiff() - */ - function diffPartsCustomEquality(ary1, ary2, equal) { - if (ary1 == null || ary2 == null || !Array.isArray(ary1) || !Array.isArray(ary2)) { - if (ary1 == null && ary2 == null) { - return { added: [], removed: [] }; - } - // else, incorrect arguments - if ((ary1 != null && !Array.isArray(ary1)) || (ary2 != null && !Array.isArray(ary2)) || ary1 === undefined || ary2 === undefined) { - throw new Error("incorrect usage ([" + ary1 + "], [" + ary2 + "]), expected (Array ary1, Array ary2)"); - } - // if one array is null and the other is not, the difference is just the non-null array's values - if (ary1 == null && ary2 != null) { - return { - added: ary2.slice(), - removed: [] - }; - } - else /*if (ary1 != null && ary2 == null)*/ { - return { - added: [], - removed: ary1.slice() - }; - } - } - var added = []; - var removed = []; - var ary2Used = []; - var ary1Size = ary1.length; - var ary2Size = ary2.length; - // keep track of each element in 'ary2' that does not exist in 'ary1' - for (var i = 0; i < ary1Size; i++) { - var elem1 = ary1[i]; - var matchingIdx2 = -1; - for (var ii = 0; ii < ary2Size; ii++) { - if (ary2Used[ii] !== true && equal(elem1, ary2[ii])) { - matchingIdx2 = ii; - break; - } - } - // items that only exist in 'ary1' are 'removed' - if (matchingIdx2 === -1) { - removed.push(ary1[i]); - } - else { - ary2Used[matchingIdx2] = true; - } - } - // items that only exist in 'ary2' are 'added' - for (var ii = 0; ii < ary2Size; ii++) { - if (!ary2Used[ii]) { - added.push(ary2[ii]); - } - } - return { - added: added, - removed: removed - }; - } - Arrays.diffPartsCustomEquality = diffPartsCustomEquality; - function distinct(ary, propName) { - if (ary == null || ary.length < 2) { - return ary || null; - } - var res = [ary[0]]; - if (propName == null) { - for (var i = 1, size = ary.length; i < size; i++) { - if (res.indexOf(ary[i]) === -1) { - res.push(ary[i]); - } - } - } - else { - for (var i = 1, size = ary.length; i < size; i++) { - if (Arrays.indexOfProp(res, propName, ary[i][propName]) === -1) { - res.push(ary[i]); - } - } - } - return res; - } - Arrays.distinct = distinct; - function fastRemove(ary, value) { - var aryLen = 0; - if (ary == null || (aryLen = ary.length) === 0) { - return ary; - } - var idx = ary.indexOf(value); - if (idx > -1) { - ary[idx] = ary[aryLen - 1]; - ary.pop(); - } - return ary; - } - Arrays.fastRemove = fastRemove; - function fastRemoveIndex(ary, index) { - var aryLen = 0; - if (ary == null || (aryLen = ary.length) === 0) { - return ary; - } - if (aryLen > 1) { - ary[index] = ary[aryLen - 1]; - } - ary.pop(); - return ary; - } - Arrays.fastRemoveIndex = fastRemoveIndex; - /** Split an array of values into matching and non-matching arrays using a filter - * For example: Arrays.filterSplit([1, 2, 3, 4, 5], function (value, idx, ary) { return value % 2 == 0; }) - * returns: { all: [1, 2, 3, 4, 5], matching: [2, 4], notMatching: [1, 3, 5] } - * - * @param ary the array of values to filter - * @param filterFunc the function to filter the values, - * true stores items in the returned 'matching' property, - * false stores items in the returned 'notMatching' property - * @returns a filter result object contains the original array 'all' and arrays of 'matching' and 'notMatching' items - */ - function filterSplit(ary, filterFunc) { - if (ary == null) { - return toBiFilterResult([], [], []); - } - if (typeof filterFunc !== "function") { - throw new Error("incorrect parameter 'filterFunc', must be a 'function(value: E, index: number, array: E[]): boolean'"); - } - var matching = []; - var notMatching = []; - for (var i = 0, size = ary.length; i < size; i++) { - var value = ary[i]; - if (filterFunc(value, i, ary)) { - matching.push(value); - } - else { - notMatching.push(value); - } - } - return toBiFilterResult(ary, matching, notMatching); - } - Arrays.filterSplit = filterSplit; - // convert an array of items and arrays containing matching and non-matching items to an 'BiFilterResult' object - function toBiFilterResult(all, matching, notMatching) { - return { - all: all, - matching: matching, - notMatching: notMatching - }; - } - /** Search for objects in an array containing a property matching a given input property. - * For example: Arrays.findAllProp([ {name: "billy", value: 5}, {name: "sam", value: 5}, {name: "overhill", value: 3} ], "value", 5) - * returns: {name: "billy", value: 5}, {name: "sam", value: 5} - * because the matching object has a property "value" with a value of 5 - * - * @param ary the array to search - * @param propName the name of the property to search for on each object - * @param propValue the property value to compare - * @returns an array of objects containing properties named 'propName' with values equal to 'propValue', - * returns a new empty array if no matching object was found - */ - function findMatchingProps(ary, propName, propValue) { - if (ary == null || propName == null || propValue === undefined) { - return null; - } - var res = []; - for (var i = 0, size = ary.length; i < size; i++) { - if (ary[i][propName] === propValue) { - res.push(ary[i]); - } - } - return res; - } - Arrays.findMatchingProps = findMatchingProps; - /** Return the first matching value in an array using a filter function, null if no matches. - * Optional: throw an exception if more than one result is found. - * For example: Arrays.first([ {key: 27, value: "A"}, {key: 46, value: "B"}, {key: 84, value: "C"}, {key: 84, value: "D"} ], function (obj) { return obj.key === 84; }) - * returns: {key: 84, value: "C"} - * - * @param ary the array of values to search - * @param filter the filter to apply to 'ary' - * @returns the first (lowest index) value passed to 'filter' from 'ary' that returns true, or null if a match cannot be found - */ - function first(ary, filter, ensureOne) { - if (ensureOne === void 0) { ensureOne = false; } - var idx = firstIndex(ary, filter, ensureOne); - return idx < 0 ? null : ary[idx]; - } - Arrays.first = first; - /** Return the index of the first matching value in an array using a filter function, null if no matches. - * @see #first() - */ - function firstIndex(ary, filter, ensureOne) { - if (ensureOne === void 0) { ensureOne = false; } - if (ary == null || filter == null) { - return -1; - } - var resultIdx = -1; - var resultCount = 0; - for (var i = 0, size = ary.length; i < size; i++) { - if (filter(ary[i], i, ary) === true) { - if (resultCount === 0) { - resultIdx = i; - if (!ensureOne) { - resultCount++; - break; - } - } - resultCount++; - throw new Error("found multiple results, expected to find one"); - } - } - if (resultCount === 1) { - return resultIdx; - } - return -1; - } - Arrays.firstIndex = firstIndex; - function last(ary, filterFunc) { - var idx = lastIndex(ary, filterFunc); - return idx < 0 ? null : ary[idx]; - } - Arrays.last = last; - /** Return the last value in an array that matches a filter, null if no matches - * @param ary the array of values to search - * @param filterFunc the filter to apply - * @returns the highest-index value passed to 'filterFunc' from 'ary' that returns true, null if no value returns true - */ - function lastIndex(ary, filterFunc) { - if (ary == null) { - return -1; - } - for (var i = ary.length - 1; i > -1; i--) { - if (filterFunc(ary[i], i, ary) == true) { - return i; - } - } - return -1; - } - Arrays.lastIndex = lastIndex; - /** Search for an object in an array containing a property matching a given input property. - * Optional: throw an exception if more than one result is found. - * For example: Arrays.firstProp([ {name: "billy", value: 4}, {name: "sam", value: 5}, {name: "will", value: 5} ], "value", 5) - * returns: {name: "sam", value: 5} - * Or example: Arrays.firstProp([ {name: "billy", value: 4}, {name: "sam", value: 4}, {name: "will", value: 5} ], "value", 5, true) - * throws an error because the value appears more than once and the 'ensureOne' parameter = true - * - * @param ary the array of values to search - * @param propName the name of the property to search for on each object - * @param propValue the property value to compare - * @returns the first (lowest index) matching value from the input array, or null if a result cannot be found - */ - function firstProp(ary, propName, propValue, ensureOne) { - if (ensureOne === void 0) { ensureOne = false; } - if (ary == null || propName == null) { - return null; - } - var result = null; - var resultCount = 0; - for (var i = 0, size = ary.length; i < size; i++) { - var obj = ary[i]; - if (obj != null && obj[propName] === propValue) { - if (resultCount === 0) { - result = obj; - if (!ensureOne) { - resultCount++; - break; - } - } - resultCount++; - throw new Error("found multiple results for '" + propName + "'='" + propValue + "', expected to find one"); - } - } - if (resultCount === 1) { - return result; - } - return null; - } - Arrays.firstProp = firstProp; - /** Get a property from each object in an array of objects - * @param ary the array of objects - * @param propName the name of the property to get - * @param distinct optional boolean which indicates whether unique results only should be returned - * @returns an array of the specified property from each object in 'ary' - */ - function pluck(ary, propName, distinct) { - if (ary == null || propName == null) { - return []; - } - if (!distinct) { - var results = new Array(ary.length); - for (var i = ary.length - 1; i > -1; i--) { - results[i] = ary[i][propName]; - } - return results; - } - else { - var results = []; - for (var i = 0, size = ary.length; i < size; i++) { - var value = ary[i][propName]; - if (results.indexOf(value) < 0) { - results.push(value); - } - } - return results; - } - } - Arrays.pluck = pluck; - /** Search for the index of an object with a specified property in an array. - * For example: Arrays.indexOfPropValue([ {name: "billy", value: 12}, {name: "sam", value: 12} ], "value", 12) - * returns: 0 - * because the first object with the property "value" with a value of 12 was at index 0 - * - * @param ary the array to search - * @param propName the name of the property to search for on each object - * @param propValue the property value to compare - * @param offset optional, 'ary' offset at which to start search, supports negative offset same as 'Array.indexOf(T, number)' - * @returns the array index of an object with a matching property, -1 if no matching object was found - */ - function indexOfProp(ary, propName, propValue, offset) { - if (ary == null || propName == null || propValue === undefined) { - return -1; - } - for (var size = ary.length, i = offset < 0 ? (size + offset > 0 ? size + offset : 0) : (offset || 0); i < size; i++) { - if (ary[i][propName] === propValue) { - return i; - } - } - return -1; - } - Arrays.indexOfProp = indexOfProp; - /** Search for the last index of an object with a specified property in an array - * For example: Arrays.lastIndexOfPropValue([ {text: "john's bid", value: 12}, {text: "test bid", value: 12} ], "value", 12) - * returns: 1 - * because the last object with the property "value" with a value of 12 was at index 1 - * - * @param ary the array to search - * @param propName the name of the property to search for on each object - * @param propValue the property value to compare - * @returns the array index of an object with a matching property, -1 if no matching object was found - */ - function lastIndexOfProp(ary, propName, propValue) { - if (ary == null || propName == null || propValue === undefined) { - return -1; - } - for (var i = ary.length - 1; i > -1; i--) { - if (ary[i][propName] === propValue) { - return i; - } - } - return -1; - } - Arrays.lastIndexOfProp = lastIndexOfProp; - /** Check if two arrays are equal, element by element - * For example: Arrays.equal(["A", 23, true], ["A", 23, true]) - * returns: true - * Or example: Arrays.equal(["A", 23, true], ["A", 13]) - * returns: false - * - * @param ary1 the first array to compare - * @param ary2 the second array to compare - */ - function equal(ary1, ary2) { - if (ary1 == null || ary2 == null || ary1.length !== ary2.length) { - return false; - } - for (var i = 0, size = ary1.length; i < size; i++) { - if (ary1[i] !== ary2[i]) { - return false; - } - } - return true; - } - Arrays.equal = equal; - /** Check whether two arrays are equal, ignoring the order of the elements in each array. - * elements are compared using strict (i.e. '===') equality. - * For example: Arrays.looseEqual([26, "Alpha", 5], [5, 26, "Alpha"]) - * returns: true - * Or example: Arrays.looseEqual([34, "A", "QA"], [7, 34, "A"]) - * returns: false - * - * @param ary1 the first array to compare - * @param ary2 the second array to compare - * @returns true if both arrays contain the same elements in any order, or if both arrays are null. - * False if one or more elements differ between the two arrays - */ - function looseEqual(ary1, ary2) { - if (ary1 == null || ary2 == null || !Array.isArray(ary1) || !Array.isArray(ary2)) { - if (ary1 == null && ary2 == null) { - return true; - } - if ((ary1 != null && !Array.isArray(ary1)) || (ary2 != null && !Array.isArray(ary2)) || ary1 === undefined || ary2 === undefined) { - throw new Error("incorrect usage ([" + ary1 + "], [" + ary2 + "]), " + "expected (Array ary1, Array ary2)"); - } - if (ary1 == null || ary2 == null) { - return false; - } - } - if (ary1.length !== ary2.length) { - return false; - } - var matchingCount = 0; - for (var i = ary1.length - 1; i > -1; i--) { - if (ary2.indexOf(ary1[i]) === -1) { - return false; - } - matchingCount++; - } - return matchingCount == ary2.length; - } - Arrays.looseEqual = looseEqual; - /** Transforms the elements of an array into a new array - * For example: Arrays.map([1, 2, 3, 4], (value) => value % 3) - * returns: [1, 2, 0, 1] - * - * @param ary the array to map - * @returns a new array with each index containing the result of passing the original 'ary' element at that index through the 'mapFunc', or an empty array if the 'ary' is null - */ - function map(ary, mapFunc) { - if (ary == null) { - return []; - } - var res = []; - for (var i = 0, size = ary.length; i < size; i++) { - res.push(mapFunc(ary[i], i, ary)); - } - return res; - } - Arrays.map = map; - /** Maps and filters an array in one operation by passing a two field object to the map-filter - * function as a destination 'out' parameter like C#'s 'out' parameters - * For example: Arrays.mapFilter([1, 2, 3, 4, 5, 6, 7], function (value, dstOut) { dstOut.isValid = (value % 3 !== 0); }) - * returns: [1, 2, 4, 5, 7] - * Or example: Arrays.mapFilter(['A', 'B', 'C', 'D', 'C', 'A', 'B'], function (value, dstOut) { dstOut.isValid = (value !== 'D'); dstOut.value = value.toLowerCase(); }) - * returns: ['a', 'b', 'c', 'c', 'a', 'b'] - * - * @param ary the array AND filter to map - * @param mapFilterFunc since JS and TS don't have 'out' parameters - * this function accepts a value and sets 'dstOut.isValid' true if the value is accepted, false if it is filtered out, - * and stores the mapped result for valid values in 'dstOut.value'. - * NOTE: if 'dstOut.value' is left null, the input 'value' is stored in the returned array - * @returns an array of filtered and mapped result values - */ - function mapFilter(ary, mapFilterFunc) { - if (ary == null) { - return []; - } - if (typeof mapFilterFunc !== "function") { - throw new Error("incorrect parameter 'mapFilterFunc', must be a 'function(value, dstOut: { value; isValid }): void'"); - } - var results = []; - var nil = {}; - var dstOut = { value: nil, isValid: false }; - for (var i = 0, size = ary.length; i < size; i++) { - dstOut.isValid = false; - dstOut.value = nil; - var inputVal = ary[i]; - mapFilterFunc(inputVal, dstOut); - if (dstOut.isValid === true) { - results.push(dstOut.value !== nil ? dstOut.value : inputVal); - } - } - return results; - } - Arrays.mapFilter = mapFilter; - /** Like #mapFilter() except null return values are filtered out instead of using an two parameter 'out' style object with an 'isValid' flag - * @param the array of values to map-filter - * @param mapFunc the Array#map() style function to transform input values, - * null returned values are not stored in the returned array, allowing the function to filter - * @returns an array of non-null mapped result values - */ - function mapFilterNotNull(ary, mapFunc) { - if (ary == null) { - return []; - } - if (typeof mapFunc !== "function") { - throw new Error("incorrect parameter 'mapFilterFunc', must be a 'function(value): Object'"); - } - var results = []; - for (var i = 0, size = ary.length; i < size; i++) { - var res = mapFunc(ary[i], i, ary); - if (res != null) { - results.push(res); - } - } - return results; - } - Arrays.mapFilterNotNull = mapFilterNotNull; - function removeAll(ary, toRemove, fastRemove) { - if (ary == null || toRemove == null) { - return ary; - } - var idx; - if (fastRemove) { - // remove all matches by swapping them to the end of the array and shrinking the array - for (var i = 0, size = toRemove.length; i < size; i++) { - if ((idx = ary.indexOf(toRemove[i])) > -1) { - Arrays.fastRemoveIndex(ary, idx); - } - } - } - else { - // find the indices to remove - var indicesToSkip = []; - for (var i = 0, size = toRemove.length; i < size; i++) { - if ((idx = ary.indexOf(toRemove[i])) > -1) { - indicesToSkip.push(idx); - } - } - // rebuild the array without the items to remove - if (indicesToSkip.length > 0) { - var newI = 0; - var nextSkipIndexI = 0; - var nextSkipIndex = indicesToSkip[nextSkipIndexI]; - for (var i = 0, size = ary.length; i < size; i++) { - if (i === nextSkipIndex) { - nextSkipIndexI++; - nextSkipIndex = indicesToSkip[nextSkipIndexI]; - } - else { - ary[newI] = ary[i]; - newI++; - } - } - ary.length = ary.length - indicesToSkip.length; - } - } - return ary; - } - Arrays.removeAll = removeAll; - /** Remove the first instance of a matching value from an array - * @returns the removed index or -1 if the value could not be found - */ - function removeValue(ary, value) { - var idx = ary.indexOf(value); - if (idx > -1) { - removeIndex(ary, idx); - } - return idx; - } - Arrays.removeValue = removeValue; - function removeIndex(ary, index) { - if (ary == null) { - return null; - } - var size = ary.length; - if (size < 1 || index < 0 || index >= size) { - return ary; - } - for (var i = index + 1; i < size; i++) { - ary[i - 1] = ary[i]; - } - ary[size - 1] = null; - ary.length = size - 1; - return ary; - } - Arrays.removeIndex = removeIndex; - /** Set a property on every object in an array. - * Useful for clearing a specific property to false or null. - * @param ary the array of objects - * @param propName the name of the property to set - * @param propValue the value to assigned to each object's 'propName' property - */ - function setAllProp(ary, propName, propValue) { - if (ary == null || propName == null) { - return; - } - for (var i = ary.length - 1; i > -1; i--) { - ary[i][propName] = propValue; - } - } - Arrays.setAllProp = setAllProp; - /** - * @returns the input array, sorted in numeric order (ascending by default, with second parameter flag to sort descending) - */ - function sortNumeric(ary, descending) { - if (descending === void 0) { descending = false; } - if (descending === false) { - ary.sort(function (a, b) { return a - b; }); - } - else { - ary.sort(function (a, b) { return b - a; }); - } - return ary; - } - Arrays.sortNumeric = sortNumeric; - /** Create an array containing the contents of two arrays. - * For example: Arrays.spliceArray([0, 1, 1, 5], [10, 15, 20], 2, 1) - * returns: [0, 1, 10, 15, 20, 5] - * - * @param origAry the initial array to copy - * @param insertAry the array to insert into 'origAry' - * @param index the 'origAry' index at which to insert the elements from 'insertAry' - * @param deleteCount optional (default: 0) the number of elements to not copy from 'origAry' starting at 'index' - * @returns the 'origAry' or a new array containing the contents of 'origAry' and 'insertAry' - */ - function splice(origAry, insertAry, index, deleteCount, copyToNewAry) { - if (deleteCount === void 0) { deleteCount = 0; } - if (origAry == null) { - if (insertAry == null) { - return []; - } - else { - return insertAry.slice(0); - } - } - if ((origAry != null && !Array.isArray(origAry)) || (insertAry != null && !Array.isArray(insertAry))) { - throw new Error("incorrect usage ([" + origAry + "], [" + insertAry + "], " + index + ", " + (deleteCount || 0) + "), " + "expected (Array, Array, Integer[, Integer])"); - } - if (deleteCount === 0 && (insertAry == null || insertAry.length === 0)) { - return (copyToNewAry ? origAry.slice() : origAry); - } - var tmp; - // add to the end of the array - if (index === origAry.length && deleteCount === 0) { - tmp = (copyToNewAry ? origAry.slice() : origAry); - if (insertAry != null && insertAry.length > 0) { - Array.prototype.push.apply(tmp, insertAry); - } - } - else if (index === 0 && deleteCount === 0) { - tmp = (copyToNewAry ? origAry.slice() : origAry); - if (insertAry != null && insertAry.length > 0) { - Array.prototype.unshift.apply(tmp, insertAry); - } - } - else { - // copy up to the index to insert, then insert the array, and copying the remaining portion - tmp = origAry.slice(0, index); - if (insertAry != null && insertAry.length > 0) { - Array.prototype.push.apply(tmp, insertAry); - } - for (var i = index + deleteCount, size = origAry.length; i < size; i++) { - tmp.push(origAry[i]); - } - } - return tmp; - } - Arrays.splice = splice; - /** Swap two elements in an array - * For example: Arrays.swap(["A", "B", "C", "D"], 1, 2) - * returns: ["A", "C", "B", "D"] - * - * @param ary the array of elements - * @param i1 the first index of the two indexes to swap - * @param i2 the second index of the two indexes to swap - */ - function swap(ary, i1, i2) { - var tmp = ary[i2]; - ary[i2] = ary[i1]; - ary[i1] = tmp; - return ary; - } - Arrays.swap = swap; - function toMap(ary, prop) { - if (ary == null) { - return {}; - } - return Array.prototype.reduce.call(ary, function (map, itm) { - map[itm[prop]] = itm; - return map; - }, {}); - } - Arrays.toMap = toMap; - /** Return elements that exist in two arrays. - * For example: Arrays.union([1, 2, 3, 4, 5, "A"], [1, 2, 4, "A"]) - * returns: [1, 2, 4, "A"] - * - * @param ary1 the first array - * @param ary2 the second array - * @returns an array of shared elements between 'ary1' and 'ary2' - */ - function union(ary1, ary2) { - if (ary1 == null || ary2 == null) { - if (ary1 == null && ary2 != null) { - return ary2.slice(); - } - else if (ary1 != null && ary2 == null) { - return ary1.slice(); - } - else { - return []; - } - } - var results = []; - for (var i = 0, size = ary1.length; i < size; i++) { - var idx = ary2.indexOf(ary1[i]); - if (idx > -1) { - results.push(ary1[i]); - } - } - return results; - } - Arrays.union = union; - /** Find the maximum value in an array of numbers - * @param ary the array of numbers to search - */ - function max(ary) { - var max = Number.NEGATIVE_INFINITY; - for (var i = 0, size = ary.length; i < size; i++) { - max = ary[i] > max ? ary[i] : max; - } - return max; - } - Arrays.max = max; - /** Find the maximum value in an array of numbers - * @param ary the array of numbers to search - */ - function maxValueIndex(ary) { - var max = Number.NEGATIVE_INFINITY; - var maxI = -1; - for (var i = 0, size = ary.length; i < size; i++) { - if (ary[i] > max) { - max = ary[i]; - maxI = i; - } - } - return maxI; - } - Arrays.maxValueIndex = maxValueIndex; - /** Find the minimum value in an array of numbers - * @param ary the array of numbers to search - */ - function min(ary) { - var min = Number.POSITIVE_INFINITY; - for (var i = 0, size = ary.length; i < size; i++) { - min = ary[i] < min ? ary[i] : min; - } - return min; - } - Arrays.min = min; - /** Find the minimum value in an array of numbers - * @param ary the array of numbers to search - */ - function minValueIndex(ary) { - var min = Number.POSITIVE_INFINITY; - var minI = -1; - for (var i = 0, size = ary.length; i < size; i++) { - if (ary[i] < min) { - min = ary[i]; - minI = i; - } - } - return minI; - } - Arrays.minValueIndex = minValueIndex; - /** Sum the values of an array - * @param ary an array of numeric convertable values to sum; null, infinite, and NaN values in the array are treated as zero. - * If the array is null, 0 is returned. - * @returns the sum of the values in 'ary' - */ - function sum(ary, infinityToZero) { - if (ary == null) { - return 0; - } - var sum = 0; - for (var i = ary.length - 1; i > -1; i--) { - var val = ary[i]; - val = (val == null || isNaN(val) || (infinityToZero && (val === Infinity || val === Number.NEGATIVE_INFINITY || val === Number.POSITIVE_INFINITY))) ? 0 : val; - sum += val; - } - return sum; - } - Arrays.sum = sum; -})(Arrays || (Arrays = {})); -module.exports = Arrays; - -},{}],2:[function(require,module,exports){ -"use strict"; -/** Utility functions used by DataPersister implementations - * @since 2015-2-4 - */ -var DbUtil = /** @class */ (function () { - /** DB Utility configuration: - * @param dbTypeName the name to show in error message (ex: 'WebSQL') - * @param dbToStringId the Object.prototype.toString() name of the type (ex: '[Database]' for WebSQL instances). NOTE: this should match type - * @param settings configuration object with the following properties: - * `defer`: specifies the function that constructs a deferred object, such as: - * - Promise (native browser/node.js implementation) - * - [`when.js`](https://github.com/cujojs/when) - * - [`Q.js`](https://github.com/kriskowal/q) - * - [`jQuery's Deferred`](http://api.jquery.com/category/deferred-object/) - * - Other... - * `whenAll`: a Promise.all() style function for the promises returned by the 'defer' object - * `trace`: specifies the object used for logging messages. Default is `window.console`. - * `verbosity`: specifies verbosity of logging (NONDE, ERROR or DEBUG). Default is `log.NONE`. - * `logTimings`: whether to log query timings - */ - function DbUtil(dbTypeName, dbToStringId, settings) { - var _this = this; - this.trace = null; - this.NONE = DbUtil.logLevels.NONE; - this.ERROR = DbUtil.logLevels.ERROR; - this.DEBUG = DbUtil.logLevels.DEBUG; - this.verbosity = this.NONE; - this.logTimings = settings.logTimings; - this.defer = settings.defer; - this.whenAll = settings.whenAll; - this.dbTypeName = dbTypeName; - this.isDatabase = function (db) { return _this._toString(db) === dbToStringId; }; - if (!this.isFunction(settings.defer)) { - throw new Error("no 'defer' promise function option provided to " + dbTypeName + " adapter"); - } - if (settings.trace != null && this.isFunction(settings.trace.log)) { - this.trace = settings.trace; - } - if (typeof settings.verbosity !== "undefined") { - this.verbosity = settings.verbosity; - } - } - // Internal Functions - DbUtil.prototype._toString = function (obj) { return Object.prototype.toString.call(obj); }; - DbUtil.prototype.isString = function (fn) { return this._toString(fn) === "[object String]"; }; - DbUtil.prototype.isFunction = function (fn) { return this._toString(fn) === "[object Function]"; }; - DbUtil.prototype.isPromise = function (obj) { return obj && this.isFunction(obj.then); }; - /** Calls `onSuccess` or `onError` when `promise` is resolved. - * Returns a new promise that is resolved/rejected based on the - * values returned from the callbacks. - */ - DbUtil.prototype.pipe = function (p, onSuccess, onError) { - var self = this; - var dfd = this.defer(); - p.then(function (val) { - var res = onSuccess(val); - if (self.isPromise(res)) { - res.then(dfd.resolve, dfd.reject); - } - else { - dfd.resolve(res); - } - }, function (err) { - if (onError) { - err = onError(err); - } - if (self.isPromise(err)) { - err.then(dfd.resolve, dfd.reject); - } - else { - dfd.reject(err); - } - }); - return dfd.promise; - }; - /** Log statement if level > verbosity - * Usage: - * log(DEBUG, "Calling function", functionName); - * log(ERROR, "Something horrible happened:", error); - */ - DbUtil.prototype.log = function (level) { - var args = []; - for (var _i = 1; _i < arguments.length; _i++) { - args[_i - 1] = arguments[_i]; - } - var trc = this.trace; - if (level <= this.verbosity && trc != null) { - args.unshift(this.dbTypeName); - if (this.isFunction(trc.text)) { - trc.text(args, "color: purple"); - } - else if (level === this.ERROR && this.isFunction(trc.error)) { - trc.error(args); - } - else if (this.isFunction(trc.log)) { - trc.log(args); - } - } - }; - DbUtil.prototype.setConsole = function (console) { - this.trace = console; - }; - DbUtil.prototype.rejectError = function (dfd, error, options) { - if (typeof error === "string") { - error = new Error(error); - } - if (options != null) { - if (options.exception) - error.exception = options.exception; - if (options.sqlError) - error.sqlError = options.sqlError; - } - this.log(this.ERROR, "ERROR: " + (error.exception || (error.sqlError ? error.sqlError.message : error.sqlError) || error.message)); - dfd.reject(error); - return dfd.promise; - }; - DbUtil.getOptionsOrDefault = function (opts, defaultOpts) { - var defaultCompress = (defaultOpts != null && defaultOpts.compress) || false; - var defaultKeyAutoGenerate = (defaultOpts != null && defaultOpts.keyAutoGenerate) || null; - var defaultKeyGetter = (defaultOpts != null && defaultOpts.keyGetter) || null; - var defaultKeyColumn = (defaultOpts != null && defaultOpts.keyColumn) || null; - var defaultGroupByKey = (defaultOpts != null && defaultOpts.groupByKey) || null; - var defaultDataColumnName = (defaultOpts != null && defaultOpts.dataColumnName) || null; - var defaultChunkSize = (defaultOpts != null && defaultOpts.maxObjectsPerChunk) || null; - var defaultDeleteIfExists = (defaultOpts != null && defaultOpts.deleteIfExists) || false; - return { - compress: opts != null ? opts.compress : defaultCompress, - keyAutoGenerate: opts != null ? opts.keyAutoGenerate : defaultKeyAutoGenerate, - keyGetter: opts != null ? opts.keyGetter : defaultKeyGetter, - keyColumn: opts != null ? opts.keyColumn : defaultKeyColumn, - groupByKey: opts != null ? opts.groupByKey : defaultGroupByKey, - dataColumnName: opts != null ? (opts.dataColumnName || defaultDataColumnName) : defaultDataColumnName, - maxObjectsPerChunk: opts != null ? (opts.maxObjectsPerChunk || defaultChunkSize) : defaultChunkSize, - deleteIfExists: opts != null ? opts.deleteIfExists : defaultDeleteIfExists, - }; - }; - /** Create a timer that uses window.performance.now() - * @param name the new timer's name - */ - DbUtil.newTimer = function (name) { - var useWnd = typeof window !== "undefined"; - var startMillis = (useWnd ? window.performance.now() : new Date().getTime()); - var inst = { - name: name, - startMillis: startMillis, - endMillis: null, - measure: function () { - var endMillis = (useWnd ? window.performance.now() : new Date().getTime()); - var durationMillis = endMillis - startMillis; - inst.endMillis = endMillis; - return durationMillis; - }, - }; - return inst; - }; - /** Predefined log verbosity levels: - * `log.NONE`: No logging. - * `log.ERROR`: Log errors. - * `log.DEBUG`: Verbose logging. - */ - DbUtil.logLevels = { - NONE: 0, - ERROR: 1, - DEBUG: 2 - }; - return DbUtil; -}()); -module.exports = DbUtil; - -},{}],3:[function(require,module,exports){ -"use strict"; -var Arrays = require("ts-mortar/utils/Arrays"); -var DbUtil = require("./DbUtil"); -/* IndexedDbPersister class which implements 'DataPersister' for saving data to IndexedDB for long-term browser data storage. - * Exports 'IndexedDbSpi' interface which has two methods: getTables() and executeQueries(), which is the link between this 'IndexedDbPersister' class and the underlying IndexedDB database. - * @author TeamworkGuy2 - */ -var IndexedDbPersister = /** @class */ (function () { - /** Create a DataPersister based on an IndexedDB instance and some additional functions to control the behavior of this persister. - * @param persistenceInterface the underlying database to persist to - * @param trace the object with functions for logging debug messages and errors - * @param getDataCollections returns a list of data collections that contain the data to persist/restore to - * @param addCollection when restoring a database, call this function with each table name found and restored documents - * @param saveItemTransformation optional conversion function to pass items from 'getDataCollections()' through before persisting them - * @param restoreItemTransformation optional conversion function to pass items through after restoring them and before storing them in 'getDataCollections()' - * @param storageFailureCallback callback for handling/logging storage errors - * @param tablesToNotClear optional array of collection names to not clear when 'clearPersistentDb()' is called - * @param tablesToNotLoad optional array of collection names to not load when 'restore()' is called - */ - function IndexedDbPersister(persistenceInterface, trace, getDataCollections, addCollection, saveItemTransformation, restoreItemTransformation, storageFailureCallback, tablesToNotClear, tablesToNotLoad) { - this.tablesToNotClear = []; - this.tablesToNotLoad = []; - this.persistenceInterface = persistenceInterface; - this.logger = trace; - this.itemSaveConverter = saveItemTransformation; - this.itemLoadConverter = restoreItemTransformation; - this.getDataCollections = getDataCollections; - this.addCollection = addCollection; - this.storageFailureCallback = storageFailureCallback; - this.tablesToNotClear = tablesToNotClear || []; - this.tablesToNotLoad = tablesToNotLoad || []; - } - /** Get a list of collection names in this data persister - */ - IndexedDbPersister.prototype.getCollectionNames = function () { - return this.persistenceInterface.getTables(); - }; - /** Save this in-memory database to some form of persistent storage - * Removes tables from store that don't exist in in-memory db - */ - IndexedDbPersister.prototype.persist = function (defaultOptions, getCollectionOptions) { - var that = this; - var colls = that.getDataCollections(); - var persistCount = 0; - return this.persistenceInterface.getTables().then(function (collNames) { - var tableAdds = []; - var tableDels = []; - var tableInserts = []; - colls.forEach(function (coll) { - var opts = DbUtil.getOptionsOrDefault(getCollectionOptions != null ? getCollectionOptions(coll.name) : null, defaultOptions); - var exists = collNames.indexOf(coll.name) !== -1; - var keyCol = opts.keyColumn != null ? (typeof opts.keyColumn === "string" ? opts.keyColumn : opts.keyColumn.name) : null; - var autoIncrement = opts.keyAutoGenerate; - if (opts.deleteIfExists && exists) { - tableDels.push({ name: coll.name }); - tableAdds.push({ name: coll.name, keyPath: keyCol, autoIncrement: autoIncrement }); - } - if (!exists) { - tableAdds.push({ name: coll.name, keyPath: keyCol, autoIncrement: autoIncrement }); - } - if (coll.dirty) { - persistCount++; - if (coll.data.length > 0) { - var collData = that.prepDataForSave(coll.data, opts.maxObjectsPerChunk, opts.groupByKey, opts.keyGetter); - tableInserts.push({ name: coll.name, clear: exists, records: collData }); - } - else { - tableInserts.push({ name: coll.name, clear: exists }); - } - } - }); - return that.persistenceInterface.modifyDatabase(tableDels, tableAdds, tableInserts); - }).then(function (rs) { - var persistRes = { - collections: {} - }; - rs.inserts.forEach(function (insert) { - // reset collection 'dirty' flag after data successfully saved - var coll = colls.find(function (x) { return x.name === insert.name; }); - if (coll != null) { - coll.dirty = false; - } - persistRes.collections[insert.name] = { - size: insert.added, - dataSizeBytes: null - }; - }); - return persistRes; - }); - }; - /** Restore in-memory database from persistent store - * All in memory tables are dropped and re-added - */ - IndexedDbPersister.prototype.restore = function (defaultOptions, getCollectionOptions) { - var that = this; - var restoreRes = { - collections: {} - }; - return this.persistenceInterface.getTables().then(function (tables) { - var tablesToLoad = tables.filter(function (tbl) { return that.tablesToNotLoad.indexOf(tbl) === -1; }).map(function (tbl) { return ({ name: tbl }); }); - return that.getCollectionsRecords(tablesToLoad); - }).then(function (results) { - results.forEach(function (result) { - var rows = result.records; - var docs = []; - if (rows.length > 0) { - var opts = getCollectionOptions != null ? getCollectionOptions(result.name) : null; - var expectArrayRes = (opts == null || opts.isChunks); - docs = that.readRecords(result.records, expectArrayRes); - } - else { - //if (that.logger != null) that.logger.log("skip restoring table: " + tableName + " (0 items)"); - } - restoreRes.collections[result.name] = { - size: docs.length, - dataSizeBytes: null - }; - that.addCollection(result.name, docs); - }); - return restoreRes; - }, function (err) { - throw err; - }); - }; - /** Get all data from a specific collection - */ - IndexedDbPersister.prototype.getCollectionRecords = function (collectionName, options) { - return this.getCollectionsRecords([{ name: collectionName, options: options }]).then(function (r) { return r[0].records; }); - }; - IndexedDbPersister.prototype.getCollectionsRecords = function (collections) { - var collectionNames = Arrays.pluck(collections, "name"); - var xact = this.persistenceInterface.db.transaction(collectionNames, "readonly"); - var recordsXacts = collections.map(function (coll) { return ({ name: coll.name, getAll: xact.objectStore(coll.name).getAll() }); }); - var dfd = this.persistenceInterface.util.defer(); - xact.oncomplete = function onIdbSuccess(evt) { - var notDoneXacts = recordsXacts.filter(function (x) { return x.getAll.readyState !== "done"; }); - if (notDoneXacts.length > 0) { - throw new Error(notDoneXacts.length + " transactions are not done in 'oncomplete' callback"); - } - var results = recordsXacts.map(function (x) { return ({ name: x.name, records: x.getAll.result }); }); - dfd.resolve(results); - }; - function onIdbError(evt) { - dfd.reject(xact.error); - } - xact.onerror = onIdbError; - xact.onabort = onIdbError; - return dfd.promise; - }; - /** Add data to a specific collection - */ - IndexedDbPersister.prototype.addCollectionRecords = function (collectionName, options, records, removeExisting) { - var data = this.prepDataForSave(records, options.maxObjectsPerChunk, options.groupByKey, options.keyGetter); - return this.persistenceInterface.insertMultiple([{ - name: collectionName, - clear: removeExisting, - records: data - }]).then(function (rs) { return ({ size: rs.inserts[0].added, dataSizeBytes: null }); }); - }; - /** Remove all data from the specificed collections - */ - IndexedDbPersister.prototype.clearCollections = function (collectionNames) { - var clearColls = collectionNames.map(function (collName) { return ({ name: collName, clear: true }); }); - return this.persistenceInterface.insertMultiple(clearColls); - }; - /** Delete all data related this database from persistent storage - */ - IndexedDbPersister.prototype.clearPersistentDb = function () { - var _this = this; - return this.persistenceInterface.getTables().then(function (tables) { - var delColls = tables - .filter(function (tbl) { return _this.tablesToNotClear.indexOf(tbl) === -1; }) - .map(function (tbl) { return ({ name: tbl }); }); - return _this.persistenceInterface.modifyDatabase(delColls, null, null); - }); - }; - IndexedDbPersister.prototype.readRecords = function (rows, expectArrayRes) { - var convertFunc = this.itemLoadConverter; - var docs = []; - for (var i = 0, size = rows.length; i < size; i++) { - var dataBlob = rows[i]; - var resChunks = []; - if (convertFunc != null) { - if (expectArrayRes && Array.isArray(dataBlob)) { - for (var j = 0, sizeJ = dataBlob.length; j < sizeJ; j++) { - resChunks.push(convertFunc(dataBlob[j])); - } - } - else { - resChunks.push(convertFunc(dataBlob)); - } - } - else { - if (expectArrayRes && Array.isArray(dataBlob)) { - resChunks = dataBlob; - } - else { - resChunks.push(dataBlob); - } - } - Array.prototype.push.apply(docs, resChunks); - } - return docs; - }; - IndexedDbPersister.prototype.prepDataForSave = function (items, chunkSize, groupByKey, keyGetter) { - var resItems = items; - if (this.itemSaveConverter != null) { - var convertFunc = this.itemSaveConverter; - resItems = []; - for (var j = 0, sizeJ = items.length; j < sizeJ; j++) { - resItems.push(convertFunc(items[j])); - } - } - var data = []; - // records by chunks - if (chunkSize > 0) { - for (var i = 0, size = resItems.length; i < size; i += chunkSize) { - data.push(resItems.slice(i, i + chunkSize > size ? size : i + chunkSize)); - } - } - // records by group-by - else if (groupByKey != null && keyGetter != null) { - var groups; - if (typeof keyGetter === "string") { - groups = resItems.reduce(function (grps, rec) { - var key = rec[keyGetter]; - var grp = grps[key] || (grps[key] = []); - grp.push(rec); - return grps; - }, {}); - } - else { - groups = resItems.reduce(function (grps, rec) { - var key = keyGetter(rec); - var grp = grps[key] || (grps[key] = []); - grp.push(rec); - return grps; - }, {}); - } - data = Object.keys(groups).map(function (k) { return groups[k]; }); - } - // records as-is from collection.data array - else { - Array.prototype.push.apply(data, resItems); - } - return data; - }; - return IndexedDbPersister; -}()); -module.exports = IndexedDbPersister; - -},{"./DbUtil":2,"ts-mortar/utils/Arrays":1}],4:[function(require,module,exports){ -"use strict"; -var DbUtil = require("./DbUtil"); -var IndexedDbSpi = /** @class */ (function () { - function IndexedDbSpi(db, util) { - this.db = db; - this.util = util; - } - IndexedDbSpi.prototype.getDatabase = function () { - return this.db; - }; - IndexedDbSpi.prototype.getTables = function () { - var names = []; - Array.prototype.push.apply(names, this.db.objectStoreNames); - var dfd = this.util.defer(); - dfd.resolve(names); - return dfd.promise; - }; - IndexedDbSpi.prototype.insertMultiple = function (collectionInserts) { - var res = { - inserts: [], - insertErrors: [] - }; - return IndexedDbSpi.inserts(this.db, this.util, collectionInserts, res); - }; - /** All-in-one function to remove IndexedDB stores, add new stores, and insert records into stores. - * This function handles bumping the DB version to trigger an 'onupgrade' callback to add and remove stores. - * @param tableDels optional list of stores to remove from the DB, these run first - * @param tableAdds optional list of stores to add to the DB, these run second - * @param tableInserts optional list of data insertions to run against the DB, these run third (after table deletes/creates) - */ - IndexedDbSpi.prototype.modifyDatabase = function (tableDels, tableAdds, tableInserts) { - var inst = this; - var name = this.db.name; - var version = this.db.version; - this.db.close(); - var res = { - createdStores: [], - createErrors: [], - deletedStores: [], - deleteErrors: [], - inserts: [], - insertErrors: [] - }; - var hasSchemaChanges = (tableAdds != null && tableAdds.length > 0) || (tableDels != null && tableDels.length > 0); - // upgrade the DB version to trigger an 'onupgradeneeded' call so we can create and/or delete object stores - return IndexedDbSpi.openDatabase(this.util, name, hasSchemaChanges ? version + 1 : version, function versionUpgrade(evt) { - // Database modifications must be performed within 'onupgrade' callback - var db = this.result; - inst.db = db; - // delete stores (first so that create stores can re-create stores) - (tableDels || []).forEach(function (tbl) { - try { - db.deleteObjectStore(tbl.name); - res.deletedStores.push(tbl); - } - catch (err) { - res.deleteErrors.push({ name: tbl.name, error: err }); - } - }); - // create stores - (tableAdds || []).forEach(function (tbl) { - try { - var createRes = db.createObjectStore(tbl.name, tbl); - res.createdStores.push(createRes); - } - catch (err) { - res.createErrors.push({ name: tbl.name, error: err }); - } - }); - }).then(function () { return IndexedDbSpi.inserts(inst.db, inst.util, tableInserts, res); }); - }; - IndexedDbSpi.prototype.destroyDatabase = function () { - var dfd = this.util.defer(); - var dbDelReq = self.indexedDB.deleteDatabase(this.db.name); - wrapRequest(dbDelReq, function destroyDbSuccess(evt) { - dfd.resolve(null); - }, function destroyDbError(evt) { - dfd.reject(dbDelReq.error); - }); - return dfd.promise; - }; - IndexedDbSpi.addOrPut = function (dbColl, tbl) { - if (tbl.records == null) { - return; - } - // TODO for now just calling put()/add() in a loop and not waiting on the resulting request to complete before inserting the next - if (tbl.overwrite) { - if (tbl.keyGetter != null) { - for (var i = 0, size = tbl.records.length; i < size; i++) { - dbColl.put(tbl.records[i], tbl.keyGetter(tbl.records[i])); - } - } - else { - for (var i = 0, size = tbl.records.length; i < size; i++) { - dbColl.put(tbl.records[i]); - } - } - } - else { - if (tbl.keyGetter != null) { - for (var i = 0, size = tbl.records.length; i < size; i++) { - dbColl.add(tbl.records[i], tbl.keyGetter(tbl.records[i])); - } - } - else { - for (var i = 0, size = tbl.records.length; i < size; i++) { - dbColl.add(tbl.records[i]); - } - } - } - }; - IndexedDbSpi.inserts = function (db, util, tableInserts, res) { - if (tableInserts == null) { - return res; - } - var pInserts = util.defer(); - var insertCount = tableInserts.length; - var insertsDone = 0; - // insert records into stores - tableInserts.forEach(function (tbl) { - var insertErrors = []; - var xact = db.transaction(tbl.name, "readwrite"); - var dbColl = xact.objectStore(tbl.name); - var clearedCount = 0; - if (tbl.clear) { - // get record count and clear the store - var countReq = dbColl.count(); - countReq.onsuccess = function onIdbSuccess(evt) { - var clearReq = dbColl.clear(); - clearReq.onsuccess = function onIdbSuccess(evt) { - clearedCount = countReq.result; - // add new records - IndexedDbSpi.addOrPut(dbColl, tbl); - }; - clearReq.onerror = function onIdbSuccess(evt) { - insertErrors.push(clearReq.error); - xact.abort(); - }; - }; - countReq.onerror = function onIdbSuccess(evt) { - insertErrors.push(countReq.error); - xact.abort(); - }; - } - else { - // add new records - IndexedDbSpi.addOrPut(dbColl, tbl); - } - xact.oncomplete = function onIdbSuccess(evt) { - res.inserts.push({ name: tbl.name, added: tbl.records != null ? tbl.records.length : 0, removed: clearedCount }); - insertsDone++; - if (insertsDone >= insertCount) { - pInserts.resolve(res); - } - }; - function onIdbError(evt) { - insertErrors.push(xact.error); - res.insertErrors.push({ name: tbl.name, errors: insertErrors }); - insertsDone++; - pInserts.reject(xact.error); - } - xact.onerror = onIdbError; - xact.onabort = onIdbError; - }); - return pInserts.promise; - }; - IndexedDbSpi.openDatabase = function (util, name, version, onupgradeneeded) { - util.log(util.DEBUG, "openDatabase", name, version); - var dfd = util.defer(); - var pUpgrade; - try { - if (typeof self === "undefined" || !self.indexedDB) { - util.rejectError(dfd, "IndexedDB not implemented"); - } - else { - var dbOpenReq = (version != null ? self.indexedDB.open(name, version) : self.indexedDB.open(name)); - wrapRequest(dbOpenReq, function openDbSuccess(evt) { - if (pUpgrade != null) { - pUpgrade.then(function (r) { return dfd.resolve(dbOpenReq.result); }, function (err) { return util.rejectError(dfd, "onupgradeneeded handler failed", { exception: err }); }); - } - else { - dfd.resolve(dbOpenReq.result); - } - }, function openDbError(evt) { - util.rejectError(dfd, "Failed to open database", { exception: dbOpenReq.error }); - }, function dbUpgradeNeeded(evt) { - // triggered when opening a new DB or an existing DB with a higher version number than last time it was opened - util.log(util.DEBUG, "upgradeNeeded", name, version); - if (onupgradeneeded != null) { - var onUpgradeRes = onupgradeneeded.call(this, evt); - if (util.isPromise(onUpgradeRes)) { - pUpgrade = onUpgradeRes; - } - } - }); - } - } - catch (ex) { - util.rejectError(dfd, "Failed to open database " + name, { exception: ex }); - } - return dfd.promise; - }; - IndexedDbSpi.newIndexedDb = function (name, version, utilSettings) { - var util = new DbUtil("IndexedDB", "[object IDBDatabase]", utilSettings); - // Create IndexedDB wrapper from native Database or by opening 'name' DB - var pOpen; - if (util.isDatabase(name)) { - var dfd = util.defer(); - dfd.resolve(name); - pOpen = dfd.promise; - } - else { - pOpen = IndexedDbSpi.openDatabase(util, name, version); - } - return pOpen.then(function (dbInst) { return new IndexedDbSpi(dbInst, util); }); - }; - return IndexedDbSpi; -}()); -function isOpenDbRequest(dbReq) { - return "onupgradeneeded" in dbReq; -} -function wrapRequest(dbReq, onsuccess, onerror, onupgradeneeded) { - dbReq.onsuccess = onsuccess; - dbReq.onerror = onerror; - if (isOpenDbRequest(dbReq)) { - if (onupgradeneeded == null) { - throw new Error("must provide an onupgradeneeded handler for open DB requests"); - } - dbReq.onupgradeneeded = onupgradeneeded; - dbReq.onblocked = onerror; - } - return dbReq; -} -module.exports = IndexedDbSpi; - -},{"./DbUtil":2}],5:[function(require,module,exports){ -"use strict"; -var Arrays = require("ts-mortar/utils/Arrays"); -var DbUtil = require("./DbUtil"); -/** WebSqlPersister class which implements 'DataPersister' for saving data to WebSQL for long-term browser data storage. - * Exports 'WebSqlSpi' interface which has two methods: getTables() and executeQueries(), which is the link between this 'WebSqlPersister' class and the underlying WebSQL database. - * @author TeamworkGuy2 - */ -var WebSqlPersister = /** @class */ (function () { - /** Create a DataPersister based on a WebSqlSpi instance and some additional functions to control the behavior of this persister. - * @param persistenceInterface the underlying database to persist to - * @param trace the object with functions for logging debug messages and errors - * @param getDataCollections returns a list of data collections that contain the data to persist/restore to - * @param addCollection when restoring a database, call this function with each table name found and restored documents - * @param saveItemTransformation optional conversion function to pass items from 'getDataCollections()' through before persisting them - * @param postSaveTransformKeyValueFilter optional JSON.stringify() 'replacer', second parameter, function which is called for each object stringified by calls to persist() - * @param restoreItemTransformation optional conversion function to pass items through after restoring them and before storing them in 'getDataCollections()' - * @param storageFailureCallback callback for handling/logging storage errors - * @param tablesToNotClear optional array of collection names to not clear when 'clearPersistentDb()' is called - * @param tablesToNotLoad optional array of collection names to not load when 'restore()' is called - */ - function WebSqlPersister(persistenceInterface, trace, getDataCollections, addCollection, saveItemTransformation, postSaveTransformKeyValueFilter, restoreItemTransformation, storageFailureCallback, tablesToNotClear, tablesToNotLoad) { - this.tablesToNotClear = []; - this.tablesToNotLoad = []; - this.persistenceInterface = persistenceInterface; - this.logger = trace; - this.itemSaveConverter = saveItemTransformation; - this.itemKeyValueFilter = postSaveTransformKeyValueFilter; - this.itemLoadConverter = restoreItemTransformation; - this.getDataCollections = getDataCollections; - this.addCollection = addCollection; - this.storageFailureCallback = storageFailureCallback; - this.tablesToNotClear = tablesToNotClear || []; - this.tablesToNotLoad = tablesToNotLoad || []; - } - /** Persist in-memory database to disk - * Removes tables from store that don't exist in in-memory db - */ - WebSqlPersister.prototype.persist = function (defaultOptions, getCollectionOptions) { - var that = this; - var timerId = DbUtil.newTimer("persist"); - var dfd = this.persistenceInterface.util.defer(); - var persistCount = 0; - var persistData = { - collections: {} - }; - function addOrUpdatePersistInfo(collName, addSize, addDataSizeBytes) { - if (persistData.collections[collName] == null) { - persistData.collections[collName] = { - size: addSize, - dataSizeBytes: addDataSizeBytes - }; - } - else { - var collPersistInfo = persistData.collections[collName]; - collPersistInfo.size = collPersistInfo.size + addSize; - collPersistInfo.dataSizeBytes = collPersistInfo.dataSizeBytes + addDataSizeBytes; - } - } - // add new tables and remove tables that do not have collections - this.persistenceInterface.getTables().then(function (tables) { - var tableNames = Arrays.pluck(tables, "name"); - var promises = []; - var colls = that.getDataCollections(); - colls.forEach(function (coll) { - var sqls = []; - var opts = DbUtil.getOptionsOrDefault(getCollectionOptions != null ? getCollectionOptions(coll.name) : null, defaultOptions); - var exists = tableNames.indexOf(coll.name) !== -1; - if (opts.deleteIfExists && exists) { - sqls.push({ sql: "DROP TABLE " + coll.name, args: [] }); - sqls.push({ sql: "CREATE TABLE " + coll.name + " (" + (opts.keyColumn != null ? opts.keyColumn.name + " " + opts.keyColumn.type + ", " : "") + opts.dataColumnName + " blob)", args: [] }); - } - if (!exists) { - sqls.push({ sql: "CREATE TABLE IF NOT EXISTS " + coll.name + " (" + (opts.keyColumn != null ? opts.keyColumn.name + " " + opts.keyColumn.type + ", " : "") + opts.dataColumnName + " blob)", args: [] }); - } - if (coll.dirty) { - if (exists) { - sqls.push({ sql: "DELETE FROM " + coll.name, args: [] }); - } - persistCount++; - // create the sql statements - if (coll.data.length > 0) { - var res = that.createInsertStatements(coll.name, coll.data, opts.keyGetter, opts.keyColumn && opts.keyColumn.name, opts.groupByKey, opts.maxObjectsPerChunk, opts.compress); - addOrUpdatePersistInfo(coll.name, res.itemCount, res.jsonSize); - sqls.push({ sql: res.sql, args: res.args }); - } - coll.dirty = false; - } - if (sqls.length > 0) { - var collPromise = that.persistenceInterface.executeQueries(sqls); - promises.push(collPromise); - } - }); - return that.persistenceInterface.util.whenAll(promises); - }).then(function (results) { - if (persistCount > 0) { - var timeMs = timerId.measure(); - var totalWriteSize = Object.keys(persistData.collections).reduce(function (prev, collName) { return prev + persistData.collections[collName].dataSizeBytes; }, 0); - if (that.logger != null) - that.logger.log("Data saved: ", Math.floor(timeMs), "(ms), ", totalWriteSize, "(bytes), meta-info: ", persistData.collections); - } - dfd.resolve(persistData); - }, function (error) { - if (error.sqlError && error.sqlError.message && error.sqlError.message.indexOf("there was not enough remaining storage space") > -1) { - if (that.storageFailureCallback) { - that.storageFailureCallback(error); - } - } - dfd.reject(error); - }); - return dfd.promise; - }; - /** Restore in-memory database from persistent storage. - * All in memory tables are dropped and re-added - */ - WebSqlPersister.prototype.restore = function (defaultOptions, getCollectionOptions) { - var that = this; - var timerId = DbUtil.newTimer("restore"); - var defaultDecompress = (defaultOptions != null && defaultOptions.decompress) || false; - var dfd = this.persistenceInterface.util.defer(); - var restoreRes = { - collections: {} - }; - var tableNames = []; - this.persistenceInterface.getTables().then(function (tables) { - tableNames = Arrays.pluck(tables, "name").filter(function (n) { return that.tablesToNotLoad.indexOf(n) === -1; }); - var sqls = tables.filter(function (t) { return that.tablesToNotLoad.indexOf(t.name) === -1; }) - .map(function (table) { return ({ sql: "SELECT * FROM " + table.name, args: [] }); }); - return that.persistenceInterface.executeQueries(sqls); - }).then(function (results) { - results.forEach(function (result, tableIndex) { - var tableName = tableNames[tableIndex]; - var docs = []; - var res = { - size: 0, - dataSizeBytes: 0 - }; - if (result.rows.length > 0) { - var opts = getCollectionOptions != null ? getCollectionOptions(tableName) : null; - var decompress = opts != null ? opts.decompress || defaultDecompress : defaultDecompress; - var dataColumnName = opts != null ? opts.dataColumnName || WebSqlPersister.defaultDataColumnName : WebSqlPersister.defaultDataColumnName; - // check whether the row format has our required column - if (result.rows.item(0)[dataColumnName]) { - docs = that.readRecords(result.rows, dataColumnName, decompress, opts == null || opts.isChunks, res); - } - else { - if (that.logger != null && that.logger.error != null) - that.logger.error("skip restoring table: " + tableName + " (unrecognized data format)"); - } - } - else { - //if (that.logger != null) that.logger.log("skip restoring table: " + tableName + " (0 items)"); - } - res.size = docs.length; - restoreRes.collections[tableName] = res; - that.addCollection(tableName, docs); - }); - var timeMs = timerId.measure(); - if (that.logger != null) - that.logger.log("Data loaded", Math.floor(timeMs), "(ms)"); - dfd.resolve(restoreRes); - }, function (err) { - dfd.reject(err); - }); - return dfd.promise; - }; - /** Get a list of collection names in this data persister - */ - WebSqlPersister.prototype.getCollectionNames = function () { - return this.persistenceInterface.getTables().then(function (tbls) { return tbls.map(function (t) { return t.name; }); }); - }; - /** Get all data from a specific collection - */ - WebSqlPersister.prototype.getCollectionRecords = function (collectionName, options) { - var that = this; - var sqls = [{ sql: "SELECT * FROM " + collectionName, args: [] }]; - return this.persistenceInterface.executeQueries(sqls).then(function (_a) { - var result = _a[0]; - var docs = []; - if (result.rows.length > 0) { - var decompress = options != null ? options.decompress || false : false; - var dataColumnName = options != null ? options.dataColumnName || WebSqlPersister.defaultDataColumnName : WebSqlPersister.defaultDataColumnName; - // check whether the row formats has our required column - if (result.rows.item(0)[dataColumnName]) { - docs = that.readRecords(result.rows, dataColumnName, decompress, options == null || options.isChunks); - } - else { - if (that.logger != null && that.logger.error != null) - that.logger.error("skip restoring table: " + collectionName + " (unrecognized data format)"); - } - } - return docs; - }); - }; - /** Add data to a specific collection - */ - WebSqlPersister.prototype.addCollectionRecords = function (collectionName, options, records, removeExisting) { - var opts = DbUtil.getOptionsOrDefault(options, { compress: false, maxObjectsPerChunk: WebSqlPersister.MAX_OBJECTS_PER_PERSIST_RECORD }); - var res = records.length > 0 ? this.createInsertStatements(collectionName, records, opts.keyGetter, opts.keyColumn && opts.keyColumn.name, opts.groupByKey, opts.maxObjectsPerChunk, opts.compress) : null; - var sqls = []; - if (removeExisting) { - sqls.push({ sql: "DELETE FROM " + collectionName, args: [] }); - } - if (records.length > 0) { - sqls.push({ sql: res.sql, args: res.args }); - } - return this.persistenceInterface.executeQueries(sqls).then(function (_a) { - var result = _a[0]; - return (res != null ? { size: res.itemCount, dataSizeBytes: res.jsonSize } : { size: 0, dataSizeBytes: 0 }); - }); - }; - /** Remove all data from the specificed collections - */ - WebSqlPersister.prototype.clearCollections = function (collectionNames) { - var sqls = collectionNames.map(function (collName) { return ({ sql: "DELETE FROM " + collName, args: [] }); }); - return this.persistenceInterface.executeQueries(sqls).then(function (results) { return null; }); - }; - /** Delete all data related this database from persistent storage - */ - WebSqlPersister.prototype.clearPersistentDb = function () { - var _this = this; - var timerId = DbUtil.newTimer("clear"); - var dfd = this.persistenceInterface.util.defer(); - this.persistenceInterface.getTables().then(function (tables) { - var sqls = tables - .filter(function (t) { return _this.tablesToNotClear.indexOf(t.name) === -1; }) - .map(function (table) { return ({ sql: "DROP TABLE " + table.name, args: [] }); }); - return _this.persistenceInterface.executeQueries(sqls); - }).then(function (sqls) { - var timeMs = timerId.measure(); - if (_this.logger != null) - _this.logger.log("Data cleared", Math.floor(timeMs), "(ms)"); - dfd.resolve(null); - }, function (err) { - dfd.reject(err); - }); - return dfd.promise; - }; - /** Reads rows from a SqlResultSetRowList. First each row's 'dataColumnName' column is parsed via JSON.parse(), then the data is processed as follows: - * - if the parsed data is an array, assume it's an array of data models, if an 'itemLoadConverter' function was provided in the constructor, use it to convert each object, else return the array of objects - * - if the parsed data is not an array, assume it is a single data model, if an 'itemLoadConverter' function was provided in the constructor, use it to convert the object, else return the object - * Note: because of this logic, using an array as a data model will not produce correct results since the array will be assumed to contain multiple individual data objects - * @param rows the result set rows to process - * @param dataColumnName the name of the column containing the model data - * @param decompress (currently not supported) whether data strings should be decompressed or not - * @param expectArrayRes whether data strings are expected to be array chunks with the actual data records inside - * @param res optional stats object in which to store info about the rows read - */ - WebSqlPersister.prototype.readRecords = function (rows, dataColumnName, decompress, expectArrayRes, res) { - var convertFunc = this.itemLoadConverter; - var docs = []; - for (var i = 0, size = rows.length; i < size; i++) { - var dataBlob = rows.item(i)[dataColumnName]; - if (res != null) { - res.dataSizeBytes += dataBlob.length; - } - if (decompress) { - //dataBlob = pako.inflate(dataBlob, { to: "string" }); - } - // NOTE: may throw error - var chunks = JSON.parse(dataBlob); - var resChunks = []; - if (convertFunc != null) { - if (expectArrayRes && Array.isArray(chunks)) { - for (var j = 0, sizeJ = chunks.length; j < sizeJ; j++) { - resChunks.push(convertFunc(chunks[j])); - } - } - else { - resChunks.push(convertFunc(chunks)); - } - chunks = null; - } - else { - if (expectArrayRes && Array.isArray(chunks)) { - resChunks = chunks; - } - else { - resChunks.push(chunks); - } - } - Array.prototype.push.apply(docs, resChunks); - } - return docs; - }; - WebSqlPersister.prototype.createInsertStatements = function (collName, items, keyGetter, keyColumn, groupByKey, chunkSize, compress) { - var sql; - var sqlArgs = []; - var resItems = items; - if (this.itemSaveConverter != null) { - var convertFunc = this.itemSaveConverter; - resItems = []; - for (var j = 0, sizeJ = items.length; j < sizeJ; j++) { - resItems.push(convertFunc(items[j])); - } - } - var itemCount = 0; - var jsonSize = 0; - // records by chunks - if (keyGetter == null && chunkSize > 0) { - sql = "INSERT INTO " + collName + " VALUES(?)"; - for (var i = 0, sz = resItems.length; i < sz; i += chunkSize) { - var data = resItems.slice(i, i + chunkSize); - var jsonData = JSON.stringify(data, this.itemKeyValueFilter); - if (compress) { - //jsonData = pako.deflate(jsonData, { to: "string" }); - } - itemCount += data.length; - jsonSize += jsonData.length; - sqlArgs.push([jsonData]); - } - } - // records by group-by - else if (keyGetter != null && groupByKey != null) { - sql = "INSERT INTO " + collName + (keyColumn != null ? " VALUES(?,?)" : " VALUES(?)"); - if (typeof keyGetter === "string") { - var uniqueKeyLists = resItems.reduce(function (mp, itm) { - var value = itm[keyGetter]; - var ary = (mp[value] || (mp[value] = [])); - ary.push(itm); - return mp; - }, {}); - } - else { - var uniqueKeyLists = resItems.reduce(function (mp, itm) { - var value = keyGetter(itm); - var ary = (mp[value] || (mp[value] = [])); - ary.push(itm); - return mp; - }, {}); - } - for (var key in uniqueKeyLists) { - var data = uniqueKeyLists[key]; - var jsonData = JSON.stringify(data, this.itemKeyValueFilter); - itemCount += data.length; - jsonSize += jsonData.length; - sqlArgs.push(keyColumn != null ? [key, jsonData] : [jsonData]); - } - } - // records by key - else if (keyGetter != null) { - sql = "INSERT INTO " + collName + (keyColumn != null ? " VALUES(?,?)" : " VALUES(?)"); - if (typeof keyGetter === "string") { - for (var i = 0, sz = resItems.length; i < sz; i++) { - var datum = resItems[i]; - var jsonData = JSON.stringify(datum, this.itemKeyValueFilter); - var keyVal = datum[keyGetter]; - itemCount += 1; - jsonSize += jsonData.length; - sqlArgs.push(keyColumn != null ? [keyVal, jsonData] : [jsonData]); - } - } - else { - for (var i = 0, sz = resItems.length; i < sz; i++) { - var datum = resItems[i]; - var jsonData = JSON.stringify(datum, this.itemKeyValueFilter); - var key = keyGetter(datum); - itemCount += 1; - jsonSize += jsonData.length; - sqlArgs.push(keyColumn != null ? [key, jsonData] : [jsonData]); - } - } - } - else { - throw new Error("unsupported persist options combination: keyGetter=" + keyGetter + ", keyColumn=" + keyColumn + ", groupByKey=" + groupByKey + ", chunkSize=" + chunkSize); - } - return { sql: sql, args: sqlArgs, itemCount: itemCount, jsonSize: jsonSize }; - }; - WebSqlPersister.MAX_OBJECTS_PER_PERSIST_RECORD = 1000; - WebSqlPersister.defaultDataColumnName = "bigString"; - return WebSqlPersister; -}()); -module.exports = WebSqlPersister; - -},{"./DbUtil":2,"ts-mortar/utils/Arrays":1}],6:[function(require,module,exports){ -"use strict"; -/// -var DbUtil = require("./DbUtil"); -/*! websql.js | MIT license | Stepan Riha | http://bitbucket.org/nonplus/websql-js - * websql.js may be freely distributed under the MIT license. - * converted to TypeScript at 2017-11-04 by TeamworkGuy2 - */ -/** Module that wraps asynchronous WebSQL calls with deferred promises and provides SQL utility methods. - * - * Promises are **resolved** when asynchronous database callback is finished. - * Promises are **rejected** with an `Error` object that may contain one or more of the following: - * - `message`: Describing what failed - * - `exception`: Exception that was thrown - * - `sqlError`: Error returned by WebSQL - * - `sql`: statement that was executing - * - * ## Using the API - * Example: - * var wsdb = WebSqlSpi.newWebSqlDb(nameOrDbInst, _version_, _displayName_, _estimatedSize_, utilSettings); - * wsdb.read({ sql: "SELECT * FROM ..." }).then(function(resultSet) { ... }); - * - * ## Public Methods ## - * - `newWebSqlDb(nameOrDb, ...)` takes the same parameters as the `window.openDatabase` function, and used default values for unspecified parameters. - * Returns: new a promise which resolves with the new `WebsqlDatabase` wrapper class. - * Usage: - * var wsdb = WebSqlSpi.newWebSqlDb("test", 1, "Test Database", 2 * 1024 * 1024, new DbUtil(...)); - * wsdb.execute({ sql: "INSERT INTO ...", args: [...] }).then(function(resultSet) { ... }) - */ -var WebSqlSpi = /** @class */ (function () { - function WebSqlSpi(db, util) { - this.db = db; - this.util = util; - this.transaction = this.transaction.bind(this); - this.readTransaction = this.readTransaction.bind(this); - } - /** Returns: promise that resolves once the database version has been changed - * Usage: - * wsdb.changeVersion(1, 2, function (xact) { - * xact.executeSQL(...); - * }).then(function() {...}); - */ - WebSqlSpi.prototype.changeVersion = function (oldVersion, newVersion, xactCallback) { - var util = this.util; - var dfd = util.defer(); - if (!util.isDatabase(this.db)) { - util.rejectError(dfd, "Database not specified (db='" + this.db + "')"); - return dfd.promise; - } - util.log(util.DEBUG, "changeVersion", oldVersion, newVersion); - try { - this.db.changeVersion("" + oldVersion, "" + newVersion, xactCallback, function (sqlError) { - util.rejectError(dfd, "Failed to change version", { sqlError: sqlError }); - }, function () { - dfd.resolve(null); - }); - } - catch (ex) { - util.rejectError(dfd, "Failed changeVersion(db, '" + oldVersion + "', '" + newVersion + "')", { exception: ex }); - } - return dfd.promise; - }; - /** Queries the sqlite_master table for user tables - * Returns: promise that resolves with an array of table information records - * Usage: - * wsdb.getTables().then(function(tables) { - * for(var i = 0; i < tables.length; i++) { - * var name = tables[i].name; - * var sql = tables[i].sql; - * ... - * } - * }); - */ - WebSqlSpi.prototype.getTables = function () { - var sql = "SELECT name, type, sql FROM sqlite_master " + - "WHERE type in ('table') AND name NOT LIKE '?_?_%' ESCAPE '?'"; - return this.execSqlStatements(this.readTransaction, "read", { sql: sql }, function (rs) { - var tables = []; - var rows = rs.rows; - for (var i = 0, size = rows.length; i < size; i++) { - tables.push(rows.item(i)); - } - return tables; - }); - }; - /** Queries the sqlite_master for a table by name - * Returns: promise that resolves with table info or with `undefined` if table - * does not exist. - * Usage: - * wsdb.tableExists("person").then(function (table) { - * alert("table " + (table ? "exists" : "does not exist")); - * }); - */ - WebSqlSpi.prototype.tableExists = function (name) { - var sql = "SELECT * FROM sqlite_master WHERE name = ?"; - return this.readRow([{ sql: sql, args: [[name]] }], function (row) { - return row || undefined; - }); - }; - /** Drops all the tables in the database. - * Returns: promise that resolves with this `WebsqlDatabase` - * Usage: - * wsdb.destroyDatabase() - * .then(function (wsdb) {...}); - */ - WebSqlSpi.prototype.destroyDatabase = function () { - return this.changeVersion(this.db.version, "", function (xact) { - var sql = "SELECT name FROM sqlite_master " + - "WHERE type in ('table') AND name NOT LIKE '?_?_%' ESCAPE '?'"; - xact.executeSql(sql, [], function (xact, rs) { - var rows = rs.rows; - for (var i = 0, size = rows.length; i < size; i++) { - var sql = 'DROP TABLE "' + rows.item(i).name + '"'; - xact.executeSql(sql); - } - }); - }); - }; - /** Calls xactCallback(xact) from within a database transaction - * Returns: promise that resolves with the database - * Usage: - * wsdb.transaction(function (xact) { - * xact.executeSQL(...); - * }).then(function (wsdb) {...}); - * - * More usage: - * var addressId; - * var personId; - * - * function insertPerson(xact) { - * return xact.executeSql("INSERT INTO person ...", [...], - * function (xact, rs) { - * personId = rs.insertId; - * insertAddress(xact, personId); - * } - * ) - * } - * - * function insertAddress(xact, personId) { - * return wsdb.executeSql(xact, "INSERT INTO address (person, ...) VALUES (?, ...)", - * [personId, ...], - * function (xact, rs) { - * addressId = rs.insertId; - * } - * ) - * } - * - * wsdb.transaction(function (xact) { - * insertPerson(xact); - * }).then(function(wsdb) { - * alert("Created person " + personId + " with address " + addressId); - * }); - */ - WebSqlSpi.prototype.transaction = function (xactCallback) { - return this.executeTransaction("transaction", xactCallback); - }; - /** Calls xactCallback(xact) from within a database read transaction - * Returns: promise that resolves with the database - * Usage: - * wsdb.readTransaction(function (xact) { - * xact.executeSQL(...); - * }).then(function (wsdb) {...}); - */ - WebSqlSpi.prototype.readTransaction = function (xactCallback) { - return this.executeTransaction("readTransaction", xactCallback); - }; - /** Call 'webSqlFunc' method on 'db' - * Implements common behavior for 'wsdb.transaction' and 'wsdb.readTransaction' - */ - WebSqlSpi.prototype.executeTransaction = function (webSqlFuncName, xactCallback) { - var util = this.util; - var dfd = util.defer(); - if (!util.isDatabase(this.db)) { - util.rejectError(dfd, "Database not specified (db='" + this.db + "')"); - return dfd.promise; - } - if (this.db[webSqlFuncName] == null) { - util.rejectError(dfd, "Database function '" + webSqlFuncName + "' does not exist"); - return dfd.promise; - } - try { - this.db[webSqlFuncName](function (xact) { - try { - xactCallback(xact); - } - catch (exception) { - util.rejectError(dfd, webSqlFuncName + " callback threw an exception", { exception: exception }); - } - }, function (sqlError) { - util.rejectError(dfd, "Failed executing " + webSqlFuncName.replace(/transaction/i, "") + " transaction", { sqlError: sqlError }); - }, function () { - dfd.resolve(null); - }); - } - catch (exception) { - util.rejectError(dfd, "Failed calling " + webSqlFuncName, { exception: exception }); - } - return dfd.promise; - }; - /** Method for executing a transaction with a one or more `sqlStatement` - * with the specified `args`, calling the `rsCallback` with the result set(s). - * The `args` and `rsCallback` are optional. - * * Passing a _single_ `sqlStatement` string with `args` that is an _array of arrays_, - * the statement is executed with each row in the `args`. - * Passing an array of `{ sql, args}` objects to `sqlStatement` - * executes the `sql` in each row with the row's `args` (or the parameter `args`). - * - * Returns: promise that resolves with `rsCallback` result - * or the resultSet, if no `rsCallback` specified. If an array of statements or arguments - * is specified, the promise resolves with an array of results/resultSets. - * - * Basic Usage: - * wsdb.execute("DELETE FROM person") - * .then(function (resultSet) {...}); - * - * Other Usage: (single `sqlStatement` with multiple sets of `args`) - * wsdb.execute("INSERT INTO person (first, last) VALUES (?, ?)", - * [ - * ["John", "Doe"], - * ["Jane", "Doe"] - * ], - * // called for each row in args - * function (rs) { - * console.log("Inserted person", rs.insertId); - * return rs.insertId; - * } - * ).then(function (insertIds) { - * var personId1 = insertIds[0], personId2 = insertIds[1]; - * ... - * }); - * - * Other Usage: (multiple `sqlStatement` with multiple sets of `args`) - * wsdb.execute( - * [{ - * sql: "UPDATE person SET (first=?, last=?) WHERE id=?", - * args: ["Robert", "Smith", 23] - * }, { - * sql: "UPDATE address SET (street=?, city=?, zip=?) WHERE id=?", - * args: ["Sesame St.", "Austin", "78758", 45] - * }], - * // called for each object in args - * function (rs) { - * console.log("Updated object: ", rs.rowsAffected); - * return rs.rowsAffected; - * } - * ).then(function (results) { - * var numPersons = results[0], numAddresses = results[1]; - * ... - * }); - */ - WebSqlSpi.prototype.executeQuery = function (sqlStatement) { - return this.execSqlStatements(this.transaction, "execute", sqlStatement, null); - }; - WebSqlSpi.prototype.executeQueries = function (sqlStatements) { - return this.execSqlStatements(this.transaction, "execute", sqlStatements, null); - }; - WebSqlSpi.prototype.execute = function (sqlStatements, rsCallback) { - return this.execSqlStatements(this.transaction, "execute", sqlStatements, rsCallback); - }; - /** Method for executing a readTransaction with a one or more `sqlStatement` - * with the specified `args`, calling the `rsCallback` with the result set(s). - * The `args` and `rsCallback` are optional. - * Passing a _single_ `sqlStatement` string with `args` that is an _array of arrays_, - * the statement is executed with each row in the `args`. - * Passing an array of `{ sql, args}` objects to `sqlStatement` - * executes the `sql` in each row with the row's `args` (or the parameter `args`). - * Returns: promise that resolves with `rsCallback` result - * or the resultSet, if no `rsCallback` specified. If an array of statements or arguments - * is specified, the promise resolves with an array of results/resultSets. - * Usage: - * wsdb.read("SELECT * FROM person WHERE first = ?", - * ["Bob"], - * function (rs) { - * var rows = rs.rows; - * for(var i = 0; i < rows.length; i++) { - * ... - * } - * return result; - * } - * ).then(function (result) {...}); - * - * Other Usage: (single `sqlStatement` with multiple sets of `args`) - * wsdb.read("SELECT * FROM person WHERE first = ?", - * [ ["Bob"], ["John"] ], - * // called for each row in args - * function (rs) { - * return rs.rows; - * } - * ).then(function (results) { - * var bobRows = results[0], johnRows = results[1]; - * ... - * }); - * - * Other Usage: (multiple `sqlStatement` with multiple sets of `args`) - * wsdb.read([{ - * sql: "SELECT * FROM person WHERE id=?", - * args: [23] - * }, { - * sql: "SELECT * FROM address WHERE state in (?, ?, ?)", - * args: ["CA", "FL", "TX"] - * }], - * // called for each object in args - * function (rs) { - * return rs.rows; - * } - * ).then(function (results) { - * var person23rows = results[0], addressRows = results[1]; - * ... - * }); - */ - WebSqlSpi.prototype.read = function (sqlStatements, rsCallback) { - return this.execSqlStatements(this.readTransaction, "read", sqlStatements, rsCallback); - }; - /** Method for executing a readTransaction with a single `sqlStatement` that's expected to return a single row. - * The `rowCallback` function is called with the first row in the resultset - * or with `undefined` if resultset contains no rows. - * If the query does not return a row, the `defaultValue` is returned instead. - * @returns promise that resolves with the `rowCallback` result or the row, if no `rowCallback` specified. - * If no rows are selected and `rowCallback` isn't specified, the promise resolves with the `defaultRow`. - * The promise is rejected if the query returns multiple rows or if it returns - * zero rows and no `rowCallback` and `defaultRow` were specified. - * Usage: - * wsdb.readRow("SELECT * FROM person WHERE id = ?", [123], function (row) { - * if(!row) { - * // person not found - * } - * else { - * ... - * } - * }).then(function (result) {...}); - */ - WebSqlSpi.prototype.readRow = function (sqlStatements, rowCallback, defaultValue) { - var util = this.util; - return util.pipe(this.read(sqlStatements), function (rs) { - var row; - if (Array.isArray(rs) || rs.rows.length > 1) { - return util.rejectError(util.defer(), new Error("Query returned " + (Array.isArray(rs) ? "array of " + rs.length + " result sets" : rs.rows.length + " rows"))); - } - else if (rs.rows.length === 0) { - if (defaultValue) { - row = defaultValue; - } - else if (rowCallback) { - row = rowCallback(); - } - else { - return util.rejectError(util.defer(), new Error("Query returned 0 rows")); - } - } - else { - row = rs.rows.item(0); - if (rowCallback) { - row = rowCallback(row); - } - } - return row; - }); - }; - WebSqlSpi.prototype.execSqlStatements = function (xactMethod, xactMethodType, sqlStatements, rsCallback) { - var start = new Date().getTime(); - if (typeof window !== "undefined" && !window["startQueriesTime"]) { - window["startQueriesTime"] = start; - } - var util = this.util; - var isAry = Array.isArray(sqlStatements); - var sqls = (isAry ? sqlStatements : [sqlStatements]); - var results = []; - var pipeReturn = util.pipe(xactMethod(function (xact) { - for (var i = 0; i < sqls.length; i++) { - var cmnd = sqls[i]; - var params = (typeof cmnd.args === "undefined" ? null : cmnd.args); - if (params == null || params.length === 0) { - xact.executeSql(cmnd.sql, null, function (xact, rs) { - results.push(rsCallback ? rsCallback(rs) : rs); - }); - } - else { - for (var j = 0, szJ = params.length; j < szJ; j++) { - xact.executeSql(cmnd.sql, params[j], function (xact, rs) { - results.push(rsCallback ? rsCallback(rs) : rs); - }); - } - } - } - }), function () { - return isAry ? results : results[0]; - }, function (err) { - err.sql = sqls; - return err; - }); - if (util.logTimings) { - pipeReturn.then(function () { - var end = new Date().getTime(); - var time = end - start; - if (typeof window !== "undefined") { - window["endQueriesTime"] = end; - } - util.log(util.DEBUG, "websql finish args: ", xactMethodType, sqls.length, sqls); - util.log(util.DEBUG, "websql runtime: ", time); - }); - } - return pipeReturn; - }; - /** Calls window.openDatabase(). - * - version defaults to `""` - * - displayName defaults to `name` - * - estimatedSize defaults to `2 * 1024 * 1024` - * Returns: promise that resolves with this `WebsqlDatabase` instance - * Usage: - * wsdb.openDatabase("test", "Test Database", 2 * 1024 * 1024)) - * .then(function(wsdb) {...}); - * More usage: - * wsdb.openDatabase("test")) - * .then(function(wsdb) {...}); - */ - WebSqlSpi.openDatabase = function (util, name, version, displayName, estimatedSize) { - util.log(util.DEBUG, "openDatabase", name, version, displayName, estimatedSize); - if (!displayName) - displayName = name; - if (!version) - version = ""; - if (!estimatedSize) { - if (typeof window !== "undefined" && window.navigator.userAgent.match(/(iPad|iPhone);.*CPU.*OS 7_0/i)) { - estimatedSize = 5 * 1024 * 1024; - } - else { - estimatedSize = 50 * 1024 * 1024; - } - } - var dfd = util.defer(); - try { - if (typeof window === "undefined" || !window.openDatabase) { - util.rejectError(dfd, "WebSQL not implemented"); - } - else { - // seems to synchronously open WebSQL, even though window.openDatabase is async - var db = window.openDatabase(name, version, displayName, estimatedSize); - if (util.isDatabase(db)) { - dfd.resolve(db); - } - else { - util.rejectError(dfd, "Failed to open database"); - } - } - } - catch (ex) { - util.rejectError(dfd, "Failed to open database " + name, { exception: ex }); - } - return dfd.promise; - }; - WebSqlSpi.newWebSqlDb = function (name, version, displayName, estimatedSize, utilSettings) { - var util = new DbUtil("WebSQL", "[object Database]", utilSettings); - // Create WebSQL wrapper from native Database or by opening 'name' DB - var pOpen; - if (util.isDatabase(name)) { - var dfd = util.defer(); - dfd.resolve(name); - pOpen = dfd.promise; - } - else { - pOpen = WebSqlSpi.openDatabase(util, name, version, displayName, estimatedSize); - } - return pOpen.then(function (dbInst) { return new WebSqlSpi(dbInst, util); }); - }; - return WebSqlSpi; -}()); -module.exports = WebSqlSpi; - -},{"./DbUtil":2}],7:[function(require,module,exports){ -"use strict"; -var DbUtil = require("../persisters/DbUtil"); -var IndexedDbPersister = require("../persisters/IndexedDbPersister"); -var IndexedDbSpi = require("../persisters/IndexedDbSpi"); -var WebSqlPersister = require("../persisters/WebSqlPersister"); -var WebSqlSpi = require("../persisters/WebSqlSpi"); -var CollectionsBrowserTestBase; -(function (CollectionsBrowserTestBase) { - // testing: - /* - * load test/tmp/index.html in a browser, then run these commands: -var idb = null; createIndexedDbPersister(1).then((i) => { idb = i; var db = idb.persistenceInterface.db; db.onabort = db.onclose = db.onerror = function closing() { console.error.apply(console, arguments); }; }); -idb.addCollection("book", [ - memDb.createBook("1984", "George Orwell", 1949), - memDb.createBook("Mere Christianity", "C.S. Lewis", 1952), - memDb.createBook("Desiring God", "John Piper", 1986), - memDb.createBook("Don't Waste Your Life", "John Piper", 2003), - memDb.createBook("The Culture Code", "Daniel Coyle", 2016) -]); -idb.getDataCollections()[1].dirty = true; -var rs = null; idb.persist({ maxObjectsPerChunk: 3, keyAutoGenerate: true }).then(r => console.log("persist done!", rs = r), (err) => console.error(err)); -var rt = null; idb.restore(null, (name) => ({ isChunks: true })).then(r => console.log("restore done!", rt = r), (err) => console.error(err)); -idb.persistenceInterface.db.close(); - */ - var colls = [{ - name: "books", - data: [], - dirty: false, - insert: function insert(dat) { Array.prototype.push.apply(this.data, dat); } - }]; - var memDb = { - listCollections: function () { return colls; }, - getCollection: function (name, auto) { return colls.find(function (x) { return x.name === name; }) || colls[0]; }, - createBook: function (name, author, publishYear) { return ({ name: name, author: author, publishYear: publishYear }); }, - }; - var storageLog = { - error: function error() { - console.error.apply(console, arguments); - debugger; - }, - log: function log() { - console.log.apply(console, arguments); - debugger; - } - }; - var persisterLog = { - error: function error() { - console.error.apply(console, arguments); - debugger; - }, - log: function log() { - console.log.apply(console, arguments); - debugger; - } - }; - var utilConfig = { - defer: function () { - var rt = { - promise: null, - resolve: null, - reject: null, - }; - var p = new Promise(function (rsl, rjc) { rt.resolve = rsl; rt.reject = rjc; }); - rt.promise = p; - return rt; - }, - whenAll: function (ps) { return Promise.all(ps); }, - trace: storageLog, - verbosity: DbUtil.logLevels.DEBUG - }; - function createIndexedDbPersister(version) { - if (version === void 0) { version = null; } - return IndexedDbSpi.newIndexedDb("lokijs-collections-test", version, utilConfig).then(function (idb) { - return new IndexedDbPersister(idb, persisterLog, function () { - return [{ name: "book_backup", data: [] }].concat(memDb.listCollections()); - }, function (collName, data) { - // when initially restoring collection data from persistent storage (during page load) don't mark collection as dirty (prevents a full save when the next persist() timer goes off) - var initiallyEmpty = memDb.getCollection(collName, false) == null; - var coll = memDb.getCollection(collName, true); - coll.insert(data); - if (initiallyEmpty) { - coll.dirty = false; - } - return coll; - }, null /*(itm) => MemDbImpl.cloneCloneDelete(itm, true)*/, null, function (storageError) { - console.error("storage error, is quota full!?", storageError.sqlError.message); - }, null, null); - }); - } - CollectionsBrowserTestBase.createIndexedDbPersister = createIndexedDbPersister; - function createWebSqlPersister(version) { - if (version === void 0) { version = null; } - return WebSqlSpi.newWebSqlDb("lokijs-collections-test", version, null, null, utilConfig).then(function (wsb) { - return new WebSqlPersister(wsb, persisterLog, function () { - return [{ name: "book_backup", data: [] }].concat(memDb.listCollections()); - }, function (collName, data) { - // when initially restoring collection data from persistent storage (during page load) don't mark collection as dirty (prevents a full save when the next persist() timer goes off) - var initiallyEmpty = memDb.getCollection(collName, false) == null; - var coll = memDb.getCollection(collName, true); - coll.insert(data); - if (initiallyEmpty) { - coll.dirty = false; - } - return coll; - }, null /*(itm) => MemDbImpl.cloneCloneDelete(itm, true)*/, function (k, v) { return (k !== "$loki" && k !== "meta" ? v : undefined); }, null, function (storageError) { - console.error("storage error, is quota full!?", storageError.sqlError.message); - }, null, null); - }); - } - CollectionsBrowserTestBase.createWebSqlPersister = createWebSqlPersister; - var Cctor = (function () { - var globals = [ - IndexedDbPersister, - IndexedDbSpi, - createIndexedDbPersister, - createWebSqlPersister, - (colls.name = "colls", colls), - (memDb.name = "memDb", memDb), - ]; - for (var i = 0, size = globals.length; i < size; i++) { - var glb = globals[i]; - window[glb.name] = glb; - console.log(glb.name); - } - }()); -})(CollectionsBrowserTestBase || (CollectionsBrowserTestBase = {})); -module.exports = CollectionsBrowserTestBase; - -},{"../persisters/DbUtil":2,"../persisters/IndexedDbPersister":3,"../persisters/IndexedDbSpi":4,"../persisters/WebSqlPersister":5,"../persisters/WebSqlSpi":6}]},{},[7]) -//# sourceMappingURL=bundle.js.map diff --git a/test/tmp/bundle.js.map b/test/tmp/bundle.js.map deleted file mode 100644 index e119336..0000000 --- a/test/tmp/bundle.js.map +++ /dev/null @@ -1,27 +0,0 @@ -{ - "version": 3, - "sources": [ - "node_modules/browser-pack/_prelude.js", - "node_modules/ts-mortar/utils/Arrays.js", - "persisters/DbUtil.js", - "persisters/IndexedDbPersister.js", - "persisters/IndexedDbSpi.js", - "persisters/WebSqlPersister.js", - "persisters/WebSqlSpi.js", - "test/CollectionsBrowserTestBase.js" - ], - "names": [], - "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5/BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1PA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1OA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpXA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACldA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", - "file": "generated.js", - "sourceRoot": "", - "sourcesContent": [ - "(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i 0) {\r\n Array.prototype.push.apply(src, toAdd);\r\n }\r\n return src;\r\n }\r\n Arrays.addAll = addAll;\r\n /** Transform and add the elements from one array to another\r\n * @param src the array to add elements to\r\n * @param toAdd the elements to transform and add\r\n * @param transformer a function to transform the 'toAdd' values before adding them to 'src'\r\n */\r\n function addAllTransform(src, toAdd, transformer) {\r\n for (var i = 0, size = toAdd.length; i < size; i++) {\r\n src.push(transformer(toAdd[i]));\r\n }\r\n return src;\r\n }\r\n Arrays.addAllTransform = addAllTransform;\r\n /** Given an array or an object, return the array, or a new array containing the object as it's only element\r\n * @param data the object or array\r\n * @param copyToNewAry optional (default: false) if the data is an array, copy the items into a new array\r\n */\r\n function asArray(data, copyToNewAry) {\r\n if (Array.isArray(data)) {\r\n return copyToNewAry ? data.slice() : data;\r\n }\r\n else {\r\n return [data];\r\n }\r\n }\r\n Arrays.asArray = asArray;\r\n /** Check if an array is not null and has any items\r\n * @param ary the array to check\r\n * @returns true if the array is not null and has a length greater than 0\r\n */\r\n function hasAny(ary) {\r\n return ary != null && ary.length > 0;\r\n }\r\n Arrays.hasAny = hasAny;\r\n /** Given an array or an object, return true if it is an object or an array containing one element, false if the array is empty or contains more than 1 element\r\n * @param data the object or array\r\n */\r\n function isOneItem(data) {\r\n return Array.isArray(data) ? data.length === 1 : true;\r\n }\r\n Arrays.isOneItem = isOneItem;\r\n /** Given an array or an object, return the object or the first element if the array contains 1 element, else return null if the array is empty or contains more than 1 element\r\n * @param data the object or array\r\n */\r\n function getIfOneItem(data) {\r\n return Array.isArray(data) ? (data.length === 1 ? data[0] : null) : data;\r\n }\r\n Arrays.getIfOneItem = getIfOneItem;\r\n /** Perform a binary search of a property in an array of values and return the index.\r\n * For example: Arrays.binarySearch([{key: 3}, {key: 10}, {key: 14}, {key: 15}], \"key\", 14)\r\n * returns: 2 indicating that the 3rd array element matches\r\n *\r\n * For example: Arrays.binarySearch([{key: 3}, {key: 10}, {key: 14}, {key: 15}], \"id\", 13)\r\n * returns: -3 indicating that no matching element was found,\r\n * but if a matching element did exist in the array, it would be at index 3\r\n */\r\n function binarySearch(ary, comparatorPropName, searchValue) {\r\n var low = 0;\r\n var high = ary.length - 1;\r\n while (low <= high) {\r\n var mid = Math.floor((low + high) / 2);\r\n var midVal = ary[mid];\r\n var compare = midVal[comparatorPropName] - searchValue;\r\n if (compare < 0) {\r\n low = mid + 1;\r\n }\r\n else if (compare > 0) {\r\n high = mid - 1;\r\n }\r\n else {\r\n return mid;\r\n }\r\n }\r\n return -(low + 1);\r\n }\r\n Arrays.binarySearch = binarySearch;\r\n /** Remove all values from an array\r\n */\r\n function clear(ary) {\r\n if (ary != null) {\r\n ary.length = 0;\r\n }\r\n }\r\n Arrays.clear = clear;\r\n /** Returns a new array containing the elements from 'ary1' followed by the elements from 'ary2'\r\n */\r\n function concat(ary1, ary2) {\r\n if (ary1 != null && ary2 != null) {\r\n return ary1.concat(ary2);\r\n }\r\n else {\r\n return (ary1 != null ? ary1.slice() : (ary2 != null ? ary2.slice() : []));\r\n }\r\n }\r\n Arrays.concat = concat;\r\n /** Check whether all of the values in the second array are contained in the first array\r\n * @param ary the array of values\r\n * @param searchFor the values to search for\r\n * @returns true if all of 'searchFor' values are contained in 'ary'\r\n */\r\n function containsAll(ary, searchFor) {\r\n if (ary == null || searchFor == null) {\r\n return false;\r\n }\r\n for (var i = 0, size = searchFor.length; i < size; i++) {\r\n if (ary.indexOf(searchFor[i]) < 0) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n }\r\n Arrays.containsAll = containsAll;\r\n /** Check whether any of the values in the second array are contained in the first array\r\n * @param ary the array of values\r\n * @param searchFor the values to search for\r\n * @returns true if any of 'searchFor' values are contained in 'ary'\r\n */\r\n function containsAny(ary, searchFor) {\r\n if (ary == null || searchFor == null) {\r\n return false;\r\n }\r\n for (var i = 0, size = searchFor.length; i < size; i++) {\r\n if (ary.indexOf(searchFor[i]) > -1) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n }\r\n Arrays.containsAny = containsAny;\r\n /** Count the number of elements in an array that match a filter\r\n * @param ary the array of values\r\n * @param filter the filter to use on 'ary'\r\n * @returns the number of 'ary' elements that return a truthy value when passed through the 'filter' function\r\n */\r\n function count(ary, filter) {\r\n var res = 0;\r\n for (var i = 0, size = ary.length; i < size; i++) {\r\n if (filter(ary[i], i, ary)) {\r\n res++;\r\n }\r\n }\r\n return res;\r\n }\r\n Arrays.count = count;\r\n /** Get the difference between two arrays. Also known as the symmetric difference (https://en.wikipedia.org/wiki/Symmetric_difference).\r\n * NOTE: duplicate values in either array are considered unique. If there are two of the same values in 'ary1', then 'ary2' must contain two of those values to cancel out both of the values from 'ary1'.\r\n * For example: Arrays.diff([1, 2, 3], [2, 4])\r\n * returns: [4, 1, 3]\r\n * which represents the differences between 'ary1' and 'ary2' (note: the returned array order is undefined)\r\n *\r\n * @param ary1 the first array to compare\r\n * @param ary2 the second array to compare\r\n * @returns of values that exist in only one of the input arrays\r\n * @see diff()\r\n */\r\n function diff(ary1, ary2, equal) {\r\n var diffRes = (equal != null ? diffPartsCustomEquality(ary1, ary2, equal) : diffParts(ary1, ary2));\r\n var looseDiff = Array.prototype.concat.apply(diffRes.added, diffRes.removed);\r\n return looseDiff;\r\n }\r\n Arrays.diff = diff;\r\n /** Return the difference between two arrays as elements added and removed from the first array.\r\n * Items which only exist in 'ary1' are called 'removed'.\r\n * Items which only exist in 'ary2' are called 'added'.\r\n * NOTE: duplicate values in either array are considered unique. If there are two of the same values in 'ary1', then 'ary2' must contain two of those values to cancel out both of the values from 'ary1'.\r\n *\r\n * For example: Arrays.diffParts([1, 2, 3], [2, 4])\r\n * returns: { added: [4], removed: [1, 3]},\r\n * which are the values to add and remove from 'ary1' to convert it to 'ary2'\r\n *\r\n * @param ary1 the master/original array to base differences on\r\n * @param ary2 the branch/new array to find differences in\r\n * @returns with 'added' and 'removed' arrays of values from 'ary1' and 'ary2'\r\n * @see looseDiff()\r\n */\r\n function diffParts(ary1, ary2) {\r\n if (ary1 == null || ary2 == null || !Array.isArray(ary1) || !Array.isArray(ary2)) {\r\n if (ary1 == null && ary2 == null) {\r\n return { added: [], removed: [] };\r\n }\r\n // else, incorrect arguments\r\n if ((ary1 != null && !Array.isArray(ary1)) || (ary2 != null && !Array.isArray(ary2)) || ary1 === undefined || ary2 === undefined) {\r\n throw new Error(\"incorrect usage ([\" + ary1 + \"], [\" + ary2 + \"]), expected (Array ary1, Array ary2)\");\r\n }\r\n // if one array is null and the other is not, the difference is just the non-null array's values\r\n if (ary1 == null && ary2 != null) {\r\n return {\r\n added: ary2.slice(),\r\n removed: []\r\n };\r\n }\r\n else /*if (ary1 != null && ary2 == null)*/ {\r\n return {\r\n added: [],\r\n removed: ary1.slice()\r\n };\r\n }\r\n }\r\n var added = [];\r\n var removed = [];\r\n var ary2Used = [];\r\n var ary1Size = ary1.length;\r\n var ary2Size = ary2.length;\r\n // keep track of each element in 'ary2' that does not exist in 'ary1'\r\n for (var i = 0; i < ary1Size; i++) {\r\n var elem1 = ary1[i];\r\n var matchingIdx2 = -1;\r\n for (var ii = 0; ii < ary2Size; ii++) {\r\n if (ary2Used[ii] !== true && elem1 === ary2[ii]) {\r\n matchingIdx2 = ii;\r\n break;\r\n }\r\n }\r\n // items that only exist in 'ary1' are 'removed'\r\n if (matchingIdx2 === -1) {\r\n removed.push(ary1[i]);\r\n }\r\n else {\r\n ary2Used[matchingIdx2] = true;\r\n }\r\n }\r\n // items that only exist in 'ary2' are 'added'\r\n for (var ii = 0; ii < ary2Size; ii++) {\r\n if (!ary2Used[ii]) {\r\n added.push(ary2[ii]);\r\n }\r\n }\r\n return {\r\n added: added,\r\n removed: removed\r\n };\r\n }\r\n Arrays.diffParts = diffParts;\r\n /** Return the difference between two arrays as elements added and removed from the first array.\r\n * Items which only exist in 'ary1' are called 'removed'.\r\n * Items which only exist in 'ary2' are called 'added'.\r\n * NOTE: duplicate values in either array are considered unique. If there are two of the same values in 'ary1', then 'ary2' must contain two of those values to cancel out both of the values from 'ary1'.\r\n *\r\n * For example: Arrays.diffParts([1, 2, 3], [2, 4])\r\n * returns: { added: [4], removed: [1, 3]},\r\n * which are the values to add and remove from 'ary1' to convert it to 'ary2'\r\n *\r\n * @param ary1 the master/original array to base differences on\r\n * @param ary2 the branch/new array to find differences in\r\n * @returns with 'added' and 'removed' arrays of values from 'ary1' and 'ary2'\r\n * @see looseDiff()\r\n */\r\n function diffPartsCustomEquality(ary1, ary2, equal) {\r\n if (ary1 == null || ary2 == null || !Array.isArray(ary1) || !Array.isArray(ary2)) {\r\n if (ary1 == null && ary2 == null) {\r\n return { added: [], removed: [] };\r\n }\r\n // else, incorrect arguments\r\n if ((ary1 != null && !Array.isArray(ary1)) || (ary2 != null && !Array.isArray(ary2)) || ary1 === undefined || ary2 === undefined) {\r\n throw new Error(\"incorrect usage ([\" + ary1 + \"], [\" + ary2 + \"]), expected (Array ary1, Array ary2)\");\r\n }\r\n // if one array is null and the other is not, the difference is just the non-null array's values\r\n if (ary1 == null && ary2 != null) {\r\n return {\r\n added: ary2.slice(),\r\n removed: []\r\n };\r\n }\r\n else /*if (ary1 != null && ary2 == null)*/ {\r\n return {\r\n added: [],\r\n removed: ary1.slice()\r\n };\r\n }\r\n }\r\n var added = [];\r\n var removed = [];\r\n var ary2Used = [];\r\n var ary1Size = ary1.length;\r\n var ary2Size = ary2.length;\r\n // keep track of each element in 'ary2' that does not exist in 'ary1'\r\n for (var i = 0; i < ary1Size; i++) {\r\n var elem1 = ary1[i];\r\n var matchingIdx2 = -1;\r\n for (var ii = 0; ii < ary2Size; ii++) {\r\n if (ary2Used[ii] !== true && equal(elem1, ary2[ii])) {\r\n matchingIdx2 = ii;\r\n break;\r\n }\r\n }\r\n // items that only exist in 'ary1' are 'removed'\r\n if (matchingIdx2 === -1) {\r\n removed.push(ary1[i]);\r\n }\r\n else {\r\n ary2Used[matchingIdx2] = true;\r\n }\r\n }\r\n // items that only exist in 'ary2' are 'added'\r\n for (var ii = 0; ii < ary2Size; ii++) {\r\n if (!ary2Used[ii]) {\r\n added.push(ary2[ii]);\r\n }\r\n }\r\n return {\r\n added: added,\r\n removed: removed\r\n };\r\n }\r\n Arrays.diffPartsCustomEquality = diffPartsCustomEquality;\r\n function distinct(ary, propName) {\r\n if (ary == null || ary.length < 2) {\r\n return ary || null;\r\n }\r\n var res = [ary[0]];\r\n if (propName == null) {\r\n for (var i = 1, size = ary.length; i < size; i++) {\r\n if (res.indexOf(ary[i]) === -1) {\r\n res.push(ary[i]);\r\n }\r\n }\r\n }\r\n else {\r\n for (var i = 1, size = ary.length; i < size; i++) {\r\n if (Arrays.indexOfProp(res, propName, ary[i][propName]) === -1) {\r\n res.push(ary[i]);\r\n }\r\n }\r\n }\r\n return res;\r\n }\r\n Arrays.distinct = distinct;\r\n function fastRemove(ary, value) {\r\n var aryLen = 0;\r\n if (ary == null || (aryLen = ary.length) === 0) {\r\n return ary;\r\n }\r\n var idx = ary.indexOf(value);\r\n if (idx > -1) {\r\n ary[idx] = ary[aryLen - 1];\r\n ary.pop();\r\n }\r\n return ary;\r\n }\r\n Arrays.fastRemove = fastRemove;\r\n function fastRemoveIndex(ary, index) {\r\n var aryLen = 0;\r\n if (ary == null || (aryLen = ary.length) === 0) {\r\n return ary;\r\n }\r\n if (aryLen > 1) {\r\n ary[index] = ary[aryLen - 1];\r\n }\r\n ary.pop();\r\n return ary;\r\n }\r\n Arrays.fastRemoveIndex = fastRemoveIndex;\r\n /** Split an array of values into matching and non-matching arrays using a filter\r\n * For example: Arrays.filterSplit([1, 2, 3, 4, 5], function (value, idx, ary) { return value % 2 == 0; })\r\n * returns: { all: [1, 2, 3, 4, 5], matching: [2, 4], notMatching: [1, 3, 5] }\r\n *\r\n * @param ary the array of values to filter\r\n * @param filterFunc the function to filter the values,\r\n * true stores items in the returned 'matching' property,\r\n * false stores items in the returned 'notMatching' property\r\n * @returns a filter result object contains the original array 'all' and arrays of 'matching' and 'notMatching' items\r\n */\r\n function filterSplit(ary, filterFunc) {\r\n if (ary == null) {\r\n return toBiFilterResult([], [], []);\r\n }\r\n if (typeof filterFunc !== \"function\") {\r\n throw new Error(\"incorrect parameter 'filterFunc', must be a 'function(value: E, index: number, array: E[]): boolean'\");\r\n }\r\n var matching = [];\r\n var notMatching = [];\r\n for (var i = 0, size = ary.length; i < size; i++) {\r\n var value = ary[i];\r\n if (filterFunc(value, i, ary)) {\r\n matching.push(value);\r\n }\r\n else {\r\n notMatching.push(value);\r\n }\r\n }\r\n return toBiFilterResult(ary, matching, notMatching);\r\n }\r\n Arrays.filterSplit = filterSplit;\r\n // convert an array of items and arrays containing matching and non-matching items to an 'BiFilterResult' object\r\n function toBiFilterResult(all, matching, notMatching) {\r\n return {\r\n all: all,\r\n matching: matching,\r\n notMatching: notMatching\r\n };\r\n }\r\n /** Search for objects in an array containing a property matching a given input property.\r\n * For example: Arrays.findAllProp([ {name: \"billy\", value: 5}, {name: \"sam\", value: 5}, {name: \"overhill\", value: 3} ], \"value\", 5)\r\n * returns: {name: \"billy\", value: 5}, {name: \"sam\", value: 5}\r\n * because the matching object has a property \"value\" with a value of 5\r\n *\r\n * @param ary the array to search\r\n * @param propName the name of the property to search for on each object\r\n * @param propValue the property value to compare\r\n * @returns an array of objects containing properties named 'propName' with values equal to 'propValue',\r\n * returns a new empty array if no matching object was found\r\n */\r\n function findMatchingProps(ary, propName, propValue) {\r\n if (ary == null || propName == null || propValue === undefined) {\r\n return null;\r\n }\r\n var res = [];\r\n for (var i = 0, size = ary.length; i < size; i++) {\r\n if (ary[i][propName] === propValue) {\r\n res.push(ary[i]);\r\n }\r\n }\r\n return res;\r\n }\r\n Arrays.findMatchingProps = findMatchingProps;\r\n /** Return the first matching value in an array using a filter function, null if no matches.\r\n * Optional: throw an exception if more than one result is found.\r\n * For example: Arrays.first([ {key: 27, value: \"A\"}, {key: 46, value: \"B\"}, {key: 84, value: \"C\"}, {key: 84, value: \"D\"} ], function (obj) { return obj.key === 84; })\r\n * returns: {key: 84, value: \"C\"}\r\n *\r\n * @param ary the array of values to search\r\n * @param filter the filter to apply to 'ary'\r\n * @returns the first (lowest index) value passed to 'filter' from 'ary' that returns true, or null if a match cannot be found\r\n */\r\n function first(ary, filter, ensureOne) {\r\n if (ensureOne === void 0) { ensureOne = false; }\r\n var idx = firstIndex(ary, filter, ensureOne);\r\n return idx < 0 ? null : ary[idx];\r\n }\r\n Arrays.first = first;\r\n /** Return the index of the first matching value in an array using a filter function, null if no matches.\r\n * @see #first()\r\n */\r\n function firstIndex(ary, filter, ensureOne) {\r\n if (ensureOne === void 0) { ensureOne = false; }\r\n if (ary == null || filter == null) {\r\n return -1;\r\n }\r\n var resultIdx = -1;\r\n var resultCount = 0;\r\n for (var i = 0, size = ary.length; i < size; i++) {\r\n if (filter(ary[i], i, ary) === true) {\r\n if (resultCount === 0) {\r\n resultIdx = i;\r\n if (!ensureOne) {\r\n resultCount++;\r\n break;\r\n }\r\n }\r\n resultCount++;\r\n throw new Error(\"found multiple results, expected to find one\");\r\n }\r\n }\r\n if (resultCount === 1) {\r\n return resultIdx;\r\n }\r\n return -1;\r\n }\r\n Arrays.firstIndex = firstIndex;\r\n function last(ary, filterFunc) {\r\n var idx = lastIndex(ary, filterFunc);\r\n return idx < 0 ? null : ary[idx];\r\n }\r\n Arrays.last = last;\r\n /** Return the last value in an array that matches a filter, null if no matches\r\n * @param ary the array of values to search\r\n * @param filterFunc the filter to apply\r\n * @returns the highest-index value passed to 'filterFunc' from 'ary' that returns true, null if no value returns true\r\n */\r\n function lastIndex(ary, filterFunc) {\r\n if (ary == null) {\r\n return -1;\r\n }\r\n for (var i = ary.length - 1; i > -1; i--) {\r\n if (filterFunc(ary[i], i, ary) == true) {\r\n return i;\r\n }\r\n }\r\n return -1;\r\n }\r\n Arrays.lastIndex = lastIndex;\r\n /** Search for an object in an array containing a property matching a given input property.\r\n * Optional: throw an exception if more than one result is found.\r\n * For example: Arrays.firstProp([ {name: \"billy\", value: 4}, {name: \"sam\", value: 5}, {name: \"will\", value: 5} ], \"value\", 5)\r\n * returns: {name: \"sam\", value: 5}\r\n * Or example: Arrays.firstProp([ {name: \"billy\", value: 4}, {name: \"sam\", value: 4}, {name: \"will\", value: 5} ], \"value\", 5, true)\r\n * throws an error because the value appears more than once and the 'ensureOne' parameter = true\r\n *\r\n * @param ary the array of values to search\r\n * @param propName the name of the property to search for on each object\r\n * @param propValue the property value to compare\r\n * @returns the first (lowest index) matching value from the input array, or null if a result cannot be found\r\n */\r\n function firstProp(ary, propName, propValue, ensureOne) {\r\n if (ensureOne === void 0) { ensureOne = false; }\r\n if (ary == null || propName == null) {\r\n return null;\r\n }\r\n var result = null;\r\n var resultCount = 0;\r\n for (var i = 0, size = ary.length; i < size; i++) {\r\n var obj = ary[i];\r\n if (obj != null && obj[propName] === propValue) {\r\n if (resultCount === 0) {\r\n result = obj;\r\n if (!ensureOne) {\r\n resultCount++;\r\n break;\r\n }\r\n }\r\n resultCount++;\r\n throw new Error(\"found multiple results for '\" + propName + \"'='\" + propValue + \"', expected to find one\");\r\n }\r\n }\r\n if (resultCount === 1) {\r\n return result;\r\n }\r\n return null;\r\n }\r\n Arrays.firstProp = firstProp;\r\n /** Get a property from each object in an array of objects\r\n * @param ary the array of objects\r\n * @param propName the name of the property to get\r\n * @param distinct optional boolean which indicates whether unique results only should be returned\r\n * @returns an array of the specified property from each object in 'ary'\r\n */\r\n function pluck(ary, propName, distinct) {\r\n if (ary == null || propName == null) {\r\n return [];\r\n }\r\n if (!distinct) {\r\n var results = new Array(ary.length);\r\n for (var i = ary.length - 1; i > -1; i--) {\r\n results[i] = ary[i][propName];\r\n }\r\n return results;\r\n }\r\n else {\r\n var results = [];\r\n for (var i = 0, size = ary.length; i < size; i++) {\r\n var value = ary[i][propName];\r\n if (results.indexOf(value) < 0) {\r\n results.push(value);\r\n }\r\n }\r\n return results;\r\n }\r\n }\r\n Arrays.pluck = pluck;\r\n /** Search for the index of an object with a specified property in an array.\r\n * For example: Arrays.indexOfPropValue([ {name: \"billy\", value: 12}, {name: \"sam\", value: 12} ], \"value\", 12)\r\n * returns: 0\r\n * because the first object with the property \"value\" with a value of 12 was at index 0\r\n *\r\n * @param ary the array to search\r\n * @param propName the name of the property to search for on each object\r\n * @param propValue the property value to compare\r\n * @param offset optional, 'ary' offset at which to start search, supports negative offset same as 'Array.indexOf(T, number)'\r\n * @returns the array index of an object with a matching property, -1 if no matching object was found\r\n */\r\n function indexOfProp(ary, propName, propValue, offset) {\r\n if (ary == null || propName == null || propValue === undefined) {\r\n return -1;\r\n }\r\n for (var size = ary.length, i = offset < 0 ? (size + offset > 0 ? size + offset : 0) : (offset || 0); i < size; i++) {\r\n if (ary[i][propName] === propValue) {\r\n return i;\r\n }\r\n }\r\n return -1;\r\n }\r\n Arrays.indexOfProp = indexOfProp;\r\n /** Search for the last index of an object with a specified property in an array\r\n * For example: Arrays.lastIndexOfPropValue([ {text: \"john's bid\", value: 12}, {text: \"test bid\", value: 12} ], \"value\", 12)\r\n * returns: 1\r\n * because the last object with the property \"value\" with a value of 12 was at index 1\r\n *\r\n * @param ary the array to search\r\n * @param propName the name of the property to search for on each object\r\n * @param propValue the property value to compare\r\n * @returns the array index of an object with a matching property, -1 if no matching object was found\r\n */\r\n function lastIndexOfProp(ary, propName, propValue) {\r\n if (ary == null || propName == null || propValue === undefined) {\r\n return -1;\r\n }\r\n for (var i = ary.length - 1; i > -1; i--) {\r\n if (ary[i][propName] === propValue) {\r\n return i;\r\n }\r\n }\r\n return -1;\r\n }\r\n Arrays.lastIndexOfProp = lastIndexOfProp;\r\n /** Check if two arrays are equal, element by element\r\n * For example: Arrays.equal([\"A\", 23, true], [\"A\", 23, true])\r\n * returns: true\r\n * Or example: Arrays.equal([\"A\", 23, true], [\"A\", 13])\r\n * returns: false\r\n *\r\n * @param ary1 the first array to compare\r\n * @param ary2 the second array to compare\r\n */\r\n function equal(ary1, ary2) {\r\n if (ary1 == null || ary2 == null || ary1.length !== ary2.length) {\r\n return false;\r\n }\r\n for (var i = 0, size = ary1.length; i < size; i++) {\r\n if (ary1[i] !== ary2[i]) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n }\r\n Arrays.equal = equal;\r\n /** Check whether two arrays are equal, ignoring the order of the elements in each array.\r\n * elements are compared using strict (i.e. '===') equality.\r\n * For example: Arrays.looseEqual([26, \"Alpha\", 5], [5, 26, \"Alpha\"])\r\n * returns: true\r\n * Or example: Arrays.looseEqual([34, \"A\", \"QA\"], [7, 34, \"A\"])\r\n * returns: false\r\n *\r\n * @param ary1 the first array to compare\r\n * @param ary2 the second array to compare\r\n * @returns true if both arrays contain the same elements in any order, or if both arrays are null.\r\n * False if one or more elements differ between the two arrays\r\n */\r\n function looseEqual(ary1, ary2) {\r\n if (ary1 == null || ary2 == null || !Array.isArray(ary1) || !Array.isArray(ary2)) {\r\n if (ary1 == null && ary2 == null) {\r\n return true;\r\n }\r\n if ((ary1 != null && !Array.isArray(ary1)) || (ary2 != null && !Array.isArray(ary2)) || ary1 === undefined || ary2 === undefined) {\r\n throw new Error(\"incorrect usage ([\" + ary1 + \"], [\" + ary2 + \"]), \" + \"expected (Array ary1, Array ary2)\");\r\n }\r\n if (ary1 == null || ary2 == null) {\r\n return false;\r\n }\r\n }\r\n if (ary1.length !== ary2.length) {\r\n return false;\r\n }\r\n var matchingCount = 0;\r\n for (var i = ary1.length - 1; i > -1; i--) {\r\n if (ary2.indexOf(ary1[i]) === -1) {\r\n return false;\r\n }\r\n matchingCount++;\r\n }\r\n return matchingCount == ary2.length;\r\n }\r\n Arrays.looseEqual = looseEqual;\r\n /** Transforms the elements of an array into a new array\r\n * For example: Arrays.map([1, 2, 3, 4], (value) => value % 3)\r\n * returns: [1, 2, 0, 1]\r\n *\r\n * @param ary the array to map\r\n * @returns a new array with each index containing the result of passing the original 'ary' element at that index through the 'mapFunc', or an empty array if the 'ary' is null\r\n */\r\n function map(ary, mapFunc) {\r\n if (ary == null) {\r\n return [];\r\n }\r\n var res = [];\r\n for (var i = 0, size = ary.length; i < size; i++) {\r\n res.push(mapFunc(ary[i], i, ary));\r\n }\r\n return res;\r\n }\r\n Arrays.map = map;\r\n /** Maps and filters an array in one operation by passing a two field object to the map-filter\r\n * function as a destination 'out' parameter like C#'s 'out' parameters\r\n * For example: Arrays.mapFilter([1, 2, 3, 4, 5, 6, 7], function (value, dstOut) { dstOut.isValid = (value % 3 !== 0); })\r\n * returns: [1, 2, 4, 5, 7]\r\n * Or example: Arrays.mapFilter(['A', 'B', 'C', 'D', 'C', 'A', 'B'], function (value, dstOut) { dstOut.isValid = (value !== 'D'); dstOut.value = value.toLowerCase(); })\r\n * returns: ['a', 'b', 'c', 'c', 'a', 'b']\r\n *\r\n * @param ary the array AND filter to map\r\n * @param mapFilterFunc since JS and TS don't have 'out' parameters\r\n * this function accepts a value and sets 'dstOut.isValid' true if the value is accepted, false if it is filtered out,\r\n * and stores the mapped result for valid values in 'dstOut.value'.\r\n * NOTE: if 'dstOut.value' is left null, the input 'value' is stored in the returned array\r\n * @returns an array of filtered and mapped result values\r\n */\r\n function mapFilter(ary, mapFilterFunc) {\r\n if (ary == null) {\r\n return [];\r\n }\r\n if (typeof mapFilterFunc !== \"function\") {\r\n throw new Error(\"incorrect parameter 'mapFilterFunc', must be a 'function(value, dstOut: { value; isValid }): void'\");\r\n }\r\n var results = [];\r\n var nil = {};\r\n var dstOut = { value: nil, isValid: false };\r\n for (var i = 0, size = ary.length; i < size; i++) {\r\n dstOut.isValid = false;\r\n dstOut.value = nil;\r\n var inputVal = ary[i];\r\n mapFilterFunc(inputVal, dstOut);\r\n if (dstOut.isValid === true) {\r\n results.push(dstOut.value !== nil ? dstOut.value : inputVal);\r\n }\r\n }\r\n return results;\r\n }\r\n Arrays.mapFilter = mapFilter;\r\n /** Like #mapFilter() except null return values are filtered out instead of using an two parameter 'out' style object with an 'isValid' flag\r\n * @param the array of values to map-filter\r\n * @param mapFunc the Array#map() style function to transform input values,\r\n * null returned values are not stored in the returned array, allowing the function to filter\r\n * @returns an array of non-null mapped result values\r\n */\r\n function mapFilterNotNull(ary, mapFunc) {\r\n if (ary == null) {\r\n return [];\r\n }\r\n if (typeof mapFunc !== \"function\") {\r\n throw new Error(\"incorrect parameter 'mapFilterFunc', must be a 'function(value): Object'\");\r\n }\r\n var results = [];\r\n for (var i = 0, size = ary.length; i < size; i++) {\r\n var res = mapFunc(ary[i], i, ary);\r\n if (res != null) {\r\n results.push(res);\r\n }\r\n }\r\n return results;\r\n }\r\n Arrays.mapFilterNotNull = mapFilterNotNull;\r\n function removeAll(ary, toRemove, fastRemove) {\r\n if (ary == null || toRemove == null) {\r\n return ary;\r\n }\r\n var idx;\r\n if (fastRemove) {\r\n // remove all matches by swapping them to the end of the array and shrinking the array\r\n for (var i = 0, size = toRemove.length; i < size; i++) {\r\n if ((idx = ary.indexOf(toRemove[i])) > -1) {\r\n Arrays.fastRemoveIndex(ary, idx);\r\n }\r\n }\r\n }\r\n else {\r\n // find the indices to remove\r\n var indicesToSkip = [];\r\n for (var i = 0, size = toRemove.length; i < size; i++) {\r\n if ((idx = ary.indexOf(toRemove[i])) > -1) {\r\n indicesToSkip.push(idx);\r\n }\r\n }\r\n // rebuild the array without the items to remove\r\n if (indicesToSkip.length > 0) {\r\n var newI = 0;\r\n var nextSkipIndexI = 0;\r\n var nextSkipIndex = indicesToSkip[nextSkipIndexI];\r\n for (var i = 0, size = ary.length; i < size; i++) {\r\n if (i === nextSkipIndex) {\r\n nextSkipIndexI++;\r\n nextSkipIndex = indicesToSkip[nextSkipIndexI];\r\n }\r\n else {\r\n ary[newI] = ary[i];\r\n newI++;\r\n }\r\n }\r\n ary.length = ary.length - indicesToSkip.length;\r\n }\r\n }\r\n return ary;\r\n }\r\n Arrays.removeAll = removeAll;\r\n /** Remove the first instance of a matching value from an array\r\n * @returns the removed index or -1 if the value could not be found\r\n */\r\n function removeValue(ary, value) {\r\n var idx = ary.indexOf(value);\r\n if (idx > -1) {\r\n removeIndex(ary, idx);\r\n }\r\n return idx;\r\n }\r\n Arrays.removeValue = removeValue;\r\n function removeIndex(ary, index) {\r\n if (ary == null) {\r\n return null;\r\n }\r\n var size = ary.length;\r\n if (size < 1 || index < 0 || index >= size) {\r\n return ary;\r\n }\r\n for (var i = index + 1; i < size; i++) {\r\n ary[i - 1] = ary[i];\r\n }\r\n ary[size - 1] = null;\r\n ary.length = size - 1;\r\n return ary;\r\n }\r\n Arrays.removeIndex = removeIndex;\r\n /** Set a property on every object in an array.\r\n * Useful for clearing a specific property to false or null.\r\n * @param ary the array of objects\r\n * @param propName the name of the property to set\r\n * @param propValue the value to assigned to each object's 'propName' property\r\n */\r\n function setAllProp(ary, propName, propValue) {\r\n if (ary == null || propName == null) {\r\n return;\r\n }\r\n for (var i = ary.length - 1; i > -1; i--) {\r\n ary[i][propName] = propValue;\r\n }\r\n }\r\n Arrays.setAllProp = setAllProp;\r\n /**\r\n * @returns the input array, sorted in numeric order (ascending by default, with second parameter flag to sort descending)\r\n */\r\n function sortNumeric(ary, descending) {\r\n if (descending === void 0) { descending = false; }\r\n if (descending === false) {\r\n ary.sort(function (a, b) { return a - b; });\r\n }\r\n else {\r\n ary.sort(function (a, b) { return b - a; });\r\n }\r\n return ary;\r\n }\r\n Arrays.sortNumeric = sortNumeric;\r\n /** Create an array containing the contents of two arrays.\r\n * For example: Arrays.spliceArray([0, 1, 1, 5], [10, 15, 20], 2, 1)\r\n * returns: [0, 1, 10, 15, 20, 5]\r\n *\r\n * @param origAry the initial array to copy\r\n * @param insertAry the array to insert into 'origAry'\r\n * @param index the 'origAry' index at which to insert the elements from 'insertAry'\r\n * @param deleteCount optional (default: 0) the number of elements to not copy from 'origAry' starting at 'index'\r\n * @returns the 'origAry' or a new array containing the contents of 'origAry' and 'insertAry'\r\n */\r\n function splice(origAry, insertAry, index, deleteCount, copyToNewAry) {\r\n if (deleteCount === void 0) { deleteCount = 0; }\r\n if (origAry == null) {\r\n if (insertAry == null) {\r\n return [];\r\n }\r\n else {\r\n return insertAry.slice(0);\r\n }\r\n }\r\n if ((origAry != null && !Array.isArray(origAry)) || (insertAry != null && !Array.isArray(insertAry))) {\r\n throw new Error(\"incorrect usage ([\" + origAry + \"], [\" + insertAry + \"], \" + index + \", \" + (deleteCount || 0) + \"), \" + \"expected (Array, Array, Integer[, Integer])\");\r\n }\r\n if (deleteCount === 0 && (insertAry == null || insertAry.length === 0)) {\r\n return (copyToNewAry ? origAry.slice() : origAry);\r\n }\r\n var tmp;\r\n // add to the end of the array\r\n if (index === origAry.length && deleteCount === 0) {\r\n tmp = (copyToNewAry ? origAry.slice() : origAry);\r\n if (insertAry != null && insertAry.length > 0) {\r\n Array.prototype.push.apply(tmp, insertAry);\r\n }\r\n }\r\n else if (index === 0 && deleteCount === 0) {\r\n tmp = (copyToNewAry ? origAry.slice() : origAry);\r\n if (insertAry != null && insertAry.length > 0) {\r\n Array.prototype.unshift.apply(tmp, insertAry);\r\n }\r\n }\r\n else {\r\n // copy up to the index to insert, then insert the array, and copying the remaining portion\r\n tmp = origAry.slice(0, index);\r\n if (insertAry != null && insertAry.length > 0) {\r\n Array.prototype.push.apply(tmp, insertAry);\r\n }\r\n for (var i = index + deleteCount, size = origAry.length; i < size; i++) {\r\n tmp.push(origAry[i]);\r\n }\r\n }\r\n return tmp;\r\n }\r\n Arrays.splice = splice;\r\n /** Swap two elements in an array\r\n * For example: Arrays.swap([\"A\", \"B\", \"C\", \"D\"], 1, 2)\r\n * returns: [\"A\", \"C\", \"B\", \"D\"]\r\n *\r\n * @param ary the array of elements\r\n * @param i1 the first index of the two indexes to swap\r\n * @param i2 the second index of the two indexes to swap\r\n */\r\n function swap(ary, i1, i2) {\r\n var tmp = ary[i2];\r\n ary[i2] = ary[i1];\r\n ary[i1] = tmp;\r\n return ary;\r\n }\r\n Arrays.swap = swap;\r\n function toMap(ary, prop) {\r\n if (ary == null) {\r\n return {};\r\n }\r\n return Array.prototype.reduce.call(ary, function (map, itm) {\r\n map[itm[prop]] = itm;\r\n return map;\r\n }, {});\r\n }\r\n Arrays.toMap = toMap;\r\n /** Return elements that exist in two arrays.\r\n * For example: Arrays.union([1, 2, 3, 4, 5, \"A\"], [1, 2, 4, \"A\"])\r\n * returns: [1, 2, 4, \"A\"]\r\n *\r\n * @param ary1 the first array\r\n * @param ary2 the second array\r\n * @returns an array of shared elements between 'ary1' and 'ary2'\r\n */\r\n function union(ary1, ary2) {\r\n if (ary1 == null || ary2 == null) {\r\n if (ary1 == null && ary2 != null) {\r\n return ary2.slice();\r\n }\r\n else if (ary1 != null && ary2 == null) {\r\n return ary1.slice();\r\n }\r\n else {\r\n return [];\r\n }\r\n }\r\n var results = [];\r\n for (var i = 0, size = ary1.length; i < size; i++) {\r\n var idx = ary2.indexOf(ary1[i]);\r\n if (idx > -1) {\r\n results.push(ary1[i]);\r\n }\r\n }\r\n return results;\r\n }\r\n Arrays.union = union;\r\n /** Find the maximum value in an array of numbers\r\n * @param ary the array of numbers to search\r\n */\r\n function max(ary) {\r\n var max = Number.NEGATIVE_INFINITY;\r\n for (var i = 0, size = ary.length; i < size; i++) {\r\n max = ary[i] > max ? ary[i] : max;\r\n }\r\n return max;\r\n }\r\n Arrays.max = max;\r\n /** Find the maximum value in an array of numbers\r\n * @param ary the array of numbers to search\r\n */\r\n function maxValueIndex(ary) {\r\n var max = Number.NEGATIVE_INFINITY;\r\n var maxI = -1;\r\n for (var i = 0, size = ary.length; i < size; i++) {\r\n if (ary[i] > max) {\r\n max = ary[i];\r\n maxI = i;\r\n }\r\n }\r\n return maxI;\r\n }\r\n Arrays.maxValueIndex = maxValueIndex;\r\n /** Find the minimum value in an array of numbers\r\n * @param ary the array of numbers to search\r\n */\r\n function min(ary) {\r\n var min = Number.POSITIVE_INFINITY;\r\n for (var i = 0, size = ary.length; i < size; i++) {\r\n min = ary[i] < min ? ary[i] : min;\r\n }\r\n return min;\r\n }\r\n Arrays.min = min;\r\n /** Find the minimum value in an array of numbers\r\n * @param ary the array of numbers to search\r\n */\r\n function minValueIndex(ary) {\r\n var min = Number.POSITIVE_INFINITY;\r\n var minI = -1;\r\n for (var i = 0, size = ary.length; i < size; i++) {\r\n if (ary[i] < min) {\r\n min = ary[i];\r\n minI = i;\r\n }\r\n }\r\n return minI;\r\n }\r\n Arrays.minValueIndex = minValueIndex;\r\n /** Sum the values of an array\r\n * @param ary an array of numeric convertable values to sum; null, infinite, and NaN values in the array are treated as zero.\r\n * If the array is null, 0 is returned.\r\n * @returns the sum of the values in 'ary'\r\n */\r\n function sum(ary, infinityToZero) {\r\n if (ary == null) {\r\n return 0;\r\n }\r\n var sum = 0;\r\n for (var i = ary.length - 1; i > -1; i--) {\r\n var val = ary[i];\r\n val = (val == null || isNaN(val) || (infinityToZero && (val === Infinity || val === Number.NEGATIVE_INFINITY || val === Number.POSITIVE_INFINITY))) ? 0 : val;\r\n sum += val;\r\n }\r\n return sum;\r\n }\r\n Arrays.sum = sum;\r\n})(Arrays || (Arrays = {}));\r\nmodule.exports = Arrays;\r\n", - "\"use strict\";\r\n/** Utility functions used by DataPersister implementations\r\n * @since 2015-2-4\r\n */\r\nvar DbUtil = /** @class */ (function () {\r\n /** DB Utility configuration:\r\n * @param dbTypeName the name to show in error message (ex: 'WebSQL')\r\n * @param dbToStringId the Object.prototype.toString() name of the type (ex: '[Database]' for WebSQL instances). NOTE: this should match type \r\n * @param settings configuration object with the following properties:\r\n * `defer`: specifies the function that constructs a deferred object, such as:\r\n * - Promise (native browser/node.js implementation)\r\n * - [`when.js`](https://github.com/cujojs/when)\r\n * - [`Q.js`](https://github.com/kriskowal/q)\r\n * - [`jQuery's Deferred`](http://api.jquery.com/category/deferred-object/)\r\n * - Other...\r\n * `whenAll`: a Promise.all() style function for the promises returned by the 'defer' object\r\n * `trace`: specifies the object used for logging messages. Default is `window.console`.\r\n * `verbosity`: specifies verbosity of logging (NONDE, ERROR or DEBUG). Default is `log.NONE`.\r\n * `logTimings`: whether to log query timings\r\n */\r\n function DbUtil(dbTypeName, dbToStringId, settings) {\r\n var _this = this;\r\n this.trace = null;\r\n this.NONE = DbUtil.logLevels.NONE;\r\n this.ERROR = DbUtil.logLevels.ERROR;\r\n this.DEBUG = DbUtil.logLevels.DEBUG;\r\n this.verbosity = this.NONE;\r\n this.logTimings = settings.logTimings;\r\n this.defer = settings.defer;\r\n this.whenAll = settings.whenAll;\r\n this.dbTypeName = dbTypeName;\r\n this.isDatabase = function (db) { return _this._toString(db) === dbToStringId; };\r\n if (!this.isFunction(settings.defer)) {\r\n throw new Error(\"no 'defer' promise function option provided to \" + dbTypeName + \" adapter\");\r\n }\r\n if (settings.trace != null && this.isFunction(settings.trace.log)) {\r\n this.trace = settings.trace;\r\n }\r\n if (typeof settings.verbosity !== \"undefined\") {\r\n this.verbosity = settings.verbosity;\r\n }\r\n }\r\n // Internal Functions\r\n DbUtil.prototype._toString = function (obj) { return Object.prototype.toString.call(obj); };\r\n DbUtil.prototype.isString = function (fn) { return this._toString(fn) === \"[object String]\"; };\r\n DbUtil.prototype.isFunction = function (fn) { return this._toString(fn) === \"[object Function]\"; };\r\n DbUtil.prototype.isPromise = function (obj) { return obj && this.isFunction(obj.then); };\r\n /** Calls `onSuccess` or `onError` when `promise` is resolved.\r\n * Returns a new promise that is resolved/rejected based on the\r\n * values returned from the callbacks.\r\n */\r\n DbUtil.prototype.pipe = function (p, onSuccess, onError) {\r\n var self = this;\r\n var dfd = this.defer();\r\n p.then(function (val) {\r\n var res = onSuccess(val);\r\n if (self.isPromise(res)) {\r\n res.then(dfd.resolve, dfd.reject);\r\n }\r\n else {\r\n dfd.resolve(res);\r\n }\r\n }, function (err) {\r\n if (onError) {\r\n err = onError(err);\r\n }\r\n if (self.isPromise(err)) {\r\n err.then(dfd.resolve, dfd.reject);\r\n }\r\n else {\r\n dfd.reject(err);\r\n }\r\n });\r\n return dfd.promise;\r\n };\r\n /** Log statement if level > verbosity\r\n * Usage:\r\n * log(DEBUG, \"Calling function\", functionName);\r\n * log(ERROR, \"Something horrible happened:\", error);\r\n */\r\n DbUtil.prototype.log = function (level) {\r\n var args = [];\r\n for (var _i = 1; _i < arguments.length; _i++) {\r\n args[_i - 1] = arguments[_i];\r\n }\r\n var trc = this.trace;\r\n if (level <= this.verbosity && trc != null) {\r\n args.unshift(this.dbTypeName);\r\n if (this.isFunction(trc.text)) {\r\n trc.text(args, \"color: purple\");\r\n }\r\n else if (level === this.ERROR && this.isFunction(trc.error)) {\r\n trc.error(args);\r\n }\r\n else if (this.isFunction(trc.log)) {\r\n trc.log(args);\r\n }\r\n }\r\n };\r\n DbUtil.prototype.setConsole = function (console) {\r\n this.trace = console;\r\n };\r\n DbUtil.prototype.rejectError = function (dfd, error, options) {\r\n if (typeof error === \"string\") {\r\n error = new Error(error);\r\n }\r\n if (options != null) {\r\n if (options.exception)\r\n error.exception = options.exception;\r\n if (options.sqlError)\r\n error.sqlError = options.sqlError;\r\n }\r\n this.log(this.ERROR, \"ERROR: \" + (error.exception || (error.sqlError ? error.sqlError.message : error.sqlError) || error.message));\r\n dfd.reject(error);\r\n return dfd.promise;\r\n };\r\n DbUtil.getOptionsOrDefault = function (opts, defaultOpts) {\r\n var defaultCompress = (defaultOpts != null && defaultOpts.compress) || false;\r\n var defaultKeyAutoGenerate = (defaultOpts != null && defaultOpts.keyAutoGenerate) || null;\r\n var defaultKeyGetter = (defaultOpts != null && defaultOpts.keyGetter) || null;\r\n var defaultKeyColumn = (defaultOpts != null && defaultOpts.keyColumn) || null;\r\n var defaultGroupByKey = (defaultOpts != null && defaultOpts.groupByKey) || null;\r\n var defaultDataColumnName = (defaultOpts != null && defaultOpts.dataColumnName) || null;\r\n var defaultChunkSize = (defaultOpts != null && defaultOpts.maxObjectsPerChunk) || null;\r\n var defaultDeleteIfExists = (defaultOpts != null && defaultOpts.deleteIfExists) || false;\r\n return {\r\n compress: opts != null ? opts.compress : defaultCompress,\r\n keyAutoGenerate: opts != null ? opts.keyAutoGenerate : defaultKeyAutoGenerate,\r\n keyGetter: opts != null ? opts.keyGetter : defaultKeyGetter,\r\n keyColumn: opts != null ? opts.keyColumn : defaultKeyColumn,\r\n groupByKey: opts != null ? opts.groupByKey : defaultGroupByKey,\r\n dataColumnName: opts != null ? (opts.dataColumnName || defaultDataColumnName) : defaultDataColumnName,\r\n maxObjectsPerChunk: opts != null ? (opts.maxObjectsPerChunk || defaultChunkSize) : defaultChunkSize,\r\n deleteIfExists: opts != null ? opts.deleteIfExists : defaultDeleteIfExists,\r\n };\r\n };\r\n /** Create a timer that uses window.performance.now()\r\n * @param name the new timer's name\r\n */\r\n DbUtil.newTimer = function (name) {\r\n var useWnd = typeof window !== \"undefined\";\r\n var startMillis = (useWnd ? window.performance.now() : new Date().getTime());\r\n var inst = {\r\n name: name,\r\n startMillis: startMillis,\r\n endMillis: null,\r\n measure: function () {\r\n var endMillis = (useWnd ? window.performance.now() : new Date().getTime());\r\n var durationMillis = endMillis - startMillis;\r\n inst.endMillis = endMillis;\r\n return durationMillis;\r\n },\r\n };\r\n return inst;\r\n };\r\n /** Predefined log verbosity levels:\r\n * `log.NONE`: No logging.\r\n * `log.ERROR`: Log errors.\r\n * `log.DEBUG`: Verbose logging.\r\n */\r\n DbUtil.logLevels = {\r\n NONE: 0,\r\n ERROR: 1,\r\n DEBUG: 2\r\n };\r\n return DbUtil;\r\n}());\r\nmodule.exports = DbUtil;\r\n", - "\"use strict\";\r\nvar Arrays = require(\"ts-mortar/utils/Arrays\");\r\nvar DbUtil = require(\"./DbUtil\");\r\n/* IndexedDbPersister class which implements 'DataPersister' for saving data to IndexedDB for long-term browser data storage.\r\n * Exports 'IndexedDbSpi' interface which has two methods: getTables() and executeQueries(), which is the link between this 'IndexedDbPersister' class and the underlying IndexedDB database.\r\n * @author TeamworkGuy2\r\n */\r\nvar IndexedDbPersister = /** @class */ (function () {\r\n /** Create a DataPersister based on an IndexedDB instance and some additional functions to control the behavior of this persister.\r\n * @param persistenceInterface the underlying database to persist to\r\n * @param trace the object with functions for logging debug messages and errors\r\n * @param getDataCollections returns a list of data collections that contain the data to persist/restore to\r\n * @param addCollection when restoring a database, call this function with each table name found and restored documents\r\n * @param saveItemTransformation optional conversion function to pass items from 'getDataCollections()' through before persisting them\r\n * @param restoreItemTransformation optional conversion function to pass items through after restoring them and before storing them in 'getDataCollections()'\r\n * @param storageFailureCallback callback for handling/logging storage errors\r\n * @param tablesToNotClear optional array of collection names to not clear when 'clearPersistentDb()' is called\r\n * @param tablesToNotLoad optional array of collection names to not load when 'restore()' is called\r\n */\r\n function IndexedDbPersister(persistenceInterface, trace, getDataCollections, addCollection, saveItemTransformation, restoreItemTransformation, storageFailureCallback, tablesToNotClear, tablesToNotLoad) {\r\n this.tablesToNotClear = [];\r\n this.tablesToNotLoad = [];\r\n this.persistenceInterface = persistenceInterface;\r\n this.logger = trace;\r\n this.itemSaveConverter = saveItemTransformation;\r\n this.itemLoadConverter = restoreItemTransformation;\r\n this.getDataCollections = getDataCollections;\r\n this.addCollection = addCollection;\r\n this.storageFailureCallback = storageFailureCallback;\r\n this.tablesToNotClear = tablesToNotClear || [];\r\n this.tablesToNotLoad = tablesToNotLoad || [];\r\n }\r\n /** Get a list of collection names in this data persister\r\n */\r\n IndexedDbPersister.prototype.getCollectionNames = function () {\r\n return this.persistenceInterface.getTables();\r\n };\r\n /** Save this in-memory database to some form of persistent storage\r\n * Removes tables from store that don't exist in in-memory db\r\n */\r\n IndexedDbPersister.prototype.persist = function (defaultOptions, getCollectionOptions) {\r\n var that = this;\r\n var colls = that.getDataCollections();\r\n var persistCount = 0;\r\n return this.persistenceInterface.getTables().then(function (collNames) {\r\n var tableAdds = [];\r\n var tableDels = [];\r\n var tableInserts = [];\r\n colls.forEach(function (coll) {\r\n var opts = DbUtil.getOptionsOrDefault(getCollectionOptions != null ? getCollectionOptions(coll.name) : null, defaultOptions);\r\n var exists = collNames.indexOf(coll.name) !== -1;\r\n var keyCol = opts.keyColumn != null ? (typeof opts.keyColumn === \"string\" ? opts.keyColumn : opts.keyColumn.name) : null;\r\n var autoIncrement = opts.keyAutoGenerate;\r\n if (opts.deleteIfExists && exists) {\r\n tableDels.push({ name: coll.name });\r\n tableAdds.push({ name: coll.name, keyPath: keyCol, autoIncrement: autoIncrement });\r\n }\r\n if (!exists) {\r\n tableAdds.push({ name: coll.name, keyPath: keyCol, autoIncrement: autoIncrement });\r\n }\r\n if (coll.dirty) {\r\n persistCount++;\r\n if (coll.data.length > 0) {\r\n var collData = that.prepDataForSave(coll.data, opts.maxObjectsPerChunk, opts.groupByKey, opts.keyGetter);\r\n tableInserts.push({ name: coll.name, clear: exists, records: collData });\r\n }\r\n else {\r\n tableInserts.push({ name: coll.name, clear: exists });\r\n }\r\n }\r\n });\r\n return that.persistenceInterface.modifyDatabase(tableDels, tableAdds, tableInserts);\r\n }).then(function (rs) {\r\n var persistRes = {\r\n collections: {}\r\n };\r\n rs.inserts.forEach(function (insert) {\r\n // reset collection 'dirty' flag after data successfully saved\r\n var coll = colls.find(function (x) { return x.name === insert.name; });\r\n if (coll != null) {\r\n coll.dirty = false;\r\n }\r\n persistRes.collections[insert.name] = {\r\n size: insert.added,\r\n dataSizeBytes: null\r\n };\r\n });\r\n return persistRes;\r\n });\r\n };\r\n /** Restore in-memory database from persistent store\r\n * All in memory tables are dropped and re-added\r\n */\r\n IndexedDbPersister.prototype.restore = function (defaultOptions, getCollectionOptions) {\r\n var that = this;\r\n var restoreRes = {\r\n collections: {}\r\n };\r\n return this.persistenceInterface.getTables().then(function (tables) {\r\n var tablesToLoad = tables.filter(function (tbl) { return that.tablesToNotLoad.indexOf(tbl) === -1; }).map(function (tbl) { return ({ name: tbl }); });\r\n return that.getCollectionsRecords(tablesToLoad);\r\n }).then(function (results) {\r\n results.forEach(function (result) {\r\n var rows = result.records;\r\n var docs = [];\r\n if (rows.length > 0) {\r\n var opts = getCollectionOptions != null ? getCollectionOptions(result.name) : null;\r\n var expectArrayRes = (opts == null || opts.isChunks);\r\n docs = that.readRecords(result.records, expectArrayRes);\r\n }\r\n else {\r\n //if (that.logger != null) that.logger.log(\"skip restoring table: \" + tableName + \" (0 items)\");\r\n }\r\n restoreRes.collections[result.name] = {\r\n size: docs.length,\r\n dataSizeBytes: null\r\n };\r\n that.addCollection(result.name, docs);\r\n });\r\n return restoreRes;\r\n }, function (err) {\r\n throw err;\r\n });\r\n };\r\n /** Get all data from a specific collection\r\n */\r\n IndexedDbPersister.prototype.getCollectionRecords = function (collectionName, options) {\r\n return this.getCollectionsRecords([{ name: collectionName, options: options }]).then(function (r) { return r[0].records; });\r\n };\r\n IndexedDbPersister.prototype.getCollectionsRecords = function (collections) {\r\n var collectionNames = Arrays.pluck(collections, \"name\");\r\n var xact = this.persistenceInterface.db.transaction(collectionNames, \"readonly\");\r\n var recordsXacts = collections.map(function (coll) { return ({ name: coll.name, getAll: xact.objectStore(coll.name).getAll() }); });\r\n var dfd = this.persistenceInterface.util.defer();\r\n xact.oncomplete = function onIdbSuccess(evt) {\r\n var notDoneXacts = recordsXacts.filter(function (x) { return x.getAll.readyState !== \"done\"; });\r\n if (notDoneXacts.length > 0) {\r\n throw new Error(notDoneXacts.length + \" transactions are not done in 'oncomplete' callback\");\r\n }\r\n var results = recordsXacts.map(function (x) { return ({ name: x.name, records: x.getAll.result }); });\r\n dfd.resolve(results);\r\n };\r\n function onIdbError(evt) {\r\n dfd.reject(xact.error);\r\n }\r\n xact.onerror = onIdbError;\r\n xact.onabort = onIdbError;\r\n return dfd.promise;\r\n };\r\n /** Add data to a specific collection\r\n */\r\n IndexedDbPersister.prototype.addCollectionRecords = function (collectionName, options, records, removeExisting) {\r\n var data = this.prepDataForSave(records, options.maxObjectsPerChunk, options.groupByKey, options.keyGetter);\r\n return this.persistenceInterface.insertMultiple([{\r\n name: collectionName,\r\n clear: removeExisting,\r\n records: data\r\n }]).then(function (rs) { return ({ size: rs.inserts[0].added, dataSizeBytes: null }); });\r\n };\r\n /** Remove all data from the specificed collections\r\n */\r\n IndexedDbPersister.prototype.clearCollections = function (collectionNames) {\r\n var clearColls = collectionNames.map(function (collName) { return ({ name: collName, clear: true }); });\r\n return this.persistenceInterface.insertMultiple(clearColls);\r\n };\r\n /** Delete all data related this database from persistent storage\r\n */\r\n IndexedDbPersister.prototype.clearPersistentDb = function () {\r\n var _this = this;\r\n return this.persistenceInterface.getTables().then(function (tables) {\r\n var delColls = tables\r\n .filter(function (tbl) { return _this.tablesToNotClear.indexOf(tbl) === -1; })\r\n .map(function (tbl) { return ({ name: tbl }); });\r\n return _this.persistenceInterface.modifyDatabase(delColls, null, null);\r\n });\r\n };\r\n IndexedDbPersister.prototype.readRecords = function (rows, expectArrayRes) {\r\n var convertFunc = this.itemLoadConverter;\r\n var docs = [];\r\n for (var i = 0, size = rows.length; i < size; i++) {\r\n var dataBlob = rows[i];\r\n var resChunks = [];\r\n if (convertFunc != null) {\r\n if (expectArrayRes && Array.isArray(dataBlob)) {\r\n for (var j = 0, sizeJ = dataBlob.length; j < sizeJ; j++) {\r\n resChunks.push(convertFunc(dataBlob[j]));\r\n }\r\n }\r\n else {\r\n resChunks.push(convertFunc(dataBlob));\r\n }\r\n }\r\n else {\r\n if (expectArrayRes && Array.isArray(dataBlob)) {\r\n resChunks = dataBlob;\r\n }\r\n else {\r\n resChunks.push(dataBlob);\r\n }\r\n }\r\n Array.prototype.push.apply(docs, resChunks);\r\n }\r\n return docs;\r\n };\r\n IndexedDbPersister.prototype.prepDataForSave = function (items, chunkSize, groupByKey, keyGetter) {\r\n var resItems = items;\r\n if (this.itemSaveConverter != null) {\r\n var convertFunc = this.itemSaveConverter;\r\n resItems = [];\r\n for (var j = 0, sizeJ = items.length; j < sizeJ; j++) {\r\n resItems.push(convertFunc(items[j]));\r\n }\r\n }\r\n var data = [];\r\n // records by chunks\r\n if (chunkSize > 0) {\r\n for (var i = 0, size = resItems.length; i < size; i += chunkSize) {\r\n data.push(resItems.slice(i, i + chunkSize > size ? size : i + chunkSize));\r\n }\r\n }\r\n // records by group-by\r\n else if (groupByKey != null && keyGetter != null) {\r\n var groups;\r\n if (typeof keyGetter === \"string\") {\r\n groups = resItems.reduce(function (grps, rec) {\r\n var key = rec[keyGetter];\r\n var grp = grps[key] || (grps[key] = []);\r\n grp.push(rec);\r\n return grps;\r\n }, {});\r\n }\r\n else {\r\n groups = resItems.reduce(function (grps, rec) {\r\n var key = keyGetter(rec);\r\n var grp = grps[key] || (grps[key] = []);\r\n grp.push(rec);\r\n return grps;\r\n }, {});\r\n }\r\n data = Object.keys(groups).map(function (k) { return groups[k]; });\r\n }\r\n // records as-is from collection.data array\r\n else {\r\n Array.prototype.push.apply(data, resItems);\r\n }\r\n return data;\r\n };\r\n return IndexedDbPersister;\r\n}());\r\nmodule.exports = IndexedDbPersister;\r\n", - "\"use strict\";\r\nvar DbUtil = require(\"./DbUtil\");\r\nvar IndexedDbSpi = /** @class */ (function () {\r\n function IndexedDbSpi(db, util) {\r\n this.db = db;\r\n this.util = util;\r\n }\r\n IndexedDbSpi.prototype.getDatabase = function () {\r\n return this.db;\r\n };\r\n IndexedDbSpi.prototype.getTables = function () {\r\n var names = [];\r\n Array.prototype.push.apply(names, this.db.objectStoreNames);\r\n var dfd = this.util.defer();\r\n dfd.resolve(names);\r\n return dfd.promise;\r\n };\r\n IndexedDbSpi.prototype.insertMultiple = function (collectionInserts) {\r\n var res = {\r\n inserts: [],\r\n insertErrors: []\r\n };\r\n return IndexedDbSpi.inserts(this.db, this.util, collectionInserts, res);\r\n };\r\n /** All-in-one function to remove IndexedDB stores, add new stores, and insert records into stores.\r\n * This function handles bumping the DB version to trigger an 'onupgrade' callback to add and remove stores.\r\n * @param tableDels optional list of stores to remove from the DB, these run first\r\n * @param tableAdds optional list of stores to add to the DB, these run second\r\n * @param tableInserts optional list of data insertions to run against the DB, these run third (after table deletes/creates)\r\n */\r\n IndexedDbSpi.prototype.modifyDatabase = function (tableDels, tableAdds, tableInserts) {\r\n var inst = this;\r\n var name = this.db.name;\r\n var version = this.db.version;\r\n this.db.close();\r\n var res = {\r\n createdStores: [],\r\n createErrors: [],\r\n deletedStores: [],\r\n deleteErrors: [],\r\n inserts: [],\r\n insertErrors: []\r\n };\r\n var hasSchemaChanges = (tableAdds != null && tableAdds.length > 0) || (tableDels != null && tableDels.length > 0);\r\n // upgrade the DB version to trigger an 'onupgradeneeded' call so we can create and/or delete object stores\r\n return IndexedDbSpi.openDatabase(this.util, name, hasSchemaChanges ? version + 1 : version, function versionUpgrade(evt) {\r\n // Database modifications must be performed within 'onupgrade' callback\r\n var db = this.result;\r\n inst.db = db;\r\n // delete stores (first so that create stores can re-create stores)\r\n (tableDels || []).forEach(function (tbl) {\r\n try {\r\n db.deleteObjectStore(tbl.name);\r\n res.deletedStores.push(tbl);\r\n }\r\n catch (err) {\r\n res.deleteErrors.push({ name: tbl.name, error: err });\r\n }\r\n });\r\n // create stores\r\n (tableAdds || []).forEach(function (tbl) {\r\n try {\r\n var createRes = db.createObjectStore(tbl.name, tbl);\r\n res.createdStores.push(createRes);\r\n }\r\n catch (err) {\r\n res.createErrors.push({ name: tbl.name, error: err });\r\n }\r\n });\r\n }).then(function () { return IndexedDbSpi.inserts(inst.db, inst.util, tableInserts, res); });\r\n };\r\n IndexedDbSpi.prototype.destroyDatabase = function () {\r\n var dfd = this.util.defer();\r\n var dbDelReq = self.indexedDB.deleteDatabase(this.db.name);\r\n wrapRequest(dbDelReq, function destroyDbSuccess(evt) {\r\n dfd.resolve(null);\r\n }, function destroyDbError(evt) {\r\n dfd.reject(dbDelReq.error);\r\n });\r\n return dfd.promise;\r\n };\r\n IndexedDbSpi.addOrPut = function (dbColl, tbl) {\r\n if (tbl.records == null) {\r\n return;\r\n }\r\n // TODO for now just calling put()/add() in a loop and not waiting on the resulting request to complete before inserting the next\r\n if (tbl.overwrite) {\r\n if (tbl.keyGetter != null) {\r\n for (var i = 0, size = tbl.records.length; i < size; i++) {\r\n dbColl.put(tbl.records[i], tbl.keyGetter(tbl.records[i]));\r\n }\r\n }\r\n else {\r\n for (var i = 0, size = tbl.records.length; i < size; i++) {\r\n dbColl.put(tbl.records[i]);\r\n }\r\n }\r\n }\r\n else {\r\n if (tbl.keyGetter != null) {\r\n for (var i = 0, size = tbl.records.length; i < size; i++) {\r\n dbColl.add(tbl.records[i], tbl.keyGetter(tbl.records[i]));\r\n }\r\n }\r\n else {\r\n for (var i = 0, size = tbl.records.length; i < size; i++) {\r\n dbColl.add(tbl.records[i]);\r\n }\r\n }\r\n }\r\n };\r\n IndexedDbSpi.inserts = function (db, util, tableInserts, res) {\r\n if (tableInserts == null) {\r\n return res;\r\n }\r\n var pInserts = util.defer();\r\n var insertCount = tableInserts.length;\r\n var insertsDone = 0;\r\n // insert records into stores\r\n tableInserts.forEach(function (tbl) {\r\n var insertErrors = [];\r\n var xact = db.transaction(tbl.name, \"readwrite\");\r\n var dbColl = xact.objectStore(tbl.name);\r\n var clearedCount = 0;\r\n if (tbl.clear) {\r\n // get record count and clear the store\r\n var countReq = dbColl.count();\r\n countReq.onsuccess = function onIdbSuccess(evt) {\r\n var clearReq = dbColl.clear();\r\n clearReq.onsuccess = function onIdbSuccess(evt) {\r\n clearedCount = countReq.result;\r\n // add new records\r\n IndexedDbSpi.addOrPut(dbColl, tbl);\r\n };\r\n clearReq.onerror = function onIdbSuccess(evt) {\r\n insertErrors.push(clearReq.error);\r\n xact.abort();\r\n };\r\n };\r\n countReq.onerror = function onIdbSuccess(evt) {\r\n insertErrors.push(countReq.error);\r\n xact.abort();\r\n };\r\n }\r\n else {\r\n // add new records\r\n IndexedDbSpi.addOrPut(dbColl, tbl);\r\n }\r\n xact.oncomplete = function onIdbSuccess(evt) {\r\n res.inserts.push({ name: tbl.name, added: tbl.records != null ? tbl.records.length : 0, removed: clearedCount });\r\n insertsDone++;\r\n if (insertsDone >= insertCount) {\r\n pInserts.resolve(res);\r\n }\r\n };\r\n function onIdbError(evt) {\r\n insertErrors.push(xact.error);\r\n res.insertErrors.push({ name: tbl.name, errors: insertErrors });\r\n insertsDone++;\r\n pInserts.reject(xact.error);\r\n }\r\n xact.onerror = onIdbError;\r\n xact.onabort = onIdbError;\r\n });\r\n return pInserts.promise;\r\n };\r\n IndexedDbSpi.openDatabase = function (util, name, version, onupgradeneeded) {\r\n util.log(util.DEBUG, \"openDatabase\", name, version);\r\n var dfd = util.defer();\r\n var pUpgrade;\r\n try {\r\n if (typeof self === \"undefined\" || !self.indexedDB) {\r\n util.rejectError(dfd, \"IndexedDB not implemented\");\r\n }\r\n else {\r\n var dbOpenReq = (version != null ? self.indexedDB.open(name, version) : self.indexedDB.open(name));\r\n wrapRequest(dbOpenReq, function openDbSuccess(evt) {\r\n if (pUpgrade != null) {\r\n pUpgrade.then(function (r) { return dfd.resolve(dbOpenReq.result); }, function (err) { return util.rejectError(dfd, \"onupgradeneeded handler failed\", { exception: err }); });\r\n }\r\n else {\r\n dfd.resolve(dbOpenReq.result);\r\n }\r\n }, function openDbError(evt) {\r\n util.rejectError(dfd, \"Failed to open database\", { exception: dbOpenReq.error });\r\n }, function dbUpgradeNeeded(evt) {\r\n // triggered when opening a new DB or an existing DB with a higher version number than last time it was opened\r\n util.log(util.DEBUG, \"upgradeNeeded\", name, version);\r\n if (onupgradeneeded != null) {\r\n var onUpgradeRes = onupgradeneeded.call(this, evt);\r\n if (util.isPromise(onUpgradeRes)) {\r\n pUpgrade = onUpgradeRes;\r\n }\r\n }\r\n });\r\n }\r\n }\r\n catch (ex) {\r\n util.rejectError(dfd, \"Failed to open database \" + name, { exception: ex });\r\n }\r\n return dfd.promise;\r\n };\r\n IndexedDbSpi.newIndexedDb = function (name, version, utilSettings) {\r\n var util = new DbUtil(\"IndexedDB\", \"[object IDBDatabase]\", utilSettings);\r\n // Create IndexedDB wrapper from native Database or by opening 'name' DB\r\n var pOpen;\r\n if (util.isDatabase(name)) {\r\n var dfd = util.defer();\r\n dfd.resolve(name);\r\n pOpen = dfd.promise;\r\n }\r\n else {\r\n pOpen = IndexedDbSpi.openDatabase(util, name, version);\r\n }\r\n return pOpen.then(function (dbInst) { return new IndexedDbSpi(dbInst, util); });\r\n };\r\n return IndexedDbSpi;\r\n}());\r\nfunction isOpenDbRequest(dbReq) {\r\n return \"onupgradeneeded\" in dbReq;\r\n}\r\nfunction wrapRequest(dbReq, onsuccess, onerror, onupgradeneeded) {\r\n dbReq.onsuccess = onsuccess;\r\n dbReq.onerror = onerror;\r\n if (isOpenDbRequest(dbReq)) {\r\n if (onupgradeneeded == null) {\r\n throw new Error(\"must provide an onupgradeneeded handler for open DB requests\");\r\n }\r\n dbReq.onupgradeneeded = onupgradeneeded;\r\n dbReq.onblocked = onerror;\r\n }\r\n return dbReq;\r\n}\r\nmodule.exports = IndexedDbSpi;\r\n", - "\"use strict\";\r\nvar Arrays = require(\"ts-mortar/utils/Arrays\");\r\nvar DbUtil = require(\"./DbUtil\");\r\n/** WebSqlPersister class which implements 'DataPersister' for saving data to WebSQL for long-term browser data storage.\r\n * Exports 'WebSqlSpi' interface which has two methods: getTables() and executeQueries(), which is the link between this 'WebSqlPersister' class and the underlying WebSQL database.\r\n * @author TeamworkGuy2\r\n */\r\nvar WebSqlPersister = /** @class */ (function () {\r\n /** Create a DataPersister based on a WebSqlSpi instance and some additional functions to control the behavior of this persister.\r\n * @param persistenceInterface the underlying database to persist to\r\n * @param trace the object with functions for logging debug messages and errors\r\n * @param getDataCollections returns a list of data collections that contain the data to persist/restore to\r\n * @param addCollection when restoring a database, call this function with each table name found and restored documents\r\n * @param saveItemTransformation optional conversion function to pass items from 'getDataCollections()' through before persisting them\r\n * @param postSaveTransformKeyValueFilter optional JSON.stringify() 'replacer', second parameter, function which is called for each object stringified by calls to persist()\r\n * @param restoreItemTransformation optional conversion function to pass items through after restoring them and before storing them in 'getDataCollections()'\r\n * @param storageFailureCallback callback for handling/logging storage errors\r\n * @param tablesToNotClear optional array of collection names to not clear when 'clearPersistentDb()' is called\r\n * @param tablesToNotLoad optional array of collection names to not load when 'restore()' is called\r\n */\r\n function WebSqlPersister(persistenceInterface, trace, getDataCollections, addCollection, saveItemTransformation, postSaveTransformKeyValueFilter, restoreItemTransformation, storageFailureCallback, tablesToNotClear, tablesToNotLoad) {\r\n this.tablesToNotClear = [];\r\n this.tablesToNotLoad = [];\r\n this.persistenceInterface = persistenceInterface;\r\n this.logger = trace;\r\n this.itemSaveConverter = saveItemTransformation;\r\n this.itemKeyValueFilter = postSaveTransformKeyValueFilter;\r\n this.itemLoadConverter = restoreItemTransformation;\r\n this.getDataCollections = getDataCollections;\r\n this.addCollection = addCollection;\r\n this.storageFailureCallback = storageFailureCallback;\r\n this.tablesToNotClear = tablesToNotClear || [];\r\n this.tablesToNotLoad = tablesToNotLoad || [];\r\n }\r\n /** Persist in-memory database to disk\r\n * Removes tables from store that don't exist in in-memory db\r\n */\r\n WebSqlPersister.prototype.persist = function (defaultOptions, getCollectionOptions) {\r\n var that = this;\r\n var timerId = DbUtil.newTimer(\"persist\");\r\n var dfd = this.persistenceInterface.util.defer();\r\n var persistCount = 0;\r\n var persistData = {\r\n collections: {}\r\n };\r\n function addOrUpdatePersistInfo(collName, addSize, addDataSizeBytes) {\r\n if (persistData.collections[collName] == null) {\r\n persistData.collections[collName] = {\r\n size: addSize,\r\n dataSizeBytes: addDataSizeBytes\r\n };\r\n }\r\n else {\r\n var collPersistInfo = persistData.collections[collName];\r\n collPersistInfo.size = collPersistInfo.size + addSize;\r\n collPersistInfo.dataSizeBytes = collPersistInfo.dataSizeBytes + addDataSizeBytes;\r\n }\r\n }\r\n // add new tables and remove tables that do not have collections\r\n this.persistenceInterface.getTables().then(function (tables) {\r\n var tableNames = Arrays.pluck(tables, \"name\");\r\n var promises = [];\r\n var colls = that.getDataCollections();\r\n colls.forEach(function (coll) {\r\n var sqls = [];\r\n var opts = DbUtil.getOptionsOrDefault(getCollectionOptions != null ? getCollectionOptions(coll.name) : null, defaultOptions);\r\n var exists = tableNames.indexOf(coll.name) !== -1;\r\n if (opts.deleteIfExists && exists) {\r\n sqls.push({ sql: \"DROP TABLE \" + coll.name, args: [] });\r\n sqls.push({ sql: \"CREATE TABLE \" + coll.name + \" (\" + (opts.keyColumn != null ? opts.keyColumn.name + \" \" + opts.keyColumn.type + \", \" : \"\") + opts.dataColumnName + \" blob)\", args: [] });\r\n }\r\n if (!exists) {\r\n sqls.push({ sql: \"CREATE TABLE IF NOT EXISTS \" + coll.name + \" (\" + (opts.keyColumn != null ? opts.keyColumn.name + \" \" + opts.keyColumn.type + \", \" : \"\") + opts.dataColumnName + \" blob)\", args: [] });\r\n }\r\n if (coll.dirty) {\r\n if (exists) {\r\n sqls.push({ sql: \"DELETE FROM \" + coll.name, args: [] });\r\n }\r\n persistCount++;\r\n // create the sql statements\r\n if (coll.data.length > 0) {\r\n var res = that.createInsertStatements(coll.name, coll.data, opts.keyGetter, opts.keyColumn && opts.keyColumn.name, opts.groupByKey, opts.maxObjectsPerChunk, opts.compress);\r\n addOrUpdatePersistInfo(coll.name, res.itemCount, res.jsonSize);\r\n sqls.push({ sql: res.sql, args: res.args });\r\n }\r\n coll.dirty = false;\r\n }\r\n if (sqls.length > 0) {\r\n var collPromise = that.persistenceInterface.executeQueries(sqls);\r\n promises.push(collPromise);\r\n }\r\n });\r\n return that.persistenceInterface.util.whenAll(promises);\r\n }).then(function (results) {\r\n if (persistCount > 0) {\r\n var timeMs = timerId.measure();\r\n var totalWriteSize = Object.keys(persistData.collections).reduce(function (prev, collName) { return prev + persistData.collections[collName].dataSizeBytes; }, 0);\r\n if (that.logger != null)\r\n that.logger.log(\"Data saved: \", Math.floor(timeMs), \"(ms), \", totalWriteSize, \"(bytes), meta-info: \", persistData.collections);\r\n }\r\n dfd.resolve(persistData);\r\n }, function (error) {\r\n if (error.sqlError && error.sqlError.message && error.sqlError.message.indexOf(\"there was not enough remaining storage space\") > -1) {\r\n if (that.storageFailureCallback) {\r\n that.storageFailureCallback(error);\r\n }\r\n }\r\n dfd.reject(error);\r\n });\r\n return dfd.promise;\r\n };\r\n /** Restore in-memory database from persistent storage.\r\n * All in memory tables are dropped and re-added\r\n */\r\n WebSqlPersister.prototype.restore = function (defaultOptions, getCollectionOptions) {\r\n var that = this;\r\n var timerId = DbUtil.newTimer(\"restore\");\r\n var defaultDecompress = (defaultOptions != null && defaultOptions.decompress) || false;\r\n var dfd = this.persistenceInterface.util.defer();\r\n var restoreRes = {\r\n collections: {}\r\n };\r\n var tableNames = [];\r\n this.persistenceInterface.getTables().then(function (tables) {\r\n tableNames = Arrays.pluck(tables, \"name\").filter(function (n) { return that.tablesToNotLoad.indexOf(n) === -1; });\r\n var sqls = tables.filter(function (t) { return that.tablesToNotLoad.indexOf(t.name) === -1; })\r\n .map(function (table) { return ({ sql: \"SELECT * FROM \" + table.name, args: [] }); });\r\n return that.persistenceInterface.executeQueries(sqls);\r\n }).then(function (results) {\r\n results.forEach(function (result, tableIndex) {\r\n var tableName = tableNames[tableIndex];\r\n var docs = [];\r\n var res = {\r\n size: 0,\r\n dataSizeBytes: 0\r\n };\r\n if (result.rows.length > 0) {\r\n var opts = getCollectionOptions != null ? getCollectionOptions(tableName) : null;\r\n var decompress = opts != null ? opts.decompress || defaultDecompress : defaultDecompress;\r\n var dataColumnName = opts != null ? opts.dataColumnName || WebSqlPersister.defaultDataColumnName : WebSqlPersister.defaultDataColumnName;\r\n // check whether the row format has our required column\r\n if (result.rows.item(0)[dataColumnName]) {\r\n docs = that.readRecords(result.rows, dataColumnName, decompress, opts == null || opts.isChunks, res);\r\n }\r\n else {\r\n if (that.logger != null && that.logger.error != null)\r\n that.logger.error(\"skip restoring table: \" + tableName + \" (unrecognized data format)\");\r\n }\r\n }\r\n else {\r\n //if (that.logger != null) that.logger.log(\"skip restoring table: \" + tableName + \" (0 items)\");\r\n }\r\n res.size = docs.length;\r\n restoreRes.collections[tableName] = res;\r\n that.addCollection(tableName, docs);\r\n });\r\n var timeMs = timerId.measure();\r\n if (that.logger != null)\r\n that.logger.log(\"Data loaded\", Math.floor(timeMs), \"(ms)\");\r\n dfd.resolve(restoreRes);\r\n }, function (err) {\r\n dfd.reject(err);\r\n });\r\n return dfd.promise;\r\n };\r\n /** Get a list of collection names in this data persister\r\n */\r\n WebSqlPersister.prototype.getCollectionNames = function () {\r\n return this.persistenceInterface.getTables().then(function (tbls) { return tbls.map(function (t) { return t.name; }); });\r\n };\r\n /** Get all data from a specific collection\r\n */\r\n WebSqlPersister.prototype.getCollectionRecords = function (collectionName, options) {\r\n var that = this;\r\n var sqls = [{ sql: \"SELECT * FROM \" + collectionName, args: [] }];\r\n return this.persistenceInterface.executeQueries(sqls).then(function (_a) {\r\n var result = _a[0];\r\n var docs = [];\r\n if (result.rows.length > 0) {\r\n var decompress = options != null ? options.decompress || false : false;\r\n var dataColumnName = options != null ? options.dataColumnName || WebSqlPersister.defaultDataColumnName : WebSqlPersister.defaultDataColumnName;\r\n // check whether the row formats has our required column\r\n if (result.rows.item(0)[dataColumnName]) {\r\n docs = that.readRecords(result.rows, dataColumnName, decompress, options == null || options.isChunks);\r\n }\r\n else {\r\n if (that.logger != null && that.logger.error != null)\r\n that.logger.error(\"skip restoring table: \" + collectionName + \" (unrecognized data format)\");\r\n }\r\n }\r\n return docs;\r\n });\r\n };\r\n /** Add data to a specific collection\r\n */\r\n WebSqlPersister.prototype.addCollectionRecords = function (collectionName, options, records, removeExisting) {\r\n var opts = DbUtil.getOptionsOrDefault(options, { compress: false, maxObjectsPerChunk: WebSqlPersister.MAX_OBJECTS_PER_PERSIST_RECORD });\r\n var res = records.length > 0 ? this.createInsertStatements(collectionName, records, opts.keyGetter, opts.keyColumn && opts.keyColumn.name, opts.groupByKey, opts.maxObjectsPerChunk, opts.compress) : null;\r\n var sqls = [];\r\n if (removeExisting) {\r\n sqls.push({ sql: \"DELETE FROM \" + collectionName, args: [] });\r\n }\r\n if (records.length > 0) {\r\n sqls.push({ sql: res.sql, args: res.args });\r\n }\r\n return this.persistenceInterface.executeQueries(sqls).then(function (_a) {\r\n var result = _a[0];\r\n return (res != null ? { size: res.itemCount, dataSizeBytes: res.jsonSize } : { size: 0, dataSizeBytes: 0 });\r\n });\r\n };\r\n /** Remove all data from the specificed collections\r\n */\r\n WebSqlPersister.prototype.clearCollections = function (collectionNames) {\r\n var sqls = collectionNames.map(function (collName) { return ({ sql: \"DELETE FROM \" + collName, args: [] }); });\r\n return this.persistenceInterface.executeQueries(sqls).then(function (results) { return null; });\r\n };\r\n /** Delete all data related this database from persistent storage\r\n */\r\n WebSqlPersister.prototype.clearPersistentDb = function () {\r\n var _this = this;\r\n var timerId = DbUtil.newTimer(\"clear\");\r\n var dfd = this.persistenceInterface.util.defer();\r\n this.persistenceInterface.getTables().then(function (tables) {\r\n var sqls = tables\r\n .filter(function (t) { return _this.tablesToNotClear.indexOf(t.name) === -1; })\r\n .map(function (table) { return ({ sql: \"DROP TABLE \" + table.name, args: [] }); });\r\n return _this.persistenceInterface.executeQueries(sqls);\r\n }).then(function (sqls) {\r\n var timeMs = timerId.measure();\r\n if (_this.logger != null)\r\n _this.logger.log(\"Data cleared\", Math.floor(timeMs), \"(ms)\");\r\n dfd.resolve(null);\r\n }, function (err) {\r\n dfd.reject(err);\r\n });\r\n return dfd.promise;\r\n };\r\n /** Reads rows from a SqlResultSetRowList. First each row's 'dataColumnName' column is parsed via JSON.parse(), then the data is processed as follows:\r\n * - if the parsed data is an array, assume it's an array of data models, if an 'itemLoadConverter' function was provided in the constructor, use it to convert each object, else return the array of objects\r\n * - if the parsed data is not an array, assume it is a single data model, if an 'itemLoadConverter' function was provided in the constructor, use it to convert the object, else return the object\r\n * Note: because of this logic, using an array as a data model will not produce correct results since the array will be assumed to contain multiple individual data objects\r\n * @param rows the result set rows to process\r\n * @param dataColumnName the name of the column containing the model data\r\n * @param decompress (currently not supported) whether data strings should be decompressed or not\r\n * @param expectArrayRes whether data strings are expected to be array chunks with the actual data records inside\r\n * @param res optional stats object in which to store info about the rows read\r\n */\r\n WebSqlPersister.prototype.readRecords = function (rows, dataColumnName, decompress, expectArrayRes, res) {\r\n var convertFunc = this.itemLoadConverter;\r\n var docs = [];\r\n for (var i = 0, size = rows.length; i < size; i++) {\r\n var dataBlob = rows.item(i)[dataColumnName];\r\n if (res != null) {\r\n res.dataSizeBytes += dataBlob.length;\r\n }\r\n if (decompress) {\r\n //dataBlob = pako.inflate(dataBlob, { to: \"string\" });\r\n }\r\n // NOTE: may throw error\r\n var chunks = JSON.parse(dataBlob);\r\n var resChunks = [];\r\n if (convertFunc != null) {\r\n if (expectArrayRes && Array.isArray(chunks)) {\r\n for (var j = 0, sizeJ = chunks.length; j < sizeJ; j++) {\r\n resChunks.push(convertFunc(chunks[j]));\r\n }\r\n }\r\n else {\r\n resChunks.push(convertFunc(chunks));\r\n }\r\n chunks = null;\r\n }\r\n else {\r\n if (expectArrayRes && Array.isArray(chunks)) {\r\n resChunks = chunks;\r\n }\r\n else {\r\n resChunks.push(chunks);\r\n }\r\n }\r\n Array.prototype.push.apply(docs, resChunks);\r\n }\r\n return docs;\r\n };\r\n WebSqlPersister.prototype.createInsertStatements = function (collName, items, keyGetter, keyColumn, groupByKey, chunkSize, compress) {\r\n var sql;\r\n var sqlArgs = [];\r\n var resItems = items;\r\n if (this.itemSaveConverter != null) {\r\n var convertFunc = this.itemSaveConverter;\r\n resItems = [];\r\n for (var j = 0, sizeJ = items.length; j < sizeJ; j++) {\r\n resItems.push(convertFunc(items[j]));\r\n }\r\n }\r\n var itemCount = 0;\r\n var jsonSize = 0;\r\n // records by chunks\r\n if (keyGetter == null && chunkSize > 0) {\r\n sql = \"INSERT INTO \" + collName + \" VALUES(?)\";\r\n for (var i = 0, sz = resItems.length; i < sz; i += chunkSize) {\r\n var data = resItems.slice(i, i + chunkSize);\r\n var jsonData = JSON.stringify(data, this.itemKeyValueFilter);\r\n if (compress) {\r\n //jsonData = pako.deflate(jsonData, { to: \"string\" });\r\n }\r\n itemCount += data.length;\r\n jsonSize += jsonData.length;\r\n sqlArgs.push([jsonData]);\r\n }\r\n }\r\n // records by group-by\r\n else if (keyGetter != null && groupByKey != null) {\r\n sql = \"INSERT INTO \" + collName + (keyColumn != null ? \" VALUES(?,?)\" : \" VALUES(?)\");\r\n if (typeof keyGetter === \"string\") {\r\n var uniqueKeyLists = resItems.reduce(function (mp, itm) {\r\n var value = itm[keyGetter];\r\n var ary = (mp[value] || (mp[value] = []));\r\n ary.push(itm);\r\n return mp;\r\n }, {});\r\n }\r\n else {\r\n var uniqueKeyLists = resItems.reduce(function (mp, itm) {\r\n var value = keyGetter(itm);\r\n var ary = (mp[value] || (mp[value] = []));\r\n ary.push(itm);\r\n return mp;\r\n }, {});\r\n }\r\n for (var key in uniqueKeyLists) {\r\n var data = uniqueKeyLists[key];\r\n var jsonData = JSON.stringify(data, this.itemKeyValueFilter);\r\n itemCount += data.length;\r\n jsonSize += jsonData.length;\r\n sqlArgs.push(keyColumn != null ? [key, jsonData] : [jsonData]);\r\n }\r\n }\r\n // records by key\r\n else if (keyGetter != null) {\r\n sql = \"INSERT INTO \" + collName + (keyColumn != null ? \" VALUES(?,?)\" : \" VALUES(?)\");\r\n if (typeof keyGetter === \"string\") {\r\n for (var i = 0, sz = resItems.length; i < sz; i++) {\r\n var datum = resItems[i];\r\n var jsonData = JSON.stringify(datum, this.itemKeyValueFilter);\r\n var keyVal = datum[keyGetter];\r\n itemCount += 1;\r\n jsonSize += jsonData.length;\r\n sqlArgs.push(keyColumn != null ? [keyVal, jsonData] : [jsonData]);\r\n }\r\n }\r\n else {\r\n for (var i = 0, sz = resItems.length; i < sz; i++) {\r\n var datum = resItems[i];\r\n var jsonData = JSON.stringify(datum, this.itemKeyValueFilter);\r\n var key = keyGetter(datum);\r\n itemCount += 1;\r\n jsonSize += jsonData.length;\r\n sqlArgs.push(keyColumn != null ? [key, jsonData] : [jsonData]);\r\n }\r\n }\r\n }\r\n else {\r\n throw new Error(\"unsupported persist options combination: keyGetter=\" + keyGetter + \", keyColumn=\" + keyColumn + \", groupByKey=\" + groupByKey + \", chunkSize=\" + chunkSize);\r\n }\r\n return { sql: sql, args: sqlArgs, itemCount: itemCount, jsonSize: jsonSize };\r\n };\r\n WebSqlPersister.MAX_OBJECTS_PER_PERSIST_RECORD = 1000;\r\n WebSqlPersister.defaultDataColumnName = \"bigString\";\r\n return WebSqlPersister;\r\n}());\r\nmodule.exports = WebSqlPersister;\r\n", - "\"use strict\";\r\n/// \r\nvar DbUtil = require(\"./DbUtil\");\r\n/*! websql.js | MIT license | Stepan Riha | http://bitbucket.org/nonplus/websql-js\r\n * websql.js may be freely distributed under the MIT license.\r\n * converted to TypeScript at 2017-11-04 by TeamworkGuy2\r\n */\r\n/** Module that wraps asynchronous WebSQL calls with deferred promises and provides SQL utility methods.\r\n *\r\n * Promises are **resolved** when asynchronous database callback is finished.\r\n * Promises are **rejected** with an `Error` object that may contain one or more of the following:\r\n * - `message`: Describing what failed\r\n * - `exception`: Exception that was thrown\r\n * - `sqlError`: Error returned by WebSQL\r\n * - `sql`: statement that was executing\r\n *\r\n * ## Using the API\r\n * Example:\r\n * var wsdb = WebSqlSpi.newWebSqlDb(nameOrDbInst, _version_, _displayName_, _estimatedSize_, utilSettings);\r\n * wsdb.read({ sql: \"SELECT * FROM ...\" }).then(function(resultSet) { ... });\r\n *\r\n * ## Public Methods ##\r\n * - `newWebSqlDb(nameOrDb, ...)` takes the same parameters as the `window.openDatabase` function, and used default values for unspecified parameters.\r\n * Returns: new a promise which resolves with the new `WebsqlDatabase` wrapper class.\r\n * Usage:\r\n * var wsdb = WebSqlSpi.newWebSqlDb(\"test\", 1, \"Test Database\", 2 * 1024 * 1024, new DbUtil(...));\r\n * wsdb.execute({ sql: \"INSERT INTO ...\", args: [...] }).then(function(resultSet) { ... })\r\n */\r\nvar WebSqlSpi = /** @class */ (function () {\r\n function WebSqlSpi(db, util) {\r\n this.db = db;\r\n this.util = util;\r\n this.transaction = this.transaction.bind(this);\r\n this.readTransaction = this.readTransaction.bind(this);\r\n }\r\n /** Returns: promise that resolves once the database version has been changed\r\n * Usage:\r\n * wsdb.changeVersion(1, 2, function (xact) {\r\n * xact.executeSQL(...);\r\n * }).then(function() {...});\r\n */\r\n WebSqlSpi.prototype.changeVersion = function (oldVersion, newVersion, xactCallback) {\r\n var util = this.util;\r\n var dfd = util.defer();\r\n if (!util.isDatabase(this.db)) {\r\n util.rejectError(dfd, \"Database not specified (db='\" + this.db + \"')\");\r\n return dfd.promise;\r\n }\r\n util.log(util.DEBUG, \"changeVersion\", oldVersion, newVersion);\r\n try {\r\n this.db.changeVersion(\"\" + oldVersion, \"\" + newVersion, xactCallback, function (sqlError) {\r\n util.rejectError(dfd, \"Failed to change version\", { sqlError: sqlError });\r\n }, function () {\r\n dfd.resolve(null);\r\n });\r\n }\r\n catch (ex) {\r\n util.rejectError(dfd, \"Failed changeVersion(db, '\" + oldVersion + \"', '\" + newVersion + \"')\", { exception: ex });\r\n }\r\n return dfd.promise;\r\n };\r\n /** Queries the sqlite_master table for user tables\r\n * Returns: promise that resolves with an array of table information records\r\n * Usage:\r\n * wsdb.getTables().then(function(tables) {\r\n * for(var i = 0; i < tables.length; i++) {\r\n * var name = tables[i].name;\r\n * var sql = tables[i].sql;\r\n * ...\r\n * }\r\n * });\r\n */\r\n WebSqlSpi.prototype.getTables = function () {\r\n var sql = \"SELECT name, type, sql FROM sqlite_master \" +\r\n \"WHERE type in ('table') AND name NOT LIKE '?_?_%' ESCAPE '?'\";\r\n return this.execSqlStatements(this.readTransaction, \"read\", { sql: sql }, function (rs) {\r\n var tables = [];\r\n var rows = rs.rows;\r\n for (var i = 0, size = rows.length; i < size; i++) {\r\n tables.push(rows.item(i));\r\n }\r\n return tables;\r\n });\r\n };\r\n /** Queries the sqlite_master for a table by name\r\n * Returns: promise that resolves with table info or with `undefined` if table\r\n * does not exist.\r\n * Usage:\r\n * wsdb.tableExists(\"person\").then(function (table) {\r\n * alert(\"table \" + (table ? \"exists\" : \"does not exist\"));\r\n * });\r\n */\r\n WebSqlSpi.prototype.tableExists = function (name) {\r\n var sql = \"SELECT * FROM sqlite_master WHERE name = ?\";\r\n return this.readRow([{ sql: sql, args: [[name]] }], function (row) {\r\n return row || undefined;\r\n });\r\n };\r\n /** Drops all the tables in the database.\r\n * Returns: promise that resolves with this `WebsqlDatabase`\r\n * Usage:\r\n * wsdb.destroyDatabase()\r\n * .then(function (wsdb) {...});\r\n */\r\n WebSqlSpi.prototype.destroyDatabase = function () {\r\n return this.changeVersion(this.db.version, \"\", function (xact) {\r\n var sql = \"SELECT name FROM sqlite_master \" +\r\n \"WHERE type in ('table') AND name NOT LIKE '?_?_%' ESCAPE '?'\";\r\n xact.executeSql(sql, [], function (xact, rs) {\r\n var rows = rs.rows;\r\n for (var i = 0, size = rows.length; i < size; i++) {\r\n var sql = 'DROP TABLE \"' + rows.item(i).name + '\"';\r\n xact.executeSql(sql);\r\n }\r\n });\r\n });\r\n };\r\n /** Calls xactCallback(xact) from within a database transaction\r\n * Returns: promise that resolves with the database\r\n * Usage:\r\n * wsdb.transaction(function (xact) {\r\n * xact.executeSQL(...);\r\n * }).then(function (wsdb) {...});\r\n *\r\n * More usage:\r\n * var addressId;\r\n * var personId;\r\n *\r\n * function insertPerson(xact) {\r\n * return xact.executeSql(\"INSERT INTO person ...\", [...],\r\n * function (xact, rs) {\r\n * personId = rs.insertId;\r\n * insertAddress(xact, personId);\r\n * }\r\n * )\r\n * }\r\n *\r\n * function insertAddress(xact, personId) {\r\n * return wsdb.executeSql(xact, \"INSERT INTO address (person, ...) VALUES (?, ...)\",\r\n * [personId, ...],\r\n * function (xact, rs) {\r\n * addressId = rs.insertId;\r\n * }\r\n * )\r\n * }\r\n *\r\n * wsdb.transaction(function (xact) {\r\n * insertPerson(xact);\r\n * }).then(function(wsdb) {\r\n * alert(\"Created person \" + personId + \" with address \" + addressId);\r\n * });\r\n */\r\n WebSqlSpi.prototype.transaction = function (xactCallback) {\r\n return this.executeTransaction(\"transaction\", xactCallback);\r\n };\r\n /** Calls xactCallback(xact) from within a database read transaction\r\n * Returns: promise that resolves with the database\r\n * Usage:\r\n * wsdb.readTransaction(function (xact) {\r\n * xact.executeSQL(...);\r\n * }).then(function (wsdb) {...});\r\n */\r\n WebSqlSpi.prototype.readTransaction = function (xactCallback) {\r\n return this.executeTransaction(\"readTransaction\", xactCallback);\r\n };\r\n /** Call 'webSqlFunc' method on 'db'\r\n * Implements common behavior for 'wsdb.transaction' and 'wsdb.readTransaction'\r\n */\r\n WebSqlSpi.prototype.executeTransaction = function (webSqlFuncName, xactCallback) {\r\n var util = this.util;\r\n var dfd = util.defer();\r\n if (!util.isDatabase(this.db)) {\r\n util.rejectError(dfd, \"Database not specified (db='\" + this.db + \"')\");\r\n return dfd.promise;\r\n }\r\n if (this.db[webSqlFuncName] == null) {\r\n util.rejectError(dfd, \"Database function '\" + webSqlFuncName + \"' does not exist\");\r\n return dfd.promise;\r\n }\r\n try {\r\n this.db[webSqlFuncName](function (xact) {\r\n try {\r\n xactCallback(xact);\r\n }\r\n catch (exception) {\r\n util.rejectError(dfd, webSqlFuncName + \" callback threw an exception\", { exception: exception });\r\n }\r\n }, function (sqlError) {\r\n util.rejectError(dfd, \"Failed executing \" + webSqlFuncName.replace(/transaction/i, \"\") + \" transaction\", { sqlError: sqlError });\r\n }, function () {\r\n dfd.resolve(null);\r\n });\r\n }\r\n catch (exception) {\r\n util.rejectError(dfd, \"Failed calling \" + webSqlFuncName, { exception: exception });\r\n }\r\n return dfd.promise;\r\n };\r\n /** Method for executing a transaction with a one or more `sqlStatement`\r\n * with the specified `args`, calling the `rsCallback` with the result set(s).\r\n * The `args` and `rsCallback` are optional.\r\n * * Passing a _single_ `sqlStatement` string with `args` that is an _array of arrays_,\r\n * the statement is executed with each row in the `args`.\r\n * Passing an array of `{ sql, args}` objects to `sqlStatement`\r\n * executes the `sql` in each row with the row's `args` (or the parameter `args`).\r\n *\r\n * Returns: promise that resolves with `rsCallback` result\r\n * or the resultSet, if no `rsCallback` specified. If an array of statements or arguments\r\n * is specified, the promise resolves with an array of results/resultSets.\r\n *\r\n * Basic Usage:\r\n * wsdb.execute(\"DELETE FROM person\")\r\n * .then(function (resultSet) {...});\r\n *\r\n * Other Usage: (single `sqlStatement` with multiple sets of `args`)\r\n * wsdb.execute(\"INSERT INTO person (first, last) VALUES (?, ?)\",\r\n * [\r\n * [\"John\", \"Doe\"],\r\n * [\"Jane\", \"Doe\"]\r\n * ],\r\n * // called for each row in args\r\n * function (rs) {\r\n * console.log(\"Inserted person\", rs.insertId);\r\n * return rs.insertId;\r\n * }\r\n * ).then(function (insertIds) {\r\n * var personId1 = insertIds[0], personId2 = insertIds[1];\r\n * ...\r\n * });\r\n *\r\n * Other Usage: (multiple `sqlStatement` with multiple sets of `args`)\r\n * wsdb.execute(\r\n * [{\r\n * sql: \"UPDATE person SET (first=?, last=?) WHERE id=?\",\r\n * args: [\"Robert\", \"Smith\", 23]\r\n * }, {\r\n * sql: \"UPDATE address SET (street=?, city=?, zip=?) WHERE id=?\",\r\n * args: [\"Sesame St.\", \"Austin\", \"78758\", 45]\r\n * }],\r\n * // called for each object in args\r\n * function (rs) {\r\n * console.log(\"Updated object: \", rs.rowsAffected);\r\n * return rs.rowsAffected;\r\n * }\r\n * ).then(function (results) {\r\n * var numPersons = results[0], numAddresses = results[1];\r\n * ...\r\n * });\r\n */\r\n WebSqlSpi.prototype.executeQuery = function (sqlStatement) {\r\n return this.execSqlStatements(this.transaction, \"execute\", sqlStatement, null);\r\n };\r\n WebSqlSpi.prototype.executeQueries = function (sqlStatements) {\r\n return this.execSqlStatements(this.transaction, \"execute\", sqlStatements, null);\r\n };\r\n WebSqlSpi.prototype.execute = function (sqlStatements, rsCallback) {\r\n return this.execSqlStatements(this.transaction, \"execute\", sqlStatements, rsCallback);\r\n };\r\n /** Method for executing a readTransaction with a one or more `sqlStatement`\r\n * with the specified `args`, calling the `rsCallback` with the result set(s).\r\n * The `args` and `rsCallback` are optional.\r\n * Passing a _single_ `sqlStatement` string with `args` that is an _array of arrays_,\r\n * the statement is executed with each row in the `args`.\r\n * Passing an array of `{ sql, args}` objects to `sqlStatement`\r\n * executes the `sql` in each row with the row's `args` (or the parameter `args`).\r\n * Returns: promise that resolves with `rsCallback` result\r\n * or the resultSet, if no `rsCallback` specified. If an array of statements or arguments\r\n * is specified, the promise resolves with an array of results/resultSets.\r\n * Usage:\r\n * wsdb.read(\"SELECT * FROM person WHERE first = ?\",\r\n * [\"Bob\"],\r\n * function (rs) {\r\n * var rows = rs.rows;\r\n * for(var i = 0; i < rows.length; i++) {\r\n * ...\r\n * }\r\n * return result;\r\n * }\r\n * ).then(function (result) {...});\r\n *\r\n * Other Usage: (single `sqlStatement` with multiple sets of `args`)\r\n * wsdb.read(\"SELECT * FROM person WHERE first = ?\",\r\n * [ [\"Bob\"], [\"John\"] ],\r\n * // called for each row in args\r\n * function (rs) {\r\n * return rs.rows;\r\n * }\r\n * ).then(function (results) {\r\n * var bobRows = results[0], johnRows = results[1];\r\n * ...\r\n * });\r\n *\r\n * Other Usage: (multiple `sqlStatement` with multiple sets of `args`)\r\n * wsdb.read([{\r\n * sql: \"SELECT * FROM person WHERE id=?\",\r\n * args: [23]\r\n * }, {\r\n * sql: \"SELECT * FROM address WHERE state in (?, ?, ?)\",\r\n * args: [\"CA\", \"FL\", \"TX\"]\r\n * }],\r\n * // called for each object in args\r\n * function (rs) {\r\n * return rs.rows;\r\n * }\r\n * ).then(function (results) {\r\n * var person23rows = results[0], addressRows = results[1];\r\n * ...\r\n * });\r\n */\r\n WebSqlSpi.prototype.read = function (sqlStatements, rsCallback) {\r\n return this.execSqlStatements(this.readTransaction, \"read\", sqlStatements, rsCallback);\r\n };\r\n /** Method for executing a readTransaction with a single `sqlStatement` that's expected to return a single row.\r\n * The `rowCallback` function is called with the first row in the resultset\r\n * or with `undefined` if resultset contains no rows.\r\n * If the query does not return a row, the `defaultValue` is returned instead.\r\n * @returns promise that resolves with the `rowCallback` result or the row, if no `rowCallback` specified.\r\n * If no rows are selected and `rowCallback` isn't specified, the promise resolves with the `defaultRow`.\r\n * The promise is rejected if the query returns multiple rows or if it returns\r\n * zero rows and no `rowCallback` and `defaultRow` were specified.\r\n * Usage:\r\n * wsdb.readRow(\"SELECT * FROM person WHERE id = ?\", [123], function (row) {\r\n * if(!row) {\r\n * // person not found\r\n * }\r\n * else {\r\n * ...\r\n * }\r\n * }).then(function (result) {...});\r\n */\r\n WebSqlSpi.prototype.readRow = function (sqlStatements, rowCallback, defaultValue) {\r\n var util = this.util;\r\n return util.pipe(this.read(sqlStatements), function (rs) {\r\n var row;\r\n if (Array.isArray(rs) || rs.rows.length > 1) {\r\n return util.rejectError(util.defer(), new Error(\"Query returned \" + (Array.isArray(rs) ? \"array of \" + rs.length + \" result sets\" : rs.rows.length + \" rows\")));\r\n }\r\n else if (rs.rows.length === 0) {\r\n if (defaultValue) {\r\n row = defaultValue;\r\n }\r\n else if (rowCallback) {\r\n row = rowCallback();\r\n }\r\n else {\r\n return util.rejectError(util.defer(), new Error(\"Query returned 0 rows\"));\r\n }\r\n }\r\n else {\r\n row = rs.rows.item(0);\r\n if (rowCallback) {\r\n row = rowCallback(row);\r\n }\r\n }\r\n return row;\r\n });\r\n };\r\n WebSqlSpi.prototype.execSqlStatements = function (xactMethod, xactMethodType, sqlStatements, rsCallback) {\r\n var start = new Date().getTime();\r\n if (typeof window !== \"undefined\" && !window[\"startQueriesTime\"]) {\r\n window[\"startQueriesTime\"] = start;\r\n }\r\n var util = this.util;\r\n var isAry = Array.isArray(sqlStatements);\r\n var sqls = (isAry ? sqlStatements : [sqlStatements]);\r\n var results = [];\r\n var pipeReturn = util.pipe(xactMethod(function (xact) {\r\n for (var i = 0; i < sqls.length; i++) {\r\n var cmnd = sqls[i];\r\n var params = (typeof cmnd.args === \"undefined\" ? null : cmnd.args);\r\n if (params == null || params.length === 0) {\r\n xact.executeSql(cmnd.sql, null, function (xact, rs) {\r\n results.push(rsCallback ? rsCallback(rs) : rs);\r\n });\r\n }\r\n else {\r\n for (var j = 0, szJ = params.length; j < szJ; j++) {\r\n xact.executeSql(cmnd.sql, params[j], function (xact, rs) {\r\n results.push(rsCallback ? rsCallback(rs) : rs);\r\n });\r\n }\r\n }\r\n }\r\n }), function () {\r\n return isAry ? results : results[0];\r\n }, function (err) {\r\n err.sql = sqls;\r\n return err;\r\n });\r\n if (util.logTimings) {\r\n pipeReturn.then(function () {\r\n var end = new Date().getTime();\r\n var time = end - start;\r\n if (typeof window !== \"undefined\") {\r\n window[\"endQueriesTime\"] = end;\r\n }\r\n util.log(util.DEBUG, \"websql finish args: \", xactMethodType, sqls.length, sqls);\r\n util.log(util.DEBUG, \"websql runtime: \", time);\r\n });\r\n }\r\n return pipeReturn;\r\n };\r\n /** Calls window.openDatabase().\r\n * - version defaults to `\"\"`\r\n * - displayName defaults to `name`\r\n * - estimatedSize defaults to `2 * 1024 * 1024`\r\n * Returns: promise that resolves with this `WebsqlDatabase` instance\r\n * Usage:\r\n * wsdb.openDatabase(\"test\", \"Test Database\", 2 * 1024 * 1024))\r\n * .then(function(wsdb) {...});\r\n * More usage:\r\n * wsdb.openDatabase(\"test\"))\r\n * .then(function(wsdb) {...});\r\n */\r\n WebSqlSpi.openDatabase = function (util, name, version, displayName, estimatedSize) {\r\n util.log(util.DEBUG, \"openDatabase\", name, version, displayName, estimatedSize);\r\n if (!displayName)\r\n displayName = name;\r\n if (!version)\r\n version = \"\";\r\n if (!estimatedSize) {\r\n if (typeof window !== \"undefined\" && window.navigator.userAgent.match(/(iPad|iPhone);.*CPU.*OS 7_0/i)) {\r\n estimatedSize = 5 * 1024 * 1024;\r\n }\r\n else {\r\n estimatedSize = 50 * 1024 * 1024;\r\n }\r\n }\r\n var dfd = util.defer();\r\n try {\r\n if (typeof window === \"undefined\" || !window.openDatabase) {\r\n util.rejectError(dfd, \"WebSQL not implemented\");\r\n }\r\n else {\r\n // seems to synchronously open WebSQL, even though window.openDatabase is async\r\n var db = window.openDatabase(name, version, displayName, estimatedSize);\r\n if (util.isDatabase(db)) {\r\n dfd.resolve(db);\r\n }\r\n else {\r\n util.rejectError(dfd, \"Failed to open database\");\r\n }\r\n }\r\n }\r\n catch (ex) {\r\n util.rejectError(dfd, \"Failed to open database \" + name, { exception: ex });\r\n }\r\n return dfd.promise;\r\n };\r\n WebSqlSpi.newWebSqlDb = function (name, version, displayName, estimatedSize, utilSettings) {\r\n var util = new DbUtil(\"WebSQL\", \"[object Database]\", utilSettings);\r\n // Create WebSQL wrapper from native Database or by opening 'name' DB\r\n var pOpen;\r\n if (util.isDatabase(name)) {\r\n var dfd = util.defer();\r\n dfd.resolve(name);\r\n pOpen = dfd.promise;\r\n }\r\n else {\r\n pOpen = WebSqlSpi.openDatabase(util, name, version, displayName, estimatedSize);\r\n }\r\n return pOpen.then(function (dbInst) { return new WebSqlSpi(dbInst, util); });\r\n };\r\n return WebSqlSpi;\r\n}());\r\nmodule.exports = WebSqlSpi;\r\n", - "\"use strict\";\r\nvar DbUtil = require(\"../persisters/DbUtil\");\r\nvar IndexedDbPersister = require(\"../persisters/IndexedDbPersister\");\r\nvar IndexedDbSpi = require(\"../persisters/IndexedDbSpi\");\r\nvar WebSqlPersister = require(\"../persisters/WebSqlPersister\");\r\nvar WebSqlSpi = require(\"../persisters/WebSqlSpi\");\r\nvar CollectionsBrowserTestBase;\r\n(function (CollectionsBrowserTestBase) {\r\n // testing:\r\n /*\r\n * load test/tmp/index.html in a browser, then run these commands:\r\nvar idb = null; createIndexedDbPersister(1).then((i) => { idb = i; var db = idb.persistenceInterface.db; db.onabort = db.onclose = db.onerror = function closing() { console.error.apply(console, arguments); }; });\r\nidb.addCollection(\"book\", [\r\n memDb.createBook(\"1984\", \"George Orwell\", 1949),\r\n memDb.createBook(\"Mere Christianity\", \"C.S. Lewis\", 1952),\r\n memDb.createBook(\"Desiring God\", \"John Piper\", 1986),\r\n memDb.createBook(\"Don't Waste Your Life\", \"John Piper\", 2003),\r\n memDb.createBook(\"The Culture Code\", \"Daniel Coyle\", 2016)\r\n]);\r\nidb.getDataCollections()[1].dirty = true;\r\nvar rs = null; idb.persist({ maxObjectsPerChunk: 3, keyAutoGenerate: true }).then(r => console.log(\"persist done!\", rs = r), (err) => console.error(err));\r\nvar rt = null; idb.restore(null, (name) => ({ isChunks: true })).then(r => console.log(\"restore done!\", rt = r), (err) => console.error(err));\r\nidb.persistenceInterface.db.close();\r\n */\r\n var colls = [{\r\n name: \"books\",\r\n data: [],\r\n dirty: false,\r\n insert: function insert(dat) { Array.prototype.push.apply(this.data, dat); }\r\n }];\r\n var memDb = {\r\n listCollections: function () { return colls; },\r\n getCollection: function (name, auto) { return colls.find(function (x) { return x.name === name; }) || colls[0]; },\r\n createBook: function (name, author, publishYear) { return ({ name: name, author: author, publishYear: publishYear }); },\r\n };\r\n var storageLog = {\r\n error: function error() {\r\n console.error.apply(console, arguments);\r\n debugger;\r\n },\r\n log: function log() {\r\n console.log.apply(console, arguments);\r\n debugger;\r\n }\r\n };\r\n var persisterLog = {\r\n error: function error() {\r\n console.error.apply(console, arguments);\r\n debugger;\r\n },\r\n log: function log() {\r\n console.log.apply(console, arguments);\r\n debugger;\r\n }\r\n };\r\n var utilConfig = {\r\n defer: function () {\r\n var rt = {\r\n promise: null,\r\n resolve: null,\r\n reject: null,\r\n };\r\n var p = new Promise(function (rsl, rjc) { rt.resolve = rsl; rt.reject = rjc; });\r\n rt.promise = p;\r\n return rt;\r\n },\r\n whenAll: function (ps) { return Promise.all(ps); },\r\n trace: storageLog,\r\n verbosity: DbUtil.logLevels.DEBUG\r\n };\r\n function createIndexedDbPersister(version) {\r\n if (version === void 0) { version = null; }\r\n return IndexedDbSpi.newIndexedDb(\"lokijs-collections-test\", version, utilConfig).then(function (idb) {\r\n return new IndexedDbPersister(idb, persisterLog, function () {\r\n return [{ name: \"book_backup\", data: [] }].concat(memDb.listCollections());\r\n }, function (collName, data) {\r\n // when initially restoring collection data from persistent storage (during page load) don't mark collection as dirty (prevents a full save when the next persist() timer goes off)\r\n var initiallyEmpty = memDb.getCollection(collName, false) == null;\r\n var coll = memDb.getCollection(collName, true);\r\n coll.insert(data);\r\n if (initiallyEmpty) {\r\n coll.dirty = false;\r\n }\r\n return coll;\r\n }, null /*(itm) => MemDbImpl.cloneCloneDelete(itm, true)*/, null, function (storageError) {\r\n console.error(\"storage error, is quota full!?\", storageError.sqlError.message);\r\n }, null, null);\r\n });\r\n }\r\n CollectionsBrowserTestBase.createIndexedDbPersister = createIndexedDbPersister;\r\n function createWebSqlPersister(version) {\r\n if (version === void 0) { version = null; }\r\n return WebSqlSpi.newWebSqlDb(\"lokijs-collections-test\", version, null, null, utilConfig).then(function (wsb) {\r\n return new WebSqlPersister(wsb, persisterLog, function () {\r\n return [{ name: \"book_backup\", data: [] }].concat(memDb.listCollections());\r\n }, function (collName, data) {\r\n // when initially restoring collection data from persistent storage (during page load) don't mark collection as dirty (prevents a full save when the next persist() timer goes off)\r\n var initiallyEmpty = memDb.getCollection(collName, false) == null;\r\n var coll = memDb.getCollection(collName, true);\r\n coll.insert(data);\r\n if (initiallyEmpty) {\r\n coll.dirty = false;\r\n }\r\n return coll;\r\n }, null /*(itm) => MemDbImpl.cloneCloneDelete(itm, true)*/, function (k, v) { return (k !== \"$loki\" && k !== \"meta\" ? v : undefined); }, null, function (storageError) {\r\n console.error(\"storage error, is quota full!?\", storageError.sqlError.message);\r\n }, null, null);\r\n });\r\n }\r\n CollectionsBrowserTestBase.createWebSqlPersister = createWebSqlPersister;\r\n var Cctor = (function () {\r\n var globals = [\r\n IndexedDbPersister,\r\n IndexedDbSpi,\r\n createIndexedDbPersister,\r\n createWebSqlPersister,\r\n (colls.name = \"colls\", colls),\r\n (memDb.name = \"memDb\", memDb),\r\n ];\r\n for (var i = 0, size = globals.length; i < size; i++) {\r\n var glb = globals[i];\r\n window[glb.name] = glb;\r\n console.log(glb.name);\r\n }\r\n }());\r\n})(CollectionsBrowserTestBase || (CollectionsBrowserTestBase = {}));\r\nmodule.exports = CollectionsBrowserTestBase;\r\n" - ] -} \ No newline at end of file diff --git a/test/tmp/index.html b/test/tmp/index.html deleted file mode 100644 index 6b2f965..0000000 --- a/test/tmp/index.html +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file