diff --git a/docs/changelog.md b/docs/changelog.md index 8720317c..ab6b6af0 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,4 +1,6 @@ ## Changelog +__4.2.0__ +Improved performance. __4.1.4__ Better error message when running over http. __4.1.3__ diff --git a/package.json b/package.json index 2f709eaf..8da45747 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "orange-orm", - "version": "4.2.0-beta.6", + "version": "4.2.0", "main": "./src/index.js", "browser": "./src/client/index.mjs", "bin": { diff --git a/src/client/index.mjs b/src/client/index.mjs index ffcbf5b4..f58d5c07 100644 --- a/src/client/index.mjs +++ b/src/client/index.mjs @@ -815,7 +815,7 @@ var fastJsonPatch = /*#__PURE__*/Object.freeze({ var require$$0 = /*@__PURE__*/getAugmentedNamespace(fastJsonPatch); -function dateToISOString$1(date) { +function dateToISOString$2(date) { let tzo = -date.getTimezoneOffset(); let dif = tzo >= 0 ? '+' : '-'; @@ -839,9 +839,9 @@ function dateToISOString$1(date) { ':' + pad(tzo % 60); } -var dateToISOString_1 = dateToISOString$1; +var dateToISOString_1 = dateToISOString$2; -let dateToISOString = dateToISOString_1; +let dateToISOString$1 = dateToISOString_1; const isNode = (typeof window === 'undefined'); function stringify$4(value) { @@ -853,7 +853,7 @@ function replacer(key, value) { return value.toString('base64'); // @ts-ignore else if (value instanceof Date && !isNaN(value)) - return dateToISOString(value); + return dateToISOString$1(value); else return value; } @@ -1587,6 +1587,57 @@ var createPatch$1 = function createPatch(original, dto, options) { }; +let dateToISOString = dateToISOString_1; + +function cloneFromDbFast(obj) { + if (obj === null || typeof obj !== 'object') + return obj; + if (Array.isArray(obj)) { + const arrClone = []; + for (let i = 0; i < obj.length; i++) { + arrClone[i] = cloneFromDbFast(obj[i]); + } + return arrClone; + } + const clone = {}; + const keys = Object.keys(obj); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + clone[key] = cloneFromDbFast(obj[key]); + } + return clone; +} + +function cloneRegular(obj) { + if (obj === null || typeof obj !== 'object') + return obj; + if (Array.isArray(obj)) { + const arrClone = []; + for (let i = 0; i < obj.length; i++) { + arrClone[i] = cloneRegular(obj[i]); + } + return arrClone; + } + else if (obj instanceof Date && !isNaN(obj)) + return dateToISOString(obj); + const clone = {}; + const keys = Object.keys(obj); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + clone[key] = cloneRegular(obj[key]); + } + return clone; +} + +function cloneFromDb$1(obj, isFast) { + if (isFast) + return cloneFromDbFast(obj); + else + return cloneRegular(obj); +} + +var cloneFromDb_1 = cloneFromDb$1; + function bind(fn, thisArg) { return function wrap() { return fn.apply(thisArg, arguments); @@ -3607,7 +3658,7 @@ function isAbsoluteURL(url) { */ function combineURLs(baseURL, relativeURL) { return relativeURL - ? baseURL.replace(/\/?\/$/, '') + '/' + relativeURL.replace(/^\/+/, '') + ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '') : baseURL; } @@ -4241,7 +4292,7 @@ function mergeConfig(config1, config2) { return config; } -const VERSION = "1.6.3"; +const VERSION = "1.6.2"; const validators$1 = {}; @@ -5298,6 +5349,7 @@ var axiosInterceptor = function create() { const createPatch = createPatch$1; const stringify = stringify_1; +const cloneFromDb = cloneFromDb_1; const netAdapter = netAdapter_1; const toKeyPositionMap = toKeyPositionMap_1; const rootMap = new WeakMap(); @@ -5524,7 +5576,7 @@ function rdbClient(options = {}) { let args = [_, strategy].concat(Array.prototype.slice.call(arguments).slice(2)); let rows = await getManyCore.apply(null, args); await metaPromise; - return proxify(rows, strategy, {fastStringify : true}); + return proxify(rows, strategy, true); } async function groupBy(strategy) { @@ -5556,7 +5608,7 @@ function rdbClient(options = {}) { await metaPromise; if (rows.length === 0) return; - return proxify(rows[0], strategy, {fastStringify : true}); + return proxify(rows[0], strategy, true); } async function getById() { @@ -5744,14 +5796,14 @@ function rdbClient(options = {}) { } - function proxify(itemOrArray, strategy, options) { + function proxify(itemOrArray, strategy, fast) { if (Array.isArray(itemOrArray)) - return proxifyArray(itemOrArray, strategy, options); + return proxifyArray(itemOrArray, strategy, fast); else - return proxifyRow(itemOrArray, strategy, options); + return proxifyRow(itemOrArray, strategy, fast); } - function proxifyArray(array, strategy, { fastStringify } = {}) { + function proxifyArray(array, strategy, fast) { let _array = array; if (_reactive) array = _reactive(array); @@ -5778,8 +5830,11 @@ function rdbClient(options = {}) { } }; - let innerProxy = new Proxy(array, handler); - rootMap.set(array, { json: fastStringify ? JSON.stringify(array) : stringify(array), strategy, originalArray: [...array] }); + + let watcher = onChange(array, () => { + rootMap.set(array, { json: cloneFromDb(array, fast), strategy, originalArray: [...array] }); + }); + let innerProxy = new Proxy(watcher, handler); if (strategy !== undefined) { const { limit, ...cleanStrategy } = { ...strategy }; fetchingStrategyMap.set(array, cleanStrategy); @@ -5787,18 +5842,18 @@ function rdbClient(options = {}) { return innerProxy; } - function proxifyRow(row, strategy, { fastStringify } = {}) { + function proxifyRow(row, strategy, fast) { let handler = { get(_target, property,) { if (property === 'save' || property === 'saveChanges') //call server then acceptChanges return saveRow.bind(null, row); - else if (property === 'delete') //call server then remove from jsonMap and original + else if (property === 'delete') //call server then remove from json and original return deleteRow.bind(null, row); else if (property === 'refresh') //refresh from server then acceptChanges return refreshRow.bind(null, row); - else if (property === 'clearChanges') //refresh from jsonMap, update original if present + else if (property === 'clearChanges') //refresh from json, update original if present return clearChangesRow.bind(null, row); - else if (property === 'acceptChanges') //remove from jsonMap + else if (property === 'acceptChanges') //remove from json return acceptChangesRow.bind(null, row); else if (property === 'toJSON') return () => { @@ -5811,8 +5866,10 @@ function rdbClient(options = {}) { } }; - let innerProxy = new Proxy(row, handler); - rootMap.set(row, { json: fastStringify ? JSON.stringify(row) : stringify(row), strategy }); + let watcher = onChange(row, () => { + rootMap.set(row, { json: cloneFromDb(row, fast), strategy }); + }); + let innerProxy = new Proxy(watcher, handler); fetchingStrategyMap.set(row, strategy); return innerProxy; } @@ -5882,12 +5939,14 @@ function rdbClient(options = {}) { async function saveArray(array, concurrencyOptions, strategy) { let deduceStrategy = false; - let { json } = rootMap.get(array); + let json = rootMap.get(array)?.json; + if (!json) + return; strategy = extractStrategy({ strategy }, array); strategy = extractFetchingStrategy(array, strategy); let meta = await getMeta(); - const patch = createPatch(JSON.parse(json), array, meta); + const patch = createPatch(json, array, meta); if (patch.length === 0) return; let body = stringify({ patch, options: { strategy, ...tableOptions, ...concurrencyOptions, deduceStrategy } }); @@ -5902,7 +5961,7 @@ function rdbClient(options = {}) { let insertedPositions = getInsertedRowsPosition(array); let { changed, strategy: newStrategy } = await p; copyIntoArray(changed, array, [...insertedPositions, ...updatedPositions]); - rootMap.set(array, { json: stringify(array), strategy: newStrategy, originalArray: [...array] }); + rootMap.set(array, { json: cloneFromDb(array), strategy: newStrategy, originalArray: [...array] }); } async function patch(patch, concurrencyOptions, strategy) { @@ -5962,7 +6021,7 @@ function rdbClient(options = {}) { return options.strategy; if (obj) { let context = rootMap.get(obj); - if (context.strategy !== undefined) { + if (context?.strategy !== undefined) { // @ts-ignore let { limit, ...strategy } = { ...context.strategy }; return strategy; @@ -5981,14 +6040,18 @@ function rdbClient(options = {}) { } function clearChangesArray(array) { - let { json } = rootMap.get(array); - let old = JSON.parse(json); + let json = rootMap.get(array)?.json; + if (!json) + return; + let old = cloneFromDb(json); array.splice(0, old.length, ...old); } function acceptChangesArray(array) { const map = rootMap.get(array); - map.json = stringify(array); + if (!map) + return; + map.json = cloneFromDb(array); map.originalArray = [...array]; } @@ -6001,7 +6064,7 @@ function rdbClient(options = {}) { let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); let { strategy } = await adapter.patch(body); array.length = 0; - rootMap.set(array, { jsonMap: stringify(array), strategy }); + rootMap.set(array, { json: cloneFromDb(array), strategy }); } function setMapValue(rowsMap, keys, row, index) { @@ -6064,7 +6127,7 @@ function rdbClient(options = {}) { array.splice(i + offset, 1); offset--; } - rootMap.set(array, { json: stringify(array), strategy, originalArray: [...array] }); + rootMap.set(array, { json: cloneFromDb(array), strategy, originalArray: [...array] }); fetchingStrategyMap.set(array, strategy); } @@ -6085,12 +6148,12 @@ function rdbClient(options = {}) { strategy = extractStrategy({ strategy }, row); strategy = extractFetchingStrategy(row, strategy); - let { json } = rootMap.get(row); + let json = rootMap.get(row)?.json; if (!json) return; let meta = await getMeta(); - let patch = createPatch([JSON.parse(json)], [row], meta); + let patch = createPatch([json], [row], meta); if (patch.length === 0) return; @@ -6099,7 +6162,7 @@ function rdbClient(options = {}) { let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); let { changed, strategy: newStrategy } = await adapter.patch(body); copyInto(changed, [row]); - rootMap.set(row, { json: stringify(row), strategy: newStrategy }); + rootMap.set(row, { json: cloneFromDb(row), strategy: newStrategy }); } async function refreshRow(row, strategy) { @@ -6123,20 +6186,23 @@ function rdbClient(options = {}) { for (let p in rows[0]) { row[p] = rows[0][p]; } - rootMap.set(row, { json: stringify(row), strategy }); + rootMap.set(row, { json: cloneFromDb(row), strategy }); fetchingStrategyMap.set(row, strategy); } function acceptChangesRow(row) { - const { strategy } = rootMap.get(row); - rootMap.set(row, { json: stringify(row), strategy }); + const data = rootMap.get(row); + if (!data) + return; + const { strategy } = data; + rootMap.set(row, { json: cloneFromDb(row), strategy }); } function clearChangesRow(row) { - let { json } = rootMap.get(row); + let json = rootMap.get(row)?.json; if (!json) return; - let old = JSON.parse(json); + let old = cloneFromDb(json); for (let p in row) { delete row[p]; } @@ -6298,6 +6364,38 @@ function column(path, ...previous) { } +function onChange(target, onChange) { + + let notified = false; + const handler = { + get(target, prop, receiver) { + const value = Reflect.get(target, prop, receiver); + if (typeof value === 'object' && value !== null) { + return new Proxy(value, handler); + } + return value; + }, + set(target, prop, value, receiver) { + if (!notified) { + notified = true; + onChange(JSON.stringify(target)); + } + return Reflect.set(target, prop, value, receiver); + + }, + deleteProperty(target, prop) { + if (!notified) { + notified = true; + onChange(JSON.stringify(target)); + } + return Reflect.deleteProperty(target, prop); + } + }; + + return new Proxy(target, handler); +} + + var client = rdbClient(); export { client as default };