diff --git a/lib/field-collection.js b/lib/field-collection.js index ac3c90e..62433ee 100644 --- a/lib/field-collection.js +++ b/lib/field-collection.js @@ -31,8 +31,10 @@ var FieldCollection = Collection.extend(lodashMixin, parentMixin, { // get or create field var field = this.get(name); if (!field) { + var path = this.parent && this.parent.path ? this.parent.path + '.' + name : name; field = this.add({ name: name, + path: path, parent: this.parent }); if (this.parent) { diff --git a/lib/field.js b/lib/field.js index 1dad6d1..590d0b4 100644 --- a/lib/field.js +++ b/lib/field.js @@ -16,6 +16,14 @@ module.exports = State.extend({ type: 'string', required: true }, + /** + * The full path in dot-notation, e.g. "address.street" + */ + path: { + type: 'string', + required: true, + default: null + }, /** * Number of times this field has been seen in a sample of documents. */ diff --git a/lib/type-collection.js b/lib/type-collection.js index a219935..3574008 100644 --- a/lib/type-collection.js +++ b/lib/type-collection.js @@ -66,14 +66,15 @@ module.exports = Collection.extend(lodashMixin, parentMixin, { */ addToType: function(value) { var field = this.parent; - + var path = this.parent ? this.parent.path : null; var typeName = getTypeName(value); var added = false; // get or create type var type = this.get(typeName); if (!type) { type = this.add({ - name: typeName + name: typeName, + path: path }); added = true; } diff --git a/lib/types/type.js b/lib/types/type.js index 2a5e8cb..830da17 100644 --- a/lib/types/type.js +++ b/lib/types/type.js @@ -16,7 +16,8 @@ var Type = AmpersandState.extend({ } }, session: { - parent: 'state' + parent: 'state', + path: 'string' }, derived: { modelType: { diff --git a/test/basic-embedded-document-array.test.js b/test/basic-embedded-document-array.test.js index 792c024..dda003d 100644 --- a/test/basic-embedded-document-array.test.js +++ b/test/basic-embedded-document-array.test.js @@ -25,5 +25,9 @@ describe('basic embedded document array', function() { following.toJSON(); }); }); + + it('should pass path down through array type', function() { + assert.equal(following.fields.get('following').arrayFields.at(0).path, 'following._id'); + }); // @todo: write more tests when not so tired... }); diff --git a/test/basic-embedded-documents.test.js b/test/basic-embedded-documents.test.js index 6e79a66..5907c20 100644 --- a/test/basic-embedded-documents.test.js +++ b/test/basic-embedded-documents.test.js @@ -35,7 +35,7 @@ describe('basic embedded documents', function() { users = getSchema('users', docs, done); }); - it('should detect all fields', function() { + it('should detect all fields names and nested paths', function() { var field_names = [ '_id', 'created_at', @@ -46,7 +46,14 @@ describe('basic embedded documents', function() { 'stats', 'twitter' ]; + + var nested_path_names = [ + 'push_token.android', + 'push_token.apple' + ]; + assert.deepEqual(users.fields.pluck('name'), field_names); + assert.deepEqual(users.fields.get('push_token').fields.pluck('path'), nested_path_names); }); it('should serialize correctly', function() { assert.doesNotThrow(function() { diff --git a/test/nested-document-path.test.js b/test/nested-document-path.test.js new file mode 100644 index 0000000..080e8e9 --- /dev/null +++ b/test/nested-document-path.test.js @@ -0,0 +1,25 @@ +var getSchema = require('../'); +var assert = require('assert'); +var BSON = require('bson'); + +/*eslint new-cap: 0, quote-props: 0*/ +describe('nested document path', function() { + var schema; + var docs = [ + { + 'foo': { + 'bar': { + 'baz': 1 + } + } + } + ]; + + before(function(done) { + schema = getSchema('nested.documents', docs, done); + }); + + it('should assemble the path correctly with dot-notation', function() { + assert.equal(schema.fields.get('foo').fields.get('bar').fields.get('baz').path, 'foo.bar.baz'); + }); +});