diff --git a/src/hooks/hooks-middleware.ts b/src/hooks/hooks-middleware.ts index 91c5bb683..ad91ad287 100644 --- a/src/hooks/hooks-middleware.ts +++ b/src/hooks/hooks-middleware.ts @@ -10,7 +10,7 @@ import { DBCoreKeyRange, } from "../public/types/dbcore"; import { nop } from '../functions/chaining-functions'; -import { getObjectDiff, setByKeyPath } from '../functions/utils'; +import { getObjectDiff, hasOwn, setByKeyPath } from '../functions/utils'; import { PSD } from '../helpers/promise'; //import { LockableTableMiddleware } from '../dbcore/lockable-table-middleware'; import { getEffectiveKeys, getExistingValues } from '../dbcore/get-effective-keys'; @@ -87,7 +87,13 @@ export const hooksMiddleware: Middleware = { if (additionalChanges) { const requestedValue = req.values[i]; Object.keys(additionalChanges).forEach(keyPath => { - setByKeyPath(requestedValue, keyPath, additionalChanges[keyPath]); + if (hasOwn(requestedValue, keyPath)) { + // keyPath is already present as a literal property of the object + requestedValue[keyPath] = additionalChanges[keyPath]; + } else { + // keyPath represents a new or existing path into the object + setByKeyPath(requestedValue, keyPath, additionalChanges[keyPath]); + } }); } } diff --git a/test/tests-table.js b/test/tests-table.js index f034104a3..b8fa9ffe2 100644 --- a/test/tests-table.js +++ b/test/tests-table.js @@ -78,6 +78,51 @@ promisedTest("Issue #841 - put() ignores date changes", async ()=> { db.folks.hook("updating").unsubscribe(updateAssertions); }); +promisedTest("Issue #966 - put() with dotted field in update hook", async () => { + const updateAssertions = (mods) => { + equal(mods["nested.field"], "value", "mods.nested.field should contain 'value'"); + equal(mods.nested, undefined, "mods.nested field should be empty"); + return {...mods}; + }; + db.folks.hook("updating", updateAssertions); + + const id = await db.folks.add({first: "first", last: "last"}); + await db.folks.put({first: "first", last: "last", "nested.field": "value"}, id); + + let obj = await db.folks.get(id); + equal(obj["nested.field"], "value", "obj.nested.field should have been successfully updated to 'value'"); + equal(obj.nested, undefined, "obj.nested field should have remained undefined"); + + db.folks.hook("updating").unsubscribe(updateAssertions); +}); + +promisedTest("Verify #1130 doesn't break contract of hook('updating')", async ()=>{ + const updateHook = (mods) => { + return {"address.postalCode": 111}; + }; + try { + const id = await db.folks.add({ + first: "Foo", + last: "Bar", + address: { + city: "Stockholm", + street: "Folkungagatan" + } + }); + db.folks.hook("updating", updateHook); + await db.folks.update(id, { + "address.streetNo": 23 + }); + let foo = await db.folks.get(id); + equal(foo.address.city, "Stockholm", "Correct city Stockholm"); + equal(foo.address.street, "Folkungagatan", "Correct street Folkungagatan"); + equal(foo.address.streetNo, 23, "Correct streetNo: 23"); + equal(foo.address.postalCode, 111, "Hooks should have added postal code"); + } finally { + db.folks.hook("updating").unsubscribe(updateHook); + } +}); + asyncTest("get", 4, function () { db.table("users").get(idOfFirstUser).then(function(obj) { equal(obj.first, "David", "Got the first object");