diff --git a/tools/python/jwutils/db/schema/Table.py b/tools/python/jwutils/db/schema/Table.py index e794416..57efbec 100644 --- a/tools/python/jwutils/db/schema/Table.py +++ b/tools/python/jwutils/db/schema/Table.py @@ -39,10 +39,11 @@ class Table(abc.ABC): # export self.__location_rule: Optional[Iterable[str]] = None self.__row_location_rule: Optional[Iterable[str]] = None self.__add_row_location_rule: Optional[Iterable[str]] = None + self.___add_child_row_location_rules: Optional[dict[str, str]] = None self.__foreign_keys_to_parent_table: Optional[OrderedDict[str, Any]] = None self.__relationships: Optional[list[tuple[str, Self]]] = None self.__model_class: Optional[Any] = None - self.__relationship_by_foreign_table: Optional[dict[str, Self]] = None + self.___relationship_by_foreign_table: Optional[dict[str, Self]] = None @property def __columns(self) -> OrderedDict[str, Any]: @@ -61,6 +62,26 @@ class Table(abc.ABC): # export self.___foreign_key_parent_tables[cfk.parent_table.name] = cfk.parent_table return self.___foreign_key_parent_tables + @property + def __relationship_by_foreign_table(self) -> dict[str, Self]: + if self.___relationship_by_foreign_table is None: + ret: dict[str, Self] = dict() + for member_name, table_name in self.relationships: + ret[member_name] = self.schema[table_name] + self.___relationship_by_foreign_table = ret + return self.___relationship_by_foreign_table + + @property + def __add_child_row_location_rules(self) -> dict[str, str]: + if self.___add_child_row_location_rules is None: + ret: dict[str, str] = {} + for foreign_table_name, foreign_table in self.__relationship_by_foreign_table.items(): + if len(self.foreign_keys_to_parent_table(foreign_table)): + rule = self._add_child_row_location_rule(foreign_table_name) + ret[foreign_table_name] = rule + self.___add_child_row_location_rules = ret + return self.___add_child_row_location_rules + def __len__(self): return len(self.__columns) @@ -172,6 +193,17 @@ class Table(abc.ABC): # export def _add_row_location_rule(self) -> Optional[str]: return self._location_rule() + '/new' + def _add_child_row_location_rule(self, parent_table_name: str) -> Optional[str]: + parent_table = self.schema[parent_table_name] + ret = self._add_row_location_rule() + for cfk in self.foreign_keys_to_parent_table(parent_table): + for fk in cfk: + token = f'/<{fk.child_column.name}>' + if ret.find(token) != -1: + continue + ret += f'/<{fk.child_column.name}>' + return ret + # -- To be used def column_default(self, name) -> Any: @@ -268,6 +300,27 @@ class Table(abc.ABC): # export ret = re.sub(f'<{col}>', quote_plus(quote_plus(str(kwargs[col]))), ret) return ret + @property + def add_child_row_location_rules(self) -> Iterable[str]: + return self.__add_child_row_location_rules.values() + + def add_child_row_location_rule(self, child_table: Union[Self, str]) -> Optional[str]: + if isinstance(child_table, Table): + child_table = child_table.name + return self.__add_child_row_location_rules.get(child_table) + + def add_child_row_location(self, parent_table: Union[Self, str], **kwargs) -> Optional[str]: + ret = self.add_child_row_location_rule(parent_table) + if isinstance(parent_table, str): + parent_table = self.schema[parent_table] + if ret is None: + return None + for cfk in self.foreign_keys_to_parent_table(parent_table): + for fk in cfk: + if fk.parent_column.name in kwargs: + ret = re.sub(f'<{fk.child_column.name}>', quote_plus(quote_plus(str(kwargs[fk.parent_column.name]))), ret) + return ret + @property def primary_keys(self) -> Iterable[str]: if self.__primary_keys is None: @@ -368,7 +421,7 @@ class Table(abc.ABC): # export self.__foreign_keys_to_parent_table[pt] = [] self.__foreign_keys_to_parent_table[pt].append(cfk) parent_table_name = parent_table if isinstance(parent_table, str) else parent_table.name - return self.__foreign_keys_to_parent_table[parent_table_name] + return self.__foreign_keys_to_parent_table[parent_table_name] if parent_table_name in self.__foreign_keys_to_parent_table else [] @property def relationships(self) -> list[tuple[str, Self]]: @@ -382,9 +435,4 @@ class Table(abc.ABC): # export def relationship(self, table: Union[Self, str]) -> bool: if isinstance(table, Table): table = table.name - if self.__relationship_by_foreign_table is None: - ret: dict[str, Self] = dict() - for member_name, table_name in self.relationships: - ret[member_name] = self.schema[table_name] - self.__relationship_by_foreign_table = ret return self.__relationship_by_foreign_table.get(table)