Skip to content

Commit

Permalink
Merge pull request #103 from opengisch/oid_constraints
Browse files Browse the repository at this point in the history
Set unique and not-null constraint on defined OID domains
  • Loading branch information
signedav authored Jun 27, 2024
2 parents 8ecc4ae + bc4f800 commit 1eccc02
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 2 deletions.
15 changes: 14 additions & 1 deletion modelbaker/dataobjects/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

from typing import TYPE_CHECKING

from qgis.core import QgsDefaultValue, QgsEditorWidgetSetup
from qgis.core import QgsDefaultValue, QgsEditorWidgetSetup, QgsFieldConstraints

if TYPE_CHECKING:
from .layers import Layer
Expand Down Expand Up @@ -61,3 +61,16 @@ def create(self, layer: Layer) -> None:
if self.default_value_expression:
default_value = QgsDefaultValue(self.default_value_expression)
layer.layer.setDefaultValueDefinition(field_idx, default_value)

if self.oid_domain:
# if defined, then set not null and unique constraints
layer.layer.setFieldConstraint(
field_idx,
QgsFieldConstraints.ConstraintNotNull,
QgsFieldConstraints.ConstraintStrengthHard,
)
layer.layer.setFieldConstraint(
field_idx,
QgsFieldConstraints.ConstraintUnique,
QgsFieldConstraints.ConstraintStrengthHard,
)
62 changes: 62 additions & 0 deletions modelbaker/utils/qgis_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
QgsAttributeEditorField,
QgsDefaultValue,
QgsExpressionContextUtils,
QgsFieldConstraints,
QgsLayerTreeLayer,
QgsLayerTreeNode,
QgsMapLayer,
Expand Down Expand Up @@ -147,6 +148,8 @@ def get_oid_settings(self):
"interlis_topic" : "OIDMadness_V1",
"default_value_expression": "uuid()",
"in_form": True
"not_null": True,
"unique": True,
"layer": QgsVectorLayer
}
}
Expand Down Expand Up @@ -198,6 +201,17 @@ def get_oid_settings(self):
oid_setting["in_form"] = bool(
self._found_tilitid(root_container) is not None
)

# get the constraints
oid_setting["not_null"] = bool(
t_ili_tid_field.constraints().constraints()
& QgsFieldConstraints.ConstraintNotNull
)
oid_setting["unique"] = bool(
t_ili_tid_field.constraints().constraints()
& QgsFieldConstraints.ConstraintUnique
)

oid_settings[tree_layer.layer().name()] = oid_setting

return oid_settings
Expand Down Expand Up @@ -250,6 +264,54 @@ def set_oid_settings(self, oid_settings):
continue
found_container.addChildElement(child.clone(found_container))

# set the constraints if not yet set and set it strong
if (
not bool(
t_ili_tid_field.constraints().constraints()
& QgsFieldConstraints.ConstraintNotNull
)
and oid_setting["not_null"]
):
layer.setFieldConstraint(
field_idx,
QgsFieldConstraints.ConstraintNotNull,
QgsFieldConstraints.ConstraintStrengthHard,
)
if (
bool(
t_ili_tid_field.constraints().constraints()
& QgsFieldConstraints.ConstraintNotNull
)
and not oid_setting["not_null"]
):
layer.removeFieldConstraint(
field_idx,
QgsFieldConstraints.ConstraintNotNull,
)
if (
not bool(
t_ili_tid_field.constraints().constraints()
& QgsFieldConstraints.ConstraintUnique
)
and oid_setting["unique"]
):
layer.setFieldConstraint(
field_idx,
QgsFieldConstraints.ConstraintUnique,
QgsFieldConstraints.ConstraintStrengthHard,
)
if (
bool(
t_ili_tid_field.constraints().constraints()
& QgsFieldConstraints.ConstraintUnique
)
and not oid_setting["unique"]
):
layer.removeFieldConstraint(
field_idx,
QgsFieldConstraints.ConstraintUnique,
)

def _found_tilitid(self, container):
"""Recursive function to dig into the form containers for the t_ili_tid returning true on success."""
for element in container.children():
Expand Down
81 changes: 80 additions & 1 deletion tests/test_projectgen_oids.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import pathlib
import tempfile

from qgis.core import QgsExpressionContextUtils, QgsProject
from qgis.core import QgsExpressionContextUtils, QgsFieldConstraints, QgsProject
from qgis.testing import start_app, unittest

from modelbaker.dataobjects.project import Project
Expand Down Expand Up @@ -315,6 +315,15 @@ def _oids_tids_none(self, generator, strategy):
assert (
default_value_definition.expression() == expected_other_expression
)
# check if not null and unique constraints are set (shouldn't be)
assert not (
t_ili_tid_field.constraints().constraints()
& QgsFieldConstraints.ConstraintUnique
)
assert not (
t_ili_tid_field.constraints().constraints()
& QgsFieldConstraints.ConstraintNotNull
)
count += 1
# ANYOID
if tree_layer.layer().name() in ["BesitzerIn"]:
Expand All @@ -337,6 +346,8 @@ def _oids_tids_none(self, generator, strategy):
assert (
default_value_definition.expression() == expected_other_expression
)
# check if not null and unique constraints are set
self._check_t_ili_tid_field_constraints(t_ili_tid_field)
count += 1
# UUIDOID
if tree_layer.layer().name() in [
Expand All @@ -361,6 +372,8 @@ def _oids_tids_none(self, generator, strategy):
default_value_definition = t_ili_tid_field.defaultValueDefinition()
assert default_value_definition is not None
assert default_value_definition.expression() == expected_uuid_expression
# check if not null and unique constraints are set
self._check_t_ili_tid_field_constraints(t_ili_tid_field)
count += 1
# STANARDOID
if tree_layer.layer().name() in [
Expand Down Expand Up @@ -389,6 +402,8 @@ def _oids_tids_none(self, generator, strategy):
default_value_definition.expression()
== expected_standard_expression
)
# check if not null and unique constraints are set
self._check_t_ili_tid_field_constraints(t_ili_tid_field)
count += 1
# I32OID
if tree_layer.layer().name() in ["Wiese", "Spass.Gebaeude"]:
Expand All @@ -409,6 +424,8 @@ def _oids_tids_none(self, generator, strategy):
default_value_definition = t_ili_tid_field.defaultValueDefinition()
assert default_value_definition is not None
assert default_value_definition.expression() == expected_i32_expression
# check if not null and unique constraints are set
self._check_t_ili_tid_field_constraints(t_ili_tid_field)
count += 1
# OIDMadness_V1.TypeID or OIDMadness_V1.TypeIDShort
if tree_layer.layer().name() in ["See", "Fluss"]:
Expand All @@ -434,6 +451,8 @@ def _oids_tids_none(self, generator, strategy):
assert (
default_value_definition.expression() == expected_other_expression
)
# check if not null and unique constraints are set
self._check_t_ili_tid_field_constraints(t_ili_tid_field)
count += 1

# should find 15
Expand Down Expand Up @@ -573,6 +592,15 @@ def _oids_tids_group(self, generator, strategy):
assert (
default_value_definition.expression() == expected_other_expression
)
# check if not null and unique constraints are set (shouldn't)
assert not (
t_ili_tid_field.constraints().constraints()
& QgsFieldConstraints.ConstraintUnique
)
assert not (
t_ili_tid_field.constraints().constraints()
& QgsFieldConstraints.ConstraintNotNull
)
count += 1
# ANYOID
if tree_layer.layer().name() in ["BesitzerIn"]:
Expand All @@ -595,6 +623,8 @@ def _oids_tids_group(self, generator, strategy):
assert (
default_value_definition.expression() == expected_other_expression
)
# check if not null and unique constraints are set
self._check_t_ili_tid_field_constraints(t_ili_tid_field)
count += 1
# UUIDOID
if tree_layer.layer().name() in [
Expand All @@ -619,6 +649,8 @@ def _oids_tids_group(self, generator, strategy):
default_value_definition = t_ili_tid_field.defaultValueDefinition()
assert default_value_definition is not None
assert default_value_definition.expression() == expected_uuid_expression
# check if not null and unique constraints are set
self._check_t_ili_tid_field_constraints(t_ili_tid_field)
count += 1
# STANARDOID
if tree_layer.layer().name() in [
Expand Down Expand Up @@ -647,6 +679,8 @@ def _oids_tids_group(self, generator, strategy):
default_value_definition.expression()
== expected_standard_expression
)
# check if not null and unique constraints are set
self._check_t_ili_tid_field_constraints(t_ili_tid_field)
count += 1
# I32OID
if tree_layer.layer().name() in ["Wiese", "Spass.Gebaeude"]:
Expand All @@ -667,6 +701,8 @@ def _oids_tids_group(self, generator, strategy):
default_value_definition = t_ili_tid_field.defaultValueDefinition()
assert default_value_definition is not None
assert default_value_definition.expression() == expected_i32_expression
# check if not null and unique constraints are set
self._check_t_ili_tid_field_constraints(t_ili_tid_field)
count += 1
# OIDMadness_V1.TypeID or OIDMadness_V1.TypeIDShort
if tree_layer.layer().name() in ["See", "Fluss"]:
Expand All @@ -692,6 +728,8 @@ def _oids_tids_group(self, generator, strategy):
assert (
default_value_definition.expression() == expected_other_expression
)
# check if not null and unique constraints are set
self._check_t_ili_tid_field_constraints(t_ili_tid_field)
count += 1

# should find 15
Expand Down Expand Up @@ -832,6 +870,15 @@ def _oids_tids_hide(self, generator, strategy):
assert (
default_value_definition.expression() == expected_other_expression
)
# check if not null and unique constraints are set (shouldn't)
assert not (
t_ili_tid_field.constraints().constraints()
& QgsFieldConstraints.ConstraintUnique
)
assert not (
t_ili_tid_field.constraints().constraints()
& QgsFieldConstraints.ConstraintNotNull
)
count += 1
# ANYOID
if tree_layer.layer().name() in ["BesitzerIn"]:
Expand All @@ -854,6 +901,8 @@ def _oids_tids_hide(self, generator, strategy):
assert (
default_value_definition.expression() == expected_other_expression
)
# check if not null and unique constraints are set
self._check_t_ili_tid_field_constraints(t_ili_tid_field)
count += 1
# UUIDOID
if tree_layer.layer().name() in ["Quartier.Gebaeude", "Wald"]:
Expand All @@ -874,6 +923,8 @@ def _oids_tids_hide(self, generator, strategy):
default_value_definition = t_ili_tid_field.defaultValueDefinition()
assert default_value_definition is not None
assert default_value_definition.expression() == expected_uuid_expression
# check if not null and unique constraints are set
self._check_t_ili_tid_field_constraints(t_ili_tid_field)
count += 1
# STANARDOID
if tree_layer.layer().name() in [
Expand Down Expand Up @@ -902,6 +953,8 @@ def _oids_tids_hide(self, generator, strategy):
default_value_definition.expression()
== expected_standard_expression
)
# check if not null and unique constraints are set
self._check_t_ili_tid_field_constraints(t_ili_tid_field)
count += 1
# I32OID
if tree_layer.layer().name() in ["Wiese", "Spass.Gebaeude"]:
Expand All @@ -922,6 +975,8 @@ def _oids_tids_hide(self, generator, strategy):
default_value_definition = t_ili_tid_field.defaultValueDefinition()
assert default_value_definition is not None
assert default_value_definition.expression() == expected_i32_expression
# check if not null and unique constraints are set
self._check_t_ili_tid_field_constraints(t_ili_tid_field)
count += 1
# OIDMadness_V1.TypeID or OIDMadness_V1.TypeIDShort
if tree_layer.layer().name() in ["See", "Fluss"]:
Expand All @@ -947,6 +1002,8 @@ def _oids_tids_hide(self, generator, strategy):
assert (
default_value_definition.expression() == expected_other_expression
)
# check if not null and unique constraints are set
self._check_t_ili_tid_field_constraints(t_ili_tid_field)
count += 1

# should find 14
Expand Down Expand Up @@ -1027,6 +1084,28 @@ def _oids_tids_hide(self, generator, strategy):

QgsProject.instance().clear()

def _check_t_ili_tid_field_constraints(self, t_ili_tid_field):
assert (
t_ili_tid_field.constraints().constraints()
& QgsFieldConstraints.ConstraintUnique
)
assert (
t_ili_tid_field.constraints().constraints()
& QgsFieldConstraints.ConstraintNotNull
)
assert (
t_ili_tid_field.constraints().constraintStrength(
QgsFieldConstraints.ConstraintUnique
)
== QgsFieldConstraints.ConstraintStrengthHard
)
assert (
t_ili_tid_field.constraints().constraintStrength(
QgsFieldConstraints.ConstraintNotNull
)
== QgsFieldConstraints.ConstraintStrengthHard
)

def _set_pg_naming(self, is_pg=True):
if is_pg:
self.tilitid_fieldname = "t_ili_tid"
Expand Down

0 comments on commit 1eccc02

Please sign in to comment.