]> git.openstreetmap.org Git - nominatim.git/blob - settings/flex-base.lua
explicit export for functions in flex-base
[nominatim.git] / settings / flex-base.lua
1 -- Core functions for Nominatim import flex style.
2 --
3
4 local module = {}
5
6 -- The single place table.
7 place_table = osm2pgsql.define_table{
8     name = "place",
9     ids = { type = 'any', id_column = 'osm_id', type_column = 'osm_type' },
10     columns = {
11         { column = 'class', type = 'text', not_null = true },
12         { column = 'type', type = 'text', not_null = true },
13         { column = 'admin_level', type = 'smallint' },
14         { column = 'name', type = 'hstore' },
15         { column = 'address', type = 'hstore' },
16         { column = 'extratags', type = 'hstore' },
17         { column = 'geometry', type = 'geometry', projection = 'WGS84', not_null = true },
18     },
19     indexes = {}
20 }
21
22 ------------- Place class ------------------------------------------
23
24 local Place = {}
25 Place.__index = Place
26
27 function Place.new(object, geom_func)
28     local self = setmetatable({}, Place)
29     self.object = object
30     self.geom_func = geom_func
31
32     self.admin_level = tonumber(self.object:grab_tag('admin_level'))
33     if self.admin_level == nil
34        or self.admin_level <= 0 or self.admin_level > 15
35        or math.floor(self.admin_level) ~= self.admin_level then
36         self.admin_level = 15
37     end
38
39     self.num_entries = 0
40     self.has_name = false
41     self.names = {}
42     self.address = {}
43     self.extratags = {}
44
45     return self
46 end
47
48 function Place:clean(data)
49     if data.delete ~= nil or data.extra ~= nil then
50         for k, v in pairs(self.object.tags) do
51             if data.delete ~= nil and data.delete(k, v) then
52                 self.object.tags[k] = nil
53             elseif data.extra ~= nil and data.extra(k, v) then
54                 self.extratags[k] = v
55                 self.object.tags[k] = nil
56             end
57         end
58     end
59 end
60
61 function Place:delete(data)
62     if data.match ~= nil then
63         for k, v in pairs(self.object.tags) do
64             if data.match(k, v) then
65                 self.object.tags[k] = nil
66             end
67         end
68     end
69 end
70
71 function Place:grab_extratags(data)
72     local count = 0
73
74     if data.match ~= nil then
75         for k, v in pairs(self.object.tags) do
76             if data.match(k, v) then
77                 self.object.tags[k] = nil
78                 self.extratags[k] = v
79                 count = count + 1
80             end
81         end
82     end
83
84     return count
85 end
86
87 function Place:grab_address(data)
88     local count = 0
89
90     if data.match ~= nil then
91         for k, v in pairs(self.object.tags) do
92             if data.match(k, v) then
93                 self.object.tags[k] = nil
94
95                 if data.include_on_name == true then
96                     self.has_name = true
97                 end
98
99                 if data.out_key ~= nil then
100                     self.address[data.out_key] = v
101                     return 1
102                 end
103
104                 if k:sub(1, 5) == 'addr:' then
105                     self.address[k:sub(6)] = v
106                 elseif k:sub(1, 6) == 'is_in:' then
107                     self.address[k:sub(7)] = v
108                 else
109                     self.address[k] = v
110                 end
111                 count = count + 1
112             end
113         end
114     end
115
116     return count
117 end
118
119 local function strip_address_prefix(k)
120     if k:sub(1, 5) == 'addr:' then
121         return k:sub(6)
122     end
123
124     if k:sub(1, 6) == 'is_in:' then
125         return k:sub(7)
126     end
127
128     return k
129 end
130
131
132 function Place:grab_address_parts(data)
133     local count = 0
134
135     if data.groups ~= nil then
136         for k, v in pairs(self.object.tags) do
137             local atype = data.groups(k, v)
138
139             if atype ~= nil then
140                 if atype == 'main' then
141                     self.has_name = true
142                     self.address[strip_address_prefix(k)] = v
143                     count = count + 1
144                 elseif atype == 'extra' then
145                     self.address[strip_address_prefix(k)] = v
146                 else
147                     self.address[atype] = v
148                 end
149                 self.object.tags[k] = nil
150             end
151         end
152     end
153
154     return count
155 end
156
157 function Place:grab_name(data)
158     local count = 0
159
160     if data.match ~= nil then
161         for k, v in pairs(self.object.tags) do
162             if data.match(k, v) then
163                 self.object.tags[k] = nil
164                 self.names[k] = v
165                 if data.include_on_name ~= false then
166                     self.has_name = true
167                 end
168                 count = count + 1
169             end
170         end
171     end
172
173     return count
174 end
175
176 function Place:grab_name_parts(data)
177     local fallback = nil
178
179     if data.groups ~= nil then
180         for k, v in pairs(self.object.tags) do
181             local atype = data.groups(k, v)
182
183             if atype ~= nil then
184                 self.names[k] = v
185                 if atype == 'main' then
186                     self.has_name = true
187                 elseif atype == 'house' then
188                     self.has_name = true
189                     fallback = {'place', 'house', 'always'}
190                 end
191             end
192         end
193     end
194
195     return fallback
196 end
197
198 function Place:grab_tag(key)
199     return self.object:grab_tag(key)
200 end
201
202 function Place:write_place(k, v, mtype, save_extra_mains)
203     if mtype == nil then
204         return 0
205     end
206
207     v = v or self.object.tags[k]
208     if v == nil then
209         return 0
210     end
211
212     if type(mtype) == 'table' then
213         mtype = mtype[v] or mtype[1]
214     end
215
216     if mtype == 'always' or (self.has_name and mtype == 'named') then
217         return self:write_row(k, v, save_extra_mains)
218     end
219
220     if mtype == 'named_with_key' then
221         local names = {}
222         local prefix = k .. ':name'
223         for namek, namev in pairs(self.object.tags) do
224             if namek:sub(1, #prefix) == prefix
225                and (#namek == #prefix
226                     or namek:sub(#prefix + 1, #prefix + 1) == ':') then
227                 names[namek:sub(#k + 2)] = namev
228             end
229         end
230
231         if next(names) ~= nil then
232             local saved_names = self.names
233             self.names = names
234
235             local results = self:write_row(k, v, save_extra_mains)
236
237             self.names = saved_names
238
239             return results
240         end
241     end
242
243     return 0
244 end
245
246 function Place:write_row(k, v, save_extra_mains)
247     if self.geometry == nil then
248         self.geometry = self.geom_func(self.object)
249     end
250     if self.geometry:is_null() then
251         return 0
252     end
253
254     if save_extra_mains then
255         for extra_k, extra_v in pairs(self.object.tags) do
256             if extra_k ~= k then
257                 self.extratags[extra_k] = extra_v
258             end
259         end
260     end
261
262     place_table:insert{
263         class = k,
264         type = v,
265         admin_level = self.admin_level,
266         name = next(self.names) and self.names,
267         address = next(self.address) and self.address,
268         extratags = next(self.extratags) and self.extratags,
269         geometry = self.geometry
270     }
271
272     if save_extra_mains then
273         for k, v in pairs(self.object.tags) do
274             self.extratags[k] = nil
275         end
276     end
277
278     self.num_entries = self.num_entries + 1
279
280     return 1
281 end
282
283
284 function module.tag_match(data)
285     if data == nil or next(data) == nil then
286         return nil
287     end
288
289     local fullmatches = {}
290     local key_prefixes = {}
291     local key_suffixes = {}
292
293     if data.keys ~= nil then
294         for _, key in pairs(data.keys) do
295             if key:sub(1, 1) == '*' then
296                 if #key > 1 then
297                     if key_suffixes[#key - 1] == nil then
298                         key_suffixes[#key - 1] = {}
299                     end
300                     key_suffixes[#key - 1][key:sub(2)] = true
301                 end
302             elseif key:sub(#key, #key) == '*' then
303                 if key_prefixes[#key - 1] == nil then
304                     key_prefixes[#key - 1] = {}
305                 end
306                 key_prefixes[#key - 1][key:sub(1, #key - 1)] = true
307             else
308                 fullmatches[key] = true
309             end
310         end
311     end
312
313     if data.tags ~= nil then
314         for k, vlist in pairs(data.tags) do
315             if fullmatches[k] == nil then
316                 fullmatches[k] = {}
317                 for _, v in pairs(vlist) do
318                     fullmatches[k][v] = true
319                 end
320             end
321         end
322     end
323
324     return function (k, v)
325         if fullmatches[k] ~= nil and (fullmatches[k] == true or fullmatches[k][v] ~= nil) then
326             return true
327         end
328
329         for slen, slist in pairs(key_suffixes) do
330             if #k >= slen and slist[k:sub(-slen)] ~= nil then
331                 return true
332             end
333         end
334
335         for slen, slist in pairs(key_prefixes) do
336             if #k >= slen and slist[k:sub(1, slen)] ~= nil then
337                 return true
338             end
339         end
340
341         return false
342     end
343 end
344
345
346 function module.tag_group(data)
347     if data == nil or next(data) == nil then
348         return nil
349     end
350
351     local fullmatches = {}
352     local key_prefixes = {}
353     local key_suffixes = {}
354
355     for group, tags in pairs(data) do
356         for _, key in pairs(tags) do
357             if key:sub(1, 1) == '*' then
358                 if #key > 1 then
359                     if key_suffixes[#key - 1] == nil then
360                         key_suffixes[#key - 1] = {}
361                     end
362                     key_suffixes[#key - 1][key:sub(2)] = group
363                 end
364             elseif key:sub(#key, #key) == '*' then
365                 if key_prefixes[#key - 1] == nil then
366                     key_prefixes[#key - 1] = {}
367                 end
368                 key_prefixes[#key - 1][key:sub(1, #key - 1)] = group
369             else
370                 fullmatches[key] = group
371             end
372         end
373     end
374
375     return function (k, v)
376         local val = fullmatches[k]
377         if val ~= nil then
378             return val
379         end
380
381         for slen, slist in pairs(key_suffixes) do
382             if #k >= slen then
383                 val = slist[k:sub(-slen)]
384                 if val ~= nil then
385                     return val
386                 end
387             end
388         end
389
390         for slen, slist in pairs(key_prefixes) do
391             if #k >= slen then
392                 val = slist[k:sub(1, slen)]
393                 if val ~= nil then
394                     return val
395                 end
396             end
397         end
398     end
399 end
400
401 -- Process functions for all data types
402 function osm2pgsql.process_node(object)
403
404     local function geom_func(o)
405         return o:as_point()
406     end
407
408     module.process_tags(Place.new(object, geom_func))
409 end
410
411 function osm2pgsql.process_way(object)
412
413     local function geom_func(o)
414         local geom = o:as_polygon()
415
416         if geom:is_null() then
417             geom = o:as_linestring()
418         end
419
420         return geom
421     end
422
423     module.process_tags(Place.new(object, geom_func))
424 end
425
426 function module.relation_as_multipolygon(o)
427     return o:as_multipolygon()
428 end
429
430 function module.relation_as_multiline(o)
431     return o:as_multilinestring():line_merge()
432 end
433
434 function osm2pgsql.process_relation(object)
435     local geom_func = module.RELATION_TYPES[object.tags.type]
436
437     if geom_func ~= nil then
438         module.process_tags(Place.new(object, geom_func))
439     end
440 end
441
442 function module.process_tags(o)
443     o:clean{delete = module.PRE_DELETE, extra = module.PRE_EXTRAS}
444
445     -- Exception for boundary/place double tagging
446     if o.object.tags.boundary == 'administrative' then
447         o:grab_extratags{match = function (k, v)
448             return k == 'place' and v:sub(1,3) ~= 'isl'
449         end}
450     end
451
452     -- name keys
453     local fallback = o:grab_name_parts{groups=module.NAMES}
454
455     -- address keys
456     if o:grab_address_parts{groups=module.ADDRESS_TAGS} > 0 and fallback == nil then
457         fallback = {'place', 'house', 'always'}
458     end
459     if o.address.country ~= nil and #o.address.country ~= 2 then
460         o.address['country'] = nil
461     end
462     if fallback == nil and o.address.postcode ~= nil then
463         fallback = {'place', 'postcode', 'always'}
464     end
465
466     if o.address.interpolation ~= nil then
467         o:write_place('place', 'houses', 'always', module.SAVE_EXTRA_MAINS)
468         return
469     end
470
471     o:clean{delete = module.POST_DELETE, extra = module.POST_EXTRAS}
472
473     -- collect main keys
474     for k, v in pairs(o.object.tags) do
475         local ktype = module.MAIN_KEYS[k]
476         if ktype == 'fallback' then
477             if o.has_name then
478                 fallback = {k, v, 'named'}
479             end
480         elseif ktype ~= nil then
481             o:write_place(k, v,module.MAIN_KEYS[k], module.SAVE_EXTRA_MAINS)
482         end
483     end
484
485     if fallback ~= nil and o.num_entries == 0 then
486         o:write_place(fallback[1], fallback[2], fallback[3], module.SAVE_EXTRA_MAINS)
487     end
488 end
489
490 ------ defaults --------------
491
492 module.RELATION_TYPES = {
493     multipolygon = module.relation_as_multipolygon,
494     boundary = module.relation_as_multipolygon,
495     waterway = module.relation_as_multiline
496 }
497
498
499 return module