| 596 | | <p></p> |
|---|
| | 597 | <p>Once you've created and associated your Unit classes, you can begin to |
|---|
| | 598 | write "business logic" code (mostly inside those classes, we hope), and |
|---|
| | 599 | "presentation logic" code (mostly outside those classes). In most cases, |
|---|
| | 600 | you will construct Expressions within your own code manually to retrieve |
|---|
| | 601 | Units. Sometimes, however, you need to persist query parameters from your |
|---|
| | 602 | users; in other cases, you might store a list of Units which match a query |
|---|
| | 603 | (regardless of who formed the necessary Expression). Finally, you might |
|---|
| | 604 | wish to manipulate lists of Units as sets: differences, intersections, |
|---|
| | 605 | and unions. The <tt>engines</tt> module addresses all of these needs.</p> |
|---|
| | 606 | |
|---|
| | 607 | <h4>Collections: Lists of Units</h4> |
|---|
| | 608 | <p>The <tt>UnitCollection</tt> class provides a means of storing a list |
|---|
| | 609 | of Units, or rather, a list of Unit ID's. You use its <tt>Type</tt> |
|---|
| | 610 | property to indicate the class of the indexed Units. That value should be |
|---|
| | 611 | the <b>name</b> of the Unit Class, <b>not</b> the class object itself |
|---|
| | 612 | (this is different than most other calls in Dejavu). If you need to |
|---|
| | 613 | retrieve the actual Unit class, call <tt>UnitCollection().unit_class()</tt>.</p> |
|---|
| | 614 | |
|---|
| | 615 | <p><tt>UnitCollection</tt> itself subclasses <tt>dejavu.Unit</tt>; you can |
|---|
| | 616 | therefore persist Unit Collections via Dejavu Storage Managers (most SM's, |
|---|
| | 617 | anyway; it's recommended that SM's handle Unit Collections, but not |
|---|
| | 618 | required. Check your SM to see if it does).</p> |
|---|
| | 619 | |
|---|
| | 620 | <p>Each Collection has a thread lock (an RLock, actually) which you should |
|---|
| | 621 | <tt>acquire()</tt> before you add an ID to the set, and <tt>release()</tt> |
|---|
| | 622 | afterward. If you use the <tt>add(ID)</tt> method, this locking is done |
|---|
| | 623 | for you.</p> |
|---|
| | 624 | |
|---|
| | 625 | <p>When you need to retrieve the actual Units which are indexed by the |
|---|
| | 626 | Collection, call the <tt>units(quota=None)</tt> method, which will |
|---|
| | 627 | look up the Units and return them in a list. Since the Collection only |
|---|
| | 628 | stores ID's, it is possible that one of the indexed Units may have been |
|---|
| | 629 | destroyed since the list was built. The <tt>units</tt> method simply |
|---|
| | 630 | passes over these "phantom" Units. You can inspect the full list of IDs |
|---|
| | 631 | in the Collection (whether they reference existing Units or not) with |
|---|
| | 632 | the <tt>ids()</tt> method.</p> |
|---|
| | 633 | |
|---|
| | 634 | <p>Collections also provide a convenience function for grouping Units |
|---|
| | 635 | by attribute: <tt>xdict(attr)</tt>. This function will look up each Unit |
|---|
| | 636 | in the Collection, inspect the attribute that you specify, and return |
|---|
| | 637 | a dictionary of the form <tt>{attr_val1: [Unit, Unit, ...]}</tt>. |
|---|
| | 638 | Each distinct attribute value will have its own key, with a list of |
|---|
| | 639 | matching Units as the value.</p> |
|---|
| | 640 | |
|---|
| | 641 | <h4>Engines</h4> |
|---|
| | 642 | <p>You can form Collections by hand, but a more powerful technique is |
|---|
| | 643 | the <tt>UnitEngine</tt>, a factory for Collections. Engines are very |
|---|
| | 644 | simple: they possess a set of <i>rules</i> which are executed when |
|---|
| | 645 | you want to take a <i>snapshot</i> of Units. The snapshot which is |
|---|
| | 646 | produced is a <tt>UnitCollection</tt> object. Whenever you call |
|---|
| | 647 | <tt>take_snapshot()</tt>, the Engine will maintain an association |
|---|
| | 648 | to the resulting Collection. You can access past snapshots with the |
|---|
| | 649 | <tt>snapshots()</tt> method.</p> |
|---|
| | 650 | |
|---|
| | 651 | <p>Engines are themselves Units, and can be persisted via Storage Managers. |
|---|
| | 652 | The only properties they possess are: an <tt>ID</tt>, a <tt>Name</tt>, |
|---|
| | 653 | an <tt>Owner</tt>, a <tt>FinalClassName</tt>, and <tt>Created</tt>, |
|---|
| | 654 | the creation date of the Engine.</p> |
|---|
| | 655 | |
|---|
| | 656 | <p>The <tt>Owner</tt> property should either be a user name, or one of the |
|---|
| | 657 | reserved names: "Public" and "System". By default, the <tt>permit()</tt> |
|---|
| | 658 | method allows a user read-access to the Engine if they are the Owner, or |
|---|
| | 659 | the Owner is "Public" or "System". Write-access is permitted if the user |
|---|
| | 660 | is the Owner, or the Owner is "Public". Feel free to override |
|---|
| | 661 | <tt>permit()</tt> in a subclass to provide different behaviors.</p> |
|---|
| | 662 | |
|---|
| | 663 | <p>The <tt>FinalClassName</tt> is set for you as you add Rules to the |
|---|
| | 664 | Engine. You can use the value of this property, for example, to tell |
|---|
| | 665 | your users, "Engine #23569 is an 'Armadillo' engine," when it produces |
|---|
| | 666 | Collections of <tt>Armadillo</tt> Units. The only time you might want to |
|---|
| | 667 | set this value is when you first create the Engine, before you have added |
|---|
| | 668 | any Rules.</p> |
|---|
| | 669 | |
|---|
| | 670 | <h4>Rules</h4> |
|---|
| | 671 | <p>Just like Collections and Engines, <tt>UnitEngineRule</tt> is <i>also</i> |
|---|
| | 672 | a subclass of <tt>Unit</tt>, and can be persisted via Storage Managers. All |
|---|
| | 673 | three work together to provide a complete, dynamic, application-level query |
|---|
| | 674 | generator.</p> |
|---|
| | 675 | |
|---|
| | 676 | <p>Okay, so what are Rules? You might say they're a "little language", |
|---|
| | 677 | with the following primitives, or "operations":</p> |
|---|
| | 678 | <table> |
|---|
| | 679 | <tr><th>Operation</th><th>Operand(s)</th><th>Description</th></tr> |
|---|
| | 680 | <tr><th colspan='3'>Operations on a single set</th></tr> |
|---|
| | 681 | <tr> |
|---|
| | 682 | <td>CREATE</td> |
|---|
| | 683 | <td>The classname of the new Type</td> |
|---|
| | 684 | <td>Creates a new Set of the specified Type. All Units of that Type |
|---|
| | 685 | are included in the new Set.</td> |
|---|
| | 686 | </tr> |
|---|
| | 687 | <tr> |
|---|
| | 688 | <td>FILTER</td> |
|---|
| | 689 | <td>A <tt>logic.Expression</tt></td> |
|---|
| | 690 | <td>Removes Units from the current Set which do not match the |
|---|
| | 691 | Expression.</td> |
|---|
| | 692 | </tr> |
|---|
| | 693 | <tr> |
|---|
| | 694 | <td>FUNCTION</td> |
|---|
| | 695 | <td>The name of a function in the <tt>Arena.engine_functions</tt> |
|---|
| | 696 | dict</td> |
|---|
| | 697 | <td>Calls the function, passing the current Set. The function |
|---|
| | 698 | should modify the Set.</td> |
|---|
| | 699 | </tr> |
|---|
| | 700 | <tr> |
|---|
| | 701 | <td>TRANSFORM</td> |
|---|
| | 702 | <td>The classname of the new Type</td> |
|---|
| | 703 | <td>Transform the current Set into a Set of associated Units |
|---|
| | 704 | (of another Type). The association must be present in the |
|---|
| | 705 | <tt>Arena.associations</tt> graph.</td> |
|---|
| | 706 | </tr> |
|---|
| | 707 | <tr> |
|---|
| | 708 | <td>RETURN</td> |
|---|
| | 709 | <td></td> |
|---|
| | 710 | <td>Optional. If omitted, the last Set handled is returned as the |
|---|
| | 711 | snapshot. If supplied, the ID of the Set to return.</td> |
|---|
| | 712 | </tr> |
|---|
| | 713 | <tr><th colspan='3'>Operations on two sets</th></tr> |
|---|
| | 714 | <tr> |
|---|
| | 715 | <td>COPY</td> |
|---|
| | 716 | <td>The Set ID of the new Set</td> |
|---|
| | 717 | <td>Copies the current Set to a new Set. The current Set is unchanged.</td> |
|---|
| | 718 | </tr> |
|---|
| | 719 | <tr> |
|---|
| | 720 | <td>DIFFERENCE</td> |
|---|
| | 721 | <td>The ID of the Set to mix in</td> |
|---|
| | 722 | <td>Removes IDs from the current Set which exist in the second Set.</td> |
|---|
| | 723 | </tr> |
|---|
| | 724 | <tr> |
|---|
| | 725 | <td>INTERSECTION</td> |
|---|
| | 726 | <td>The ID of the Set to mix in</td> |
|---|
| | 727 | <td>Removes IDs from the current Set which <i>do not</i> exist in the |
|---|
| | 728 | second Set.</td> |
|---|
| | 729 | </tr> |
|---|
| | 730 | <tr> |
|---|
| | 731 | <td>UNION</td> |
|---|
| | 732 | <td>The ID of the Set to mix in</td> |
|---|
| | 733 | <td>Adds any IDs to the current Set which exist in the second Set.</td> |
|---|
| | 734 | </tr> |
|---|
| | 735 | </table> |
|---|
| | 736 | |
|---|
| | 737 | <p>Each Rule has an <tt>Operation</tt> property (a string, one of the above), |
|---|
| | 738 | a <tt>SetID</tt>, and an <tt>Operand</tt>.</p> |
|---|