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

Improvement of Project Creation with extended INTERLIS Models #61

Merged
merged 35 commits into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
6afd7d6
testdata (ili-models) for the use cases
signedav Jul 14, 2023
cddc71c
Approach for relevance of tables on extended models in GPKG
signedav Jul 16, 2023
1797191
another bit
signedav Aug 11, 2023
9c532a5
Append topic prefix to all ambiguous layer based on a an INTERLIS model.
signedav Aug 11, 2023
adf6f8c
rename ambiguous layer alias in two steps - find duplicates and add t…
signedav Aug 14, 2023
1f2f4c5
fix tests and not concern the order of error messages
signedav Aug 14, 2023
1643377
tests for unique layer naming
signedav Aug 14, 2023
a49fa84
tests according to the model checking: proper layer naming, if layer …
signedav Aug 14, 2023
efc9746
concern optimize strategies on extended models by grouping or hiding …
signedav Aug 14, 2023
92b9fa0
remove duplicate code with function
signedav Aug 14, 2023
fca2361
bump to ili2db 4.11.1
signedav Aug 28, 2023
1a0cf99
make OptimizeStrategy global and consider it for Relations
signedav Sep 7, 2023
ca838b9
gpkg tests
signedav Sep 8, 2023
6ad125d
black style them
signedav Sep 11, 2023
24cd5a8
AFAIK it does not make to chech if the 'parent' layer has the same sr…
signedav Sep 11, 2023
ceb4152
finalize tests for GPKG
signedav Sep 11, 2023
5fe5d2f
tests for mssql and postgres
signedav Sep 12, 2023
af5df36
support postgres for relevance
signedav Sep 13, 2023
d574228
use default is_relevant true
signedav Sep 13, 2023
672e3ef
pg/mssql support but mssql not complete
signedav Sep 13, 2023
8f78d72
Emitting relevant topics used for smart basket handling
signedav Sep 13, 2023
accb267
relevant_topics in layer
signedav Sep 13, 2023
4c21239
alltopics and relevanttopics on gpkg finalized and failing and unfini…
signedav Sep 14, 2023
9d7c273
relevant_topics postgres support and tests
signedav Sep 15, 2023
4172a07
Fixed error when model has multiple extensions within multiple models…
signedav Sep 20, 2023
4a3d2e2
mssql not done status
signedav Sep 22, 2023
d38d74e
fixed mssql query
signedav Sep 22, 2023
231cc26
Bump ili2db to 5.0.0
signedav Sep 22, 2023
962dd83
Merge branch 'main' into extended-models
signedav Sep 25, 2023
6ecffa4
Update modelbaker/generator/generator.py
signedav Sep 25, 2023
acb2d27
remove print
signedav Sep 25, 2023
599e8d5
fix missing assignement
signedav Sep 26, 2023
254e918
fixup
signedav Sep 26, 2023
b09991e
finally working relevance part for mssql
signedav Oct 1, 2023
0a7375b
remove unused mssql code and provide proper ignoring a reference to t…
signedav Oct 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,10 @@ Is enforced with pre-commit. To use, make:
```
pip install pre-commit
pre-commit install
```00
```

And to run it over all the files (with infile changes):

```
pre-commit run --color=always --all-file
```
Expand Down
28 changes: 23 additions & 5 deletions modelbaker/dataobjects/layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
)
from qgis.PyQt.QtCore import QCoreApplication, QSettings

from ..generator.config import IGNORED_FIELDNAMES
from ..generator.config import BASKET_FIELDNAMES, IGNORED_FIELDNAMES
from ..utils.globals import OptimizeStrategy
from .form import Form, FormFieldWidget, FormRelationWidget, FormTab


Expand All @@ -54,6 +55,9 @@ def __init__(
is_basket_table=False,
is_dataset_table=False,
ili_name=None,
is_relevant=True,
all_topics=[], # all the topics this class (or an instance of it) are located
relevant_topics=[], # the topics of the most extended instance of it only
definitionfile=None,
qmlstylefile=None,
styles={},
Expand Down Expand Up @@ -99,6 +103,10 @@ def __init__(
f"{self.ili_name.split('.')[0]}.{self.ili_name.split('.')[1]}"
)

self.is_relevant = is_relevant
self.all_topics = all_topics
self.relevant_topics = relevant_topics

self.definitionfile = definitionfile
self.qmlstylefile = qmlstylefile
self.styles = styles
Expand All @@ -123,6 +131,9 @@ def dump(self):
definition["coordinateprecision"] = self.coordinate_precision
definition["modeltopicname"] = self.model_topic_name
definition["ili_name"] = self.ili_name
definition["is_relevant"] = self.is_relevant
definition["all_topics"] = self.all_topics
definition["relevant_topics"] = self.relevant_topics
definition["definitionfile"] = self.definitionfile
definition["qmlstylefile"] = self.qmlstylefile
definition["styles"] = self.styles
Expand All @@ -141,6 +152,9 @@ def load(self, definition):
self.coordinate_precision = definition["coordinateprecision"]
self.model_topic_name = definition["modeltopicname"]
self.ili_name = definition["ili_name"]
self.is_relevant = definition["is_relevant"]
self.all_topics = definition["all_topics"]
self.relevant_topics = definition["relevant_topics"]
self.definitionfile = definition["definitionfile"]
self.qmlstylefile = definition["qmlstylefile"]
self.styles = definition["styles"]
Expand Down Expand Up @@ -250,6 +264,11 @@ def post_generate(self, project):
relations_to_add = []
for relation in project.relations:
if relation.referenced_layer == self:
if (
not relation.referencing_layer.is_relevant
and project.optimize_strategy == OptimizeStrategy.GROUP
):
continue

# 1:n relation will be added only if does not point to a pure link table
if (
Expand All @@ -266,10 +285,9 @@ def post_generate(self, project):
if nm_relation.referenced_layer == self:
continue

# relations to the same table with different geometries should not be added
if (
self.srid
and nm_relation.referenced_layer.srid == self.srid
not nm_relation.referenced_layer.is_relevant
and project.optimize_strategy == OptimizeStrategy.GROUP
):
continue

Expand Down Expand Up @@ -332,7 +350,7 @@ def isPureLinkTable(self, project):

remaining_fields = set()
for field in self.fields:
if field.name not in IGNORED_FIELDNAMES:
if field.name not in IGNORED_FIELDNAMES + BASKET_FIELDNAMES:
remaining_fields.add(field.name)

# Remove all fields that are referencing fields
Expand Down
10 changes: 9 additions & 1 deletion modelbaker/dataobjects/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from qgis.PyQt.QtCore import QObject, pyqtSignal
from qgis.PyQt.QtXml import QDomDocument

from ..utils.globals import OptimizeStrategy
from .layers import Layer
from .legend import LegendGroup
from .relations import Relation
Expand All @@ -43,7 +44,13 @@
class Project(QObject):
layer_added = pyqtSignal(str)

def __init__(self, auto_transaction=True, evaluate_default_values=True, context={}):
def __init__(
self,
auto_transaction=True,
evaluate_default_values=True,
context={},
optimize_strategy=OptimizeStrategy.NONE,
):
QObject.__init__(self)
self.crs = None
self.name = "Not set"
Expand All @@ -57,6 +64,7 @@ def __init__(self, auto_transaction=True, evaluate_default_values=True, context=
self.layouts = {}
self.mapthemes = {}
self.context = context
self.optimize_strategy = optimize_strategy

# {Layer_class_name: {dbattribute: {Layer_class, cardinality, Layer_domain, key_field, value_field]}
self.bags_of_enum = dict()
Expand Down
1 change: 1 addition & 0 deletions modelbaker/dbconnector/db_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def get_tables_info(self):
extent [a string: "xmin;ymin;xmax;ymax"]
table_alias
model
relevance
"""
return []

Expand Down
91 changes: 87 additions & 4 deletions modelbaker/dbconnector/gpkg_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,77 @@ def _get_tables_info(self):
GROUP BY tablename
) as coord_decimals,
substr(c.iliname, 0, instr(c.iliname, '.')) AS model,
attrs.sqlname as attribute_name, """
attrs.sqlname as attribute_name,
{relevance_field},
{topics},""".format(
relevance_field="""CASE WHEN c.iliname IN (
-- used to get the class names from the full names
WITH names AS (
WITH class_level_name AS(
WITH topic_level_name AS (
SELECT
thisClass as fullname,
substr(thisClass, 0, instr(thisClass, '.')) as model,
substr(ltrim(thisClass,substr(thisClass, 0, instr(thisClass, '.'))),2) as topicclass
FROM T_ILI2DB_INHERITANCE
)
SELECT *, ltrim(topicclass,substr(topicclass, 0, instr(topicclass, '.'))) as class_with_dot
FROM topic_level_name
)
SELECT fullname, model, topicclass, substr(class_with_dot, instr(class_with_dot,'.')+1) as class
FROM class_level_name
)
SELECT i.baseClass as base
FROM T_ILI2DB_INHERITANCE i
LEFT JOIN names extend_names
ON thisClass = extend_names.fullname
LEFT JOIN names base_names
ON baseClass = base_names.fullname
-- it's extended
WHERE baseClass IS NOT NULL
-- in a different model
AND base_names.model != extend_names.model
AND (
-- with the same name
base_names.class = extend_names.class
OR
-- multiple times in the same extended model
(SELECT MAX(count) FROM (SELECT COUNT(baseClass) AS count FROM T_ILI2DB_INHERITANCE JOIN names extend_names ON thisClass = extend_names.fullname WHERE baseClass = i.baseClass GROUP BY baseClass, extend_names.model) AS counts )>1
)
)
THEN FALSE ELSE TRUE END AS relevance""",
# topics - where this class or an instance of it is located - are emitted by going recursively through the inheritance table.
# if something of this topic where the current class is located has been extended, it gets the next child topic.
# the relevant topics for optimization are the ones that are not more extended (or in the very last class).
topics="""(SELECT group_concat(childTopic) FROM {topic_pedigree}) as all_topics,
(SELECT group_concat(childTopic) FROM {topic_pedigree} WHERE NOT is_a_base) as relevant_topics""".format(
topic_pedigree="""(WITH RECURSIVE children(is_a_base, childTopic, baseTopic) AS (
SELECT
(CASE
WHEN substr( thisClass, 0, instr(substr( thisClass, instr(thisClass, '.')+1), '.')+instr(thisClass, '.')) IN (SELECT substr( i.baseClass, 0, instr(substr( i.baseClass, instr(i.baseClass, '.')+1), '.')+instr(i.baseClass, '.')) FROM T_ILI2DB_INHERITANCE i WHERE substr( i.thisClass, 0, instr(i.thisClass, '.') ) != substr( i.baseClass, 0, instr(i.baseClass, '.')))
THEN TRUE
ELSE FALSE
END) AS is_a_base,
substr( thisClass, 0, instr(substr( thisClass, instr(thisClass, '.')+1), '.')+instr(thisClass, '.')) as childTopic,
substr( baseClass, 0, instr(substr( baseClass, instr(baseClass, '.')+1), '.')+instr(baseClass, '.')) as baseTopic
FROM T_ILI2DB_INHERITANCE
WHERE baseTopic = substr( c.iliname, 0, instr(substr( c.iliname, instr(c.iliname, '.')+1), '.')+instr(c.iliname, '.'))
UNION
SELECT
(CASE
WHEN substr( thisClass, 0, instr(substr( thisClass, instr(thisClass, '.')+1), '.')+instr(thisClass, '.')) IN (SELECT substr( i.baseClass, 0, instr(substr( i.baseClass, instr(i.baseClass, '.')+1), '.')+instr(i.baseClass, '.')) FROM T_ILI2DB_INHERITANCE i WHERE substr( i.thisClass, 0, instr(i.thisClass, '.')) != substr( i.baseClass, 0,instr(i.baseClass, '.')))
THEN TRUE
ELSE FALSE
END) AS is_a_base,
substr( inheritance.thisClass, 0, instr(substr( inheritance.thisClass, instr(inheritance.thisClass, '.')+1), '.')+instr(inheritance.thisClass, '.')) as childTopic ,
substr( inheritance.baseClass, 0, instr(substr( inheritance.baseClass, instr(baseClass, '.')+1), '.')+instr(inheritance.baseClass, '.')) as baseTopic FROM children
JOIN T_ILI2DB_INHERITANCE as inheritance
ON substr( inheritance.baseClass, 0, instr(substr( inheritance.baseClass, instr(inheritance.baseClass, '.')+1), '.')+instr(inheritance.baseClass, '.')) = children.childTopic -- when the childTopic is as well the baseTopic of another childTopic
WHERE substr( inheritance.thisClass, 0, instr(substr( inheritance.thisClass, instr(inheritance.thisClass, '.')+1), '.')+instr(inheritance.thisClass, '.')) != children.childTopic --break the recursion when the coming childTopic will be the same
)
SELECT childTopic, baseTopic, is_a_base FROM children)"""
),
)
interlis_joins = """LEFT JOIN T_ILI2DB_TABLE_PROP p
ON p.tablename = s.name
AND p.tag = 'ch.ehi.ili2db.tableKind'
Expand All @@ -151,7 +221,6 @@ def _get_tables_info(self):
ON s.name == c.sqlname
LEFT JOIN t_ili2db_attrname attrs
ON c.iliname = attrs.iliname """

try:
cursor.execute(
"""
Expand Down Expand Up @@ -755,12 +824,26 @@ def get_topics_info(self):
cursor.execute(
"""
SELECT DISTINCT substr(CN.IliName, 0, instr(CN.IliName, '.')) as model,
substr(substr(CN.IliName, instr(CN.IliName, '.')+1),0, instr(substr(CN.IliName, instr(CN.IliName, '.')+1),'.')) as topic
substr(substr(CN.IliName, instr(CN.IliName, '.')+1),0, instr(substr(CN.IliName, instr(CN.IliName, '.')+1),'.')) as topic,
{relevance}
FROM T_ILI2DB_CLASSNAME as CN
JOIN T_ILI2DB_TABLE_PROP as TP
ON CN.sqlname = TP.tablename
WHERE topic != '' and TP.setting != 'ENUM'
"""
""".format(
# it's relevant, when it's not extended
# relevance is emitted by going recursively through the inheritance table. If nothing on this topic is extended, it is relevant. Otherwise it's not.
relevance="""
CASE WHEN (WITH RECURSIVE children(childTopic, baseTopic) AS (
SELECT substr( thisClass, 0, instr(substr( thisClass, instr(thisClass, '.')+1), '.')+instr(thisClass, '.')) as childTopic , substr( baseClass, 0, instr(substr( baseClass, instr(baseClass, '.')+1), '.')+instr(baseClass, '.')) as baseTopic
FROM T_ILI2DB_INHERITANCE
WHERE baseTopic = substr( CN.IliName, 0, instr(substr( CN.IliName, instr(CN.IliName, '.')+1), '.')+instr(CN.IliName, '.')) -- model.topic
UNION
SELECT substr( inheritance.thisClass, 0, instr(substr( inheritance.thisClass, instr(inheritance.thisClass, '.')+1), '.')+instr(inheritance.thisClass, '.')) as childTopic , substr( inheritance.baseClass, 0, instr(substr( inheritance.baseClass, instr(baseClass, '.')+1), '.')+instr(inheritance.baseClass, '.')) as baseTopic FROM children
JOIN T_ILI2DB_INHERITANCE as inheritance ON substr( inheritance.baseClass, 0, instr(substr( inheritance.baseClass, instr(baseClass, '.')+1), '.')+instr(inheritance.baseClass, '.')) = children.childTopic
)SELECT count(childTopic) FROM children)>0 THEN FALSE ELSE TRUE END AS relevance
"""
)
)
contents = cursor.fetchall()
cursor.close()
Expand Down
Loading
Loading