Contact: fumanchu@aminus.org

Log in as guest/dejavu to create tickets

I think I've seen this ORM somewhere before...

Changeset 120

Show
Ignore:
Timestamp:
12/08/05 11:30:24
Author:
fumanchu
Message:

Sandbox.multirecall has now been folded into Sandbox.xrecall (and therefore into Sandbox.recall). Storage Managers still have a separate multirecall method.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/arenas.py

    r119 r120  
    233233        unit.sandbox = None 
    234234     
    235     def xrecall(self, cls, expr=None): 
     235    def xrecall(self, classes, expr=None): 
    236236        """Iterator over units of cls which match expr.""" 
    237          
     237        if classes.__class__.__name__ == "UnitJoin": 
     238            for unitrow in self.xmulti(classes, expr): 
     239                yield unitrow 
     240            return 
     241         
     242        cls = classes 
    238243        self.arena.log("RECALL %s: %s" % (cls.__name__, expr), LOGRECALL) 
    239244         
     
    275280                    yield unit 
    276281     
    277     def recall(self, cls, expr=None): 
     282    def recall(self, classes, expr=None): 
    278283        """List of units of class 'cls' which match expr.""" 
    279         return [x for x in self.xrecall(cls, expr)] 
    280      
    281     def multirecall(self, classes, expr=None): 
    282         """multirecall(classes, expr) -> [[unit, ...], [unit, ...], ...] 
     284        return [x for x in self.xrecall(classes, expr)] 
     285     
     286    def xmulti(self, classes, expr=None): 
     287        """xmulti(classes, expr) -> [[unit, ...], [unit, ...], ...] 
    283288        Recall units of each cls if they together match the expr. 
    284          
    285         Units of each additional cls pair will be recalled; however, only 
    286         those Units with associations to Units in the previous set will be 
    287         returned. For you database guys, it's a set of inner joins, each of 
    288         which is between each class and its direct antecedent in the list. 
    289289         
    290290        Each yielded value will be a list of Units, in the same order as 
     
    292292        code like: 
    293293         
    294         for invoice, price in sandbox.multirecall([Invoice, Price], f): 
     294        for invoice, price in sandbox.xmulti(Invoice & Price, f): 
    295295            deal_with(invoice) 
    296296            deal_with(price) 
  • trunk/doc/advanced.html

    r119 r120  
    133133        </li> 
    134134    <li><tt>multirecall(self, classes, expr):</tt> Recommended. 
     135        The 'classes' argument will be a UnitJoin and its children. 
    135136        This method must return an iterable of lists; each item in each list 
    136         will be a Unit. The Units must be of the supplied classes, in order, 
    137         and must all match Expression(*resultset) together. 
     137        will be a Unit. The Units must be of the supplied classes, in order 
     138        (see the UnitJoin.classes method), and must all match 
     139        expr(*resultset) together. 
    138140        </li> 
    139141</ul> 
  • trunk/doc/modeling.html

    r119 r120  
    323323cache.</p> 
    324324 
     325<h5>Recalling multiple classes at once (JOINs)</h5> 
     326 
     327<p>In addition to providing a single class to <tt>recall</tt>, you have 
     328the option of providing a tree of classes, a nested set of 
     329<tt class='def'>UnitJoin(class1, class2, leftbiased=None)</tt> 
     330instances.</p> 
     331 
     332 
     333<p>The "leftbiased" argument specifies how the results will be 
     334joined:</p> 
     335 
     336<table> 
     337<tr><th>leftbiased</th><th>Join Type</th><th>Description</th><th>Operator</th></tr> 
     338<tr> 
     339    <td>None</td> 
     340    <td>Inner Join</td> 
     341    <td>All related pairs of both classes will be returned.</td> 
     342    <td><tt>&</tt> or <tt>+</tt></td> 
     343</tr> 
     344<tr> 
     345    <td>True</td> 
     346    <td>Left Join</td> 
     347    <td>All related pairs of both classes will be returned. In addition, 
     348        if any Unit in class1 has no match in class2, we return a single 
     349        row with Unit1 and a "null Unit" (a Unit, all of whose properties 
     350        are None).</td> 
     351    <td><tt>&lt;&lt;</tt></td> 
     352</tr> 
     353<tr> 
     354    <td>False</td> 
     355    <td>Right Join</td> 
     356    <td>All related pairs of both classes will be returned. In addition, 
     357        if any Unit in class2 has no match in class1, we return a single 
     358        row with a "null Unit" (a Unit, all of whose properties are None) 
     359        and Unit2.</td> 
     360    <td><tt>&gt;&gt;</tt></td> 
     361</tr> 
     362</table> 
     363 
     364<p>Look hard? Fear not. There's a <b>much</b> easier way to join units than 
     365writing a big tree of UnitJoins. Use the &amp;, &lt;&lt;, and &gt;&gt; 
     366operators directly with Unit classes:</p> 
     367 
     368<pre>tree = (Book &lt;&lt; Publisher) & Author</pre> 
     369 
     370<p>This example will automatically produce a UnitJoin tree for you, 
     371with Book 'left joined' to Publisher, and then 'inner joined' to 
     372Author.</p> 
     373 
     374<p>When you provide multiple classes, the <tt>recall</tt> method returns 
     375a list of rows. Each row will be a list of units, one per class in the 
     376<tt>classes</tt> arg. The <tt>expr</tt> arg should be a 
     377<tt>logic.Expression</tt> which can evaluate all of the 
     378units in any given row at once. 
     379 
     380<pre>pubs = box.recall(Publisher & Book, 
     381                  logic.Expression(lambda p, b: p.ID == 4))</pre> 
     382 
     383This example will retrieve a series of [Publisher, Book] pairs. 
     384Note that all three constructs (the UnitJoins, the lambda, and 
     385the resulting rows) have the same classes listed in order from 
     386left to right.</p> 
     387 
     388<p>In database terminology, this technique performs a series of joins 
     389between each pair of classes in your UnitJoin tree. However, repeated units 
     390in the results will reference the same object; in the example above, each 
     391Publisher unit will be the same object, since we limited that expression to 
     392a single Publisher. So we might examine multiple rows in the "pubs" list, 
     393but the first unit in each row will be the same unit instance.</p> 
     394 
     395<p>The relationships (joins) between each class are specified by 
     396Unit Associations (see <a href='#associations'>below</a>).</p> 
     397 
    325398<h5>xrecall()</h5> 
    326399<p>Just like recall, but returns an iterator instead of a list. Use xrecall 
     
    341414If multiple Units match the criteria, only the first one is returned 
    342415(although the rest are probably loaded into memory).</p> 
    343  
    344 <h5>multirecall()</h5> 
    345 <p>The <tt class='def'>multirecall(classes, expr)</tt> method yields 
    346 a series of unitsets. Each unitset will be a list of units, one per 
    347 class in the <tt>classes</tt> arg. The <tt>expr</tt> arg should be a 
    348 <tt>logic.Expression</tt> which can evaluate all of the units in 
    349 any given unitset at once. 
    350 <pre>pubs = box.multirecall((Publisher, Book), 
    351                        logic.Expression(lambda p, b: p.ID == 4))</pre> 
    352 This example will retrieve a series of (Publisher, Book) pairs.</p> 
    353  
    354 <p>In database terminology, the multirecall method performs a series of 
    355 full inner joins between each class and its neighbor. That is, class 1 
    356 is joined to class 2, then class 2 is joined to class 3, etcetera. 
    357 Since each join is an inner join, the result set is guaranteed 
    358 to contain a complete set of units for each iteration; however, repeated 
    359 units will reference the same object; in the example above, each Publisher 
    360 unit will be the same object, since we limited that expression to a single 
    361 Publisher. So we might iterate over "pubs" multiple times, but each time, 
    362 the first unit in the set will be the same unit instance.</p> 
    363  
    364 <p>The relationships (joins) between each class are specified by 
    365 Unit Associations (see <a href='#associations'>below</a>).</p> 
    366416 
    367417<h4>Forgetting and Repressing</h4> 
  • trunk/test/zoo_fixture.py

    r119 r120  
    441441         
    442442        f = logic.Expression(lambda z, a: z.Name == 'San Diego Zoo') 
    443         zooed_animals = [(z, a) for z, a in 
    444                          box.multirecall(Zoo & Animal, f)] 
     443        zooed_animals = box.recall(Zoo & Animal, f) 
    445444        self.assertEqual(len(zooed_animals), 2) 
    446445         
     
    458457        sdexpr = logic.filter(Name='San Diego Zoo') 
    459458        leo = logic.Expression(lambda z, a: a.Species == 'Leopard') 
    460         zooed_animals = [(z, a) for z, a in 
    461                          box.multirecall(Zoo & Animal, sdexpr + leo)] 
     459        zooed_animals = box.recall(Zoo & Animal, sdexpr + leo) 
    462460        self.assertEqual(len(zooed_animals), 0) 
    463461         
    464462        # Now try the same expr with INNER, LEFT, and RIGHT JOINs. 
    465         zooed_animals = list(box.multirecall(Zoo & Animal)
     463        zooed_animals = box.recall(Zoo & Animal
    466464        self.assertEqual(len(zooed_animals), 6) 
    467465        self.assertEqual(set([(z.Name, a.Species) for z, a in zooed_animals]), 
     
    473471                              ("Sea_World", "Adelie Penguin")])) 
    474472         
    475         zooed_animals = list(box.multirecall(Zoo >> Animal)
     473        zooed_animals = box.recall(Zoo >> Animal
    476474        self.assertEqual(len(zooed_animals), 12) 
    477475        self.assertEqual(set([(z.Name, a.Species) for z, a in zooed_animals]), 
     
    490488                              ])) 
    491489         
    492         zooed_animals = list(box.multirecall(Zoo << Animal)
     490        zooed_animals = box.recall(Zoo << Animal
    493491        self.assertEqual(len(zooed_animals), 7) 
    494492        self.assertEqual(set([(z.Name, a.Species) for z, a in zooed_animals]), 
     
    504502        # Try a multiple-arg expression 
    505503        f = logic.Expression(lambda a, z: a.Legs >= 4 and z.Admission < 10) 
    506         animal_zoos = [(a, z) for a, z in box.multirecall(Animal & Zoo, f)] 
     504        animal_zoos = box.recall(Animal & Zoo, f) 
    507505        self.assertEqual(len(animal_zoos), 4) 
    508506        names = [a.Species for a, z in animal_zoos] 
     
    513511        tree = (Animal >> Zoo) >> Vet 
    514512        f = logic.Expression(lambda a, z, v: z.Name == 'Sea_World') 
    515         azv = list(box.multirecall(tree, f)) 
    516         self.assertEqual(len(azv), 2) 
     513        self.assertEqual(len(box.recall(tree, f)), 2) 
    517514         
    518515        # MSAccess can't handle an INNER JOIN nested in an OUTER JOIN. 
     
    530527        def set_azv(): 
    531528            f = logic.Expression(lambda a, z, v: z.Name == 'Sea_World') 
    532             azv.append([(a, z, v) for a, z, v in 
    533                         box.multirecall(trees[0], f)]) 
     529            azv.append(box.recall(trees[0], f)) 
    534530         
    535531        smname = arena.stores['testSM'].__class__.__name__