ravendb
Version:
RavenDB client for Node.js
193 lines • 8.75 kB
JavaScript
import { TypeUtil } from "../Utility/TypeUtil.js";
import { DocumentsChanges } from "../Documents/Session/DocumentsChanges.js";
import { CONSTANTS } from "../Constants.js";
import { throwError } from "../Exceptions/index.js";
export class JsonOperation {
static entityChanged(newObj, documentInfo, changes) {
const docChanges = changes ? [] : null;
if (!documentInfo.newDocument && documentInfo.document) {
return JsonOperation._compareJson("", documentInfo.id, documentInfo.document, newObj, changes, docChanges);
}
if (!changes) {
return true;
}
JsonOperation._newChange(null, null, null, null, docChanges, "DocumentAdded");
changes[documentInfo.id] = docChanges;
return true;
}
static _fieldPathCombine(path1, path2) {
return !path1 ? path2 : path1 + "." + path2;
}
static _compareJson(fieldPath, id, originalJson, newJson, changes, docChanges) {
const newJsonProps = Object.entries(newJson).filter(([_, value]) => typeof value !== "undefined").map(x => x[0]);
const oldJsonProps = Object.entries(originalJson).filter(([_, value]) => typeof value !== "undefined").map(x => x[0]);
const newFields = new Set(newJsonProps.filter(x => !oldJsonProps.includes(x)));
const removedFields = oldJsonProps.filter(x => !newJsonProps.includes(x));
for (const field of removedFields) {
if (!changes) {
return true;
}
JsonOperation._newChange(fieldPath, field, null, originalJson[field], docChanges, "RemovedField");
}
for (const prop of newJsonProps) {
if (CONSTANTS.Documents.Metadata.LAST_MODIFIED === prop ||
CONSTANTS.Documents.Metadata.COLLECTION === prop ||
CONSTANTS.Documents.Metadata.CHANGE_VECTOR === prop ||
CONSTANTS.Documents.Metadata.ID === prop ||
CONSTANTS.Documents.Metadata.KEY === prop) {
continue;
}
if (newFields.has(prop)) {
if (!changes) {
return true;
}
JsonOperation._newChange(fieldPath, prop, newJson[prop], null, docChanges, "NewField");
continue;
}
const newProp = newJson[prop];
const oldProp = originalJson[prop];
let changed;
const typeOfNewProp = typeof newProp;
if (typeOfNewProp === "number"
|| typeOfNewProp === "boolean"
|| typeOfNewProp === "string") {
if (newProp === oldProp || JsonOperation._compareValues(oldProp, newProp)) {
continue;
}
if (!changes) {
return true;
}
JsonOperation._newChange(fieldPath, prop, newProp, oldProp, docChanges, "FieldChanged");
}
else if (!newProp) {
if (oldProp) {
if (!changes) {
return true;
}
JsonOperation._newChange(fieldPath, prop, null, oldProp, docChanges, "FieldChanged");
}
}
else if (Array.isArray(newProp)) {
if (!Array.isArray(oldProp)) {
if (!changes) {
return true;
}
JsonOperation._newChange(fieldPath, prop, newProp, oldProp, docChanges, "FieldChanged");
}
changed = JsonOperation._compareJsonArray(JsonOperation._fieldPathCombine(fieldPath, prop), id, oldProp, newProp, changes, docChanges, prop);
if (!changes && changed) {
return true;
}
}
else if (TypeUtil.isObject(newProp)) {
if (!oldProp) {
if (!changes) {
return true;
}
JsonOperation._newChange(fieldPath, prop, newProp, null, docChanges, "FieldChanged");
}
else {
changed = JsonOperation._compareJson(JsonOperation._fieldPathCombine(fieldPath, prop), id, oldProp, newProp, changes, docChanges);
if (!changes && changed) {
return true;
}
}
}
else {
throwError("InvalidArgumentException", `Unknown type of JSON property: ${typeOfNewProp}.`);
}
}
if (!changes || docChanges.length <= 0) {
return false;
}
changes[id] = docChanges;
return true;
}
static _compareValues(oldProp, newProp) {
return oldProp === newProp; // triple equals compares type as well
}
static _compareJsonArray(fieldPath, id, oldArray, newArray, changes, docChanges, propName) {
// if we don't care about the changes
if (oldArray.length !== newArray.length && !changes) {
return true;
}
let position = 0;
let changed = false;
let oldArrayItem = oldArray[position];
let typeOfOldArrayItem = typeof oldArrayItem;
let newArrayItem = newArray[position];
let typeOfNewArrayItem = typeof newArrayItem;
while (position < oldArray.length && position < newArray.length) {
if (TypeUtil.isObject(oldArrayItem)) {
if (TypeUtil.isObject(newArrayItem)) {
changed = changed || this._compareJson(JsonOperation._addIndexFieldPath(fieldPath, position), id, oldArrayItem, newArrayItem, changes, docChanges);
}
else {
changed = true;
if (changes) {
this._newChange(JsonOperation._addIndexFieldPath(fieldPath, position), propName, newArrayItem, oldArrayItem, docChanges, "ArrayValueAdded");
}
}
}
else if (Array.isArray(oldArrayItem)) {
if (Array.isArray(newArrayItem)) {
changed = changed
|| this._compareJsonArray(JsonOperation._addIndexFieldPath(fieldPath, position), id, oldArrayItem, newArrayItem, changes, docChanges, propName);
}
else {
changed = true;
if (changes) {
this._newChange(JsonOperation._addIndexFieldPath(fieldPath, position), propName, newArrayItem, oldArrayItem, docChanges, "ArrayValueChanged");
}
}
}
else if (!oldArrayItem) {
if (newArrayItem) {
changed = true;
if (changes) {
this._newChange(JsonOperation._addIndexFieldPath(fieldPath, position), propName, newArrayItem, oldArrayItem, docChanges, "ArrayValueAdded");
}
}
}
else {
if (oldArrayItem !== newArrayItem) {
if (changes) {
this._newChange(JsonOperation._addIndexFieldPath(fieldPath, position), propName, newArrayItem, oldArrayItem, docChanges, "ArrayValueChanged");
}
changed = true;
}
}
position++;
oldArrayItem = oldArray[position];
typeOfOldArrayItem = typeof oldArrayItem;
newArrayItem = newArray[position];
typeOfNewArrayItem = typeof newArrayItem;
}
if (!changes) {
return changed;
}
// if one of the arrays is larger than the other
while (position < oldArray.length) {
this._newChange(fieldPath, propName, null, oldArray[position], docChanges, "ArrayValueRemoved");
position++;
}
while (position < newArray.length) {
this._newChange(fieldPath, propName, newArray[position], null, docChanges, "ArrayValueAdded");
position++;
}
return changed;
}
static _addIndexFieldPath(fieldPath, position) {
return fieldPath + "[" + position + "]";
}
static _newChange(fieldPath, name, newValue, oldValue, docChanges, change) {
const documentsChanges = new DocumentsChanges();
documentsChanges.fieldName = name;
documentsChanges.fieldNewValue = newValue;
documentsChanges.fieldOldValue = oldValue;
documentsChanges.change = change;
documentsChanges.fieldPath = fieldPath;
docChanges.push(documentsChanges);
}
}
//# sourceMappingURL=JsonOperation.js.map