UNPKG

5.87 kBJavaScriptView Raw
1'use strict';
2
3const _ = require('lodash');
4const Query = require('./Query');
5
6function createAddressShould(vs) {
7 const should = {
8 bool: {
9 _name: 'fallback.address',
10 must: [
11 {
12 match_phrase: {
13 'address_parts.number': {
14 query: vs.var('input:housenumber')
15 }
16 }
17 },
18 {
19 match_phrase: {
20 'address_parts.street': {
21 query: vs.var('input:street')
22 }
23 }
24 }
25 ],
26 filter: {
27 term: {
28 layer: 'address'
29 }
30 }
31 }
32 };
33
34 if (vs.isset('boost:address')) {
35 should.bool.boost = vs.var('boost:address');
36 }
37
38 return should;
39}
40
41function createUnitAndAddressShould(vs) {
42 const should = {
43 bool: {
44 _name: 'fallback.address',
45 must: [
46 {
47 match_phrase: {
48 'address_parts.unit': {
49 query: vs.var('input:unit')
50 }
51 }
52 },
53 {
54 match_phrase: {
55 'address_parts.number': {
56 query: vs.var('input:housenumber')
57 }
58 }
59 },
60 {
61 match_phrase: {
62 'address_parts.street': {
63 query: vs.var('input:street')
64 }
65 }
66 }
67 ],
68 filter: {
69 term: {
70 layer: 'address'
71 }
72 }
73 }
74 };
75
76 if (vs.isset('boost:address')) {
77 should.bool.boost = vs.var('boost:address');
78 }
79
80 return should;
81}
82
83function createPostcodeAndAddressShould(vs) {
84 const should = {
85 bool: {
86 _name: 'fallback.address',
87 must: [
88 {
89 match_phrase: {
90 'address_parts.zip': {
91 query: vs.var('input:postcode')
92 }
93 }
94 },
95 {
96 match_phrase: {
97 'address_parts.number': {
98 query: vs.var('input:housenumber')
99 }
100 }
101 },
102 {
103 match_phrase: {
104 'address_parts.street': {
105 query: vs.var('input:street')
106 }
107 }
108 }
109 ],
110 filter: {
111 term: {
112 layer: 'address'
113 }
114 }
115 }
116 };
117
118 if (vs.isset('boost:address')) {
119 should.bool.boost = vs.var('boost:address');
120 }
121
122 return should;
123}
124
125function createStreetShould(vs) {
126 const should = {
127 bool: {
128 _name: 'fallback.street',
129 must: [
130 {
131 match_phrase: {
132 'address_parts.street': {
133 query: vs.var('input:street')
134 }
135 }
136 }
137 ],
138 filter: {
139 term: {
140 layer: 'street'
141 }
142 }
143 }
144 };
145
146 if (vs.isset('boost:street')) {
147 should.bool.boost = vs.var('boost:street');
148 }
149
150 return should;
151
152}
153
154function createLayerIdsShould(layer, ids) {
155 // create an object initialize with terms.'parent.locality_id' (or whatever)
156 // must use array syntax for 2nd parameter as _.set interprets '.' as new object
157 return _.set({}, ['terms', `parent.${layer}_id`], ids);
158}
159
160class AddressesUsingIdsQuery extends Query {
161 constructor() {
162 super();
163 }
164
165 render(vs) {
166 // establish a base query with 'street' should condition and size/track_scores
167 const base = {
168 query: {
169 function_score: {
170 query: {
171 bool: {
172 minimum_should_match: 1,
173 should: [
174 createStreetShould(vs)
175 ]
176 }
177 }
178 }
179 },
180 size: vs.var('size'),
181 track_scores: vs.var('track_scores')
182 };
183
184 // add unit/housenumber/street if available
185 if (vs.isset('input:housenumber') && vs.isset('input:postcode')) {
186 base.query.function_score.query.bool.should.push(createPostcodeAndAddressShould(vs));
187 }
188 // add unit/housenumber/street if available
189 if (vs.isset('input:housenumber') && vs.isset('input:unit')) {
190 base.query.function_score.query.bool.should.push(createUnitAndAddressShould(vs));
191 }
192 else if (vs.isset('input:housenumber')) {
193 base.query.function_score.query.bool.should.push(createAddressShould(vs));
194 }
195
196 // if there are layer->id mappings, add the layers with non-empty ids
197 if (vs.isset('input:layers')) {
198 // using $ due to reference object and not scalar object
199 const layers_to_ids = vs.var('input:layers').$;
200
201 // add the layers-to-ids 'should' conditions
202 // if layers_to_ids is:
203 // {
204 // locality: [1, 2],
205 // localadmin: [],
206 // region: [3, 4]
207 // }
208 // then this adds the results of:
209 // - createShould('locality', [1, 2])
210 // - createShould('region', [3, 4])
211 // to an array
212 const id_filters = Object.keys(layers_to_ids).reduce((acc, layer) => {
213 if (!_.isEmpty(layers_to_ids[layer])) {
214 acc.push(createLayerIdsShould(layer, layers_to_ids[layer]));
215 }
216 return acc;
217 }, []);
218
219 // add filter.bool.minimum_should_match and filter.bool.should,
220 // creating intermediate objects as it goes
221 _.set(base.query.function_score.query.bool, 'filter.bool', {
222 minimum_should_match: 1,
223 should: id_filters
224 });
225
226 }
227
228 // add any scores (_.compact removes falsey values from arrays)
229 if (!_.isEmpty(this._score)) {
230 base.query.function_score.functions = _.compact(this._score.map(view => view(vs)));
231 }
232
233 // add any filters
234 if (!_.isEmpty(this._filter)) {
235 // add filter.bool.must, creating intermediate objects if they don't exist
236 // using _.set does away with the need to check for object existence
237 // _.compact removes falsey values from arrays
238 _.set(
239 base.query.function_score.query.bool,
240 'filter.bool.must',
241 _.compact(this._filter.map(view => view(vs))));
242
243 }
244
245 return base;
246 }
247
248}
249
250module.exports = AddressesUsingIdsQuery;