pelias-schema 10.0.0 → 10.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,11 +3,15 @@ const Joi = require('@hapi/joi');
3
3
  // Schema Configuration
4
4
  // schema.indexName: populated by defaults if not overridden
5
5
  // schema.icuTokenizer: boolean, optional, defaults to false
6
+ // schema.unstoredFields: array of field paths to index but omit from _source, optional
7
+ // schema.excludedFields: array of field paths to remove from the mapping, optional
6
8
  // esclient: object, validation performed by elasticsearch module
7
9
  const schema = Joi.object().required().keys({
8
10
  schema: Joi.object().required().keys({
9
11
  indexName: Joi.string().required(),
10
- icuTokenizer: Joi.boolean().optional()
12
+ icuTokenizer: Joi.boolean().optional(),
13
+ unstoredFields: Joi.array().items(Joi.string()).optional(),
14
+ excludedFields: Joi.array().items(Joi.string()).optional()
11
15
  }),
12
16
  esclient: Joi.object().required()
13
17
  }).unknown(true);
@@ -0,0 +1,28 @@
1
+ const _ = require('lodash');
2
+
3
+ // convert a dotted field path such as 'parent.county_a' into its location in a mapping
4
+ const mappingPath = (field) => _.flatMap(field.split('.'), (part) => ['properties', part]);
5
+
6
+ /**
7
+ * apply field configuration from `schema` section of pelias config to a mapping
8
+ *
9
+ * unstoredFields: fields that are indexed but omitted from _source
10
+ * excludedFields: fields removed from the mapping entirely
11
+ */
12
+ function configureFields(mapping, schemaConfig) {
13
+ const unstored = _.get(schemaConfig, 'unstoredFields', []);
14
+ const excluded = _.get(schemaConfig, 'excludedFields', []);
15
+
16
+ const configured = _.cloneDeep(mapping);
17
+
18
+ if (!_.isEmpty(unstored)) {
19
+ const excludes = _.get(configured, '_source.excludes', []);
20
+ _.set(configured, '_source.excludes', _.union(excludes, unstored));
21
+ }
22
+
23
+ excluded.forEach((field) => _.unset(configured, mappingPath(field)));
24
+
25
+ return configured;
26
+ }
27
+
28
+ module.exports = configureFields;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pelias-schema",
3
- "version": "10.0.0",
3
+ "version": "10.1.0",
4
4
  "author": "pelias",
5
5
  "description": "Elasticsearch schema files and tooling for Pelias",
6
6
  "homepage": "https://github.com/pelias/schema",
package/schema.js CHANGED
@@ -1,6 +1,9 @@
1
+ const config = require('pelias-config').generate();
2
+ const configureFields = require('./mappings/configureFields');
3
+
1
4
  const schema = {
2
5
  settings: require('./settings')(),
3
- mappings: require('./mappings/document'),
6
+ mappings: configureFields(require('./mappings/document'), config.schema),
4
7
  };
5
8
 
6
9
  module.exports = schema;
@@ -84,6 +84,43 @@ module.exports.tests.interface = function(test, common) {
84
84
 
85
85
  });
86
86
 
87
+ test('config with array of strings for unstoredFields and excludedFields should not throw error', function(t) {
88
+ var config = {
89
+ schema: {
90
+ indexName: 'example_index',
91
+ unstoredFields: ['addendum', 'parent.county_a'],
92
+ excludedFields: ['popularity']
93
+ },
94
+ esclient: {}
95
+ };
96
+
97
+ t.doesNotThrow(function() {
98
+ configValidation.validate(config);
99
+ }, 'no error should have been thrown');
100
+
101
+ t.end();
102
+ });
103
+
104
+ test('config with non-array unstoredFields or excludedFields should throw error', function(t) {
105
+ ['unstoredFields', 'excludedFields'].forEach((key) => {
106
+ [null, 17, 'addendum', {}, true, [17]].forEach((value) => {
107
+ var config = {
108
+ schema: {
109
+ indexName: 'example_index',
110
+ [key]: value
111
+ },
112
+ esclient: {}
113
+ };
114
+
115
+ t.throws(function() {
116
+ configValidation.validate(config);
117
+ }, new RegExp(`"schema.${key}(\\[0\\])?" must be`), `${key} must be an array of strings`);
118
+ });
119
+ });
120
+
121
+ t.end();
122
+ });
123
+
87
124
  };
88
125
 
89
126
  module.exports.all = function (tape, common) {
@@ -0,0 +1,49 @@
1
+ const configureFields = require('../mappings/configureFields');
2
+ const document = require('../mappings/document');
3
+
4
+ module.exports.tests = {};
5
+
6
+ module.exports.tests.unstored = function(test, common) {
7
+ test('no config leaves mapping unchanged', function(t) {
8
+ t.deepEqual(configureFields(document, undefined), document);
9
+ t.deepEqual(configureFields(document, {}), document);
10
+ t.end();
11
+ });
12
+
13
+ test('unstored fields are appended to _source excludes', function(t) {
14
+ const mapping = configureFields(document, { unstoredFields: ['addendum', 'parent.*_a', 'shape'] });
15
+ t.deepEqual(mapping._source.excludes, ['shape', 'phrase', 'addendum', 'parent.*_a']);
16
+ t.deepEqual(mapping.properties, document.properties, 'properties unchanged');
17
+ t.end();
18
+ });
19
+ };
20
+
21
+ module.exports.tests.excluded = function(test, common) {
22
+ test('excluded fields are removed from mapping', function(t) {
23
+ const mapping = configureFields(document, { excludedFields: ['popularity', 'parent.county_a', 'not_a_field'] });
24
+ t.false(mapping.properties.popularity, 'top level field removed');
25
+ t.false(mapping.properties.parent.properties.county_a, 'nested field removed');
26
+ t.true(mapping.properties.parent.properties.county, 'sibling field kept');
27
+ t.true(mapping.properties.population, 'other fields kept');
28
+ t.end();
29
+ });
30
+
31
+ test('original mapping is not modified', function(t) {
32
+ configureFields(document, { unstoredFields: ['addendum'], excludedFields: ['popularity', 'parent.county_a'] });
33
+ t.deepEqual(document._source.excludes, ['shape', 'phrase']);
34
+ t.true(document.properties.popularity);
35
+ t.true(document.properties.parent.properties.county_a);
36
+ t.end();
37
+ });
38
+ };
39
+
40
+ module.exports.all = function (tape, common) {
41
+
42
+ function test(name, testFunction) {
43
+ return tape('configureFields: ' + name, testFunction);
44
+ }
45
+
46
+ for( var testCase in module.exports.tests ){
47
+ module.exports.tests[testCase](test, common);
48
+ }
49
+ };
package/test/run.js CHANGED
@@ -11,6 +11,7 @@ var common = {
11
11
  var tests = [
12
12
  require('./compile.js'),
13
13
  require('./document.js'),
14
+ require('./configureFields.js'),
14
15
  require('./partial-centroid.js'),
15
16
  require('./partial-admin.js'),
16
17
  require('./partial-keyword.js'),