1 -- Core functions for Nominatim import flex style.
6 -- The single place table.
7 place_table = osm2pgsql.define_table{
9 ids = { type = 'any', id_column = 'osm_id', type_column = 'osm_type' },
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 },
22 ------------- Place class ------------------------------------------
27 function Place.new(object, geom_func)
28 local self = setmetatable({}, Place)
30 self.geom_func = geom_func
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
48 function Place:clean(data)
49 for k, v in pairs(self.object.tags) do
50 if data.delete ~= nil and data.delete(k, v) then
51 self.object.tags[k] = nil
52 elseif data.extra ~= nil and data.extra(k, v) then
54 self.object.tags[k] = nil
59 function Place:delete(data)
60 if data.match ~= nil then
61 for k, v in pairs(self.object.tags) do
62 if data.match(k, v) then
63 self.object.tags[k] = nil
69 function Place:grab_extratags(data)
72 if data.match ~= nil then
73 for k, v in pairs(self.object.tags) do
74 if data.match(k, v) then
75 self.object.tags[k] = nil
85 function Place:grab_address(data)
88 if data.match ~= nil then
89 for k, v in pairs(self.object.tags) do
90 if data.match(k, v) then
91 self.object.tags[k] = nil
93 if data.include_on_name == true then
97 if data.out_key ~= nil then
98 self.address[data.out_key] = v
102 if k:sub(1, 5) == 'addr:' then
103 self.address[k:sub(6)] = v
104 elseif k:sub(1, 6) == 'is_in:' then
105 self.address[k:sub(7)] = v
117 local function strip_address_prefix(k)
118 if k:sub(1, 5) == 'addr:' then
122 if k:sub(1, 6) == 'is_in:' then
130 function Place:grab_address_parts(data)
133 if data.groups ~= nil then
134 for k, v in pairs(self.object.tags) do
135 local atype = data.groups(k, v)
138 if atype == 'main' then
140 self.address[strip_address_prefix(k)] = v
142 elseif atype == 'extra' then
143 self.address[strip_address_prefix(k)] = v
145 self.address[atype] = v
147 self.object.tags[k] = nil
155 function Place:grab_name(data)
158 if data.match ~= nil then
159 for k, v in pairs(self.object.tags) do
160 if data.match(k, v) then
161 self.object.tags[k] = nil
163 if data.include_on_name ~= false then
174 function Place:grab_name_parts(data)
177 if data.groups ~= nil then
178 for k, v in pairs(self.object.tags) do
179 local atype = data.groups(k, v)
183 self.object.tags[k] = nil
184 if atype == 'main' then
186 elseif atype == 'house' then
188 fallback = {'place', 'house', 'always'}
197 function Place:grab_tag(key)
198 return self.object:grab_tag(key)
201 function Place:write_place(k, v, mtype, save_extra_mains)
206 v = v or self.object.tags[k]
211 if type(mtype) == 'table' then
212 mtype = mtype[v] or mtype[1]
215 if mtype == 'always' or (self.has_name and mtype == 'named') then
216 return self:write_row(k, v, save_extra_mains)
219 if mtype == 'named_with_key' then
221 local prefix = k .. ':name'
222 for namek, namev in pairs(self.object.tags) do
223 if namek:sub(1, #prefix) == prefix
224 and (#namek == #prefix
225 or namek:sub(#prefix + 1, #prefix + 1) == ':') then
226 names[namek:sub(#k + 2)] = namev
230 if next(names) ~= nil then
231 local saved_names = self.names
234 local results = self:write_row(k, v, save_extra_mains)
236 self.names = saved_names
245 function Place:write_row(k, v, save_extra_mains)
246 if self.geometry == nil then
247 self.geometry = self.geom_func(self.object)
249 if self.geometry:is_null() then
253 if save_extra_mains then
254 for extra_k, extra_v in pairs(self.object.tags) do
256 self.extratags[extra_k] = extra_v
264 admin_level = self.admin_level,
265 name = next(self.names) and self.names,
266 address = next(self.address) and self.address,
267 extratags = next(self.extratags) and self.extratags,
268 geometry = self.geometry
271 if save_extra_mains then
272 for k, v in pairs(self.object.tags) do
273 self.extratags[k] = nil
277 self.num_entries = self.num_entries + 1
283 function module.tag_match(data)
284 if data == nil or next(data) == nil then
288 local fullmatches = {}
289 local key_prefixes = {}
290 local key_suffixes = {}
292 if data.keys ~= nil then
293 for _, key in pairs(data.keys) do
294 if key:sub(1, 1) == '*' then
296 if key_suffixes[#key - 1] == nil then
297 key_suffixes[#key - 1] = {}
299 key_suffixes[#key - 1][key:sub(2)] = true
301 elseif key:sub(#key, #key) == '*' then
302 if key_prefixes[#key - 1] == nil then
303 key_prefixes[#key - 1] = {}
305 key_prefixes[#key - 1][key:sub(1, #key - 1)] = true
307 fullmatches[key] = true
312 if data.tags ~= nil then
313 for k, vlist in pairs(data.tags) do
314 if fullmatches[k] == nil then
316 for _, v in pairs(vlist) do
317 fullmatches[k][v] = true
323 return function (k, v)
324 if fullmatches[k] ~= nil and (fullmatches[k] == true or fullmatches[k][v] ~= nil) then
328 for slen, slist in pairs(key_suffixes) do
329 if #k >= slen and slist[k:sub(-slen)] ~= nil then
334 for slen, slist in pairs(key_prefixes) do
335 if #k >= slen and slist[k:sub(1, slen)] ~= nil then
345 function module.tag_group(data)
346 if data == nil or next(data) == nil then
350 local fullmatches = {}
351 local key_prefixes = {}
352 local key_suffixes = {}
354 for group, tags in pairs(data) do
355 for _, key in pairs(tags) do
356 if key:sub(1, 1) == '*' then
358 if key_suffixes[#key - 1] == nil then
359 key_suffixes[#key - 1] = {}
361 key_suffixes[#key - 1][key:sub(2)] = group
363 elseif key:sub(#key, #key) == '*' then
364 if key_prefixes[#key - 1] == nil then
365 key_prefixes[#key - 1] = {}
367 key_prefixes[#key - 1][key:sub(1, #key - 1)] = group
369 fullmatches[key] = group
374 return function (k, v)
375 local val = fullmatches[k]
380 for slen, slist in pairs(key_suffixes) do
382 val = slist[k:sub(-slen)]
389 for slen, slist in pairs(key_prefixes) do
391 val = slist[k:sub(1, slen)]
400 -- Process functions for all data types
401 function osm2pgsql.process_node(object)
403 local function geom_func(o)
407 module.process_tags(Place.new(object, geom_func))
410 function osm2pgsql.process_way(object)
412 local function geom_func(o)
413 local geom = o:as_polygon()
415 if geom:is_null() then
416 geom = o:as_linestring()
422 module.process_tags(Place.new(object, geom_func))
425 function module.relation_as_multipolygon(o)
426 return o:as_multipolygon()
429 function module.relation_as_multiline(o)
430 return o:as_multilinestring():line_merge()
433 function osm2pgsql.process_relation(object)
434 local geom_func = module.RELATION_TYPES[object.tags.type]
436 if geom_func ~= nil then
437 module.process_tags(Place.new(object, geom_func))
441 function module.process_tags(o)
442 o:clean{delete = module.PRE_DELETE, extra = module.PRE_EXTRAS}
444 -- Exception for boundary/place double tagging
445 if o.object.tags.boundary == 'administrative' then
446 o:grab_extratags{match = function (k, v)
447 return k == 'place' and v:sub(1,3) ~= 'isl'
452 local fallback = o:grab_name_parts{groups=module.NAMES}
455 if o:grab_address_parts{groups=module.ADDRESS_TAGS} > 0 and fallback == nil then
456 fallback = {'place', 'house', 'always'}
458 if o.address.country ~= nil and #o.address.country ~= 2 then
459 o.address['country'] = nil
461 if fallback == nil and o.address.postcode ~= nil then
462 fallback = {'place', 'postcode', 'always'}
465 if o.address.interpolation ~= nil then
466 o:write_place('place', 'houses', 'always', module.SAVE_EXTRA_MAINS)
470 o:clean{delete = module.POST_DELETE, extra = module.POST_EXTRAS}
473 for k, v in pairs(o.object.tags) do
474 local ktype = module.MAIN_KEYS[k]
475 if ktype == 'fallback' then
477 fallback = {k, v, 'named'}
479 elseif ktype ~= nil then
480 o:write_place(k, v,module.MAIN_KEYS[k], module.SAVE_EXTRA_MAINS)
484 if fallback ~= nil and o.num_entries == 0 then
485 o:write_place(fallback[1], fallback[2], fallback[3], module.SAVE_EXTRA_MAINS)
489 --------- Convenience functions for simple style configuration -----------------
491 function module.set_prefilters(data)
492 module.PRE_DELETE = module.tag_match{keys = data.delete_keys, tags = data.delete_tags}
493 module.PRE_EXTRAS = module.tag_match{keys = data.extratag_keys,
494 tags = data.extratag_tags}
497 function module.set_main_tags(data)
498 module.MAIN_KEYS = data
501 function module.set_name_tags(data)
502 module.NAMES = module.tag_group(data)
505 function module.set_address_tags(data)
506 module.ADDRESS_TAGS = module.tag_group(data)
509 function module.set_unused_handling(data)
510 if data.extra_keys == nil and data.extra_tags == nil then
511 module.POST_DELETE = module.tag_match{data.delete_keys, tags = data.delete_tags}
512 module.POST_EXTRAS = nil
513 module.SAVE_EXTRA_MAINS = true
514 elseif data.delete_keys == nil and data.delete_tags == nil then
515 module.POST_DELETE = nil
516 module.POST_EXTRAS = module.tag_match{data.extra_keys, tags = data.extra_tags}
517 module.SAVE_EXTRA_MAINS = false
519 error("unused handler can have only 'extra_keys' or 'delete_keys' set.")
523 ------ defaults --------------
525 module.RELATION_TYPES = {
526 multipolygon = module.relation_as_multipolygon,
527 boundary = module.relation_as_multipolygon,
528 waterway = module.relation_as_multiline