summaryrefslogtreecommitdiff
path: root/examples/beaker_caching/advanced.py
diff options
context:
space:
mode:
Diffstat (limited to 'examples/beaker_caching/advanced.py')
-rw-r--r--examples/beaker_caching/advanced.py79
1 files changed, 79 insertions, 0 deletions
diff --git a/examples/beaker_caching/advanced.py b/examples/beaker_caching/advanced.py
new file mode 100644
index 000000000..6a8db082c
--- /dev/null
+++ b/examples/beaker_caching/advanced.py
@@ -0,0 +1,79 @@
+"""advanced.py
+
+Illustrate usage of Query combined with the FromCache option,
+including front-end loading, cache invalidation, namespace techniques
+and collection caching.
+
+"""
+
+import __init__ # if running as a script
+from model import Person, Address, cache_address_bits
+from meta import Session, FromCache
+from sqlalchemy.orm import eagerload
+
+def load_name_range(start, end, invalidate=False):
+ """Load Person objects on a range of names.
+
+ start/end are integers, range is then
+ "person <start>" - "person <end>".
+
+ The cache option we set up is called "name_range", indicating
+ a range of names for the Person class.
+
+ The `Person.addresses` collections are also cached. Its basically
+ another level of tuning here, as that particular cache option
+ can be transparently replaced with eagerload(Person.addresses).
+ The effect is that each Person and his/her Address collection
+ is cached either together or separately, affecting the kind of
+ SQL that emits for unloaded Person objects as well as the distribution
+ of data within the cache.
+ """
+ q = Session.query(Person).\
+ filter(Person.name.between("person %.2d" % start, "person %.2d" % end)).\
+ options(cache_address_bits).\
+ options(FromCache("default", "name_range"))
+
+ # have the "addresses" collection cached separately
+ # each lazyload of Person.addresses loads from cache.
+ q = q.options(FromCache("default", "by_person", Person.addresses))
+
+ # alternatively, eagerly load the "addresses" collection, so that they'd
+ # be cached together. This issues a bigger SQL statement and caches
+ # a single, larger value in the cache per person rather than two
+ # separate ones.
+ #q = q.options(eagerload(Person.addresses))
+
+ # if requested, invalidate the cache on current criterion.
+ if invalidate:
+ q.invalidate()
+
+ return q.all()
+
+print "two through twelve, possibly from cache:\n"
+print ", ".join([p.name for p in load_name_range(2, 12)])
+
+print "\ntwenty five through forty, possibly from cache:\n"
+print ", ".join([p.name for p in load_name_range(25, 40)])
+
+# loading them again, no SQL is emitted
+print "\ntwo through twelve, from the cache:\n"
+print ", ".join([p.name for p in load_name_range(2, 12)])
+
+# but with invalidate, they are
+print "\ntwenty five through forty, invalidate first:\n"
+print ", ".join([p.name for p in load_name_range(25, 40, True)])
+
+# illustrate the address loading from either cache/already
+# on the Person
+print "\n\nPeople plus addresses, two through twelve, addresses possibly from cache"
+for p in load_name_range(2, 12):
+ print p.format_full()
+
+# illustrate the address loading from either cache/already
+# on the Person
+print "\n\nPeople plus addresses, two through twelve, addresses from cache"
+for p in load_name_range(2, 12):
+ print p.format_full()
+
+print "\n\nIf this was the first run of advanced.py, try "\
+ "a second run. Only one SQL statement will be emitted."