Skip to content

Commit e2dd8e9

Browse files
committed
refactor compareJson(), fix getCircularReplacer() and updateMetadata()
1 parent 875175c commit e2dd8e9

File tree

3 files changed

+54
-38
lines changed

3 files changed

+54
-38
lines changed

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "pythagora",
3-
"version": "0.0.58",
3+
"version": "0.0.60",
44
"author": {
55
"name": "Zvonimir Sabljic",
66
"email": "[email protected]"
@@ -39,6 +39,9 @@
3939
"tryrequire": "^3.0.0",
4040
"uuid": "^9.0.0"
4141
},
42+
"devDependencies": {
43+
"mongodb": "^5.6.0"
44+
},
4245
"contributors": [
4346
{
4447
"name": "Zvonimir Sabljic",

pythagora_tests/unit/src/helpers/mongodb/mongoObjToJson.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import {ObjectId} from "mongodb";
2-
import {mongoObjToJson} from "../../../../../src/helpers/mongodb";
1+
const {ObjectId} = require("mongodb");
2+
const {mongoObjToJson} = require("../../../../../src/helpers/mongodb");
33

44
describe("mongoObjToJson", () => {
55
test('should convert ObjectId to string format', () => {
@@ -20,7 +20,7 @@ describe("mongoObjToJson", () => {
2020
test('should handle nested objects and arrays', () => {
2121
const objectId = new ObjectId();
2222
const date = new Date();
23-
const regex = /^test$/i;
23+
const regex = new RegExp(/^test$/i);
2424
const input = {
2525
_id: objectId,
2626
dates: [{ time: date }],

src/utils/common.js

Lines changed: 47 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const {
77
PYTHAGORA_TESTS_DIR,
88
PYTHAGORA_DELIMITER
99
} = require("../const/common");
10+
const path = require('path');
1011
let mongodb;
1112
// this is needed so that "mongodb" is not required before mongo patches are applied
1213
const ObjectId = class {
@@ -93,43 +94,47 @@ function stringToDate(str) {
9394
function isJSONObject(value) {
9495
return Object.prototype.toString.call(value) === "[object Object]";
9596
}
96-
9797
function compareJson(a, b, strict) {
98-
// TODO make more complex by running tests right after capture
9998
if (a === b) return true;
100-
else if (typeof a !== typeof b) return false;
101-
else if (!a || !b) return false;
102-
else if (Array.isArray(a) && Array.isArray(b)) {
99+
if (typeof a !== typeof b) return false;
100+
if ((!a && a !== 0) || (!b && b !== 0)) return false;
101+
102+
if (Array.isArray(a) && Array.isArray(b)) {
103103
if (a.length !== b.length) return false;
104-
// TODO optimize because this is O(n^2)
105-
return a.reduce((acc, item, index) => acc && !!b.find(b2 => compareJson(item, b2, strict)), true);
106-
} else if (typeof a === 'string' && typeof b === 'string') {
107-
return objectIdAsStringRegex.test(a) && objectIdAsStringRegex.test(b) && !strict ? true : a === b;
104+
return a.every((itemA) => b.some((itemB) => compareJson(itemA, itemB, strict))) &&
105+
b.every((itemB) => a.some((itemA) => compareJson(itemA, itemB, strict)));
108106
}
109-
let ignoreKeys = ['stacktrace'];
110-
// let ignoreIfKeyContains = ['token'];
111-
let aProps = Object.getOwnPropertyNames(a);
112-
let bProps = Object.getOwnPropertyNames(b);
113-
if (aProps.length !== bProps.length) {
114-
return false;
107+
108+
if (typeof a === 'string' && typeof b === 'string') {
109+
return objectIdAsStringRegex.test(a) && objectIdAsStringRegex.test(b) && !strict ? true : a === b;
115110
}
116-
for (let i = 0; i < aProps.length; i++) {
117-
let propName = aProps[i];
118-
if (
119-
a[propName] !== b[propName] &&
120-
(!isDate(a[propName]) && !isDate(a[propName])) &&
121-
!ignoreKeys.includes(propName) &&
122-
!(isObjectId(a[propName]) && isObjectId(b[propName]))// &&
123-
// !ignoreIfKeyContains.some(function(v) { return propName.indexOf(v) >= 0; })
124-
) {
111+
112+
if (typeof a === 'object' && typeof b === 'object') {
113+
let ignoreKeys = ['stacktrace'];
114+
let aProps = Object.getOwnPropertyNames(a);
115+
let bProps = Object.getOwnPropertyNames(b);
116+
117+
if (aProps.length !== bProps.length) {
118+
return false;
119+
}
120+
121+
for (let i = 0; i < aProps.length; i++) {
122+
let propName = aProps[i];
123+
124+
if (ignoreKeys.includes(propName)) continue;
125+
if (isObjectId(a[propName]) && isObjectId(b[propName])) continue;
126+
127+
// Perform deep comparison first
125128
if (typeof a[propName] === 'object') {
126129
if (!compareJson(a[propName], b[propName], strict))
127130
return false;
128-
} else
129-
return false;
131+
} else if (a[propName] !== b[propName]) return false; // If a[propName] and b[propName] are not objects, use !== for comparison
130132
}
133+
return true;
131134
}
132-
return true;
135+
136+
// If a and b are neither arrays nor objects, use !== for comparison
137+
return a !== b ? false : true;
133138
}
134139

135140
function compareJsonDetailed(a, b, strict) {
@@ -220,17 +225,20 @@ function stringToRegExp(str) {
220225
const getCircularReplacer = () => {
221226
const seen = new WeakSet();
222227
return (key, value) => {
223-
value = _.clone(value);
224-
if (isLegacyObjectId(value)) value = (new ObjectId(Buffer.from(value.id.data))).toString();
225-
else if (value instanceof RegExp) value = `RegExp("${value.toString()}")`;
226-
else if (Array.isArray(value) && value.find(v => isLegacyObjectId(v))) {
227-
value = value.map(v => isLegacyObjectId(v) ? (new ObjectId(Buffer.from(v.id.data))).toString() : v);
228-
} if (typeof value === "object" && value !== null) {
228+
if (typeof value === "object" && value !== null) {
229229
if (seen.has(value)) {
230230
return;
231231
}
232232
seen.add(value);
233233
}
234+
235+
// Handle the specific types after checking for circular references
236+
if (isLegacyObjectId(value)) value = (new ObjectId(Buffer.from(value.id.data))).toString();
237+
else if (value instanceof RegExp) value = `RegExp("${value.toString()}")`;
238+
else if (Array.isArray(value) && value.find(v => isLegacyObjectId(v))) {
239+
value = value.map(v => isLegacyObjectId(v) ? (new ObjectId(Buffer.from(v.id.data))).toString() : v);
240+
}
241+
234242
return value;
235243
};
236244
};
@@ -329,7 +337,12 @@ function insertVariablesInText(text, variables) {
329337
}
330338

331339
function updateMetadata(newMetadata) {
332-
fs.writeFileSync(`./${PYTHAGORA_METADATA_DIR}/${METADATA_FILENAME}`, JSON.stringify(newMetadata, getCircularReplacer(), 2));
340+
const dirPath = `./${PYTHAGORA_METADATA_DIR}`;
341+
const filePath = path.join(dirPath, METADATA_FILENAME);
342+
if (!fs.existsSync(dirPath)) {
343+
fs.mkdirSync(dirPath, { recursive: true });
344+
}
345+
fs.writeFileSync(filePath, JSON.stringify(newMetadata, getCircularReplacer(), 2));
333346
}
334347

335348
function comparePaths(path1, path2) {

0 commit comments

Comments
 (0)