Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better performance #111

Merged
merged 17 commits into from
Jun 25, 2024
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "orange-orm",
"version": "4.1.4",
"version": "4.2.0-beta.6",
"main": "./src/index.js",
"browser": "./src/client/index.mjs",
"bin": {
Expand Down
50 changes: 50 additions & 0 deletions src/client/cloneFromDb.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
let dateToISOString = require('../dateToISOString');

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(obj, isFast) {
if (isFast)
return cloneFromDbFast(obj);
else
return cloneRegular(obj);
}

module.exports = cloneFromDb;
109 changes: 78 additions & 31 deletions src/client/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const createPatch = require('./createPatch');
const stringify = require('./stringify');
const cloneFromDb = require('./cloneFromDb');
const netAdapter = require('./netAdapter');
const toKeyPositionMap = require('./toKeyPositionMap');
const rootMap = new WeakMap();
Expand Down Expand Up @@ -228,7 +229,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);
return proxify(rows, strategy, true);
}

async function groupBy(strategy) {
Expand Down Expand Up @@ -260,7 +261,7 @@ function rdbClient(options = {}) {
await metaPromise;
if (rows.length === 0)
return;
return proxify(rows[0], strategy);
return proxify(rows[0], strategy, true);
}

async function getById() {
Expand Down Expand Up @@ -448,14 +449,14 @@ function rdbClient(options = {}) {
}


function proxify(itemOrArray, strategy) {
function proxify(itemOrArray, strategy, fast) {
if (Array.isArray(itemOrArray))
return proxifyArray(itemOrArray, strategy);
return proxifyArray(itemOrArray, strategy, fast);
else
return proxifyRow(itemOrArray, strategy);
return proxifyRow(itemOrArray, strategy, fast);
}

function proxifyArray(array, strategy) {
function proxifyArray(array, strategy, fast) {
let _array = array;
if (_reactive)
array = _reactive(array);
Expand All @@ -482,27 +483,30 @@ function rdbClient(options = {}) {
}

};
let innerProxy = new Proxy(array, handler);
rootMap.set(array, { json: 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);
}
return innerProxy;
}

function proxifyRow(row, strategy) {
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 () => {
Expand All @@ -515,8 +519,10 @@ function rdbClient(options = {}) {
}

};
let innerProxy = new Proxy(row, handler);
rootMap.set(row, { json: 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;
}
Expand Down Expand Up @@ -586,12 +592,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 } });
Expand All @@ -606,7 +614,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) {
Expand Down Expand Up @@ -666,7 +674,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;
Expand All @@ -685,14 +693,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];
}

Expand All @@ -705,7 +717,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) {
Expand Down Expand Up @@ -768,7 +780,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);
}

Expand All @@ -789,12 +801,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;

Expand All @@ -803,7 +815,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) {
Expand All @@ -827,20 +839,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];
}
Expand Down Expand Up @@ -1002,4 +1017,36 @@ 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);
}


module.exports = rdbClient();
Loading
Loading