mirror of
https://github.com/osm-search/Nominatim.git
synced 2026-02-26 11:08:13 +00:00
Select all entrances for results in one query
This commit is contained in:
@@ -338,6 +338,11 @@ BEGIN
|
|||||||
END IF;
|
END IF;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
|
-- When an existing way is updated, recalculate entrances
|
||||||
|
IF existingplacex.osm_type = 'W' and (existingplacex.rank_search > 27 or existingplacex.class IN ('landuse', 'leisure')) THEN
|
||||||
|
PERFORM place_update_entrances(existingplacex.place_id, existingplacex.osm_id);
|
||||||
|
END IF;
|
||||||
|
|
||||||
-- Abort the insertion (we modified the existing place instead)
|
-- Abort the insertion (we modified the existing place instead)
|
||||||
RETURN NULL;
|
RETURN NULL;
|
||||||
END;
|
END;
|
||||||
@@ -365,35 +370,3 @@ BEGIN
|
|||||||
RETURN NULL;
|
RETURN NULL;
|
||||||
END;
|
END;
|
||||||
$$ LANGUAGE plpgsql;
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION place_after_insert()
|
|
||||||
RETURNS TRIGGER
|
|
||||||
AS $$
|
|
||||||
BEGIN
|
|
||||||
{% if debug %}
|
|
||||||
RAISE WARNING 'place_after_insert: % % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type,st_area(NEW.geometry);
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
IF NEW.class IN ('routing:entrance', 'entrance') THEN
|
|
||||||
PERFORM place_update_entrances_for_node(NEW.osm_id);
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RETURN NEW;
|
|
||||||
END;
|
|
||||||
$$ LANGUAGE plpgsql;
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION place_after_delete()
|
|
||||||
RETURNS TRIGGER
|
|
||||||
AS $$
|
|
||||||
BEGIN
|
|
||||||
{% if debug %}
|
|
||||||
RAISE WARNING 'place_after_delete: % % % % %',OLD.osm_type,OLD.osm_id,OLD.class,OLD.type,st_area(OLD.geometry);
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
IF OLD.class IN ('routing:entrance', 'entrance') THEN
|
|
||||||
PERFORM place_update_entrances_for_node(OLD.osm_id);
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RETURN NULL;
|
|
||||||
END;
|
|
||||||
$$ LANGUAGE plpgsql;
|
|
||||||
|
|||||||
@@ -818,8 +818,6 @@ DECLARE
|
|||||||
nameaddress_vector INTEGER[];
|
nameaddress_vector INTEGER[];
|
||||||
addr_nameaddress_vector INTEGER[];
|
addr_nameaddress_vector INTEGER[];
|
||||||
|
|
||||||
entrances JSONB;
|
|
||||||
|
|
||||||
linked_place BIGINT;
|
linked_place BIGINT;
|
||||||
|
|
||||||
linked_node_id BIGINT;
|
linked_node_id BIGINT;
|
||||||
|
|||||||
@@ -625,24 +625,6 @@ END;
|
|||||||
$$ LANGUAGE plpgsql;
|
$$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION place_update_entrances_for_node(osmid BIGINT)
|
|
||||||
RETURNS INTEGER
|
|
||||||
AS $$
|
|
||||||
DECLARE
|
|
||||||
entrance_way RECORD;
|
|
||||||
BEGIN
|
|
||||||
FOR entrance_way IN
|
|
||||||
SELECT osm_id, place_id FROM planet_osm_ways JOIN placex ON placex.osm_id = planet_osm_ways.id WHERE osmid=ANY(nodes)
|
|
||||||
LOOP
|
|
||||||
PERFORM place_update_entrances(entrance_way.place_id, entrance_way.osm_id);
|
|
||||||
END LOOP;
|
|
||||||
|
|
||||||
RETURN NULL;
|
|
||||||
END;
|
|
||||||
$$
|
|
||||||
LANGUAGE plpgsql;
|
|
||||||
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION place_update_entrances(placeid BIGINT, osmid BIGINT)
|
CREATE OR REPLACE FUNCTION place_update_entrances(placeid BIGINT, osmid BIGINT)
|
||||||
RETURNS INTEGER
|
RETURNS INTEGER
|
||||||
AS $$
|
AS $$
|
||||||
|
|||||||
@@ -24,10 +24,6 @@ CREATE TRIGGER place_before_delete BEFORE DELETE ON place
|
|||||||
FOR EACH ROW EXECUTE PROCEDURE place_delete();
|
FOR EACH ROW EXECUTE PROCEDURE place_delete();
|
||||||
CREATE TRIGGER place_before_insert BEFORE INSERT ON place
|
CREATE TRIGGER place_before_insert BEFORE INSERT ON place
|
||||||
FOR EACH ROW EXECUTE PROCEDURE place_insert();
|
FOR EACH ROW EXECUTE PROCEDURE place_insert();
|
||||||
CREATE TRIGGER place_after_insert AFTER INSERT ON place
|
|
||||||
FOR EACH ROW EXECUTE PROCEDURE place_after_insert();
|
|
||||||
CREATE TRIGGER place_after_delete AFTER DELETE ON place
|
|
||||||
FOR EACH ROW EXECUTE PROCEDURE place_after_delete();
|
|
||||||
|
|
||||||
CREATE TRIGGER location_postcode_before_update BEFORE UPDATE ON location_postcode
|
CREATE TRIGGER location_postcode_before_update BEFORE UPDATE ON location_postcode
|
||||||
FOR EACH ROW EXECUTE PROCEDURE postcode_update();
|
FOR EACH ROW EXECUTE PROCEDURE postcode_update();
|
||||||
|
|||||||
@@ -470,8 +470,7 @@ async def add_result_details(conn: SearchConnection, results: List[BaseResultT],
|
|||||||
await complete_parented_places(conn, result)
|
await complete_parented_places(conn, result)
|
||||||
if details.entrances:
|
if details.entrances:
|
||||||
log().comment('Query entrances details')
|
log().comment('Query entrances details')
|
||||||
for result in results:
|
await complete_entrances_details(conn, results)
|
||||||
await complete_entrances_details(conn, result)
|
|
||||||
if details.keywords:
|
if details.keywords:
|
||||||
log().comment('Query keywords')
|
log().comment('Query keywords')
|
||||||
for result in results:
|
for result in results:
|
||||||
@@ -723,17 +722,19 @@ async def complete_linked_places(conn: SearchConnection, result: BaseResult) ->
|
|||||||
result.linked_rows.append(_result_row_to_address_row(row))
|
result.linked_rows.append(_result_row_to_address_row(row))
|
||||||
|
|
||||||
|
|
||||||
async def complete_entrances_details(conn: SearchConnection, result: BaseResult) -> None:
|
async def complete_entrances_details(conn: SearchConnection, results: List[BaseResultT]) -> None:
|
||||||
""" Retrieve information about tagged entrances for this place.
|
""" Retrieve information about tagged entrances for this place.
|
||||||
"""
|
"""
|
||||||
if result.source_table != SourceTable.PLACEX:
|
|
||||||
return
|
|
||||||
|
|
||||||
t = conn.t.place_entrance
|
t = conn.t.place_entrance
|
||||||
sql = sa.select(t.c.entrances).where(t.c.place_id == result.place_id)
|
place_ids = (r.place_id for r in results)
|
||||||
|
sql = sa.select(t.c.place_id, t.c.entrances).where(t.c.place_id.in_(place_ids))
|
||||||
|
|
||||||
for results in await conn.execute(sql):
|
current_result = None
|
||||||
result.entrances = [EntranceDetails(**r) for r in results[0]]
|
for place_id, entrances in await conn.execute(sql):
|
||||||
|
if current_result is None or place_id != current_result.place_id:
|
||||||
|
current_result = next((r for r in results if r.place_id == place_id), None)
|
||||||
|
assert current_result is not None
|
||||||
|
current_result.entrances = [EntranceDetails(**r) for r in entrances]
|
||||||
|
|
||||||
|
|
||||||
async def complete_keywords(conn: SearchConnection, result: BaseResult) -> None:
|
async def complete_keywords(conn: SearchConnection, result: BaseResult) -> None:
|
||||||
|
|||||||
@@ -247,6 +247,23 @@ def check_result_for_field_absence(nominatim_result, attributes):
|
|||||||
assert all(a not in nominatim_result.result for a in attributes)
|
assert all(a not in nominatim_result.result for a in attributes)
|
||||||
|
|
||||||
|
|
||||||
|
@then(step_parse(
|
||||||
|
r'the result contains array field (?P<field>\S+) where element (?P<num>\d+) contains'),
|
||||||
|
converters={'num': int})
|
||||||
|
def check_result_array_field_for_attributes(nominatim_result, datatable, field, num):
|
||||||
|
assert nominatim_result.is_simple()
|
||||||
|
|
||||||
|
if datatable[0] == ['param', 'value']:
|
||||||
|
pairs = datatable[1:]
|
||||||
|
else:
|
||||||
|
pairs = zip(datatable[0], datatable[1])
|
||||||
|
|
||||||
|
prefix = f"{field}+{num}+"
|
||||||
|
|
||||||
|
for k, v in pairs:
|
||||||
|
assert ResultAttr(nominatim_result.result, prefix + k) == v
|
||||||
|
|
||||||
|
|
||||||
@then(step_parse('the result set contains(?P<exact> exactly)?'))
|
@then(step_parse('the result set contains(?P<exact> exactly)?'))
|
||||||
def check_result_list_match(nominatim_result, datatable, exact):
|
def check_result_list_match(nominatim_result, datatable, exact):
|
||||||
assert not nominatim_result.is_simple()
|
assert not nominatim_result.is_simple()
|
||||||
|
|||||||
@@ -36,7 +36,9 @@ Feature: Object details
|
|||||||
| W | 429210603 | 1 |
|
| W | 429210603 | 1 |
|
||||||
Then a HTTP 200 is returned
|
Then a HTTP 200 is returned
|
||||||
And the result is valid json
|
And the result is valid json
|
||||||
And the result has attributes entrances
|
And the result contains array field entrances where element 0 contains
|
||||||
|
| osm_id | type | lat | lon |
|
||||||
|
| 6580031131 | yes | 47.2489382 | 9.5284033 |
|
||||||
|
|
||||||
Scenario: Details with linkedplaces
|
Scenario: Details with linkedplaces
|
||||||
When sending v1/details
|
When sending v1/details
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ Feature: Entrance nodes are recorded
|
|||||||
| osm | class | type | geometry |
|
| osm | class | type | geometry |
|
||||||
| W1 | building | yes | (1,2,3,4,1) |
|
| W1 | building | yes | (1,2,3,4,1) |
|
||||||
And the ways
|
And the ways
|
||||||
| id | nodes |
|
| id | nodes |
|
||||||
| 1 | 10,20,30,40 |
|
| 1 | 1, 2, 3, 4, 1 |
|
||||||
When importing
|
When importing
|
||||||
Then placex contains exactly
|
Then placex contains exactly
|
||||||
| object | place_id |
|
| object | place_id |
|
||||||
@@ -18,63 +18,68 @@ Feature: Entrance nodes are recorded
|
|||||||
Then place_entrance contains exactly
|
Then place_entrance contains exactly
|
||||||
| place_id | entrances |
|
| place_id | entrances |
|
||||||
When updating places
|
When updating places
|
||||||
| osm | class | type | geometry |
|
| osm | class | type | geometry |
|
||||||
| N10 | entrance | main | 1 |
|
| N1 | entrance | main | 1 |
|
||||||
|
| W1 | building | yes | (1,2,3,4,1) |
|
||||||
Then placex contains exactly
|
Then placex contains exactly
|
||||||
| object | place_id |
|
| object | place_id |
|
||||||
| W1 | 1 |
|
| W1 | 1 |
|
||||||
And place_entrance contains exactly
|
And place_entrance contains exactly
|
||||||
| place_id | entrances |
|
| place_id | entrances |
|
||||||
| 1 | [{'lat': 0, 'lon': 0, 'type': 'main', 'osm_id': 10, 'extratags': None}] |
|
| 1 | [{'lat': 0, 'lon': 0, 'type': 'main', 'osm_id': 1, 'extratags': None}] |
|
||||||
|
|
||||||
Scenario: A building with a updated entrance node
|
Scenario: A building with a updated entrance node
|
||||||
Given the grid
|
Given the grid
|
||||||
| 1 | 2 |
|
| 1 | 2 |
|
||||||
| 4 | 3 |
|
| 4 | 3 |
|
||||||
Given the places
|
Given the places
|
||||||
| osm | class | type | geometry |
|
| osm | class | type | geometry |
|
||||||
| W1 | building | yes | (1,2,3,4,1) |
|
| N1 | barrier | gate | 1 |
|
||||||
| N10 | barrier | gate | 1 |
|
| W1 | building | yes | (1,2,3,4,1) |
|
||||||
And the ways
|
And the ways
|
||||||
| id | nodes |
|
| id | nodes |
|
||||||
| 1 | 10,20,30,40 |
|
| 1 | 1, 2, 3, 4, 1 |
|
||||||
When importing
|
When importing
|
||||||
Then placex contains exactly
|
Then placex contains exactly
|
||||||
| object | place_id |
|
| object | place_id |
|
||||||
| W1 | 1 |
|
| N1 | 1 |
|
||||||
| N10 | 2 |
|
| W1 | 2 |
|
||||||
Then place_entrance contains exactly
|
Then place_entrance contains exactly
|
||||||
| place_id | entrances |
|
| place_id | entrances |
|
||||||
When updating places
|
When updating places
|
||||||
| osm | class | type | geometry |
|
| osm | class | type | geometry |
|
||||||
| N10 | entrance | main | 1 |
|
| N1 | entrance | main | 1 |
|
||||||
|
| W1 | building | yes | (1,2,3,4,1) |
|
||||||
Then placex contains exactly
|
Then placex contains exactly
|
||||||
| object | place_id |
|
| object | place_id |
|
||||||
| W1 | 1 |
|
| N1 | 1 |
|
||||||
| N10 | 2 |
|
| W1 | 2 |
|
||||||
And place_entrance contains exactly
|
And place_entrance contains exactly
|
||||||
| place_id | entrances |
|
| place_id | entrances |
|
||||||
| 1 | [{'lat': 0, 'lon': 0, 'type': 'main', 'osm_id': 10, 'extratags': None}] |
|
| 2 | [{'lat': 0, 'lon': 0, 'type': 'main', 'osm_id': 1, 'extratags': None}] |
|
||||||
|
|
||||||
Scenario: A building with a removed entrance
|
Scenario: A building with a removed entrance
|
||||||
Given the grid
|
Given the grid
|
||||||
| 1 | 2 |
|
| 1 | 2 |
|
||||||
| 4 | 3 |
|
| 4 | 3 |
|
||||||
Given the places
|
Given the places
|
||||||
| osm | class | type | geometry |
|
| osm | class | type | geometry |
|
||||||
| W1 | building | yes | (1,2,3,4,1) |
|
| N1 | entrance | main | 1 |
|
||||||
| N10 | entrance | main | 1 |
|
| W1 | building | yes | (1,2,3,4,1) |
|
||||||
And the ways
|
And the ways
|
||||||
| id | nodes |
|
| id | nodes |
|
||||||
| 1 | 10,20,30,40 |
|
| 1 | 1, 2, 3, 4, 1 |
|
||||||
When importing
|
When importing
|
||||||
Then placex contains exactly
|
Then placex contains exactly
|
||||||
| object | place_id |
|
| object | place_id |
|
||||||
| W1 | 1 |
|
| W1 | 1 |
|
||||||
And place_entrance contains exactly
|
And place_entrance contains exactly
|
||||||
| place_id | entrances |
|
| place_id | entrances |
|
||||||
| 1 | [{'lat': 0, 'lon': 0, 'type': 'main', 'osm_id': 10, 'extratags': None}] |
|
| 1 | [{'lat': 0, 'lon': 0, 'type': 'main', 'osm_id': 1, 'extratags': None}] |
|
||||||
When marking for delete N10
|
When marking for delete N1
|
||||||
|
And updating places
|
||||||
|
| osm | class | type | geometry |
|
||||||
|
| W1 | building | yes | (2,3,4,2) |
|
||||||
Then placex contains exactly
|
Then placex contains exactly
|
||||||
| object | place_id |
|
| object | place_id |
|
||||||
| W1 | 1 |
|
| W1 | 1 |
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
"""
|
"""
|
||||||
Helper functions to compare expected values.
|
Helper functions to compare expected values.
|
||||||
"""
|
"""
|
||||||
|
import collections.abc
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
import math
|
import math
|
||||||
@@ -102,8 +103,13 @@ class ResultAttr:
|
|||||||
self.subobj = self.obj
|
self.subobj = self.obj
|
||||||
for sub in self.key.split('+'):
|
for sub in self.key.split('+'):
|
||||||
done += f"[{sub}]"
|
done += f"[{sub}]"
|
||||||
assert sub in self.subobj, \
|
if isinstance(self.subobj, collections.abc.Sequence) and sub.isdigit():
|
||||||
f"Missing attribute {done}. Full object:\n{_pretty(self.obj)}"
|
sub = int(sub)
|
||||||
|
assert sub < len(self.subobj), \
|
||||||
|
f"Out of bound index {done}. Full object:\n{_pretty(self.obj)}"
|
||||||
|
else:
|
||||||
|
assert sub in self.subobj, \
|
||||||
|
f"Missing attribute {done}. Full object:\n{_pretty(self.obj)}"
|
||||||
self.subobj = self.subobj[sub]
|
self.subobj = self.subobj[sub]
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
|
|||||||
Reference in New Issue
Block a user