コード例 #1
0
ファイル: constraint.py プロジェクト: valhuber/LogicBank
    def execute(self, logic_row: LogicRow):
        # logic_row.log(f'Constraint BEGIN {str(self)} on {str(logic_row)}')
        if self._function is not None:
            value = self._function(row=logic_row.row,
                                   old_row=logic_row.old_row,
                                   logic_row=logic_row)
        else:
            value = self._as_condition(row=logic_row.row)

        if value:
            pass
        elif not value:
            row = logic_row.row
            msg = eval(f'f"""{self._error_msg}"""')
            from sqlalchemy import exc
            # exception = exc.DBAPIError(msg, None, None)  # 'statement', 'params', and 'orig'
            logic_row.log(f'Constraint Failure: {msg}')
            ll = RuleBank()
            if ll.constraint_event:
                ll.constraint_event(message=msg,
                                    logic_row=logic_row,
                                    constraint=self)
            raise ConstraintException(msg)
        else:
            raise RuntimeError(
                f'Constraint did not return boolean: {str(self)}')
        logic_row.log_engine(f'Constraint END {str(self)} on {str(logic_row)}')
コード例 #2
0
ファイル: copy.py プロジェクト: valhuber/Logic-Bank
    def __init__(self, derive: InstrumentedAttribute, from_parent: any):
        super(Copy, self).__init__(derive)
        if isinstance(from_parent, str):
            names = from_parent.split('.')
            self._from_parent_role = names[0]
            self._from_column = names[1]
        elif isinstance(from_parent, InstrumentedAttribute):
            self._from_column = from_parent.key
            table_class = from_parent.class_
            parent_class_name = self.get_class_name(table_class)
            pass
            attrs = self._derive.parent.attrs
            found_attr = None
            for each_attr in attrs:
                if isinstance(each_attr, RelationshipProperty):
                    each_parent_class_nodal_name = each_attr.entity.class_
                    each_parent_class_name = self.get_class_name(
                        each_parent_class_nodal_name)
                    if each_parent_class_name == parent_class_name:
                        if found_attr is not None:
                            raise Exception(
                                "TODO / copy - disambiguate relationship")
                        found_attr = each_attr
            if found_attr is None:
                raise Exception("Invalid 'as_sum_of' - not a reference to: " +
                                self.table + " in " + self.__str__())
            else:
                self._from_parent_role = found_attr.key

        else:
            pass
        rb = RuleBank()
        rb.deposit_rule(self)
コード例 #3
0
 def __init__(self,
              validate: object,
              error_msg: str = "Missing Parent",
              enable: bool = True):
     super(ParentCheck, self).__init__(validate)
     self._error_msg = error_msg
     self._enable = enable
     ll = RuleBank()
     ll.deposit_rule(self)
コード例 #4
0
ファイル: parent_cascade.py プロジェクト: valhuber/LogicBank
 def __init__(self,
              validate: object,
              error_msg: str = "Unable to delete - existing Child rows",
              relationship: str = "*",
              action: str = 'nullify'):
     super(ParentCascade, self).__init__(validate)
     self._error_msg = error_msg
     if not isinstance(action, ParentCascadeAction):
         raise Exception("Invalid Action: " + str(action))
     self._action = action
     self._relationship = relationship
     ll = RuleBank()
     ll.deposit_rule(self)
コード例 #5
0
def validate(a_session: session, engine: Engine):
    """
    Determine formula execution order based on "row.xx" references,
    (or raise exception if cycles detected).
    """
    list_rules = "\n\nValidate Rule Bank"
    rules_bank = RuleBank()

    for each_key in rules_bank.orm_objects:
        validate_formula_dependencies(class_name=each_key)
    list_rules += rules_bank.__str__()
    print(list_rules)
    return True
コード例 #6
0
ファイル: logic_row.py プロジェクト: valhuber/LogicBank
    def early_row_event_all_classes(self, verb_reason: str):
        """
        if exists: rules_bank._early_row_event_all_classes(self)

        Args:
            verb_reason: debug string (not used)

        Returns:

        """
        rules_bank = RuleBank()
        if rules_bank._early_row_event_all_classes is not None:
            # self.log("early_row_event_all_classes - " + verb_reason)
            rules_bank._early_row_event_all_classes(self)
コード例 #7
0
def setup(a_session: session):
    """
    Create the RuleBank

    Register before_flush listeners

    """
    rules_bank = RuleBank()
    event.listen(a_session, "before_flush", before_flush)
    event.listen(a_session, "before_commit", before_commit)

    rules_bank.orm_objects = {}
    rules_bank._at = datetime.now()
    return rules_bank
コード例 #8
0
    def update_referenced_parent_attributes(self, dependencies: list):
        """
        Used by Formulas and constraints log their dependence on parent attributes
        This sets RuleBank.TableRules[mapped_class].referring_children
        dependencies is a list

        But, can't do this now, because meta_contains_role_name = False
        So, do it on the fly in logic_row (which is an ugh)
        """
        meta_contains_role_name = False
        if meta_contains_role_name is False:
            return
        else:
            meta_data = rule_bank_withdraw.get_meta_data()
            child_meta = meta_data.tables[self.table]
            parent_role_name = dependencies[1]
            foreign_keys = child_meta.foreign_keys
            for each_foreign_key in foreign_keys:  # eg, OrderDetail has OrderHeader, Product
                each_parent_class_name = each_foreign_key.name
                each_parent_role_name = each_foreign_key.key
                if parent_role_name == each_parent_role_name:  # eg, OrderHeader
                    rule_bank = RuleBank()
                    if each_parent_class_name not in rule_bank.orm_objects:
                        self._tables[rule_bank] = TableRules()
                    table_rules = self._tables[rule_bank]
                    if table_rules.referring_children is None:
                        table_rules.referring_children = {}
                    if parent_role_name not in table_rules.referring_children:
                        table_rules.referring_children[parent_role_name] = []
                    table_rules.referring_children.append(dependencies[2])
                    engine_logger.debug(
                        prt("child parent dependency: " + dependencies[1]))
                    break
コード例 #9
0
    def __init__(self, row: base, old_row: base, ins_upd_dlt: str,
                 nest_level: int, a_session: session, row_sets: object):
        """
        Note adds self to row_sets (if supplied), for later commit-phase logic
        """
        self.session = a_session
        self.row = row  # type(base)
        """ mapped row """
        self.old_row = old_row
        """ old mapped row """
        self.ins_upd_dlt = ins_upd_dlt
        self.ins_upd_dlt_initial = ins_upd_dlt  # order inserted, then adjusted
        self.nest_level = nest_level
        self.reason = "?"  # set by insert, update and delete
        """ if starts with cascade, triggers cascade processing """

        self.row_sets = row_sets
        if row_sets is not None:  # eg, for debug as in upd_order_shipped test
            row_sets.add_processed(logic_row=self)

        rb = RuleBank()
        self.rb = rb
        self.session = rb._session
        self.engine = rb._engine
        self.some_base = declarative_base()

        self.name = type(self.row).__name__
        self.table_meta = None
        if self.row is not None:
            self.table_meta = row.metadata.tables[type(self.row).__name__]
        if self.engine is not None:  # e.g, for testing legacy logic (no RuleBank)
            self.inspector = Inspector.from_engine(self.engine)
コード例 #10
0
def aggregate_rules(child_logic_row: LogicRow) -> dict:
    """returns dict(<parent_role_name>, sum/count_rules[] for given child_table_name

    This requires we **invert** the RuleBank,
      to find sums that reference child_table_name, grouped by parent_role
    e.g., for child_logic_row "Order", we return
      ["Order", (Customer.balance, Customer.order_count...)
      ["Employee, (Employee.order_count)]
    """
    result_role_rules_list = {}  # dict of RoleRules

    child_mapper = object_mapper(child_logic_row.row)
    rule_bank = RuleBank()
    relationships = child_mapper.relationships
    for each_relationship in relationships:  # eg, order has parents cust & emp, child orderdetail
        if each_relationship.direction == sqlalchemy.orm.interfaces.MANYTOONE:  # cust, emp
            child_role_name = each_relationship.back_populates  # eg, OrderList
            if child_role_name is None:
                child_role_name = child_mapper.class_.__name__  # default TODO design review
            parent_role_name = each_relationship.key  # eg, Customer TODO design review
            parent_class_name = each_relationship.entity.class_.__name__
            if parent_class_name in rule_bank._tables:
                parent_rules = rule_bank._tables[parent_class_name].rules
                for each_parent_rule in parent_rules:  # (..  bal = sum(OrderList.amount) )
                    if isinstance(each_parent_rule, (Sum, Count)):
                        if each_parent_rule._child_role_name == child_role_name:
                            if parent_role_name not in result_role_rules_list:
                                result_role_rules_list[parent_role_name] = []
                            result_role_rules_list[parent_role_name].append(
                                each_parent_rule)
                            each_parent_rule._parent_role_name = parent_role_name
    return result_role_rules_list
コード例 #11
0
ファイル: logic_row.py プロジェクト: valhuber/LogicBank
    def check_parents_on_update(self):
        """ per ParentCheck rule, verify parents exist.

        If disabled, ignore (with warning).
        """

        list_ref_integ_rules = rule_bank_withdraw.rules_of_class(
            self, ParentCheck)
        if list_ref_integ_rules:
            ref_integ_rule = list_ref_integ_rules[0]
            if ref_integ_rule._enable:
                child_mapper = object_mapper(self.row)
                my_relationships = child_mapper.relationships
                for each_relationship in my_relationships:  # eg, order has parents cust & emp, child orderdetail
                    if each_relationship.direction == sqlalchemy.orm.interfaces.MANYTOONE:  # cust, emp
                        parent_role_name = each_relationship.key  # eg, OrderList
                        if not self.is_foreign_key_null(each_relationship):
                            # continue
                            reason = "Cascading PK change to: " + \
                                     each_relationship.key + "->" + \
                                     each_relationship.back_populates
                            if self.reason == reason:
                                """
                                The parent doing the cascade obviously exists,
                                and note: try to getattr it will fail
                                (FIXME design review - perhaps SQLAlchemy is not checking cache?)
                                """
                                pass
                            else:
                                self.get_parent_logic_row(
                                    parent_role_name)  # sets the accessor
                                does_parent_exist = getattr(
                                    self.row, parent_role_name)
                                if does_parent_exist is None and ref_integ_rule._enable == True:
                                    msg = "Missing Parent: " + parent_role_name
                                    self.log(msg)
                                    ll = RuleBank()
                                    if ll.constraint_event:
                                        ll.constraint_event(message=msg,
                                                            logic_row=self,
                                                            constraint=None)
                                    raise ConstraintException(msg)
                                else:
                                    self.log("Warning: Missing Parent: " +
                                             parent_role_name)
                                    pass  # if you don't care, I don't care
        return self
コード例 #12
0
ファイル: sum.py プロジェクト: valhuber/Logic-Bank
 def __init__(self, derive: InstrumentedAttribute, as_sum_of: any,
              where: any):
     super(Sum, self).__init__(derive=derive, where=where)
     self._as_sum_of = as_sum_of  # could probably super-ize parent accessor
     if isinstance(as_sum_of, str):
         self._child_role_name = self._as_sum_of.split(".")[
             0]  # child role retrieves children
         self._child_summed_field = self._as_sum_of.split(".")[1]
     elif isinstance(as_sum_of, InstrumentedAttribute):
         self._child_summed_field = as_sum_of.key
         child_attrs = as_sum_of.parent.attrs
         self._child_role_name = self.get_child_role_name(
             child_attrs=child_attrs)
     else:
         raise Exception(
             "as_sum_of must be either string, or <mapped-class.column>: " +
             str(as_sum_of))
     rb = RuleBank()
     rb.deposit_rule(self)
コード例 #13
0
def get_formula_rules(class_name: str) -> list:
    """withdraw rules of designated a_class
    """
    rule_bank = RuleBank()
    rules_list = []
    role_rules_list = {}  # dict of RoleRules
    for each_rule in rule_bank._tables[class_name].rules:
        if isinstance(each_rule, Formula):
            rules_list.append(each_rule)
    return rules_list
コード例 #14
0
    def __init__(self, derive: InstrumentedAttribute, as_count_of: object,
                 where: any):
        super(Count, self).__init__(derive=derive, where=where)

        if not isinstance(as_count_of, sqlalchemy.orm.DeclarativeMeta):
            raise Exception("rule definition error, not mapped class: " +
                            str(as_count_of))
        self._as_count_of = as_count_of
        self._as_count_of_class_name = self.get_class_name(as_count_of)
        local_attrs = as_count_of._sa_class_manager.local_attrs  # FIXME design
        for each_local_attr in local_attrs:
            random_attr = local_attrs[each_local_attr]
            child_attrs = random_attr.parent.attrs
            break
        self._child_role_name = self.get_child_role_name(
            child_attrs=child_attrs)

        rb = RuleBank()
        rb.deposit_rule(self)
コード例 #15
0
def compute_formula_execution_order() -> bool:
    """
    Determine formula execution order based on "row.xx" references (dependencies),
    (or raise exception if cycles detected).
    """
    global version
    rules_bank = RuleBank()
    for each_key in rules_bank.orm_objects:
        compute_formula_execution_order_for_class(class_name=each_key)

    logic_logger = logging.getLogger("logic_logger")
    rule_count = 0
    logic_logger.debug(f'\nThe following rules have been activated\n')
    list_rules = rules_bank.__str__()
    loaded_rules = list(list_rules.split("\n"))
    for each_rule in loaded_rules:
        logic_logger.debug(each_rule)
        rule_count += 1
    logic_logger.info(f'Logic Bank {__version__} - {rule_count} rules loaded')
    return True
コード例 #16
0
def generic_rules_of_class(a_class: (Formula, Constraint,
                                     EarlyRowEvent)) -> list:
    """withdraw rules of the "*" (any) class
    """
    rule_bank = RuleBank()
    rules_list = []
    role_rules_list = {}  # dict of RoleRules
    if "*" in rule_bank._tables:
        for each_rule in rule_bank._tables["*"].rules:
            if isinstance(each_rule, a_class):
                rules_list.append(each_rule)
    return rules_list
コード例 #17
0
ファイル: logic_row.py プロジェクト: valhuber/LogicBank
    def load_parents_on_insert(self):
        """ sqlalchemy lazy does not work for inserts... do it here because...
        1. RI would require the sql anyway
        2. Provide a consistent model - your parents are always there for you
            - eg, see add_order event rule - references {sales_rep.Manager.FirstName}
        """

        ref_integ_enabled = True
        list_ref_integ_rules = rule_bank_withdraw.rules_of_class(
            self, ParentCheck)
        if list_ref_integ_rules:
            ref_integ_rule = list_ref_integ_rules[0]

        child_mapper = object_mapper(self.row)
        my_relationships = child_mapper.relationships
        for each_relationship in my_relationships:  # eg, order has parents cust & emp, child orderdetail
            if each_relationship.direction == sqlalchemy.orm.interfaces.MANYTOONE:  # cust, emp
                parent_role_name = each_relationship.key  # eg, OrderList
                if self.is_foreign_key_null(each_relationship) is False:
                    # continue - foreign key not null - parent *should* exist
                    self.get_parent_logic_row(
                        parent_role_name)  # sets the accessor
                    does_parent_exist = getattr(self.row, parent_role_name)
                    if does_parent_exist:
                        pass  # yes, parent exists... it's all fine
                    elif ref_integ_enabled:
                        msg = "Missing Parent: " + parent_role_name
                        self.log(msg)
                        ll = RuleBank()
                        if ll.constraint_event:
                            ll.constraint_event(message=msg,
                                                logic_row=self,
                                                constraint=None)
                        raise ConstraintException(msg)
                    else:
                        self.log("Warning: Missing Parent: " +
                                 parent_role_name)
                        pass  # if you don't care, I don't care
        return self
コード例 #18
0
def copy_rules(logic_row: LogicRow) -> CopyRulesForTable:
    """dict(<role_name>, copy_rules[]
    """
    rule_bank = RuleBank()
    role_rules_list = {}  # dict of RoleRules
    if logic_row.name in rule_bank._tables:
        for each_rule in rule_bank._tables[logic_row.name].rules:
            if isinstance(each_rule, Copy):
                role_name = each_rule._from_parent_role
                if role_name not in role_rules_list:
                    role_rules_list[role_name] = []
                role_rules_list[role_name].append(each_rule)
    return role_rules_list
コード例 #19
0
def rules_of_class(
    logic_row: LogicRow,
    a_class: (Formula, Constraint, EarlyRowEvent)) -> list:
    """withdraw rules of designated a_class
    """
    rule_bank = RuleBank()
    rules_list = []
    role_rules_list = {}  # dict of RoleRules
    if logic_row.name in rule_bank._tables:
        for each_rule in rule_bank._tables[logic_row.name].rules:
            if isinstance(each_rule, a_class):
                rules_list.append(each_rule)
    return rules_list
コード例 #20
0
 def __init__(
         self,
         validate: object,
         error_msg: str,
         calling: Callable = None,
         as_condition: object = None):  # str or lambda boolean expression
     super(Constraint, self).__init__(validate)
     # self.table = validate  # setter finds object
     self._error_msg = error_msg
     self._as_condition = as_condition
     self._calling = calling
     if calling is None and as_condition is None:
         raise Exception(
             f'Constraint {str} requires calling or as_expression')
     if calling is not None and as_condition is not None:
         raise Exception(
             f'Constraint {str} either calling or as_expression')
     if calling is not None:
         self._function = calling
     elif isinstance(as_condition, str):
         self._as_condition = lambda row: eval(as_condition)
     ll = RuleBank()
     ll.deposit_rule(self)
コード例 #21
0
ファイル: formula.py プロジェクト: valhuber/Logic-Bank
    def __init__(self, derive: InstrumentedAttribute,
                 as_exp: str = None,              # for very short expressions
                 as_expression: Callable = None,  # short, with type checking
                 calling: Callable = None         # complex formula
                 ):
        """
        Specify rep
          * as_exp - string (for very short expressions - price * quantity)
          * ex_expression - lambda (for type checking)
          * calling - function (for more complex formula, with old_row)

        """
        super(Formula, self).__init__(derive)

        self._as_exp = as_exp
        self._as_expression = as_expression
        self._function = calling

        self._as_exp_lambda = None   # we exec this, or _function

        valid_count = 0
        if as_exp is not None:
            self._as_exp_lambda = lambda row: eval(as_exp)
            valid_count += 1
        if as_expression is not None:
            self._as_exp_lambda = as_expression
            valid_count += 1
        if calling is not None:
            valid_count += 1
        if valid_count != 1:
            raise Exception(f'Formula requires one of as_exp, as_expression or calling')
        self._dependencies = []
        text = self.get_rule_text()
        self.parse_dependencies(rule_text=text)
        self._exec_order = -1  # will be computed in rule_bank_setup (all rules loaded)
        rb = RuleBank()
        rb.deposit_rule(self)
コード例 #22
0
def setup(a_session: session, an_engine: Engine):
    """
    Initialize the RuleBank

    """
    rules_bank = RuleBank()
    rules_bank._session = a_session
    event.listen(a_session, "before_flush", before_flush)
    event.listen(a_session, "before_commit", before_commit)

    rules_bank.orm_objects = {}
    rules_bank._at = datetime.now()

    rules_bank._engine = an_engine
    rules_bank._metadata = MetaData(bind=an_engine, reflect=True)
    from sqlalchemy.ext.declarative import declarative_base
    rules_bank._base = declarative_base()

    return
コード例 #23
0
def get_referring_children(parent_logic_row: LogicRow) -> dict:
    """
    return RulesBank[class_name].referring_children (create if None)
    referring_children is <parent_role_name>, parent_attribute_list()
    """
    rule_bank = RuleBank()
    if parent_logic_row.name not in rule_bank._tables:
        return {}
    else:
        # sigh, best to have built this in rule_bank_setup, but unable to get mapper
        # FIXME design is this threadsafe?
        table_rules = rule_bank._tables[parent_logic_row.name]
        result = table_rules.referring_children
        table_rules.referring_children = {}
        parent_mapper = object_mapper(parent_logic_row.row)
        parent_relationships = parent_mapper.relationships
        for each_parent_relationship in parent_relationships:  # eg, order has parents cust & emp, child orderdetail
            if each_parent_relationship.direction == sqlalchemy.orm.interfaces.ONETOMANY:  # cust, emp
                parent_role_name = each_parent_relationship.back_populates  # eg, OrderList
                table_rules.referring_children[parent_role_name] = []
                child_role_name = each_parent_relationship.key
                child_class_name = get_child_class_name(
                    each_parent_relationship)  # eg, OrderDetail
                if child_class_name not in rule_bank._tables:
                    pass  # eg, banking - ALERT is child of customer, has no rules, that's ok
                else:
                    child_table_rules = rule_bank._tables[
                        child_class_name].rules
                    search_for_rew_parent = "row." + parent_role_name
                    for each_rule in child_table_rules:
                        if isinstance(
                                each_rule,
                            (Formula,
                             Constraint)):  # eg, OrderDetail.ShippedDate
                            rule_text = each_rule.get_rule_text(
                            )  #        eg, row.OrderHeader.ShippedDate
                            rule_words = rule_text.split()
                            for each_word in rule_words:
                                if each_word.startswith(search_for_rew_parent):
                                    rule_terms = each_word.split(".")
                                    # if parent_role_name not in table_rules.referring_children:
                                    #    table_rules.referring_children[parent_role_name] = ()
                                    table_rules.referring_children[
                                        parent_role_name].append(rule_terms[2])
        return table_rules.referring_children
コード例 #24
0
def setup_early_row_event_all_classes(early_row_event_all_classes: callable):
    ll = RuleBank()
    ll._early_row_event_all_classes = early_row_event_all_classes
コード例 #25
0
ファイル: constraint.py プロジェクト: valhuber/LogicBank
 def __init__(
     self,
     validate: object,
     error_msg: str,
     calling: Callable = None,
     as_condition: object = None,  # str or lambda boolean expression
     error_attributes: Sequence[InstrumentedAttribute] = None):
     super(Constraint, self).__init__(validate)
     # self.table = validate  # setter finds object
     self._error_msg = error_msg
     self._as_condition = as_condition
     self._calling = calling
     self.error_attributes = error_attributes
     if calling is None and as_condition is None:
         msg = "Constraint " + str + " requires calling or as_expression"
         ll = RuleBank()
         if ll.constraint_event:
             ll.constraint_event(message=msg,
                                 logic_row=None,
                                 constraint=None)
         raise ConstraintException(msg)
     if calling is not None and as_condition is not None:
         msg = "Constraint " + str + " either calling or as_expression"
         ll = RuleBank()
         if ll.constraint_event:
             ll.constraint_event(message=msg,
                                 logic_row=None,
                                 constraint=None)
         raise ConstraintException(msg)
     if calling is not None:
         self._function = calling
     elif isinstance(as_condition, str):
         self._as_condition = lambda row: eval(as_condition)
     ll = RuleBank()
     ll.deposit_rule(self)
コード例 #26
0
ファイル: row_event.py プロジェクト: valhuber/Logic-Bank
 def __init__(self, on_class: object,
              calling: Callable = None):
     super(AbstractRowEvent, self).__init__(on_class)
     self._function = calling
     ll = RuleBank()
     ll.deposit_rule(self)
コード例 #27
0
ファイル: logic_row.py プロジェクト: valhuber/LogicBank
    def cascade_delete_children(self):
        """
        This recursive descent is required to adjust dependent sums/counts on passive_deletes; ie,

        when (and only when) the DBMS - and *not* SQLAlchemy - does the deletes.

        (When SQLAlchemy does deletes, these are queued through the normal delete logic.)
        @see nw/tests/test_dlt_order.py
        """

        parent_mapper = object_mapper(self.row)
        my_relationships = parent_mapper.relationships
        for each_relationship in my_relationships:  # eg, cust has child OrderDetail
            if each_relationship.direction == sqlalchemy.orm.interfaces.ONETOMANY:  # eg, OrderDetail
                child_role_name = each_relationship.key  # eg, OrderList
                if each_relationship.cascade.delete and each_relationship.passive_deletes:
                    child_rows = getattr(self.row, child_role_name)
                    for each_child_row in child_rows:
                        old_child = self.make_copy(each_child_row)
                        each_child_logic_row = LogicRow(row=each_child_row,
                                                        old_row=old_child,
                                                        ins_upd_dlt="dlt",
                                                        nest_level=1 +
                                                        self.nest_level,
                                                        a_session=self.session,
                                                        row_sets=self.row_sets)
                        each_child_logic_row.delete(
                            reason="Cascade Delete to run rules on - " +
                            child_role_name)
                        self.session.delete(
                            each_child_row
                        )  # deletes in beforeFlush are not re-queued
        enforce_cascade = False
        if enforce_cascade:  # disabled - SQLAlchemy DOES enforce cascade delete/nullify; prevent way less important
            """
            per parent_cascade rule(s), nullify (child FKs), delete (children), prevent (if children exist)

            Default is ParentCascadeAction.PREVENT.

            This recursive descent is required to adjust dependent sums/counts.
            """
            list_parent_cascade_rules = rule_bank_withdraw.rules_of_class(
                self, ParentCascade)
            defined_relns = {}
            for each_parent_cascade_rule in list_parent_cascade_rules:
                defined_relns[each_parent_cascade_rule.
                              _relationship] = each_parent_cascade_rule
            for each_relationship in my_relationships:  # eg, Order has child OrderDetail
                if each_relationship.direction == sqlalchemy.orm.interfaces.ONETOMANY:  # eg, OrderDetail
                    each_child_role_name = each_relationship.key  # eg, OrderDetailList
                    refinteg_action = ParentCascadeAction.PREVENT
                    if each_child_role_name in defined_relns:
                        refinteg_action = defined_relns[
                            each_child_role_name]._action
                    child_rows = getattr(self.row, each_child_role_name)
                    for each_child_row in child_rows:
                        old_child = self.make_copy(each_child_row)
                        each_child_logic_row = LogicRow(row=each_child_row,
                                                        old_row=old_child,
                                                        ins_upd_dlt="dlt",
                                                        nest_level=1 +
                                                        self.nest_level,
                                                        a_session=self.session,
                                                        row_sets=self.row_sets)

                        if refinteg_action == ParentCascadeAction.DELETE:  # each_relationship.cascade.delete:
                            each_child_logic_row.delete(
                                reason="Cascade Delete - " +
                                each_child_role_name)

                        elif refinteg_action == ParentCascadeAction.NULLIFY:
                            for p, c in each_relationship.local_remote_pairs:
                                setattr(each_child_row, c.name, None)
                            each_child_logic_row.update(
                                reason="Cascade Nullify - " +
                                each_child_role_name)

                        elif refinteg_action == ParentCascadeAction.PREVENT:
                            msg = "Delete rejected - " + each_child_role_name + " has rows"
                            ll = RuleBank()
                            if ll.constraint_event:
                                ll.constraint_event(message=msg,
                                                    logic_row=self,
                                                    constraint=None)
                            raise ConstraintException(msg)
                        else:
                            raise Exception("Invalid parent_cascade action: " +
                                            refinteg_action)
コード例 #28
0
def get_session():
    rule_bank = RuleBank()
    return rule_bank._session
コード例 #29
0
def get_meta_data():
    rule_bank = RuleBank()
    return rule_bank._metadata