-
Notifications
You must be signed in to change notification settings - Fork 8
Managing Rules
Rules are Declarative. It's important to review that link, and consider the guidelines on this page.
It's well to start off by remembering things you don't do with rules:
- Order - unlike code where order is critical, rule execution is via system-discovered dependencies. When you change the logic, the execution order changes accordingly. This means you just add rules without worrying about ordering.
- Call - you don't call the rules, the rule engine does. This means your logic always runs.
- Optimize - SQLs are pruned and optimized for you (e.g., adjustments)
New users will recognize Event rules immediately - they are a familiar metaphor (triggers etc). And you will certainly use them.
But rules are much more efficient of your time, so it pays - a lot - to spend the design time to search for a rule solution before you jump into code. It's a higher level of abstraction, where you focus on what, not how:
Rules are like spreadsheet formulas:
automatically reactive to changes in referenced values
automatically chained
Begin by stating the requirement, e.g., Check Credit
. Then, define
rules that implement the requirement.
Rules are about the data, so it's useful to superimpose the rules on a database diagram:
The simplest way to discover rules is using your IDE, as described in the Logic Bank Tutorial.
Or, review the Rule-Summary.
Rules depend on database design, so these concepts below are crucial.
SQLAlchemy depends on model files. If you have an existing database, as described here.
Normalize your database design as usual.
That said, you can get sometimes-enormous performance gains by introducing performance denormalizations for sum / count aggregates. Many of the examples use stored aggregates, but it's a choice: you can alter the stored / non-stored design without affecting your logic or your apps; see Denormalizations.
The interesting rules (sums, counts, parent references) depend on relationships. It's great to have these in the database, but if that's not possible, you can still define them in SQLAlchemy:
# from examples/nw/db/models.py, for Customer...
OrderList = relationship("Order",
backref="Customer",
cascade="all, delete",
passive_deletes=True, # means database RI will do the deleting
cascade_backrefs=True)
Enforce Referential Integrity (RI) with support from the DBMS, SQLAlchemy and Logic Bank. For more information, see Referential Integrity.
A typical approach for extensibility is to define columns as rows, e.g., each column is a child row:
primary-key | col-name | value
Such columns are not visible to SQLAlchemy, or Logic Bank.
Rules are a different paradigm than code, and there are important patterns in their use.
While most of the examples focus multi-field / multi-table, it's a great idea to start simple with single-field constraints. And don't forget - constraints invoke standard Python, so you're fully enabled to utilize all the existing libraries for credit checks, etc.
Another piece of low-hanging fruit is referential integrity. If you are unable to enforce it in your database (e.g., no schema access), you can use Logic Bank - check out Referential Integrity Support.
You often define aggregates to test them in constraints.
You may even do it when the aggregate value is not
of direct business interest.
The Check Credit
illustrates this pattern (Customer.Balance
) is
the derived result.
Counts are useful since 0 means there are no children. See Orders for Commissioned Employees Only.
The oldRow
is provided so you can see
whether (or how much) a value changed.
See our favorite example: Sufficient Raise.
Logic includes Python, not just Rules. You can set breakpoints and step in Python code, as usual.
Rule Logging can reduce the need for tedious debug sessions.
User Project Operations
Logic Bank Internals