From 60a88a223501f30b7c1d99698139155b5adcccf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Carrillo?= Date: Mon, 2 Jun 2025 12:07:49 -0500 Subject: [PATCH 1/3] Add method to supress any catalogue reference layer that doesn't have a BAG OF attribute (when using coalesceCatalogueRef) --- modelbaker/dataobjects/layers.py | 4 ++ modelbaker/dbconnector/db_connector.py | 1 + modelbaker/dbconnector/gpkg_connector.py | 3 ++ modelbaker/dbconnector/mssql_connector.py | 3 ++ modelbaker/dbconnector/pg_connector.py | 11 ++++ modelbaker/generator/generator.py | 65 +++++++++++++++++++++++ 6 files changed, 87 insertions(+) diff --git a/modelbaker/dataobjects/layers.py b/modelbaker/dataobjects/layers.py index 01eccc13..207703d9 100644 --- a/modelbaker/dataobjects/layers.py +++ b/modelbaker/dataobjects/layers.py @@ -73,6 +73,7 @@ def __init__( qmlstylefile: Optional[str] = None, styles: dict[str, dict[str, str]] = {}, is_enum: bool = False, + base_class: str = None, ) -> None: self.provider = provider self.uri = uri @@ -94,6 +95,7 @@ def __init__( self.is_domain = is_domain self.is_structure = is_structure self.is_enum = is_enum + self.base_class = base_class self.is_nmrel = is_nmrel self.srid = srid @@ -144,6 +146,7 @@ def dump(self) -> dict: definition["qmlstylefile"] = self.qmlstylefile definition["styles"] = self.styles definition["form"] = self.__form.dump() + definition["base_class"] = self.base_class return definition def load(self, definition: dict) -> None: @@ -165,6 +168,7 @@ def load(self, definition: dict) -> None: self.qmlstylefile = definition["qmlstylefile"] self.styles = definition["styles"] self.__form.load(definition["form"]) + self.base_class = definition["base_class"] def create(self) -> Union[QgsRasterLayer, QgsVectorLayer]: if self.definitionfile: diff --git a/modelbaker/dbconnector/db_connector.py b/modelbaker/dbconnector/db_connector.py index 25260e6b..605e98c9 100644 --- a/modelbaker/dbconnector/db_connector.py +++ b/modelbaker/dbconnector/db_connector.py @@ -77,6 +77,7 @@ def get_tables_info(self): table_alias model relevance + base_class """ return [] diff --git a/modelbaker/dbconnector/gpkg_connector.py b/modelbaker/dbconnector/gpkg_connector.py index 1d865dce..5c1b147d 100644 --- a/modelbaker/dbconnector/gpkg_connector.py +++ b/modelbaker/dbconnector/gpkg_connector.py @@ -149,6 +149,7 @@ def _get_tables_info(self): attrs.sqlname as attribute_name, {relevance_field}, {topics}, + i.baseclass as base_class, {translations} -- Optional. Trailing comma omitted on purpose. """.format( relevance_field="""CASE WHEN c.iliname IN ( @@ -229,6 +230,8 @@ def _get_tables_info(self): AND alias.tag = 'ch.ehi.ili2db.dispName' LEFT JOIN T_ILI2DB_CLASSNAME c ON s.name == c.sqlname + LEFT JOIN T_ILI2DB_INHERITANCE i + ON c.iliname = i.thisclass LEFT JOIN T_ILI2DB_ATTRNAME attrs ON c.iliname = attrs.iliname {translations}""".format( diff --git a/modelbaker/dbconnector/mssql_connector.py b/modelbaker/dbconnector/mssql_connector.py index 69328b46..42a0b5d0 100644 --- a/modelbaker/dbconnector/mssql_connector.py +++ b/modelbaker/dbconnector/mssql_connector.py @@ -132,6 +132,7 @@ def get_tables_info(self): ln + " , left(c.iliname, charindex('.', c.iliname)-1) AS model" ) stmt += ln + " , c.iliname AS ili_name" + stmt += ln + " , inh.baseclass AS base_class" stmt += ln + " , STUFF(" stmt += ln + " (SELECT ';' + CAST(cp.setting AS VARCHAR(MAX))" stmt += ln + " FROM {schema}.t_ili2db_column_prop cp" @@ -253,6 +254,8 @@ def get_tables_info(self): stmt += ln + " AND alias.tag = 'ch.ehi.ili2db.dispName'" stmt += ln + "LEFT JOIN {schema}.t_ili2db_classname AS c" stmt += ln + " ON tbls.TABLE_NAME = c.sqlname" + stmt += ln + "LEFT JOIN {schema}.t_ili2db_inheritance AS inh" + stmt += ln + " ON c.iliname = inh.thisclass" stmt += ln + "LEFT JOIN {schema}.t_ili2db_attrname AS attrs" stmt += ln + " ON c.iliname = attrs.iliname" stmt += ln + "LEFT JOIN INFORMATION_SCHEMA.COLUMNS AS clm" diff --git a/modelbaker/dbconnector/pg_connector.py b/modelbaker/dbconnector/pg_connector.py index 99c9c163..b31c984b 100644 --- a/modelbaker/dbconnector/pg_connector.py +++ b/modelbaker/dbconnector/pg_connector.py @@ -158,7 +158,9 @@ def get_tables_info(self): coord_decimals = "" alias_left_join = "" model_name = "" + base_class = "" model_where = "" + base_class_left_join = "" attribute_name = "" attribute_left_join = "" translations_left_join = "" @@ -202,6 +204,7 @@ def get_tables_info(self): self.schema ) model_name = "left(c.iliname, strpos(c.iliname, '.')-1) AS model," + base_class = "inh.baseclass as base_class," relevance = """ CASE WHEN c.iliname IN ( WITH names AS ( @@ -290,6 +293,10 @@ def get_tables_info(self): ON tbls.tablename = c.sqlname""".format( self.schema ) + base_class_left_join = """LEFT JOIN {}.t_ili2db_inheritance inh + ON c.iliname = inh.thisclass""".format( + self.schema + ) attribute_name = "attrs.sqlname as attribute_name," attribute_left_join = """LEFT JOIN {}.t_ili2db_attrname attrs ON c.iliname = attrs.iliname""".format( @@ -321,6 +328,7 @@ def get_tables_info(self): {kind_settings_field} {table_alias} {model_name} + {base_class} {ili_name} {extent} {attribute_name} @@ -339,6 +347,7 @@ def get_tables_info(self): {domain_left_join} {alias_left_join} {model_where} + {base_class_left_join} {attribute_left_join} {translations_left_join} LEFT JOIN public.geometry_columns g @@ -352,6 +361,7 @@ def get_tables_info(self): kind_settings_field=kind_settings_field, table_alias=table_alias, model_name=model_name, + base_class=base_class, ili_name=ili_name, extent=extent, coord_decimals=coord_decimals, @@ -362,6 +372,7 @@ def get_tables_info(self): alias_left_join=alias_left_join, translations_left_join=translations_left_join, model_where=model_where, + base_class_left_join=base_class_left_join, attribute_name=attribute_name, attribute_left_join=attribute_left_join, schema_where=schema_where, diff --git a/modelbaker/generator/generator.py b/modelbaker/generator/generator.py index ceee00a8..e5c17050 100644 --- a/modelbaker/generator/generator.py +++ b/modelbaker/generator/generator.py @@ -180,6 +180,8 @@ def layers(self, filter_layer_list: list = []) -> list[Layer]: if not relevant_topics and base_topic and base_topic.count(".") > 0: relevant_topics.append(base_topic) + base_class = record.get("base_class", None) + # If raw_naming is True, the layername should be the tablename # Otherwise get table name in this order: # - translation if exists, @@ -312,6 +314,7 @@ def layers(self, filter_layer_list: list = []) -> list[Layer]: all_topics, relevant_topics, is_enum=is_enum, + base_class=base_class, ) # Configure fields for current table @@ -635,6 +638,68 @@ def relations(self, layers, filter_layer_list=[]): } return (relations, bags_of_enum) + @staticmethod + def supress_catalogue_reference_layers(available_layers, relations, bags_of_enum): + # Check for catalogue items and reference layers + catalogue_items = [] # List of dicts + catalogue_refs = [] # List of dicts + for layer in available_layers: + if ( + layer.is_domain + and not layer.is_enum + and layer.base_class == "CatalogueObjects_V1.Catalogues.Item" + ): + catalogue_items.append({"name": layer.name, "ili_name": layer.ili_name}) + + if layer.is_structure and layer.base_class in ( + "CatalogueObjects_V1.Catalogues.CatalogueReference", + "CatalogueObjects_V1.Catalogues.MandatoryCatalogueReference", + ): + catalogue_refs.append({"name": layer.name, "ili_name": layer.ili_name}) + + layers_to_remove = [] + + # Remove reference layer if they are not BAG OF + for item in catalogue_items: + is_bag_of = False + for bag_of_layer_k, bag_of_layer_v in bags_of_enum.items(): + for bag_of_attr_k, bag_of_data in bag_of_layer_v.items(): + if ( + item["name"] == bag_of_data[2].name + ): # BAG OF's target_layer_name + is_bag_of = True + + if is_bag_of: + # It's a BAG OF, leave it, cause users will need it to add data + continue + + # The ref has no BAG OF pointing to the item, therefore, + # we'll supress the ref cause users won't need it to add data. + + # First get the ref pointing to the item + for relation in relations: + if relation.referenced_layer.ili_name == item["ili_name"]: + for ref in catalogue_refs: + if relation.referencing_layer.ili_name == ref["ili_name"]: + # We've found the corresponding ref structure + layers_to_remove.append(ref["ili_name"]) + break + + # Finally, remove the ref layers that we've found are not BAGS OF from the list, + # as well as the relations where they are involved (i.e., referenced/referencing) + for layer_to_remove in layers_to_remove: + available_layers = [ + layer for layer in available_layers if layer_to_remove != layer.ili_name + ] + relations = [ + relation + for relation in relations + if relation.referenced_layer.ili_name != layer_to_remove + and relation.referencing_layer.ili_name != layer_to_remove + ] + + return available_layers, relations + def generate_node(self, layers, node_name, item_properties): if item_properties.get("group"): node = LegendGroup( From afd150109e99b84e61e6a3221f38a261d6380e57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Carrillo?= Date: Wed, 4 Jun 2025 10:12:33 -0500 Subject: [PATCH 2/3] [tests] Suppress catalogue ref (when not bag of): Add unit tests for GPKG and PG (MSSQL db connector does not find bag_ofs yet) --- modelbaker/generator/generator.py | 4 +- tests/test_projectgen.py | 162 ++++++++++++++++++ tests/testdata/ilimodels/gebaeude_V1_6.ili | 71 ++++++++ .../ilimodels/gebaeude_bag_of_V1_6.ili | 72 ++++++++ 4 files changed, 307 insertions(+), 2 deletions(-) create mode 100644 tests/testdata/ilimodels/gebaeude_V1_6.ili create mode 100644 tests/testdata/ilimodels/gebaeude_bag_of_V1_6.ili diff --git a/modelbaker/generator/generator.py b/modelbaker/generator/generator.py index e5c17050..60f2536d 100644 --- a/modelbaker/generator/generator.py +++ b/modelbaker/generator/generator.py @@ -639,7 +639,7 @@ def relations(self, layers, filter_layer_list=[]): return (relations, bags_of_enum) @staticmethod - def supress_catalogue_reference_layers(available_layers, relations, bags_of_enum): + def suppress_catalogue_reference_layers(available_layers, relations, bags_of_enum): # Check for catalogue items and reference layers catalogue_items = [] # List of dicts catalogue_refs = [] # List of dicts @@ -674,7 +674,7 @@ def supress_catalogue_reference_layers(available_layers, relations, bags_of_enum continue # The ref has no BAG OF pointing to the item, therefore, - # we'll supress the ref cause users won't need it to add data. + # we'll suppress the ref cause users won't need it to add data. # First get the ref pointing to the item for relation in relations: diff --git a/tests/test_projectgen.py b/tests/test_projectgen.py index e28076c4..77faba34 100644 --- a/tests/test_projectgen.py +++ b/tests/test_projectgen.py @@ -4369,6 +4369,168 @@ def test_array_mapping_mssql(self): assert count == 1 + def test_catalogue_reference_layer_bag_of_postgis(self): + importer = iliimporter.Importer() + importer.tool = DbIliMode.ili2pg + importer.configuration = iliimporter_config(importer.tool) + importer.configuration.ilifile = testdata_path( + "ilimodels/gebaeude_bag_of_V1_6.ili" + ) + importer.configuration.ilimodels = "Gebaeudeinventar_Bag_Of_V1_6" + importer.configuration.dbschema = ( + "catalogue_ref_bag_of_{:%Y%m%d%H%M%S%f}".format(datetime.datetime.now()) + ) + + importer.configuration.srs_code = 2056 + importer.configuration.inheritance = "smart2" + importer.stdout.connect(self.print_info) + importer.stderr.connect(self.print_error) + assert importer.run() == iliimporter.Importer.SUCCESS + + generator = Generator( + DbIliMode.ili2pg, + get_pg_connection_string(), + importer.configuration.inheritance, + importer.configuration.dbschema, + ) + + available_layers = generator.layers() + relations, bags_of = generator.relations(available_layers) + + layer_count_before = len(available_layers) + relation_count_before = len(relations) + + available_layers, relations = generator.suppress_catalogue_reference_layers( + available_layers, relations, bags_of + ) + + layer_count_after = len(available_layers) + relation_count_after = len(relations) + + # Test that no reference layer and therefore, no relation, has been removed + assert layer_count_before == layer_count_after + assert relation_count_before == relation_count_after + + def test_catalogue_reference_layer_bag_of_geopackage(self): + importer = iliimporter.Importer() + importer.tool = DbIliMode.ili2gpkg + importer.configuration = iliimporter_config(importer.tool) + importer.configuration.ilifile = testdata_path( + "ilimodels/gebaeude_bag_of_V1_6.ili" + ) + importer.configuration.ilimodels = "Gebaeudeinventar_Bag_Of_V1_6" + importer.configuration.dbfile = os.path.join( + self.basetestpath, + "tmp_catalogue_ref_bag_of_{:%Y%m%d%H%M%S%f}.gpkg".format( + datetime.datetime.now() + ), + ) + importer.configuration.srs_code = 2056 + importer.configuration.inheritance = "smart2" + importer.stdout.connect(self.print_info) + importer.stderr.connect(self.print_error) + assert importer.run() == iliimporter.Importer.SUCCESS + config_manager = GpkgCommandConfigManager(importer.configuration) + uri = config_manager.get_uri() + + generator = Generator(DbIliMode.ili2gpkg, uri, "smart2") + + available_layers = generator.layers() + relations, bags_of = generator.relations(available_layers) + + layer_count_before = len(available_layers) + relation_count_before = len(relations) + + available_layers, relations = generator.suppress_catalogue_reference_layers( + available_layers, relations, bags_of + ) + + layer_count_after = len(available_layers) + relation_count_after = len(relations) + + # Test that no reference layer and therefore, no relation, has been removed + assert layer_count_before == layer_count_after + assert relation_count_before == relation_count_after + + def test_catalogue_reference_layer_no_bag_of_postgis(self): + importer = iliimporter.Importer() + importer.tool = DbIliMode.ili2pg + importer.configuration = iliimporter_config(importer.tool) + importer.configuration.ilifile = testdata_path("ilimodels/gebaeude_V1_6.ili") + importer.configuration.ilimodels = "Gebaeudeinventar_V1_6" + importer.configuration.dbschema = ( + "catalogue_ref_no_bag_of_{:%Y%m%d%H%M%S%f}".format(datetime.datetime.now()) + ) + + importer.configuration.srs_code = 2056 + importer.configuration.inheritance = "smart2" + importer.stdout.connect(self.print_info) + importer.stderr.connect(self.print_error) + assert importer.run() == iliimporter.Importer.SUCCESS + + generator = Generator( + DbIliMode.ili2pg, + get_pg_connection_string(), + importer.configuration.inheritance, + importer.configuration.dbschema, + ) + + available_layers = generator.layers() + relations, bags_of = generator.relations(available_layers) + + layer_count_before = len(available_layers) + relation_count_before = len(relations) + + available_layers, relations = generator.suppress_catalogue_reference_layers( + available_layers, relations, bags_of + ) + + layer_count_after = len(available_layers) + relation_count_after = len(relations) + + # Test that one layer and one relation have been removed + assert layer_count_before == layer_count_after + 1 + assert relation_count_before == relation_count_after + 1 + + def test_catalogue_reference_layer_no_bag_of_geopackage(self): + importer = iliimporter.Importer() + importer.tool = DbIliMode.ili2gpkg + importer.configuration = iliimporter_config(importer.tool) + importer.configuration.ilifile = testdata_path("ilimodels/gebaeude_V1_6.ili") + importer.configuration.ilimodels = "Gebaeudeinventar_V1_6" + importer.configuration.dbfile = os.path.join( + self.basetestpath, + "tmp_catalogue_ref_no_bag_of_{:%Y%m%d%H%M%S%f}.gpkg".format( + datetime.datetime.now() + ), + ) + importer.configuration.srs_code = 2056 + importer.configuration.inheritance = "smart2" + importer.stdout.connect(self.print_info) + importer.stderr.connect(self.print_error) + assert importer.run() == iliimporter.Importer.SUCCESS + config_manager = GpkgCommandConfigManager(importer.configuration) + uri = config_manager.get_uri() + + generator = Generator(DbIliMode.ili2gpkg, uri, "smart2") + + available_layers = generator.layers() + relations, bags_of = generator.relations(available_layers) + + layer_count_before = len(available_layers) + relation_count_before = len(relations) + + available_layers, relations = generator.suppress_catalogue_reference_layers( + available_layers, relations, bags_of + ) + + layer_count_after = len(available_layers) + relation_count_after = len(relations) + + # Test that one layer and one relation have been removed + assert layer_count_before == layer_count_after + 1 + assert relation_count_before == relation_count_after + 1 + def test_relation_editor_widget_for_no_geometry_layers(self): importer = iliimporter.Importer() diff --git a/tests/testdata/ilimodels/gebaeude_V1_6.ili b/tests/testdata/ilimodels/gebaeude_V1_6.ili new file mode 100644 index 00000000..e96e4879 --- /dev/null +++ b/tests/testdata/ilimodels/gebaeude_V1_6.ili @@ -0,0 +1,71 @@ +INTERLIS 2.3; + +MODEL Gebaeudeinventar_V1_6 (de) + +AT "mailto:signedav@localhost" + +VERSION "2023-01-19" = + IMPORTS GeometryCHLV95_V1, CatalogueObjects_V1, LocalisationCH_V1; + + TOPIC Katalog = + + CLASS Heizungstyp_Item + EXTENDS CatalogueObjects_V1.Catalogues.Item = + Code : MANDATORY TEXT; + Beschreibung : MANDATORY LocalisationCH_V1.MultilingualText; + END Heizungstyp_Item; + + STRUCTURE Heizungstyp_Ref + EXTENDS CatalogueObjects_V1.Catalogues.MandatoryCatalogueReference = + Reference (EXTENDED) : MANDATORY REFERENCE TO (EXTERNAL) Heizungstyp_Item; + END Heizungstyp_Ref; + + END Katalog; + + TOPIC Gebaeude = + DEPENDS ON Gebaeudeinventar_V1_6.Katalog; + + DOMAIN + Kanton = ( + AG,AI,AR,BE,BL,BS,FR,GE,GL,GR,JU,LU,NE,NW,OW,SG,SH,SO,SZ,TG,TI,UR,VD,VS,ZG,ZH + ); + + CLASS Gebaeude = + + EGID : MANDATORY TEXT*16; + Kantonskuerzel : MANDATORY Kanton; + Grundstuecksnummer : 0 .. 99999; + Name : TEXT; + Koordinaten : MANDATORY GeometryCHLV95_V1.Coord2; + Status : MANDATORY TEXT; + Bauperiode : MANDATORY TEXT; + Flaeche : 0.00 .. 99999.99; + Geschosse : 0 .. 999; + Zivilschutzraum : MANDATORY BOOLEAN; + Heizung : MANDATORY Gebaeudeinventar_V1_6.Katalog.Heizungstyp_Ref; + Datum_Heizung : INTERLIS.XMLDate; + + UNIQUE EGID; + SET CONSTRAINT WHERE DEFINED (Heizung) : + DEFINED (Datum_Heizung); + + END Gebaeude; + + CLASS Adresse = + AdrID : MANDATORY TEXT*16; + Strasse : TEXT*200; + Nummer : TEXT*8; + PLZ : 0 .. 9999; + Ort : MANDATORY TEXT*200; + + UNIQUE AdrID; + END Adresse; + + ASSOCIATION AdresseGebaeude = + GebaeudeAdresse -- {1..*} Adresse; + Gebaeude -<#> {1} Gebaeude; + END AdresseGebaeude; + + END Gebaeude; + +END Gebaeudeinventar_V1_6. diff --git a/tests/testdata/ilimodels/gebaeude_bag_of_V1_6.ili b/tests/testdata/ilimodels/gebaeude_bag_of_V1_6.ili new file mode 100644 index 00000000..a9016b3a --- /dev/null +++ b/tests/testdata/ilimodels/gebaeude_bag_of_V1_6.ili @@ -0,0 +1,72 @@ +INTERLIS 2.3; + +MODEL Gebaeudeinventar_Bag_Of_V1_6 (de) + +AT "mailto:signedav@localhost" + +VERSION "2023-01-19" = + IMPORTS GeometryCHLV95_V1, CatalogueObjects_V1, LocalisationCH_V1; + + TOPIC Katalog = + + CLASS Heizungstyp_Item + EXTENDS CatalogueObjects_V1.Catalogues.Item = + Code : MANDATORY TEXT; + Beschreibung : MANDATORY LocalisationCH_V1.MultilingualText; + END Heizungstyp_Item; + + STRUCTURE Heizungstyp_Ref + EXTENDS CatalogueObjects_V1.Catalogues.MandatoryCatalogueReference = + Reference (EXTENDED) : MANDATORY REFERENCE TO (EXTERNAL) Heizungstyp_Item; + END Heizungstyp_Ref; + + END Katalog; + + TOPIC Gebaeude = + DEPENDS ON Gebaeudeinventar_Bag_Of_V1_6.Katalog; + + DOMAIN + Kanton = ( + AG,AI,AR,BE,BL,BS,FR,GE,GL,GR,JU,LU,NE,NW,OW,SG,SH,SO,SZ,TG,TI,UR,VD,VS,ZG,ZH + ); + + CLASS Gebaeude = + + EGID : MANDATORY TEXT*16; + Kantonskuerzel : MANDATORY Kanton; + Grundstuecksnummer : 0 .. 99999; + Name : TEXT; + Koordinaten : MANDATORY GeometryCHLV95_V1.Coord2; + Status : MANDATORY TEXT; + Bauperiode : MANDATORY TEXT; + Flaeche : 0.00 .. 99999.99; + Geschosse : 0 .. 999; + Zivilschutzraum : MANDATORY BOOLEAN; + !!@ ili2db.mapping="ARRAY" + Heizung2 : BAG {0..1} OF Gebaeudeinventar_Bag_Of_V1_6.Katalog.Heizungstyp_Ref; + Datum_Heizung : INTERLIS.XMLDate; + + UNIQUE EGID; + SET CONSTRAINT WHERE DEFINED (Heizung2) : + DEFINED (Datum_Heizung); + + END Gebaeude; + + CLASS Adresse = + AdrID : MANDATORY TEXT*16; + Strasse : TEXT*200; + Nummer : TEXT*8; + PLZ : 0 .. 9999; + Ort : MANDATORY TEXT*200; + + UNIQUE AdrID; + END Adresse; + + ASSOCIATION AdresseGebaeude = + GebaeudeAdresse -- {1..*} Adresse; + Gebaeude -<#> {1} Gebaeude; + END AdresseGebaeude; + + END Gebaeude; + +END Gebaeudeinventar_Bag_Of_V1_6. From 491f8665150ff91a655311f5b8e9793d8eed3a2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Carrillo?= Date: Fri, 6 Jun 2025 10:36:22 -0500 Subject: [PATCH 3/3] [tests] Don't suppress catalogue ref (when LIST OF): Add unit tests for GPKG and PG (MSSQL db connector does not find list_ofs yet) --- tests/test_projectgen.py | 83 +++++++++++++++++++ .../ilimodels/gebaeude_list_of_V1_6.ili | 72 ++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 tests/testdata/ilimodels/gebaeude_list_of_V1_6.ili diff --git a/tests/test_projectgen.py b/tests/test_projectgen.py index 77faba34..e513ac2f 100644 --- a/tests/test_projectgen.py +++ b/tests/test_projectgen.py @@ -4452,6 +4452,89 @@ def test_catalogue_reference_layer_bag_of_geopackage(self): assert layer_count_before == layer_count_after assert relation_count_before == relation_count_after + def test_catalogue_reference_layer_list_of_postgis(self): + importer = iliimporter.Importer() + importer.tool = DbIliMode.ili2pg + importer.configuration = iliimporter_config(importer.tool) + importer.configuration.ilifile = testdata_path( + "ilimodels/gebaeude_list_of_V1_6.ili" + ) + importer.configuration.ilimodels = "Gebaeudeinventar_List_Of_V1_6" + importer.configuration.dbschema = ( + "catalogue_ref_list_of_{:%Y%m%d%H%M%S%f}".format(datetime.datetime.now()) + ) + + importer.configuration.srs_code = 2056 + importer.configuration.inheritance = "smart2" + importer.stdout.connect(self.print_info) + importer.stderr.connect(self.print_error) + assert importer.run() == iliimporter.Importer.SUCCESS + + generator = Generator( + DbIliMode.ili2pg, + get_pg_connection_string(), + importer.configuration.inheritance, + importer.configuration.dbschema, + ) + + available_layers = generator.layers() + relations, bags_of = generator.relations(available_layers) + + layer_count_before = len(available_layers) + relation_count_before = len(relations) + + available_layers, relations = generator.suppress_catalogue_reference_layers( + available_layers, relations, bags_of + ) + + layer_count_after = len(available_layers) + relation_count_after = len(relations) + + # Test that no reference layer and therefore, no relation, has been removed + assert layer_count_before == layer_count_after + assert relation_count_before == relation_count_after + + def test_catalogue_reference_layer_list_of_geopackage(self): + importer = iliimporter.Importer() + importer.tool = DbIliMode.ili2gpkg + importer.configuration = iliimporter_config(importer.tool) + importer.configuration.ilifile = testdata_path( + "ilimodels/gebaeude_list_of_V1_6.ili" + ) + importer.configuration.ilimodels = "Gebaeudeinventar_List_Of_V1_6" + importer.configuration.dbfile = os.path.join( + self.basetestpath, + "tmp_catalogue_ref_list_of_{:%Y%m%d%H%M%S%f}.gpkg".format( + datetime.datetime.now() + ), + ) + importer.configuration.srs_code = 2056 + importer.configuration.inheritance = "smart2" + importer.stdout.connect(self.print_info) + importer.stderr.connect(self.print_error) + assert importer.run() == iliimporter.Importer.SUCCESS + config_manager = GpkgCommandConfigManager(importer.configuration) + uri = config_manager.get_uri() + + generator = Generator(DbIliMode.ili2gpkg, uri, "smart2") + + available_layers = generator.layers() + relations, bags_of = generator.relations(available_layers) + + layer_count_before = len(available_layers) + relation_count_before = len(relations) + + available_layers, relations = generator.suppress_catalogue_reference_layers( + available_layers, relations, bags_of + ) + + layer_count_after = len(available_layers) + relation_count_after = len(relations) + + # Test that no reference layer and therefore, no relation, has been removed + assert layer_count_before == layer_count_after + assert relation_count_before == relation_count_after + def test_catalogue_reference_layer_no_bag_of_postgis(self): importer = iliimporter.Importer() importer.tool = DbIliMode.ili2pg diff --git a/tests/testdata/ilimodels/gebaeude_list_of_V1_6.ili b/tests/testdata/ilimodels/gebaeude_list_of_V1_6.ili new file mode 100644 index 00000000..0a69e0b0 --- /dev/null +++ b/tests/testdata/ilimodels/gebaeude_list_of_V1_6.ili @@ -0,0 +1,72 @@ +INTERLIS 2.3; + +MODEL Gebaeudeinventar_List_Of_V1_6 (de) + +AT "mailto:signedav@localhost" + +VERSION "2023-01-19" = + IMPORTS GeometryCHLV95_V1, CatalogueObjects_V1, LocalisationCH_V1; + + TOPIC Katalog = + + CLASS Heizungstyp_Item + EXTENDS CatalogueObjects_V1.Catalogues.Item = + Code : MANDATORY TEXT; + Beschreibung : MANDATORY LocalisationCH_V1.MultilingualText; + END Heizungstyp_Item; + + STRUCTURE Heizungstyp_Ref + EXTENDS CatalogueObjects_V1.Catalogues.MandatoryCatalogueReference = + Reference (EXTENDED) : MANDATORY REFERENCE TO (EXTERNAL) Heizungstyp_Item; + END Heizungstyp_Ref; + + END Katalog; + + TOPIC Gebaeude = + DEPENDS ON Gebaeudeinventar_List_Of_V1_6.Katalog; + + DOMAIN + Kanton = ( + AG,AI,AR,BE,BL,BS,FR,GE,GL,GR,JU,LU,NE,NW,OW,SG,SH,SO,SZ,TG,TI,UR,VD,VS,ZG,ZH + ); + + CLASS Gebaeude = + + EGID : MANDATORY TEXT*16; + Kantonskuerzel : MANDATORY Kanton; + Grundstuecksnummer : 0 .. 99999; + Name : TEXT; + Koordinaten : MANDATORY GeometryCHLV95_V1.Coord2; + Status : MANDATORY TEXT; + Bauperiode : MANDATORY TEXT; + Flaeche : 0.00 .. 99999.99; + Geschosse : 0 .. 999; + Zivilschutzraum : MANDATORY BOOLEAN; + !!@ ili2db.mapping="ARRAY" + Heizung3 : LIST {0..1} OF Gebaeudeinventar_List_Of_V1_6.Katalog.Heizungstyp_Ref; + Datum_Heizung : INTERLIS.XMLDate; + + UNIQUE EGID; + SET CONSTRAINT WHERE DEFINED (Heizung3) : + DEFINED (Datum_Heizung); + + END Gebaeude; + + CLASS Adresse = + AdrID : MANDATORY TEXT*16; + Strasse : TEXT*200; + Nummer : TEXT*8; + PLZ : 0 .. 9999; + Ort : MANDATORY TEXT*200; + + UNIQUE AdrID; + END Adresse; + + ASSOCIATION AdresseGebaeude = + GebaeudeAdresse -- {1..*} Adresse; + Gebaeude -<#> {1} Gebaeude; + END AdresseGebaeude; + + END Gebaeude; + +END Gebaeudeinventar_List_Of_V1_6.