Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interlis update #414

Merged
merged 8 commits into from
Sep 30, 2024
Merged

Interlis update #414

merged 8 commits into from
Sep 30, 2024

Conversation

domi4484
Copy link
Contributor

@domi4484 domi4484 commented Sep 11, 2024

Fixes #397

This fixes 2 issues:

  • We are using the SqlAlchemy session as a cache, even if the documentation recommends not doing so because the instances in the session are weak references. To countourn that we use flag_dirty which in turn makes all not new objects look like modified even if they are not.
  • Objects updated are not written in the DB, because we don't tell SqlAlchemy which columns are changed (we replace internal values directly (private API)). Yes we flag the object as dirty but at the moment of writing SqlAlchemy notice that no column of that object was changed, and it skips it

The proposed solution keeps the session/cache but tries to tell sql alchemy which attributes where really changed.
Maybe long term it would be better to build an own cache.

Warning

This could have some performance implications. Need to be tested.

To help me debugging this one I pimped up a bit the import dialog with better display of the importing changes:

  • For categories I added a * state in case there is a modified item inside
  • Put the "Raw infos" into a tree widget
  • For modified item, show a Old value column with the current DB value
  • Highlight changed attributes in orange

image

@domi4484 domi4484 changed the title Test interlis update Interlis update Sep 11, 2024
@cymed
Copy link
Contributor

cymed commented Sep 12, 2024

@domi4484 the Error "SIA405_Base_Abwasser_1_LV95: model(s) not found" has been appearing regularly in CI. I don't know why, but re-running the tests usually helps

@cymed cymed added the INTERLIS About INTERLIS exchange format (import / export) label Sep 12, 2024
@domi4484
Copy link
Contributor Author

@domi4484 the Error "SIA405_Base_Abwasser_1_LV95: model(s) not found" has been appearing regularly in CI. I don't know why, but re-running the tests usually helps

I have also seen it sometimes. It seems that the repository 405.sia.ch is not always available. Maybe we could ask them if they are aware of it?

To avoid the issue in future we could download a copy of the needed models to keep within the source of the plugin.

ili2db error:

Warning: repository <https://405.sia.ch/models/> ignored; java.net.ConnectException: Connection timed out (Connection timed out); Connection timed out (Connection timed out)

@domi4484 domi4484 marked this pull request as ready for review September 17, 2024 18:45
@ponceta
Copy link
Member

ponceta commented Sep 18, 2024

Needs testing but looks promising! Thank you @domi4484 !

@ponceta
Copy link
Member

ponceta commented Sep 18, 2024

I imported the VSA test organisations
Then the VSA DSS dataset
Then modified my data
Then reimport the VSA DSS dataset

Got this error message :

sqlalchemy.exc.ArgumentError: Executable SQL or text() construct expected, got . 
Traceback (most recent call last):
  File "C:\Users/pulpoar/AppData/Roaming/QGIS/QGIS3\profiles\pulpoar/python/plugins\teksi_wastewater\teksi_wastewater_plugin.py", line 612, in actionImportClicked
    self.interlisImporterExporter.action_import()
  File "C:\Users/pulpoar/AppData/Roaming/QGIS/QGIS3\profiles\pulpoar/python/plugins\teksi_wastewater\interlis\gui\interlis_importer_exporter_gui.py", line 79, in action_import
    raise exception
  File "C:\Users/pulpoar/AppData/Roaming/QGIS/QGIS3\profiles\pulpoar/python/plugins\teksi_wastewater\interlis\gui\interlis_importer_exporter_gui.py", line 60, in action_import
    self.interlis_importer_exporter.interlis_import(
  File "C:\Users/pulpoar/AppData/Roaming/QGIS/QGIS3\profiles\pulpoar/python/plugins\teksi_wastewater\interlis\interlis_importer_exporter.py", line 148, in interlis_import
    raise exception
  File "C:\Users/pulpoar/AppData/Roaming/QGIS/QGIS3\profiles\pulpoar/python/plugins\teksi_wastewater\interlis\interlis_importer_exporter.py", line 106, in interlis_import
    tww_session = self._import_from_intermediate_schema(import_model)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users/pulpoar/AppData/Roaming/QGIS/QGIS3\profiles\pulpoar/python/plugins\teksi_wastewater\interlis\interlis_importer_exporter.py", line 261, in _import_from_intermediate_schema
    interlisImporterToIntermediateSchema.tww_import(skip_closing_tww_session=True)
  File "C:\Users/pulpoar/AppData/Roaming/QGIS/QGIS3\profiles\pulpoar/python/plugins\teksi_wastewater\interlis\interlis_model_mapping\interlis_importer_to_intermediate_schema.py", line 41, in tww_import
    raise exception
  File "C:\Users/pulpoar/AppData/Roaming/QGIS/QGIS3\profiles\pulpoar/python/plugins\teksi_wastewater\interlis\interlis_model_mapping\interlis_importer_to_intermediate_schema.py", line 33, in tww_import
    self._tww_import(skip_closing_tww_session)
  File "C:\Users/pulpoar/AppData/Roaming/QGIS/QGIS3\profiles\pulpoar/python/plugins\teksi_wastewater\interlis\interlis_model_mapping\interlis_importer_to_intermediate_schema.py", line 66, in _tww_import
    self._import_sia405_abwasser()
  File "C:\Users/pulpoar/AppData/Roaming/QGIS/QGIS3\profiles\pulpoar/python/plugins\teksi_wastewater\interlis\interlis_model_mapping\interlis_importer_to_intermediate_schema.py", line 116, in _import_sia405_abwasser
    self._import_haltung_alternativverlauf()
  File "C:\Users/pulpoar/AppData/Roaming/QGIS/QGIS3\profiles\pulpoar/python/plugins\teksi_wastewater\interlis\interlis_model_mapping\interlis_importer_to_intermediate_schema.py", line 1929, in _import_haltung_alternativverlauf
    reach_progression_alternative = self.create_or_update(
                                    ^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users/pulpoar/AppData/Roaming/QGIS/QGIS3\profiles\pulpoar/python/plugins\teksi_wastewater\interlis\interlis_model_mapping\interlis_importer_to_intermediate_schema.py", line 450, in create_or_update
    value = self.session_tww.scalar(value)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\OSGeo4W\apps\Python312\Lib\site-packages\sqlalchemy\orm\session.py", line 2354, in scalar
    return self._execute_internal(
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\OSGeo4W\apps\Python312\Lib\site-packages\sqlalchemy\orm\session.py", line 2089, in _execute_internal
    statement = coercions.expect(roles.StatementRole, statement)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\OSGeo4W\apps\Python312\Lib\site-packages\sqlalchemy\sql\coercions.py", line 396, in expect
    resolved = impl._literal_coercion(
               ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\OSGeo4W\apps\Python312\Lib\site-packages\sqlalchemy\sql\coercions.py", line 634, in _literal_coercion
    self._raise_for_expected(element, argname)
  File "C:\OSGeo4W\apps\Python312\Lib\site-packages\sqlalchemy\sql\coercions.py", line 518, in _raise_for_expected
    raise exc.ArgumentError(msg, code=code) from err
sqlalchemy.exc.ArgumentError: Executable SQL or text() construct expected, got .

Restart QGIS

Same error.

@ponceta
Copy link
Member

ponceta commented Sep 18, 2024

It looks a bit slower than before but it is quite better in terms of visibility (what we import, what we will update,...)

@domi4484
Copy link
Contributor Author

@ponceta thanks for testing! The error should be fixed with the last commit.

But I have seen another glitch, new to be imported objects are displayed as modified instead of new.

It looks a bit slower than before but it is quite better in terms of visibility (what we import, what we will update,...)

In fact on my machine the DSS import take pretty much the same time (around 40 seconds) with both versions

@ponceta
Copy link
Member

ponceta commented Sep 20, 2024

image

2024-09-20T10:16:12 WARNING Subclass Count error : Too many superclass entries for tww_od.wastewater_structure

Importing again using new commit.

    Workaround :
    Disabling 
    - re_maintenance_event_wastewater_structure
    - re_building_group_disposal
    Import works.

@ponceta
Copy link
Member

ponceta commented Sep 20, 2024

It works well for the organisations :

Import Organisations
Modify an organisation
Re-import organisations

image

@ponceta
Copy link
Member

ponceta commented Sep 20, 2024

Bugs on update :

  1. re_maintenance_event_wastewater_structure
  2. re_building_group_disposal

image

  1. wastewater_node (situation3d_geometry)

image

  1. reach (length_effective)

image

  1. cover (situation3d_geometry)

image

  1. bio_ecol_assessment (time_point / date_last_examen)

image

  1. building_group (renovation_date)

image

  1. Measure (date_entry)

image

  1. measurement_result (time, value)

image

  1. mutation (date_mutation)

image

  1. profile_geometry (x,y)

image

  1. maintenance (time_point)

image

Remaining questions :

  • if modification date is older than actual data, do we warn the user?
  • if there are no modifications (attribute or geometry) but the last_modification attribute, do we modify the last_modification with the import data last_modification?

@ponceta ponceta added the plugin Concerns the wastewater plugin label Sep 24, 2024
Check for already existing re_... instances
@domi4484
Copy link
Contributor Author

@ponceta most points should be solved with last commit, but there is one open issue with geometries that I am not sure how to solve.

It seems to me that in the model we have sometimes redundant data: for example for wastewater_node ther is bottom_level and the z coordinate of situation3d_geometry and following happens:

  1. On first import (example wastewater_node 1.001):
Bottom level Situation geom Z
Database before None None
Importing value 1913.5 0.0
Database after 1913.5 1913.5
  1. On second import of the same data we lose Z information!
Bottom level Situation geom Z
Database before 1913.5 1913.5
Importing value 1913.5 0.0
Database after 0.0 0.0
  1. On third import of same data Z is back
Bottom level Situation geom Z
Database before 0.0 0.0
Importing value 1913.5 0.0
Database after 1913.5 1913.5
  1. On forth import we lose Z again
  2. and so on...

First import:
image

Second import
image

Third import
image

@cymed
Copy link
Contributor

cymed commented Sep 27, 2024

The problem lies here:

CREATE OR REPLACE FUNCTION tww_app.synchronize_level_with_altitude_on_wastewater_node()
RETURNS trigger AS
$BODY$
BEGIN
CASE
WHEN TG_OP = 'INSERT' THEN
NEW.situation3d_geometry = ST_SetSRID( ST_MakePoint( ST_X(NEW.situation3d_geometry), ST_Y(NEW.situation3d_geometry), COALESCE(NEW.bottom_level,'NaN') ), %1$s);
WHEN TG_OP = 'UPDATE' THEN
IF NEW.bottom_level <> OLD.bottom_level OR (NEW.bottom_level IS NULL AND OLD.bottom_level IS NOT NULL) OR (NEW.bottom_level IS NOT NULL AND OLD.bottom_level IS NULL) THEN
NEW.situation3d_geometry = ST_SetSRID( ST_MakePoint( ST_X(NEW.situation3d_geometry), ST_Y(NEW.situation3d_geometry), COALESCE(NEW.bottom_level,'NaN') ), %1$s);
ELSE
IF ST_Z(NEW.situation3d_geometry) <> ST_Z(OLD.situation3d_geometry) THEN
NEW.bottom_level = NULLIF(ST_Z(NEW.situation3d_geometry),'NaN');
END IF;
END IF;
END CASE;
RETURN NEW;
END; $BODY$

@ponceta
Copy link
Member

ponceta commented Sep 27, 2024

@domi4484 we constructed these functions in the past with @3nids.

Could you exchange with him and find the better of the two worlds? Is this due to QGIS or SQLAlchemy cache?

@cymed
Copy link
Contributor

cymed commented Sep 27, 2024

@ponceta For now, we only Force3D the input situation geometry in

The smart thing to do imho is to force the sohlenkote as z value on the importer side. The input geometry should then be equal to the existing one, thus not fire the trigger. Same goes for cover

@domi4484
Copy link
Contributor Author

The smart thing to do imho is to force the sohlenkote as z value on the importer side. The input geometry should then be equal to the existing one, thus not fire the trigger. Same goes for cover

This sounds the more correct way to me. Ill implement it like that.
But still I don't completely understand why we keep both Z and bottom_level in TWW. Are there situation where the values should not be equal?

@cymed
Copy link
Contributor

cymed commented Sep 27, 2024

Are there situation where the values should not be equal?

There is no such case. The only reason we have both values is that most users edit in 2.5d while the geometry is 3d and the attribute setup is mirroring the 2.5d INTERLIS structure

@ponceta
Copy link
Member

ponceta commented Sep 27, 2024

Altitude can come from geometry (3D point import) or attribute (bottom level). That's the best solution we found yet to have both approach working.

I'm open to any suggestions on how to do it better. ;-)

@domi4484
Copy link
Contributor Author

I'm open to any suggestions on how to do it better. ;-)

It's just that it can be confusing to have redundant data in the DB. Another possibility would be to remove the quote and bottom_level columns and have a view to expose the Z coordinate as quote/bottom_level. But I am not an expert at all at postgres, maybe is not worth adding additional complexity to the model.

Now the suggestion from @cymed are implemented. @ponceta it would be nice if you can test again.

  1. reach (length_effective)

This still looks as modified, can it be that a trigger recompute this to a different value? In that case I don't now what we could do to handle that on import

@sjib
Copy link
Contributor

sjib commented Sep 30, 2024

Altitude can come from geometry (3D point import) or attribute (bottom level). That's the best solution we found yet to have both approach working.

I'm open to any suggestions on how to do it better. ;-)

Some thoughts from my side:

I would like to suggest the following principals:
a) An INTERLIS import should never change any dataset without the user knowing that anything is beeing changed and have the possibility to deny it.
b) INTERLIS transfer is still based on 2.5 D - so I suggest that the 2.5 D attributes (levels) are treated as the superior information and z-information in 3D geometries is updated in the DB based on that information if it is conflicting. Else we risk to loose information on the import process.

c) As we are coming from the 2.5 D world and are still on the way towards the 3D modelling we should (re-)define some hierarchy on how information is changed:
We have the following 3D attributes with overlapping information:

  • cover.geometry3D_geometry and cover.level
  • wastewater_node.geometry3D_geometry and wastewater_node.bottom_level
  • reach.progression3D and reach_point.level (from and to)

May be we have to distinguish between

  1. editing and adding new information in TEKSI and (where we have the triggers that make sure we are in sync always)
  2. the INTERLIS import process? (where we have follow rule b)

And may be we have to have a tool that updates data to a stage so that we do not have conflicting information in the DB (like level exists, but respective z-value is missing or set to 0.00).
That would be good to have that also in qgep, so that we first solve those conflicts before going for an INTERLIS export.

For the migration process qgep to tww we have the intermediary points in progression3D that we are not able to transfer with INTERLIS - so we should treat them in an extra issue.

Hope this helps

@cymed
Copy link
Contributor

cymed commented Sep 30, 2024

I would like to suggest the following principals:
a) An INTERLIS import should never change any dataset without the user knowing that anything is being changed and have the possibility to deny it.

Except Attributes introduced by TWW that are currently set to NULL

b) INTERLIS transfer is still based on 2.5 D - so I suggest that the 2.5 D attributes (levels) are treated as the superior information and z-information in 3D geometries is updated in the DB based on that information if it is conflicting. Else we risk to loose information on the import process.

On Import I agree. On Editing I think we should use the Z of the node, transfer it into the level field, and allow overruling it.

c) As we are coming from the 2.5 D world and are still on the way towards the 3D modelling we should (re-)define some hierarchy on how information is changed: We have the following 3D attributes with overlapping information:

* cover.geometry3D_geometry and cover.level

* wastewater_node.geometry3D_geometry and wastewater_node.bottom_level

* reach.progression3D and reach_point.level (from and to)

May be we have to distinguish between

1. editing and adding new information in TEKSI and (where we have the triggers that make sure we are in sync always)

2. the INTERLIS import process? (where we have follow rule b)

From a DB Admin perspective it is smarter to implicitly store 2.5D-values in the Z coordinate of the point and expose them via a view (Single PointZ of truth). We lose no information, but an attribute. This ensures we have no contradictory information

And may be we have to have a tool that updates data to a stage so that we do not have conflicting information in the DB (like level exists, but respective z-value is missing or set to 0.00). That would be good to have that also in qgep, so that we first solve those conflicts before going for an INTERLIS export.

This is only necessary if we continue to save duplicate data

For the migration process qgep to tww we have the intermediary points in progression3D that we are not able to transfer with INTERLIS - so we should treat them in an extra issue.

Hope this helps

@ponceta ponceta merged commit 44f630e into main Sep 30, 2024
4 checks passed
@ponceta ponceta deleted the interlisUpdate branch September 30, 2024 08:14
@ponceta
Copy link
Member

ponceta commented Sep 30, 2024

This is great improvement to the actual plugin and solves many issues. Thank you a lot @domi4484

@cymed @sjib I'll open several issues for remaining tasks and opportunities. I let you do the same if you feel additionnal work on the plugin is required.

@cymed
Copy link
Contributor

cymed commented Oct 1, 2024

@domi4484 does this functionality base on primary keys to check for updates? In the AG-xx extensions we work with views, which means we have no primary keys.

@domi4484
Copy link
Contributor Author

domi4484 commented Oct 2, 2024

@cymed it tries to get an existing row by obj_id. If we can select one its an update, otherwise a new object

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
INTERLIS About INTERLIS exchange format (import / export) plugin Concerns the wastewater plugin
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Interlis Update does not update
4 participants