diff --git a/CHANGELOG.md b/CHANGELOG.md index cdbf1338acc..6a5946ab844 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Bugfixes: - newRxError is not a constructor [#719](https://github.com/pubkey/rxdb/issues/719) thanks [@errorx666](https://github.com/errorx666) - Collection name validation is too strict [#720](https://github.com/pubkey/rxdb/issues/720) thanks [@errorx666](https://github.com/errorx666) - Field names can't be one character long [#717](https://github.com/pubkey/rxdb/issues/717) thanks [@errorx666](https://github.com/errorx666) + - Invalid value persists in document after failed update [#734](https://github.com/pubkey/rxdb/issues/734) thanks [@rybaczewa](https://github.com/rybaczewa) ### 7.7.0 (July 6, 2018) diff --git a/src/plugins/update.js b/src/plugins/update.js index c3630f54920..ea84228d3ae 100644 --- a/src/plugins/update.js +++ b/src/plugins/update.js @@ -5,10 +5,13 @@ */ import modifyjs from 'modifyjs'; import deepEqual from 'deep-equal'; +import { + clone +} from '../util.js'; export function update(updateObj) { + const oldDocData = clone(this._data); const newDoc = modifyjs(this._data, updateObj); - Object.keys(this._data).forEach((previousPropName) => { if (newDoc[previousPropName]) { // if we don't check inequality, it triggers an update attempt on fields that didn't really change, @@ -24,7 +27,13 @@ export function update(updateObj) { .filter(newPropName => !deepEqual(this._data[newPropName], newDoc[newPropName])) .forEach(newPropName => this._data[newPropName] = newDoc[newPropName]); - return this.save(); + return this.save() + .then(() => this) + .catch(err => { + // save was not successfull, reset doc-data + this._data = oldDocData; + throw err; + }); } export async function RxQueryUpdate(updateObj) { diff --git a/test/unit.test.js b/test/unit.test.js index 0064ce2df9a..1edbd98216a 100644 --- a/test/unit.test.js +++ b/test/unit.test.js @@ -7,6 +7,7 @@ const nodeAndBrowser = [ '../test_tmp/unit/instance-of-check.test.js', '../test_tmp/unit/rx-schema.test.js', '../test_tmp/unit/key-compression.test.js', + '../test_tmp/unit/bug-report.test.js', '../test_tmp/unit/socket.test.js', '../test_tmp/unit/rx-database.test.js', '../test_tmp/unit/rx-collection.test.js', @@ -35,8 +36,7 @@ const nodeAndBrowser = [ '../test_tmp/unit/local-documents.test.js', '../test_tmp/unit/in-memory.test.js', '../test_tmp/unit/server.test.js', - '../test_tmp/unit/attachments.test.js', - '../test_tmp/unit/bug-report.test.js' + '../test_tmp/unit/attachments.test.js' ]; const last = [ diff --git a/test/unit/rx-document.test.js b/test/unit/rx-document.test.js index b30561f218f..9785e0fe8c5 100644 --- a/test/unit/rx-document.test.js +++ b/test/unit/rx-document.test.js @@ -12,7 +12,7 @@ import * as RxDocument from '../../dist/lib/rx-document'; import * as RxDatabase from '../../dist/lib/index'; config.parallel('rx-document.test.js', () => { - describe('statics', () => {}); + describe('statics', () => { }); describe('.get()', () => { describe('positive', () => { it('get a value', async () => { @@ -39,7 +39,7 @@ config.parallel('rx-document.test.js', () => { c.database.destroy(); }); }); - describe('negative', () => {}); + describe('negative', () => { }); }); describe('.set()', () => { describe('positive', () => { @@ -762,5 +762,69 @@ config.parallel('rx-document.test.js', () => { db.destroy(); }); + it('#734 Invalid value persists in document after failed update', async () => { + // create a schema + const schemaEnum = ['A', 'B']; + const mySchema = { + version: 0, + type: 'object', + properties: { + children: { + type: 'array', + items: { + type: 'object', + properties: { + name: { type: 'string' }, + abLetter: { + type: 'string', + enum: schemaEnum, + }, + } + } + } + } + }; + + // generate a random database-name + const name = util.randomCouchString(10); + + // create a database + const db = await RxDB.create({ + name, + adapter: 'memory', + ignoreDuplicate: true + }); + // create a collection + const collection = await db.collection({ + name: util.randomCouchString(10), + schema: mySchema + }); + + // insert a document + const doc = await collection.insert({ + children: [ + { name: 'foo', abLetter: 'A' }, + { name: 'bar', abLetter: 'B' }, + ], + }); + + const colDoc = await collection.findOne({ _id: doc._id }).exec(); + + + try { + await colDoc.update({ + $set: { + 'children.1.abLetter': 'invalidEnumValue', + }, + }); + } catch (err) { + } + + assert.equal(colDoc.children[1].abLetter, 'B'); + + + // clean up afterwards + db.destroy(); + }); }); });