Skip to content
New issue

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

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

Already on GitHub? # to your account

feat(persist): Deep merge records in batchUpdate #3386

Merged
merged 13 commits into from
Jan 31, 2025
11 changes: 11 additions & 0 deletions docs-v2/reference/scripts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,17 @@ await nango.batchDelete(githubIssuesToDelete, 'GitHubIssue');
</ResponseField>
</Expandable>

### Update records

Updates records in the Nango cache by merging the given data into the existing record. The `id` field is required in each record and used to determine what existing record to merge into.

The merge algorithm used is a deep merge. This means that nested objects and arrays are merged recursively. Any fields not present in the update record are left unchanged.

```js
const githubIssues: Pick<GitHubIssue, "id" | "state">[] = ...; // Create partial GitHub Issue update records with only id and state.

await nango.batchUpdate(githubIssues, 'GitHubIssue');
```

# Action-specific helper methods

Expand Down
3 changes: 3 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions packages/records/lib/models/records.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,39 @@
});

describe('updating records', () => {
it('should deep merge records', async () => {
const connectionId = rnd.number();
const environmentId = rnd.number();
const model = rnd.string();
const syncId = uuid.v4();
const records = [{ id: '1', person: { name: 'John Doe', age: 35, children: [{ name: 'Jenny Doe', age: 3 }] } }];

const inserted = await upsertRecords({ records, connectionId, environmentId, model, syncId, syncJobId: 1 });
expect(inserted).toStrictEqual({ addedKeys: ['1'], updatedKeys: [], deletedKeys: [], nonUniqueKeys: [] });

Check failure on line 222 in packages/records/lib/models/records.integration.test.ts

View workflow job for this annotation

GitHub Actions / tests

packages/records/lib/models/records.integration.test.ts > Records service > updating records > should deep merge records

AssertionError: expected { addedKeys: [ '1' ], …(4) } to strictly equal { addedKeys: [ '1' ], …(3) } - Expected + Received Object { "addedKeys": Array [ "1", ], "deletedKeys": Array [], + "nextMerging": Object { + "strategy": "override", + }, "nonUniqueKeys": Array [], "updatedKeys": Array [], } ❯ packages/records/lib/models/records.integration.test.ts:222:30

const updated = await updateRecords({
records: [{ id: '1', person: { age: 36, children: [{}, { name: 'Maurice Doe', age: 1 }] } }],
connectionId,
model,
syncId,
syncJobId: 2
});
expect(updated).toStrictEqual({ addedKeys: [], updatedKeys: ['1'], deletedKeys: [], nonUniqueKeys: [] });

const { records: found } = (await Records.getRecords({ connectionId, model })).unwrap();
expect(found.length).toBe(1);
expect(found?.[0]).toMatchObject({
person: {
name: 'John Doe',
age: 36,
children: [
{ name: 'Jenny Doe', age: 3 },
{ name: 'Maurice Doe', age: 1 }
]
}
});
});

describe('should respect merging strategy', () => {
it('when strategy = override', async () => {
const connectionId = rnd.number();
Expand Down
6 changes: 2 additions & 4 deletions packages/records/lib/models/records.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { Err, Ok, retry, stringToHash } from '@nangohq/utils';
import type { Result } from '@nangohq/utils';
import type { Knex } from 'knex';
import { Cursor } from '../cursor.js';
import merge from 'lodash-es/merge.js';

dayjs.extend(utc);

Expand Down Expand Up @@ -449,10 +450,7 @@ export async function update({

const newRecord: FormattedRecord = {
...newRecordRest,
json: {
...oldRecordData,
...newRecordData
},
json: merge({}, oldRecordData, newRecordData),
updated_at: new Date()
};
recordsToUpdate.push(newRecord);
Expand Down
1 change: 1 addition & 0 deletions packages/records/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@nangohq/utils": "file:../utils",
"dayjs": "1.11.10",
"knex": "3.1.0",
"lodash-es": "^4.17.21",
"md5": "2.3.0",
"pg": "8.11.3",
"uuid": "9.0.1"
Expand Down
Loading