]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- added an example dynamic_dict/dynamic_dict.py, illustrating
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 7 May 2008 14:48:04 +0000 (14:48 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 7 May 2008 14:48:04 +0000 (14:48 +0000)
a simple way to place dictionary behavior on top of
a dynamic_loader.

CHANGES
examples/dynamic_dict/dynamic_dict.py [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index 6c2de2878975ba76b4de985704bbb26ace059f37..8ec857dadde7e63c3ba647606f6a9d1f6f8fedf1 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -69,6 +69,10 @@ CHANGES
       their operands and only operate on sets, frozensets or
       subclasses of the collection type. Previously, they would
       accept any duck-typed set.
+      
+    - added an example dynamic_dict/dynamic_dict.py, illustrating
+      a simple way to place dictionary behavior on top of 
+      a dynamic_loader.
 
 - sql
     - Added COLLATE support via the .collate(<collation>)
diff --git a/examples/dynamic_dict/dynamic_dict.py b/examples/dynamic_dict/dynamic_dict.py
new file mode 100644 (file)
index 0000000..682def7
--- /dev/null
@@ -0,0 +1,83 @@
+"""Illustrates how to place a dictionary-like facade on top of a dynamic_loader, so\r
+that dictionary operations (assuming simple string keys) can operate upon a large \r
+collection without loading the full collection at once.\r
+\r
+This is something that may eventually be added as a feature to dynamic_loader() itself.\r
+\r
+Similar approaches could be taken towards sets and dictionaries with non-string keys \r
+although the hash policy of the members would need to be distilled into a filter() criterion.\r
+\r
+"""\r
+\r
+class MyProxyDict(object):\r
+    def __init__(self, parent, collection_name, keyname):\r
+        self.parent = parent\r
+        self.collection_name = collection_name\r
+        self.keyname = keyname\r
+        \r
+    def collection(self):\r
+        return getattr(self.parent, self.collection_name)\r
+    collection = property(collection)\r
+    \r
+    def keys(self):\r
+        # this can be improved to not query all columns\r
+        return [getattr(x, self.keyname) for x in self.collection.all()]\r
+        \r
+    def __getitem__(self, key):\r
+        x = self.collection.filter_by(**{self.keyname:key}).first()\r
+        if x:\r
+            return x\r
+        else:\r
+            raise KeyError(key)\r
+\r
+    def __setitem__(self, key, value):\r
+        try:\r
+            existing = self[key]\r
+            self.collection.remove(existing)\r
+        except KeyError:\r
+            pass\r
+        self.collection.append(value)\r
+\r
+from sqlalchemy.ext.declarative import declarative_base\r
+from sqlalchemy import *\r
+from sqlalchemy.orm import *\r
+\r
+Base = declarative_base(engine=create_engine('sqlite://'))\r
+\r
+class MyParent(Base):\r
+    __tablename__ = 'parent'\r
+    id = Column(Integer, primary_key=True)\r
+    name = Column(String(50))\r
+    _collection = dynamic_loader("MyChild", cascade="all, delete-orphan")\r
+    \r
+    def child_map(self):\r
+        return MyProxyDict(self, '_collection', 'key')\r
+    child_map = property(child_map)\r
+    \r
+class MyChild(Base):\r
+    __tablename__ = 'child'\r
+    id = Column(Integer, primary_key=True)\r
+    key = Column(String(50))\r
+    parent_id = Column(Integer, ForeignKey('parent.id'))\r
+\r
+    \r
+Base.metadata.create_all()\r
+\r
+sess = create_session(autoflush=True, transactional=True)\r
+\r
+p1 = MyParent(name='p1')\r
+sess.save(p1)\r
+\r
+p1.child_map['k1'] = k1 = MyChild(key='k1')\r
+p1.child_map['k2'] = k2 = MyChild(key='k2')\r
+\r
+\r
+assert p1.child_map.keys() == ['k1', 'k2']\r
+\r
+assert p1.child_map['k1'] is k1\r
+\r
+p1.child_map['k2'] = k2b = MyChild(key='k2')\r
+assert p1.child_map['k2'] is k2b\r
+\r
+assert sess.query(MyChild).all() == [k1, k2b]\r
+\r