Skip to content

Commit

Permalink
Change attribute set is_view_field (#2426)
Browse files Browse the repository at this point in the history
* Ch attribute set is_view_field

* Added-write-fields-and-updated-is-view-field

* implement function to determinate is_view_field, primary and write_fields

* include meta

* updated global meta

* include models.py

* added chyron_background/font_color2 to example-data

* update writing of modelspy

* linting of generate_modelspy and modelspy

* Update fieldspy

* update linting fieldspy

---------

Co-authored-by: Ralf Peschke <ralf.peschke@intevation.de>
  • Loading branch information
reicda and r-peschke authored Jun 25, 2024
1 parent d32b5db commit 1ad3345
Show file tree
Hide file tree
Showing 4 changed files with 506 additions and 64 deletions.
130 changes: 121 additions & 9 deletions cli/generate_models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import string
import sys
from collections import ChainMap
from textwrap import dedent
from typing import Any, Optional
Expand All @@ -20,6 +21,15 @@
)
from openslides_backend.shared.patterns import KEYSEPARATOR, Collection

sys.path.append("global")

from meta.dev.src.helper_get_names import ( # type: ignore # noqa
FieldSqlErrorType,
HelperGetNames,
InternalHelper,
TableFieldType,
)

SOURCE = "./global/meta/models.yml"

DESTINATION = os.path.abspath(
Expand Down Expand Up @@ -97,6 +107,8 @@ def main() -> None:
global MODELS
MODELS = open_yml_file(args.filename)

InternalHelper.MODELS = MODELS

# Load and parse models.yml
with open_output(DESTINATION, args.check) as dest:
dest.write(FILE_TEMPLATE)
Expand Down Expand Up @@ -163,7 +175,9 @@ def __init__(self, collection: str, fields: dict[str, dict[str, Any]]) -> None:
for field_name, field in fields.items():
if field.get("calculated"):
continue
self.attributes[field_name] = Attribute(field)
self.attributes[field_name] = Attribute(
field.copy(), collection, field_name
)

def get_code(self) -> str:
verbose_name = " ".join(self.collection.split("_"))
Expand Down Expand Up @@ -201,12 +215,16 @@ class Attribute(Node):
equal_fields: str | list[str] | None = None
constraints: dict[str, Any]
is_view_field: bool = False
is_primary: bool = False
write_fields: tuple[str, str, str, list[str]] | None = None

FIELD_TEMPLATE = string.Template(
" ${field_name} = fields.${field_class}(${properties})\n"
)

def __init__(self, value: str | dict) -> None:
def __init__(
self, value: str | dict, collection_name: str, field_name: str
) -> None:
self.FIELD_CLASSES = {
**COMMON_FIELD_CLASSES,
**RELATION_FIELD_CLASSES,
Expand All @@ -216,20 +234,20 @@ def __init__(self, value: str | dict) -> None:
if isinstance(value, str):
self.type = value
else:
self.type = value.pop("type")
self.type = value.get("type", "")
if self.type in RELATION_FIELD_CLASSES.keys():
self.is_view_field, self.is_primary, self.write_fields = (
self.get_view_field_state_write_fields(
collection_name, field_name, value
)
)
self.to = To(value.pop("to"))
self.on_delete = value.pop("on_delete", None)
if (
self.type.endswith("relation-list")
or value.get("sql")
or (value.get("to") and not value.get("reference"))
):
self.is_view_field = True
else:
assert self.type in COMMON_FIELD_CLASSES.keys(), (
"Invalid type: " + self.type
)
value.pop("type")
self.required = value.pop("required", False)
self.read_only = value.pop("read_only", False)
self.constant = value.pop("constant", False)
Expand Down Expand Up @@ -262,6 +280,8 @@ def get_code(self, field_name: str) -> str:
properties += f"on_delete=fields.OnDelete.{self.on_delete}, "
if self.is_view_field:
properties += "is_view_field=True, "
if self.is_primary:
properties += "is_primary=True, "
if self.required:
properties += "required=True, "
if self.read_only:
Expand All @@ -274,8 +294,11 @@ def get_code(self, field_name: str) -> str:
properties += f"equal_fields={repr(self.equal_fields)}, "
if self.constraints:
properties += f"constraints={repr(self.constraints)}, "
if self.write_fields is not None:
properties += f"write_fields={repr(self.write_fields)}, "
if self.in_array_constraints and self.type in ("string[]", "number[]"):
properties += f"in_array_constraints={repr(self.in_array_constraints)}"

return self.FIELD_TEMPLATE.substitute(
dict(
field_name=field_name,
Expand All @@ -284,6 +307,95 @@ def get_code(self, field_name: str) -> str:
)
)

def get_view_field_state_write_fields(
self, collection_name: str, field_name: str, value: dict[str, Any]
) -> tuple[bool, bool, tuple[str, str, str, list[TableFieldType]] | None]:
"""
Purpose:
Checks whether a field is a view field and if other fields need to be written in an intermediate
table.
Input:
- collection_name
- field_name
- value : represents the definition of the field ( field_name in collection_name )
Returns:
- is_view_field : whether the field is a view field or not
- is_primary: wether the field is primary or not
- write_fields:
- None if no fields need to be written
- Tuple
table_name : name of the intermediate table
field1
field2
foreign_fields
"""
# variable declaration
own: TableFieldType
field_type: str
state: FieldSqlErrorType
primary: bool
error: str
is_view_field: bool
foreign: TableFieldType
foreign_type: str
table_name: str = ""
field1: str = ""
field2: str = ""
write_fields: tuple[str, str, str, list[str]] | None = None

# create TableFieldType own out of collection_name, field_name, value as field_def
own = TableFieldType(collection_name, field_name, value)
field_type = own.field_def.get("type", None)

# get the foreign field list and check the relations
foreign_fields = InternalHelper.get_definitions_from_foreign_list(
value.get("to", None), value.get("reference", None)
)
state, primary, _, error = InternalHelper.check_relation_definitions(
own, foreign_fields
)
is_view_field = state == FieldSqlErrorType.SQL

if field_type == "relation-list":
foreign = foreign_fields[0]
foreign_type = foreign.field_def.get("type", None)

if foreign_type == "relation-list":
table_name = HelperGetNames.get_nm_table_name(own, foreign)
field1 = HelperGetNames.get_field_in_n_m_relation_list(
own, foreign.table
)
field2 = HelperGetNames.get_field_in_n_m_relation_list(
foreign, own.table
)
if field1 == field2:
field1 += "_1"
field2 += "_2"
write_fields = (table_name, field1, field2, [])

elif foreign_type == "generic-relation-list":
table_name = HelperGetNames.get_gm_table_name(own)
field1 = f"{own.table}_{own.ref_column}"
field2 = own.column[:-1]
for n, field in enumerate(foreign_fields):
foreign_fields[n] = (
field2 + "_" + f"{field.table}_{field.ref_column}"
)
write_fields = (table_name, field1, field2, foreign_fields)

elif field_type == "generic-relation-list":
table_name = HelperGetNames.get_gm_table_name(own)
field1 = f"{own.table}_{own.ref_column}"
field2 = own.column[:-1]
for n, field in enumerate(foreign_fields):
foreign_fields[n] = field2 + "_" + f"{field.table}_{field.ref_column}"

write_fields = (table_name, field1, field2, foreign_fields)

assert error == "", error

return is_view_field, primary, write_fields


class To(Node):
to: dict[Collection, str] # collection <-> field_name
Expand Down
4 changes: 2 additions & 2 deletions global/data/example-data.json
Original file line number Diff line number Diff line change
Expand Up @@ -2359,8 +2359,8 @@
"header_font_color": "#f5f5f5",
"header_h1_color": "#317796",
"chyron_background_color": "#317796",
"chyron_font_color": "#ffffff",
"chyron_background_color_2": "#134768",
"chyron_font_color": "#ffffff",
"chyron_font_color_2": "#ffffff",
"show_header_footer": true,
"show_title": true,
Expand Down Expand Up @@ -2405,8 +2405,8 @@
"header_font_color": "#f5f5f5",
"header_h1_color": "#317796",
"chyron_background_color": "#317796",
"chyron_font_color": "#ffffff",
"chyron_background_color_2": "#134768",
"chyron_font_color": "#ffffff",
"chyron_font_color_2": "#ffffff",
"show_header_footer": true,
"show_title": true,
Expand Down
4 changes: 4 additions & 0 deletions openslides_backend/models/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ def __init__(
default: Any | None = None,
constraints: dict[str, Any] | None = None,
is_view_field: bool = False,
is_primary: bool = False,
write_fields: tuple[str, str, str, list[str]] | None = None,
) -> None:
self.required = required
self.read_only = read_only
Expand All @@ -63,6 +65,8 @@ def __init__(
constraints["enum"].append(None)
self.constraints = constraints or {}
self.is_view_field = is_view_field
self.is_primary = is_primary
self.write_fields = write_fields
self.schema_validator = fastjsonschema.compile(self.get_schema())

def get_schema(self) -> Schema:
Expand Down
Loading

0 comments on commit 1ad3345

Please sign in to comment.