diff --git a/README.md b/README.md index 881ec886..73644d20 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,12 @@ It **updates a local copy of the OSM database** in near real-time, and provides ## Demo -We've deployed a rudimentary demo that keeps a database up-to-date for (some country), +We've deployed a basic demo that keeps a database up-to-date for (some country), rendering buildings and highlighting the ones identified as "un-squared": [https://underpass.live](https://underpass.live) -Screenshot 2023-11-22 at 10 32 56 +Screenshot 2024-06-05 at 15 51 57 ## Getting started diff --git a/m4/ax_boost_timer.m4 b/m4/ax_boost_timer.m4 index 95c98335..35254128 100644 --- a/m4/ax_boost_timer.m4 +++ b/m4/ax_boost_timer.m4 @@ -67,8 +67,8 @@ AC_DEFUN([AX_BOOST_TIMER], [AC_LANG_PUSH([C++]) CXXFLAGS_SAVE=$CXXFLAGS - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], - [[boost::timer timer;]])], + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], + [[boost::timer::auto_cpu_timer t;]])], ax_cv_boost_timer=yes, ax_cv_boost_timer=no) CXXFLAGS=$CXXFLAGS_SAVE AC_LANG_POP([C++]) diff --git a/python/dbapi/api/db.py b/python/dbapi/api/db.py index 1738c41e..6c1687ae 100644 --- a/python/dbapi/api/db.py +++ b/python/dbapi/api/db.py @@ -58,21 +58,21 @@ async def run(self, query, singleObject = False, asJson=False): if not self.pool: await self.connect() if self.pool: + result = None try: conn = await self.pool.acquire() result = await conn.fetch(query) + data = None if asJson: - if singleObject: - return result[0]['result'] - return result[0]['result'] + data = result[0]['result'] + elif singleObject: + data = result[0] else: - if singleObject: - return result[0] - return result + data = result + await self.pool.release(conn) + return data except Exception as e: print("\n******* \n" + query + "\n******* \n") print(e) return None - finally: - await self.pool.release(conn) - return None + diff --git a/python/dbapi/api/raw.py b/python/dbapi/api/raw.py index e8500434..a7e7ae7e 100644 --- a/python/dbapi/api/raw.py +++ b/python/dbapi/api/raw.py @@ -30,7 +30,7 @@ # Order by class OrderBy(Enum): - createdAt = "created_at" + closedAt = "closed_at" id = "id" timestamp = "timestamp" @@ -73,7 +73,7 @@ def geoFeaturesQuery(params: RawFeaturesParamsDTO, asJson: bool = False): tags, \n \ hashtags, \n \ editor, \n \ - created_at \n \ + closed_at \n \ FROM {table} \n \ LEFT JOIN changesets c ON c.id = {table}.changeset \n \ WHERE{area}{tags}{hashtag}{date} {limit}; \n \ @@ -84,7 +84,7 @@ def geoFeaturesQuery(params: RawFeaturesParamsDTO, asJson: bool = False): .format(area=params.area) if params.area else "", tags=" AND (" + tagsQueryFilter(params.tags, params.table.value) + ") \n" if params.tags else "", hashtag=" AND " + hashtagQueryFilter(params.hashtag, params.table.value) if params.hashtag else "", - date=" AND created_at >= {dateFrom} AND created_at <= {dateTo}\n" + date=" AND closed_at >= {dateFrom} AND closed_at <= {dateTo}\n" .format(dateFrom=params.dateFrom, dateTo=params.dateTo) if params.dateFrom and params.dateTo else "\n", limit=" LIMIT {limit}".format(limit=RESULTS_PER_PAGE) @@ -115,7 +115,7 @@ def listFeaturesQuery( {table}.timestamp, \n \ tags, \n \ {table}.changeset, \n \ - c.created_at \n \ + c.closed_at \n \ FROM {table} \n \ LEFT JOIN changesets c ON c.id = {table}.changeset \n \ WHERE{fromDate}{toDate}{hashtag}{area}{tags}{order} \ @@ -124,8 +124,8 @@ def listFeaturesQuery( type=osmType.value, geotype=geoType.value, table=table.value, - fromDate=" AND created_at >= '{dateFrom}'".format(dateFrom=params.dateFrom) if (params.dateFrom) else "", - toDate=" AND created_at <= '{dateTo}'".format(dateTo=params.dateTo) if (params.dateTo) else "", + fromDate=" AND closed_at >= '{dateFrom}'".format(dateFrom=params.dateFrom) if (params.dateFrom) else "", + toDate=" AND closed_at <= '{dateTo}'".format(dateTo=params.dateTo) if (params.dateTo) else "", hashtag=" AND " + hashtagQueryFilter(params.hashtag, table.value) if params.hashtag else "", area=" AND ST_Intersects(\"geom\", ST_GeomFromText('MULTIPOLYGON((({area})))', 4326) )" .format( @@ -137,7 +137,7 @@ def listFeaturesQuery( order=params.orderBy.value, limit=RESULTS_PER_PAGE_LIST, offset=params.page * RESULTS_PER_PAGE_LIST - ) if params.page else "" + ) if params.page is not None else " LIMIT {limit} OFFSET {offset}" ).replace("WHERE AND", "WHERE") if asJson: return listQueryToJSON(query, params) @@ -152,7 +152,7 @@ def listQueryToJSON(query: str, params: ListFeaturesParamsDTO): predata.timestamp, \n \ tags, \n \ predata.changeset, \n \ - predata.created_at as created_at, \n \ + predata.closed_at as closed_at, \n \ lat, \n \ lon \n \ from predata \n \ @@ -163,10 +163,10 @@ def listQueryToJSON(query: str, params: ListFeaturesParamsDTO): ) SELECT jsonb_agg(t_features.feature) as result FROM t_features;" \ .format( query=query, - date="created_at >= '{dateFrom}' AND created_at <= '{dateTo}'" + date="closed_at >= '{dateFrom}' AND closed_at <= '{dateTo}'" .format( dateFrom=params.dateFrom if (params.dateFrom) else "", - dateTo=" AND created_at <= '{dateTo}'".format(dateTo=params.dateTo) if (params.dateTo) else "" + dateTo=" AND closed_at <= '{dateTo}'".format(dateTo=params.dateTo) if (params.dateTo) else "" ) if params.dateFrom and params.dateTo else "", orderBy=" AND {orderBy} IS NOT NULL ORDER BY {orderBy} DESC" .format( @@ -238,7 +238,7 @@ async def getPolygons( params.table = Table.polygons result = await self.db.run(geoFeaturesQuery(params, asJson), asJson=asJson) if asJson: - return result + return result or {} return deserializeTags(result) # Get line features @@ -250,7 +250,7 @@ async def getLines( params.table = Table.lines result = await self.db.run(geoFeaturesQuery(params, asJson), asJson=asJson) if asJson: - return result + return result or {} return deserializeTags(result) @@ -263,7 +263,7 @@ async def getNodes( params.table = Table.nodes result = await self.db.run(geoFeaturesQuery(params, asJson), asJson=asJson) if asJson: - return result + return result or {} return deserializeTags(result) # Get all (polygon, line, node) features diff --git a/python/dbapi/api/rawValidation.py b/python/dbapi/api/rawValidation.py index eec66a6e..0ac4d4fb 100644 --- a/python/dbapi/api/rawValidation.py +++ b/python/dbapi/api/rawValidation.py @@ -30,7 +30,7 @@ from .filters import tagsQueryFilter, hashtagQueryFilter from .serialization import queryToJSON from .config import RESULTS_PER_PAGE, RESULTS_PER_PAGE_LIST, DEBUG -from .raw import RawFeaturesParamsDTO, ListFeaturesParamsDTO, rawQueryToJSON, listQueryToJSON +from .raw import RawFeaturesParamsDTO, ListFeaturesParamsDTO, rawQueryToJSON, listQueryToJSON, OrderBy from .serialization import deserializeTags import json @@ -92,8 +92,8 @@ def countQuery( ) \ select count, total from count_validated_features, count_features".format( table=params.table.value, - dateFrom=" AND created_at >= '{dateFrom}'".format(dateFrom=params.dateFrom) if (params.dateFrom) else "", - dateTo=" AND created_at <= '{dateTo}'".format(dateTo=params.dateTo) if (params.dateTo) else "", + dateFrom=" AND closed_at >= '{dateFrom}'".format(dateFrom=params.dateFrom) if (params.dateFrom) else "", + dateTo=" AND closed_at <= '{dateTo}'".format(dateTo=params.dateTo) if (params.dateTo) else "", area=" AND ST_Intersects(\"geom\", ST_GeomFromText('MULTIPOLYGON((({area})))', 4326) )".format(area=params.area) if params.area else "", tags=" AND (" + tagsQueryFilter(params.tags, params.table.value) + ") \n" if params.tags else "", hashtag=" AND " + hashtagQueryFilter(params.hashtag, params.table.value) if params.hashtag else "", @@ -115,7 +115,7 @@ def geoFeaturesQuery(params: RawValidationFeaturesParamsDTO, asJson: bool = Fals status, \n \ hashtags, \n \ editor, \n \ - created_at \n \ + closed_at \n \ FROM {table} \n \ LEFT JOIN changesets c ON c.id = {table}.changeset \n \ LEFT JOIN validation ON validation.osm_id = {table}.osm_id \ @@ -127,7 +127,7 @@ def geoFeaturesQuery(params: RawValidationFeaturesParamsDTO, asJson: bool = Fals .format(area=params.area) if params.area else "", tags=" AND (" + tagsQueryFilter(params.tags, params.table.value) + ") \n" if params.tags else "", hashtag=" AND " + hashtagQueryFilter(params.hashtag, params.table.value) if params.hashtag else "", - date=" AND created_at >= {dateFrom} AND created_at <= {dateTo}\n" + date=" AND closed_at >= {dateFrom} AND closed_at <= {dateTo}\n" .format(dateFrom=params.dateFrom, dateTo=params.dateTo) if params.dateFrom and params.dateTo else "\n", status=" AND status = '{status}'".format(status=params.status.value) if (params.status) else "", @@ -148,6 +148,7 @@ def listFeaturesQuery( geoType:GeoType = GeoType[params.table] osmType:OsmType = OsmType[params.table] table:Table = Table[params.table] + orderBy:OrderBy = OrderBy[params.orderBy] query = "( \ SELECT '{type}' as type, \n \ @@ -158,7 +159,7 @@ def listFeaturesQuery( {table}.timestamp, \n \ tags, \n \ {table}.changeset, \n \ - c.created_at, \n \ + c.closed_at, \n \ status \n \ FROM {table} \n \ LEFT JOIN changesets c ON c.id = {table}.changeset \n \ @@ -169,8 +170,8 @@ def listFeaturesQuery( type=osmType.value, geotype=geoType.value, table=table.value, - fromDate=" AND created_at >= '{dateFrom}'".format(dateFrom=params.dateFrom) if (params.dateFrom) else "", - toDate=" AND created_at <= '{dateTo}'".format(dateTo=params.dateTo) if (params.dateTo) else "", + fromDate=" AND closed_at >= '{dateFrom}'".format(dateFrom=params.dateFrom) if (params.dateFrom) else "", + toDate=" AND closed_at <= '{dateTo}'".format(dateTo=params.dateTo) if (params.dateTo) else "", hashtag=" AND " + hashtagQueryFilter(params.hashtag, table.value) if params.hashtag else "", area=" AND ST_Intersects(\"geom\", ST_GeomFromText('MULTIPOLYGON((({area})))', 4326) )" .format( @@ -180,10 +181,10 @@ def listFeaturesQuery( status=" AND status = '{status}'".format(status=params.status.value) if (params.status) else "", order=" AND {order} IS NOT NULL ORDER BY {order} DESC LIMIT {limit} OFFSET {offset}" .format( - order=params.orderBy.value, + order=orderBy.value, limit=RESULTS_PER_PAGE_LIST, offset=params.page * RESULTS_PER_PAGE_LIST - ) if params.page else "" + ) if params.page is not None else " LIMIT {limit} OFFSET {offset}" ).replace("WHERE AND", "WHERE") if asJson: return listQueryToJSON(query, params) diff --git a/python/dbapi/api/stats.py b/python/dbapi/api/stats.py index 9495a091..698d361c 100644 --- a/python/dbapi/api/stats.py +++ b/python/dbapi/api/stats.py @@ -44,7 +44,7 @@ def featureCountQuery(params: StatsParamsDTO, asJson: bool = False): .format(area=params.area) if params.area else "", tags=" AND (" + tagsQueryFilter(params.tags, params.table.value) + ") \n" if params.tags else "", hashtag=" AND " + hashtagQueryFilter(params.hashtag, params.table.value) if params.hashtag else "", - date=" AND created_at >= {dateFrom} AND created_at <= {dateTo}\n" + date=" AND closed_at >= {dateFrom} AND closed_at <= {dateTo}\n" .format(dateFrom=params.dateFrom, dateTo=params.dateTo) if params.dateFrom and params.dateTo else "\n" ).replace("WHERE AND", "WHERE") @@ -65,6 +65,7 @@ async def getNodesCount( result = await self.db.run(featureCountQuery(params), singleObject=True) if asJson: return json.dumps(dict(result)) + return result async def getLinesCount( self, @@ -75,6 +76,7 @@ async def getLinesCount( result = await self.db.run(featureCountQuery(params), singleObject=True) if asJson: return json.dumps(dict(result)) + return result async def getPolygonsCount( self, diff --git a/python/restapi/models.py b/python/restapi/models.py index 32bc6aeb..e79def91 100644 --- a/python/restapi/models.py +++ b/python/restapi/models.py @@ -32,14 +32,14 @@ class BaseRequest(BaseModel): featureType: str = None class BaseListRequest(BaseRequest): - orderBy: str = None + orderBy: str = "id" page: int = None class BaseRawValidationRequest(BaseRequest): status: str = None class RawValidationListRequest(BaseRawValidationRequest): - orderBy: str = None + orderBy: str = "id" page: int = None class RawRequest(BaseRequest):