From c735762bb335a3a8334bbd6debb5edc7d44a9d1a Mon Sep 17 00:00:00 2001 From: Will Bartlett Date: Wed, 26 Sep 2018 12:21:51 +0100 Subject: [PATCH 1/7] Adds tests for current '_id' fieldname behavior --- test/helper/schemas.js | 16 +++++++++++++++- test/unit/primary.test.js | 4 ++++ test/unit/rx-schema.test.js | 20 ++++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/test/helper/schemas.js b/test/helper/schemas.js index d352b0d41fa..0ad65c1c07f 100644 --- a/test/helper/schemas.js +++ b/test/helper/schemas.js @@ -270,10 +270,24 @@ export const nostringIndex = { } }, required: ['firstName', 'lastName'] - }; +export const _idPrimary = { + description: 'the primary is \'_id\'', + version: 0, + type: 'object', + properties: { + _id: { + type: 'string', + primary: true + }, + firstName: { + type: 'string' + } + }, + required: ['firstName'] +}; export const bigHuman = { title: 'human schema', diff --git a/test/unit/primary.test.js b/test/unit/primary.test.js index 931bb73e9f2..af32defa48f 100644 --- a/test/unit/primary.test.js +++ b/test/unit/primary.test.js @@ -59,6 +59,10 @@ config.parallel('primary.test.js', () => { schemaObj.properties.passportId.encrypted = true; assert.throws(() => RxSchema.create(schemaObj), Error); }); + it('throw if primary is _id', async () => { + const schemaObj = clone(schemas._idPrimary); + assert.throws(() => RxSchema.create(schemaObj), Error); + }); }); }); describe('.validate()', () => { diff --git a/test/unit/rx-schema.test.js b/test/unit/rx-schema.test.js index 87bf427bdb0..920e6710e21 100755 --- a/test/unit/rx-schema.test.js +++ b/test/unit/rx-schema.test.js @@ -266,6 +266,26 @@ config.parallel('rx-schema.test.js', () => { } }), Error); }); + it('throw when _id is not primary', async () => { + assert.throws(() => SchemaCheck.checkSchema({ + title: 'schema', + version: 0, + description: 'save as fieldname', + properties: { + userId: { + type: 'string', + primary: true + }, + _id: { + type: 'string', + }, + firstName: { + type: 'string' + } + }, + required: ['firstName'] + }), Error); + }); }); }); describe('.normalize()', () => { From 77b448b8feb89f433bde29dc1efb732d3100a7df Mon Sep 17 00:00:00 2001 From: Will Bartlett Date: Wed, 26 Sep 2018 12:25:40 +0100 Subject: [PATCH 2/7] Adds special casing for _id in schemas --- src/plugins/schema-check.js | 11 ++++------- src/rx-schema.js | 0 test/helper/schema-objects.js | 7 +++++++ test/unit/key-compression.test.js | 0 test/unit/primary.test.js | 13 +++++++++---- test/unit/rx-schema.test.js | 0 6 files changed, 20 insertions(+), 11 deletions(-) mode change 100755 => 100644 src/rx-schema.js mode change 100755 => 100644 test/unit/key-compression.test.js mode change 100755 => 100644 test/unit/rx-schema.test.js diff --git a/src/plugins/schema-check.js b/src/plugins/schema-check.js index bc0cf7bd29e..69fe1a3f785 100644 --- a/src/plugins/schema-check.js +++ b/src/plugins/schema-check.js @@ -20,6 +20,7 @@ import { */ export function checkFieldNameRegex(fieldName) { if (fieldName === '') return; + if (fieldName === '_id') return; if (['properties', 'language'].includes(fieldName)) { throw RxError.newRxError('SC23', { @@ -117,6 +118,9 @@ export function validateFieldsDeep(jsonSchema) { if (!isNested) { // check underscore fields if (fieldName.charAt(0) === '_') { + if (fieldName === '_id' && schemaObj.primary) { + return; + } throw RxError.newRxError('SC8', { fieldName }); @@ -150,13 +154,6 @@ export function validateFieldsDeep(jsonSchema) { * @throws {Error} if something is not ok */ export function checkSchema(jsonID) { - // check _id - if (jsonID.properties._id) { - throw RxError.newRxError('SC9', { - schema: jsonID - }); - } - // check _rev if (jsonID.properties._rev) { throw RxError.newRxError('SC10', { diff --git a/src/rx-schema.js b/src/rx-schema.js old mode 100755 new mode 100644 diff --git a/test/helper/schema-objects.js b/test/helper/schema-objects.js index 3d8c2443b5e..fe2a2585519 100644 --- a/test/helper/schema-objects.js +++ b/test/helper/schema-objects.js @@ -124,3 +124,10 @@ export function point() { y: faker.random.number() }; } + +export function _idPrimary() { + return { + _id: randomToken(12), + firstName: faker.name.firstName() + }; +} diff --git a/test/unit/key-compression.test.js b/test/unit/key-compression.test.js old mode 100755 new mode 100644 diff --git a/test/unit/primary.test.js b/test/unit/primary.test.js index af32defa48f..9d9519a52bc 100644 --- a/test/unit/primary.test.js +++ b/test/unit/primary.test.js @@ -59,10 +59,6 @@ config.parallel('primary.test.js', () => { schemaObj.properties.passportId.encrypted = true; assert.throws(() => RxSchema.create(schemaObj), Error); }); - it('throw if primary is _id', async () => { - const schemaObj = clone(schemas._idPrimary); - assert.throws(() => RxSchema.create(schemaObj), Error); - }); }); }); describe('.validate()', () => { @@ -73,6 +69,15 @@ config.parallel('primary.test.js', () => { assert.ok(schema.validate(obj)); }); }); + + describe('positive', () => { + it('should validate when primary key is _id', () => { + const schema = RxSchema.create(schemas._idPrimary); + const obj = schemaObjects._idPrimary(); + assert.ok(schema.validate(obj)); + }); + }); + describe('negative', () => { it('should not validate the human without primary', () => { const schema = RxSchema.create(schemas.primaryHuman); diff --git a/test/unit/rx-schema.test.js b/test/unit/rx-schema.test.js old mode 100755 new mode 100644 From 481c2ca9fd708d8cf57e75f4b95ddb9c2269b691 Mon Sep 17 00:00:00 2001 From: Will Bartlett Date: Wed, 26 Sep 2018 12:25:58 +0100 Subject: [PATCH 3/7] Removes SchemaCheck error message --- src/plugins/error-messages.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/error-messages.js b/src/plugins/error-messages.js index 04340ae09ce..291ed978066 100644 --- a/src/plugins/error-messages.js +++ b/src/plugins/error-messages.js @@ -130,7 +130,6 @@ const CODES = { SC6: 'SchemaCheck: primary can only be defined at top-level', SC7: 'SchemaCheck: default-values can only be defined at top-level', SC8: 'SchemaCheck: first level-fields cannot start with underscore _', - SC9: 'SchemaCheck: schema defines ._id, this will be done automatically', SC10: 'SchemaCheck: schema defines ._rev, this will be done automatically', SC11: 'SchemaCheck: schema need an number>=0 as version', SC12: 'SchemaCheck: primary can only be defined once', From bf78a71f46ebe2a2b6ce89a5b6f97f97f95dadd2 Mon Sep 17 00:00:00 2001 From: Will Bartlett Date: Wed, 26 Sep 2018 13:15:53 +0100 Subject: [PATCH 4/7] Allow insertion of documents where _id is set and primary key is _id --- src/rx-collection.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rx-collection.js b/src/rx-collection.js index 571b86a2edf..43225052a6c 100644 --- a/src/rx-collection.js +++ b/src/rx-collection.js @@ -368,7 +368,7 @@ export class RxCollection { json = clone(json); json = this.schema.fillObjectWithDefaults(json); - if (json._id) { + if (json._id && this.schema.primaryPath !== '_id') { throw RxError.newRxError('COL2', { data: json }); From b8b2091e90f1143fc3179d01293265baf39abf56 Mon Sep 17 00:00:00 2001 From: Will Bartlett Date: Wed, 26 Sep 2018 13:18:24 +0100 Subject: [PATCH 5/7] Adds tests for _id behaviour in RxCollection.insert() --- test/unit/rx-collection.test.js | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/test/unit/rx-collection.test.js b/test/unit/rx-collection.test.js index bf37cecd36e..9209cdd111a 100644 --- a/test/unit/rx-collection.test.js +++ b/test/unit/rx-collection.test.js @@ -282,6 +282,32 @@ config.parallel('rx-collection.test.js', () => { await collection.insert(schemaObjects.human()); db.destroy(); }); + it('should insert an object with _id set', async () => { + const db = await RxDatabase.create({ + name: util.randomCouchString(10), + adapter: 'memory' + }); + const collection = await db.collection({ + name: 'idprimary', + schema: schemas._idPrimary + }); + await collection.insert(schemaObjects._idPrimary()); + db.destroy(); + }); + it('should insert human (_id given)', async () => { + const db = await RxDatabase.create({ + name: util.randomCouchString(10), + adapter: 'memory' + }); + const collection = await db.collection({ + name: 'human', + schema: schemas.human + }); + const human = schemaObjects.human(); + human._id = util.randomCouchString(20); + await collection.insert(human); + db.destroy(); + }); it('should insert nested human', async () => { const db = await RxDatabase.create({ name: util.randomCouchString(10), @@ -346,14 +372,14 @@ config.parallel('rx-collection.test.js', () => { ); db.destroy(); }); - it('should not insert broken human (_id given)', async () => { + it('should not insert when _id given but _id is not primary', async () => { const db = await RxDatabase.create({ name: util.randomCouchString(10), adapter: 'memory' }); const collection = await db.collection({ - name: 'human', - schema: schemas.human + name: 'humanfinal', + schema: schemas.humanFinal }); const human = schemaObjects.human(); human._id = util.randomCouchString(20); From fc5fe34b06cafac4f0509f30962879eadcd8ec9a Mon Sep 17 00:00:00 2001 From: Will Bartlett Date: Wed, 26 Sep 2018 13:19:53 +0100 Subject: [PATCH 6/7] Update COL2 error message for updated behaviour --- src/plugins/error-messages.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/error-messages.js b/src/plugins/error-messages.js index 291ed978066..88994b4239e 100644 --- a/src/plugins/error-messages.js +++ b/src/plugins/error-messages.js @@ -51,7 +51,7 @@ const CODES = { // rx-collection COL1: 'RxDocument.insert() You cannot insert an existing document', - COL2: 'RxCollection.insert() do not provide ._id, it will be generated', + COL2: 'RxCollection.insert() do not provide ._id when it is not the primary key', COL3: 'RxCollection.upsert() does not work without primary', COL4: 'RxCollection.atomicUpsert() does not work without primary', COL5: 'RxCollection.find() if you want to search by _id, use .findOne(_id)', From 62832b1c53038445840369911ac8238342eaa646 Mon Sep 17 00:00:00 2001 From: Will Bartlett Date: Wed, 26 Sep 2018 16:40:29 +0100 Subject: [PATCH 7/7] Adds positive test for _id as primary in RxSchema --- test/unit/rx-schema.test.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/unit/rx-schema.test.js b/test/unit/rx-schema.test.js index 920e6710e21..171563f4060 100644 --- a/test/unit/rx-schema.test.js +++ b/test/unit/rx-schema.test.js @@ -64,6 +64,22 @@ config.parallel('rx-schema.test.js', () => { it('validate point', () => { SchemaCheck.checkSchema(schemas.point); }); + it('validate _id when primary', async () => { + SchemaCheck.checkSchema({ + title: 'schema', + version: 0, + properties: { + _id: { + type: 'string', + primary: true + }, + firstName: { + type: 'string' + } + }, + required: ['firstName'] + }); + }); }); describe('negative', () => { it('break when index is no string', () => {