"""Metadata model for edits."""
import duckdb
from banffprocessor.exceptions import MetadataConstraintError
from banffprocessor.metadata.models.metadataclass import MetadataClass
from banffprocessor.nls import _
[docs]
class Edits(MetadataClass):
"""Metadata class for defining edits."""
def __init__(self, editid: str, leftside: str, rightside: str, operator: str,
modifier: str | None = None, dbconn: duckdb.DuckDBPyConnection = duckdb) -> None:
"""Validate and create metadata entry, if validation passes."""
self.editid = editid
self.leftside = leftside
#constraint invalidLeftSide
if(self.leftside is not None) and (self.leftside.find("'") != -1 or self.leftside.find('"') != -1):
msg = _("Constraint violated in {} table: ").format(self.__class__.__name__)
msg += _("{} value must not contain any single or double quotes.").format("leftside")
raise MetadataConstraintError(msg)
self.rightside = rightside
#constraint invalidRightSide
if(self.rightside is not None) and (self.rightside.find("'") != -1 or self.rightside.find('"') != -1):
msg = _("Constraint violated in {} table: ").format(self.__class__.__name__)
msg += _("{} value must not contain any single or double quotes.").format("rightside")
raise MetadataConstraintError(msg)
# xmltodict auto converts the html entities used by the XML tables to unicode
# i.e. '<' becomes '<', '>=' becomes '>='
# Therefore they don't need to be converted manually here, however they may
# in the future should something change in the way the file is created
self.operator = operator
#constraint invalidOperator
if(self.operator is not None) and (self.operator not in {"<", "<=", ">", ">=", "=", "!="}):
msg = _("Constraint violated in {} table: ").format(self.__class__.__name__)
msg += _("{} value must be one of {}.").format("operator", " '<', '<=', '>', '>=', '=', '!=' ")
raise MetadataConstraintError(msg)
self.modifier = modifier
#constraint invalidModifier
if(self.modifier is not None) and (self.modifier.upper() not in {"", "PASS", "FAIL", "ACCEPTE", "REJET"}):
msg = _("Constraint violated in {} table: ").format(self.__class__.__name__)
msg += _("{} value must be one of {}.").format("Modifier", " '', 'PASS', 'FAIL', 'ACCEPTE', 'REJET' ")
raise MetadataConstraintError(msg)
# Not in original processor, just for convenience
if(self.modifier is None or self.modifier == ""):
self.edit = self.leftside + " " + self.operator + " " + self.rightside + ";"
else:
self.edit = self.modifier + ": " + self.leftside + " " + self.operator + " " + self.rightside + ";"
# Note that the order of attributes must match the order in the create statement
statement = f"INSERT INTO banff.{self.__class__.__name__} VALUES (?, ?, ?, ?, ?, ?)" # noqa: S608
dbconn.execute(statement,[self.editid, self.leftside, self.operator, self.rightside, self.modifier, self.edit])
[docs]
@classmethod
def initialize(cls, dbconn: duckdb.DuckDBPyConnection = duckdb) -> None:
"""Create duckdb table to store the metadata."""
cls.setup(dbconn=dbconn)
create_statement = f"""CREATE TABLE banff.{cls.__name__} (
editid VARCHAR PRIMARY KEY,
leftside VARCHAR,
operator VARCHAR,
rightside VARCHAR,
modifier VARCHAR,
edit VARCHAR
)
"""
dbconn.execute(create_statement)
[docs]
@staticmethod
def get_schema(root_element_name: str = "banffProcessor") -> str:
"""Return schema (XSD) contents as a string."""
return f"""<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="{root_element_name}">
<xs:complexType>
<xs:sequence>
<xs:element name="edits" maxOccurs="1000" minOccurs="0">
<xs:complexType>
<xs:all>
<xs:element name="editid">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="100"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="leftside">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="6000"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="operator">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="<"/>
<xs:enumeration value="<="/>
<xs:enumeration value=">"/>
<xs:enumeration value=">="/>
<xs:enumeration value="="/>
<xs:enumeration value="!="/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="rightside">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="1000"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element minOccurs="0" name="modifier" nillable="true">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="ACCEPTE"/>
<xs:enumeration value="FAIL"/>
<xs:enumeration value="PASS"/>
<xs:enumeration value="REJET"/>
<xs:enumeration value="accepte"/>
<xs:enumeration value="fail"/>
<xs:enumeration value="pass"/>
<xs:enumeration value="rejet"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:all>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>"""