1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
Collection
==========
The Collection class is a generic base for the Collection pattern: you
can have a Collection of branches, a Collection of translation templates
and so on. This is a more flexible and generic version of Sets and
Subsets.
The base Collection class is a very thin wrapper around Storm. You use
it by deriving your own collection type from it. In this example, we
look at collections of Kumquats.
Kumquats are very simple things. All they have is a key to identify
them.
>>> from storm.locals import Count, Int, Storm
>>> from lp.services.webapp.interfaces import (
... IStoreSelector, MAIN_STORE, MASTER_FLAVOR)
>>> store = getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR)
>>> ok = store.execute("CREATE TEMP TABLE Kumquat(id integer UNIQUE)")
>>> class Kumquat(Storm):
... __storm_table__ = 'Kumquat'
... id = Int(primary=True)
... def __init__(self, id):
... self.id = id
... def __repr__(self):
... return "Kumquat-%d" % self.id
>>> obj = store.add(Kumquat(1))
>>> obj = store.add(Kumquat(2))
A custom KumquatCollection class derives from Collection. The
starting_table attribute tells Collection what it is a collection of.
>>> from lp.services.database.collection import Collection
>>> class KumquatCollection(Collection):
... starting_table = Kumquat
The collection starts out "containing" all kumquats. Nothing is queried
yet until you invoke the "select" method, which returns a Storm result
set.
>>> collection = KumquatCollection()
>>> print list(collection.select().order_by(Kumquat.id))
[Kumquat-1, Kumquat-2]
Actually, select() is just shorthand for select(Kumquat).
>>> print list(collection.select(Kumquat).order_by(Kumquat.id))
[Kumquat-1, Kumquat-2]
You can also query individual columns.
>>> list(collection.select(Kumquat.id).order_by(Kumquat.id))
[1, 2]
Since the select method returns a result set, you can even use aggregate
functions.
>>> [int(count) for count in collection.select(Count())]
[2]
You can refine the matching conditions using the refine method.
Collections are immutable, so all refinements create modified copies of
the original.
>>> one = collection.refine(Kumquat.id == 1)
>>> list(one.select(Kumquat.id))
[1]
You can join in arbitrary other classes, such as Guava.
>>> ok = store.execute("CREATE TEMP TABLE Guava(id integer UNIQUE)")
>>> class Guava(Storm):
... __storm_table__ = 'Guava'
... id = Int(primary=True)
... def __init__(self, id):
... self.id = id
... def __repr__(self):
... return "Guava-%d" % self.id
>>> obj = store.add(Guava(1))
>>> obj = store.add(Guava(3))
>>> join = collection.joinInner(Guava, Guava.id == Kumquat.id)
This includes the ability to return multiple values from the join.
>>> list(join.select(Kumquat, Guava))
[(Kumquat-1, Guava-1)]
Outer joins work in the same way.
>>> join = collection.joinOuter(Guava, Guava.id == Kumquat.id)
>>> list(join.select(Kumquat, Guava).order_by(Kumquat.id))
[(Kumquat-1, Guava-1), (Kumquat-2, None)]
|