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

Create db validation context #302

Draft
wants to merge 4 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ repos:
hooks:
- id: mypy
args: ["--install-types", "--non-interactive", "--ignore-missing-imports"]
additional_dependencies: [sqlalchemy2-stubs <= 0.0.2a20, SQLAlchemy <= 1.4]
additional_dependencies: [sqlalchemy2-stubs <= 0.0.2a20, SQLAlchemy <= 1.4.50]
exclude: docs/conf.py
27 changes: 26 additions & 1 deletion buildingmotif/api/views/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from sqlalchemy.orm.exc import NoResultFound

from buildingmotif.api.serializers.model import serialize
from buildingmotif.dataclasses import Library, Model
from buildingmotif.dataclasses import Library, Model, ValidationContext

blueprint = Blueprint("models", __name__)

Expand Down Expand Up @@ -179,3 +179,28 @@ def validate_model(models_id: int) -> flask.Response:
for focus_node, grahdiffs in vaildation_context.diffset.items()
},
}, status.HTTP_200_OK


@blueprint.route("/<model_id>/validation_contexts", methods=(["GET"]))
def get_validation_contexts(model_id: int) -> flask.Response:
# get model
try:
model = current_app.building_motif.table_connection.get_db_model(model_id)
except NoResultFound:
return {"message": f"No model with id {model_id}"}, status.HTTP_404_NOT_FOUND

validation_contexts = [
ValidationContext.load(vc.id) for vc in model.validation_contexts
]

return [
{
"message": validation_context.report_string,
"valid": validation_context.valid,
"reasons": {
focus_node: [gd.reason() for gd in grahdiffs]
for focus_node, grahdiffs in validation_context.diffset.items()
},
}
for validation_context in validation_contexts
], status.HTTP_200_OK
52 changes: 52 additions & 0 deletions buildingmotif/database/table_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
DBModel,
DBShapeCollection,
DBTemplate,
DBValidationContext,
DepsAssociation,
)

Expand Down Expand Up @@ -536,3 +537,54 @@ def delete_db_template(self, id: int) -> None:
self.logger.debug(f"Deleting template: '{db_template.name}'")

self.bm.session.delete(db_template)

def get_all_db_validation_contexts(self) -> List[DBValidationContext]:
"""Get all database validation contexts.

:return: all DBValidationContext
:rtype: List[DBValidationContext]
"""
return self.bm.session.query(DBValidationContext).all()

def create_db_validation_context(self, valid, report_string, model_id):
"""_summary_"""
report_id = str(uuid.uuid4())

db_validation_context = DBValidationContext(
valid=valid,
report_string=report_string,
report_id=report_id,
model_id=model_id,
)

self.bm.session.add(db_validation_context)

self.bm.session.flush()

return db_validation_context

def get_db_validation_context(self, id: int) -> DBValidationContext:
"""Get database validation_context by id.

:param id: id of DBValidationContext
:type id: int
:return: DBValidationContext
:rtype: DBValidationContext
"""
db_validation_context = (
self.bm.session.query(DBValidationContext)
.filter(DBValidationContext.id == id)
.one()
)
return db_validation_context

def delete_db_validation_context(self, id: int) -> None:
"""Delete database validation_context.

:param id: id of deleted DBValidationContext
:type id: int
"""

db_validation_context = self.get_db_validation_context(id)
self.logger.debug(f"Deleting validation_context: '{db_validation_context.id}'")
self.bm.session.delete(db_validation_context)
50 changes: 49 additions & 1 deletion buildingmotif/database/tables.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
from typing import Dict, List

from sqlalchemy import Column, ForeignKey, Integer, String, Text, UniqueConstraint
from sqlalchemy import (
TEXT,
Boolean,
Column,
ForeignKey,
Integer,
String,
Text,
UniqueConstraint,
)
from sqlalchemy.orm import Mapped, declarative_base, relationship

# from sqlalchemy.dialects.postgresql import JSON
Expand All @@ -26,6 +35,10 @@ class DBModel(Base):
cascade="all,delete",
)

validation_contexts: Mapped[List["DBValidationContext"]] = relationship(
"DBValidationContext", back_populates="model", cascade="all,delete"
)


class DBShapeCollection(Base):
"""A ShapeCollection is a collection of shapes, which are used to validate
Expand Down Expand Up @@ -113,3 +126,38 @@ class DBTemplate(Base):
name="name_library_unique_constraint",
),
)


class ValidationContextShapeCollectionAssociation(Base):
"""Many-to-many relationship between DBValidationContexts and DBShapeCollection."""

__tablename__ = "validation_context_shape_collection_association"

id: Mapped[int] = Column(Integer, primary_key=True)
shape_collection_id: Mapped[int] = Column(ForeignKey("shape_collection.id"))
validation_context_id: Mapped[int] = Column(ForeignKey("validation_context.id"))

__table_args__ = (
UniqueConstraint(
"shape_collection_id",
"validation_context_id",
name="validation_context_shape_collection_unique_constraint",
),
)


class DBValidationContext(Base):
__tablename__ = "validation_context"

id: Mapped[int] = Column(Integer, primary_key=True)
valid: Mapped[bool] = Column(Boolean, nullable=False)
report_string: Mapped[str] = Column(TEXT, nullable=False)
report_id: Mapped[str] = Column(String(), nullable=False)

shape_collections: Mapped[List[DBShapeCollection]] = relationship(
"DBShapeCollection", secondary="validation_context_shape_collection_association"
)
model_id: Mapped[int] = Column(Integer, ForeignKey("models.id"), nullable=False)
model: Mapped[DBModel] = relationship(
"DBModel", back_populates="validation_contexts"
)
2 changes: 1 addition & 1 deletion buildingmotif/dataclasses/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
from buildingmotif.dataclasses.model import Model # noqa
from buildingmotif.dataclasses.shape_collection import ShapeCollection # noqa
from buildingmotif.dataclasses.template import Template # noqa
from buildingmotif.dataclasses.validation import ValidationContext # noqa
from buildingmotif.dataclasses.validation_context import ValidationContext # noqa
26 changes: 13 additions & 13 deletions buildingmotif/dataclasses/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from buildingmotif import get_building_motif
from buildingmotif.dataclasses.shape_collection import ShapeCollection
from buildingmotif.dataclasses.validation import ValidationContext
from buildingmotif.dataclasses.validation_context import ValidationContext
from buildingmotif.namespaces import A
from buildingmotif.utils import Triple, copy_graph, rewrite_shape_graph

Expand Down Expand Up @@ -185,12 +185,12 @@ def validate(
# inplace=True,
)
assert isinstance(report_g, rdflib.Graph)
return ValidationContext(
shape_collections,
valid,
report_g,
report_str,
self,
return ValidationContext.create(
shape_collections=shape_collections,
valid=valid,
report=report_g,
report_string=report_str,
model=self,
)

def compile(self, shape_collections: List["ShapeCollection"]):
Expand Down Expand Up @@ -287,12 +287,12 @@ def test_model_against_shapes(
advanced=True,
js=True,
)
results[shape_uri] = ValidationContext(
shape_collections,
valid,
report_g,
report_str,
self,
results[shape_uri] = ValidationContext.create(
shape_collections=shape_collections,
valid=valid,
report=report_g,
report_string=report_str,
model=self,
)

return results
Expand Down
Loading