diff --git a/exposurelib/database.py b/exposurelib/database.py index 37274a12426304919cb8e98c28b2ff348cda44d4..01241f55783340c3965926dd6e40c4f5562998e6 100644 --- a/exposurelib/database.py +++ b/exposurelib/database.py @@ -68,7 +68,7 @@ class AbstractExposure(AbstractDatabase, ABC): def __init__(self): super().__init__() - def clean_up_orphan_asset_reference(self): + def remove_orphan_asset_reference(self): """ Remove all reference assets that are pointing with their `entity_id` to non-existent entities. @@ -89,43 +89,62 @@ class AbstractExposure(AbstractDatabase, ABC): self.cursor.execute(sql_statement) self.connection.commit() - def clean_up_reference_exposure(self, country_iso_code): + def remove_exposure(self, country_iso_code, reference=False): """ - Remove all reference entities with given country ISO code and their respective - reference assets. + Remove all entities with given country ISO code and their respective assets in either + the reference exposure tables or the final exposure tables. Args: country_iso_code (str): ISO 3166-1 alpha-3 code of the country + reference (bool, default: `True`): + If `True`, remove entities and assets from the reference tables, otherwise + from the final tables """ - # Delete all reference assets of reference entities of the given country - logger.info( - f"Removing reference assets of reference entities of country {country_iso_code}" - ) + if reference: + info = "reference " + asset_table = "AssetReference" + entity_table = "EntityReference" + else: + info = "" + asset_table = "Asset" + entity_table = "Entity" + + # Delete all assets of entities of the given country + logger.info(f"Removing {info}assets of {info}entities of country {country_iso_code}") sql_statement = f""" - DELETE FROM AssetReference + DELETE FROM {asset_table} WHERE entity_id IN ( SELECT id - FROM EntityReference - WHERE country_iso_code = '{country_iso_code}' + FROM {entity_table} + INNER JOIN {self.tile_table} + ON {self.tile_table}.quadkey = {entity_table}.quadkey + WHERE {self.tile_table}.country_iso_code = '{country_iso_code}' ) """ self.cursor.execute(sql_statement) - # Delete all reference entities of the given country - logger.info("Removing reference entities of country %s" % country_iso_code) + # Delete all entities of the given country + logger.info(f"Removing {info}entities of country %s" % country_iso_code) sql_statement = f""" - DELETE FROM EntityReference - WHERE country_iso_code = '{country_iso_code}' + DELETE FROM {entity_table} + WHERE id IN + ( + SELECT id + FROM {entity_table} + INNER JOIN {self.tile_table} + ON {self.tile_table}.quadkey = {entity_table}.quadkey + WHERE {self.tile_table}.country_iso_code = '{country_iso_code}' + ) """ self.cursor.execute(sql_statement) self.connection.commit() - def clean_up_asset_country(self, country_iso_code): + def remove_asset_country(self, country_iso_code): """ - Remove the country-average asset distribution for the country with ID `country_iso_code' + Remove the country-average asset distribution for the country with ID `country_iso_code` to avoid duplicates. Args: @@ -144,6 +163,36 @@ class AbstractExposure(AbstractDatabase, ABC): self.cursor.execute(sql_statement) self.connection.commit() + def remove_exposure_by_quadkey(self, quadkey): + """ + Remove all entities of a tile and their respective assets. + + Args: + quadkey (str): + Quadkey of the tile + """ + + # Delete all assets of entities of the given tile + logger.debug(f"Removing assets of entities of tile {quadkey}") + sql_statement = f""" + DELETE FROM Asset + WHERE entity_id IN + ( + SELECT id + FROM Entity + WHERE quadkey = '{quadkey}' + ) + """ + self.cursor.execute(sql_statement) + + # Delete all entities of the given tile + logger.debug(f"Removing entities of tile {quadkey}") + sql_statement = f""" + DELETE FROM Entity + WHERE quadkey = '{quadkey}' + """ + self.cursor.execute(sql_statement) + def taxonomy_string_exists(self, taxonomy_string): """ Checks if the `taxonomy_string` entry is already present in the `Taxonomy` table. @@ -241,6 +290,42 @@ class AbstractExposure(AbstractDatabase, ABC): else: return result[0] + def insert_tile_entity(self, quadkey): + """ + Inserts a tile and its geometry into the `Entity` table and returns the tile-entity ID. + A database trigger checks if the same entity is already present in the table and cancels + the insert process in this case. + + Args: + quadkey (str): + Quadkey of the tile. + + Returns: + ID of the inserted tile entity + """ + + geom = "ST_GeomFromText('%s', 4326)" % get_geom_of_quadkey(quadkey) + sql_statement = "INSERT INTO Entity (quadkey, geom, osm_id) " + sql_statement += "VALUES ('%s', %s, NULL) " % (quadkey, geom) + + # The RETURNING statement is not supported for SQLite versions < 3.35.0. + # Therefore, we call `get_entity_id` + if isinstance(self, SpatiaLiteExposure): + if self.old_sqlite_version: + try: + self.cursor.execute(sql_statement) + except Exception as E: + logger.debug(E) + return self.get_entity_id(quadkey=quadkey) + else: + sql_statement += "RETURNING id" + self.cursor.execute(sql_statement) + return self.cursor.fetchone()[0] + else: + sql_statement += "RETURNING id" + self.cursor.execute(sql_statement) + return self.cursor.fetchone()[0] + class SpatiaLiteExposure(SpatiaLiteDatabase, AbstractExposure): """ @@ -859,37 +944,6 @@ class SpatiaLiteExposure(SpatiaLiteDatabase, AbstractExposure): export_db.connection.execute("VACUUM") export_db.close() - def insert_tile_entity(self, quadkey): - """ - Inserts a tile and its geometry into the `Entity` table and returns the tile-entity ID. - A database trigger checks if the same entity is already present in the table and cancels - the insert process in this case. - - Args: - quadkey (str): - Quadkey of the tile. - - Returns: - ID of the inserted tile entity - """ - - geom = "GeomFromText('%s', 4326)" % get_geom_of_quadkey(quadkey) - sql_statement = "INSERT INTO Entity (quadkey, geom, osm_id) " - sql_statement += "VALUES ('%s', %s, NULL) " % (quadkey, geom) - - # The RETURNING statement is not supported for SQLite versions < 3.35.0. - # Therefore, we call `get_entity_id` - if self.old_sqlite_version: - try: - self.cursor.execute(sql_statement) - except Exception as E: - logger.debug(E) - return self.get_entity_id(quadkey=quadkey) - else: - sql_statement += "RETURNING id" - self.cursor.execute(sql_statement) - return self.cursor.fetchone()[0] - def insert_building_entity(self, quadkey, osm_id, geom): """ Inserts a building into the `Entity` table. Additionally, a tile entity for the same