Skip to content

Commit

Permalink
feat: nested objects comparison added
Browse files Browse the repository at this point in the history
  • Loading branch information
saostad committed May 23, 2024
1 parent 8420fd4 commit 4c36da1
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 17 deletions.
24 changes: 14 additions & 10 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,26 @@ First, define the source and destination data arrays. In this example, we have `

```ts
const src = [
{ id: 1, firstName: "John", lastName: "Doe" },
{ id: 2, firstName: "Jane", lastName: "Diana" },
{ id: 4, firstName: "Rid", lastName: "Lomba" },
{ id: 1, company: 1, firstName: "John", lastName: "Doe", age: null },
{ id: 1, company: 2, firstName: "John", lastName: "Doe", age: null },
{ id: 2, company: 1, firstName: "Jane", lastName: "Diana", age: null },
{ id: 4, company: 1, firstName: "Rid", lastName: "Lomba", age: 25 },
{ id: 5, company: 1, firstName: "Homa", lastName: "Shiri", age: 30 },
];
const dst = [
{ id: 1, FullName: "John Doe" },
{ id: 3, FullName: "Doe Risko" },
{ id: 4, FullName: "Fids Almo" },
{ id: 1, company: 1, FullName: "John Doe", bio: { age: null } },
{ id: 3, company: 1, FullName: "Doe Risko", bio: { age: 30 } },
{ id: 4, company: 1, FullName: "Fids Almo", bio: { age: 26 } },
{ id: 5, company: 1, FullName: "Homa Shiri", bio: { age: 30 } },
];
```

## Step 2: Define the Keys

Specify the keys that uniquely identify each record in the arrays. In this example, we use the `"id"` property as the key.
Specify the keys that uniquely identify each record in the arrays. In this example, we use the `"id"` and `"company"` property as the key.

```ts
const keys = ["id"];
const keys = ["id", "company"];
```

## Step 3: Create the Sync Engine
Expand All @@ -42,11 +45,12 @@ const engine = new SyncEngine<typeof src, typeof dst>({
// Async function to map the FullName field
fn: async (row) => {
// await some async operation
return `${row.firstName} ${row.lastName}`;
return Promise.resolve(`${row.firstName} ${row.lastName}`);
},
},
// Sync function to map the id field
{ fieldName: "id", fn: (row) => row.id },
{ fieldName: "company", fn: (row) => row.company },
{ fieldName: "bio", fn: (row) => ({ age: row.age }) }, // Nested field
],
// Optional
syncFns: {
Expand Down
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@sostad/sync-engine",
"version": "1.2.1",
"version": "1.3.0",
"exports": "./mod.ts"
}
96 changes: 90 additions & 6 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ export class SyncEngine<
}
}

// Find updated records and log the changes
// Find updated records
for (const srcRecord of mappedData) {
const srcKey = this.keys.map((key) => srcRecord[key]).join("_");
const dstRecord = this.dst.find((dstRecord) => {
Expand All @@ -143,11 +143,22 @@ export class SyncEngine<

for (const [key, value] of Object.entries(srcRecord)) {
if (dstRecord[key] !== value) {
fields.push({
fieldName: key,
oldValue: dstRecord[key],
newValue: value,
});
// check if value is an object, use _shallowEqual to compare
if (typeof value === "object") {
if (!this._shallowEqual(value, dstRecord[key])) {
fields.push({
fieldName: key,
oldValue: dstRecord[key],
newValue: value,
});
}
} else {
fields.push({
fieldName: key,
oldValue: dstRecord[key],
newValue: value,
});
}
}
}

Expand All @@ -163,6 +174,19 @@ export class SyncEngine<
return { inserted, deleted, updated };
}

// to compare two objects
private _shallowEqual(src: Record<any, any>, dst: Record<any, any>) {
if (typeof src !== "object" || typeof dst !== "object") {
return false;
}
for (let key in src) {
if (src[key] !== dst[key]) {
return false;
}
}
return true;
}

public async sync(): Promise<{
inserts: any[] | null;
deletes: any[] | null;
Expand Down Expand Up @@ -225,3 +249,63 @@ export class SyncEngine<
return results;
}
}

// sample usage
const src = [
{ id: 1, company: 1, firstName: "John", lastName: "Doe", age: null },
{ id: 1, company: 2, firstName: "John", lastName: "Doe", age: null },
{ id: 2, company: 1, firstName: "Jane", lastName: "Diana", age: null },
{ id: 4, company: 1, firstName: "Rid", lastName: "Lomba", age: 25 },
{ id: 5, company: 1, firstName: "Homa", lastName: "Shiri", age: 30 },
];
const dst = [
{ id: 1, company: 1, FullName: "John Doe", bio: { age: null } },
{ id: 3, company: 1, FullName: "Doe Risko", bio: { age: 30 } },
{ id: 4, company: 1, FullName: "Fids Almo", bio: { age: 26 } },
{ id: 5, company: 1, FullName: "Homa Shiri", bio: { age: 30 } },
];
const keys = ["id", "company"];

const engine = new SyncEngine<typeof src, typeof dst>({
src,
dst,
keys,
mappings: [
{
fieldName: "FullName",
fn: async (row) => {
await new Promise((resolve) => setTimeout(resolve, 100));
return `${row.firstName} ${row.lastName}`;
},
},
{ fieldName: "id", fn: (row) => row.id },
{ fieldName: "company", fn: (row) => row.company },
{
fieldName: "bio",
fn: (row) => {
return {
age: row.age,
};
},
},
],
syncFns: {
insertFn: async (row) => {
await new Promise((resolve) => setTimeout(resolve, 500));
return row.id;
},
deleteFn: (row) => {
return row.id;
},
updateFn: async (row, fields) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
return row.id;
},
},
});

const mappings = await engine.mapFields();
console.log(mappings);

const changes = await engine.getChanges();
console.log(JSON.stringify(changes, null, 2));

0 comments on commit 4c36da1

Please sign in to comment.