Skip to content
This repository

Split out brubeck.queryset into a package instead of a single module #77

Merged
merged 3 commits into from over 1 year ago

3 participants

Michael G. H. Larsen James Dennis Ben Beecher
Michael G. H. Larsen

This should make it easier to add third-party queryset implementations inside the brubeck namespace. Also splits out the implementation into separate files. The contents of brubeck/queryset/__init__.py provide the same module interface that currently exists. Current unit tests pass.

added some commits July 20, 2012
Michael G. H. Larsen Move Queryset into its own package
Make it easier to have extra packages that provide Queryset subclasses (for Mongo/Neo4j/generic REST/etc.)
111b5a6
Michael G. H. Larsen Split RedisQueryset into its own file 976178a
Michael G. H. Larsen Split out DictQueryset into its own file e1e75df
James Dennis
Owner

I think this is a really great idea. I actually think the right idea is to move the QuerySet idea into a Schematics project instead of a Brubeck project.

James Dennis
Owner

Hey @sethmurphy - would you mind taking a look? If you think this works, we should do it and then make plans to bring the code over to schematics instead.

Ben Beecher
Collaborator

LGTM - seems like a no brainier in retrospect

James Dennis
Owner

Agreed.

Alright. Doing it!

James Dennis j2labs merged commit 40277d8 into from November 04, 2012
James Dennis j2labs closed this November 04, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 3 unique commits by 1 author.

Jul 20, 2012
Michael G. H. Larsen Move Queryset into its own package
Make it easier to have extra packages that provide Queryset subclasses (for Mongo/Neo4j/generic REST/etc.)
111b5a6
Michael G. H. Larsen Split RedisQueryset into its own file 976178a
Michael G. H. Larsen Split out DictQueryset into its own file e1e75df
This page is out of date. Refresh to see the latest.
317  brubeck/queryset.py
... ...
@@ -1,317 +0,0 @@
1  
-from request_handling import FourOhFourException
2  
-from itertools import imap
3  
-import zlib
4  
-import ujson as json
5  
-try:
6  
-    import redis
7  
-except ImportError:
8  
-    pass
9  
-
10  
-class AbstractQueryset(object):
11  
-    """The design of the `AbstractQueryset` attempts to map RESTful calls
12  
-    directly to CRUD calls. It also attempts to be compatible with a single
13  
-    item of a list of items, handling multiple statuses gracefully if
14  
-    necessary.
15  
-
16  
-    The querysets then must allow for calls to perform typical CRUD operations
17  
-    on individual items or a list of items.
18  
-
19  
-    By nature of being dependent on complete data models or ids, the system
20  
-    suggests users follow a key-value methodology. Brubeck believes this is
21  
-    what we scale into over time and should just build to this model from the
22  
-    start.
23  
-
24  
-    Implementing the details of particular databases is then to implement the
25  
-    `create_one`, `create_many`, ..., for all the CRUD operations. MySQL,
26  
-    Mongo, Redis, etc should be easy to implement while providing everything
27  
-    necessary for a proper REST API.
28  
-    """
29  
-
30  
-    MSG_OK = 'OK'
31  
-    MSG_UPDATED = 'Updated'
32  
-    MSG_CREATED = 'Created'
33  
-    MSG_NOTFOUND = 'Not Found'
34  
-    MSG_FAILED = 'Failed'
35  
-
36  
-    def __init__(self, db_conn=None, api_id='id'):
37  
-        self.db_conn = db_conn
38  
-        self.api_id = api_id
39  
-
40  
-    ###
41  
-    ### CRUD Operations
42  
-    ###
43  
-
44  
-    ### Section TODO:
45  
-    ### * Pagination
46  
-    ### * Hook in authentication
47  
-    ### * Key filtering (owner / public)
48  
-    ### * Make model instantiation an option
49  
-
50  
-    def create(self, shields):
51  
-        """Commits a list of new shields to the database
52  
-        """
53  
-        if isinstance(shields, list):
54  
-            return self.create_many(shields)
55  
-        else:
56  
-            return self.create_one(shields)
57  
-
58  
-    def read(self, ids):
59  
-        """Returns a list of items that match ids
60  
-        """
61  
-        if not ids:
62  
-            return self.read_all()
63  
-        elif isinstance(ids, list):
64  
-            return self.read_many(ids)
65  
-        else:
66  
-            return self.read_one(ids)
67  
-
68  
-    def update(self, shields):
69  
-        if isinstance(shields, list):
70  
-            return self.update_many(shields)
71  
-        else:
72  
-            return self.update_one(shields)
73  
-
74  
-    def destroy(self, item_ids):
75  
-        """ Removes items from the datastore
76  
-        """
77  
-        if isinstance(item_ids, list):
78  
-            return self.destroy_many(item_ids)
79  
-        else:
80  
-            return self.destroy_one(item_ids)
81  
-
82  
-    ###
83  
-    ### CRUD Implementations
84  
-    ###
85  
-
86  
-    ### Create Functions
87  
-
88  
-    def create_one(self, shield):
89  
-        raise NotImplementedError
90  
-
91  
-    def create_many(self, shields):
92  
-        raise NotImplementedError
93  
-
94  
-    ### Read Functions
95  
-
96  
-    def read_all(self):
97  
-        """Returns a list of objects in the db
98  
-        """
99  
-        raise NotImplementedError
100  
-
101  
-    def read_one(self, iid):
102  
-        """Returns a single item from the db
103  
-        """
104  
-        raise NotImplementedError
105  
-
106  
-    def read_many(self, ids):
107  
-        """Returns a list of objects matching ids from the db
108  
-        """
109  
-        raise NotImplementedError
110  
-
111  
-    ### Update Functions
112  
-
113  
-    def update_one(self, shield):
114  
-        raise NotImplementedError
115  
-
116  
-    def update_many(self, shields):
117  
-        raise NotImplementedError
118  
-
119  
-    ### Destroy Functions
120  
-
121  
-    def destroy_one(self, iid):
122  
-        raise NotImplementedError
123  
-
124  
-    def destroy_many(self, ids):
125  
-        raise NotImplementedError
126  
-
127  
-
128  
-class DictQueryset(AbstractQueryset):
129  
-    """This class exists as an example of how one could implement a Queryset.
130  
-    This model is an in-memory dictionary and uses the model's id as the key.
131  
-
132  
-    The data stored is the result of calling model's `to_python()` function.
133  
-    """
134  
-    def __init__(self, **kw):
135  
-        """Set the db_conn to a dictionary.
136  
-        """
137  
-        super(DictQueryset, self).__init__(db_conn=dict(), **kw)
138  
-
139  
-    ### Create Functions
140  
-
141  
-    def create_one(self, shield):
142  
-        if shield.id in self.db_conn:
143  
-            status = self.MSG_UPDATED
144  
-        else:
145  
-            status = self.MSG_CREATED
146  
-
147  
-        shield_key = str(getattr(shield, self.api_id))
148  
-        self.db_conn[shield_key] = shield.to_python()
149  
-        return (status, shield)
150  
-
151  
-    def create_many(self, shields):
152  
-        statuses = [self.create_one(shield) for shield in shields]
153  
-        return statuses
154  
-
155  
-    ### Read Functions
156  
-
157  
-    def read_all(self):
158  
-        return [(self.MSG_OK, datum) for datum in self.db_conn.values()]
159  
-
160  
-
161  
-    def read_one(self, iid):
162  
-        iid = str(iid)  # TODO Should be cleaner
163  
-        if iid in self.db_conn:
164  
-            return (self.MSG_OK, self.db_conn[iid])
165  
-        else:
166  
-            return (self.MSG_FAILED, iid)
167  
-
168  
-    def read_many(self, ids):
169  
-        return [self.read_one(iid) for iid in ids]
170  
-
171  
-    ### Update Functions
172  
-    def update_one(self, shield):
173  
-        shield_key = str(getattr(shield, self.api_id))
174  
-        self.db_conn[shield_key] = shield.to_python()
175  
-        return (self.MSG_UPDATED, shield)
176  
-
177  
-    def update_many(self, shields):
178  
-        statuses = [self.update_one(shield) for shield in shields]
179  
-        return statuses
180  
-
181  
-    ### Destroy Functions
182  
-
183  
-    def destroy_one(self, item_id):
184  
-        try:
185  
-            datum = self.db_conn[item_id]
186  
-            del self.db_conn[item_id]
187  
-        except KeyError:
188  
-            raise FourOhFourException
189  
-        return (self.MSG_UPDATED, datum)
190  
-
191  
-    def destroy_many(self, ids):
192  
-        statuses = [self.destroy_one(iid) for iid in ids]
193  
-        return statuses
194  
-
195  
-class RedisQueryset(AbstractQueryset):
196  
-    """This class uses redis to store the DictShield after 
197  
-    calling it's `to_json()` method. Upon reading from the Redis
198  
-    store, the object is deserialized using json.loads().
199  
-
200  
-    Redis connection uses the redis-py api located here:
201  
-    https://github.com/andymccurdy/redis-py
202  
-    """
203  
-    # TODO: - catch connection exceptions?
204  
-    #       - set Redis EXPIRE and self.expires
205  
-    #       - confirm that the correct status is being returned in 
206  
-    #         each circumstance
207  
-    def __init__(self, compress=False, compress_level=1, **kw):
208  
-        """The Redis connection wiil be passed in **kw and is used below
209  
-        as self.db_conn.
210  
-        """
211  
-        super(RedisQueryset, self).__init__(**kw)
212  
-        self.compress = compress
213  
-        self.compress_level = compress_level
214  
-        
215  
-    def _setvalue(self, shield):
216  
-        if self.compress:
217  
-            return zlib.compress(shield.to_json(), self.compress_level)
218  
-        return shield.to_json()
219  
-
220  
-    def _readvalue(self, value):
221  
-        if self.compress:
222  
-            try:
223  
-                compressed_value = zlib.decompress(value)
224  
-                return json.loads(zlib.decompress(value))
225  
-            except Exception as e:
226  
-                # value is 0 or None from a Redis return value
227  
-                return value
228  
-        if value:
229  
-            return json.loads(value)
230  
-        return None
231  
-
232  
-    def _message_factory(self, fail_status, success_status):
233  
-        """A Redis command often returns some value or 0 after the
234  
-        operation has returned.
235  
-        """
236  
-        return lambda x: success_status if x else fail_status
237  
-
238  
-    ### Create Functions
239  
-
240  
-    def create_one(self, shield):
241  
-        shield_value = self._setvalue(shield)
242  
-        shield_key = str(getattr(shield, self.api_id))        
243  
-        result = self.db_conn.hset(self.api_id, shield_key, shield_value)
244  
-        if result:
245  
-            return (self.MSG_CREATED, shield)
246  
-        return (self.MSG_UPDATED, shield)
247  
-
248  
-    def create_many(self, shields):
249  
-        message_handler = self._message_factory(self.MSG_UPDATED, self.MSG_CREATED)
250  
-        pipe = self.db_conn.pipeline()
251  
-        for shield in shields:
252  
-            pipe.hset(self.api_id, str(getattr(shield, self.api_id)), self._setvalue(shield))
253  
-        results = zip(imap(message_handler, pipe.execute()), shields)
254  
-        pipe.reset()
255  
-        return results
256  
-        
257  
-    ### Read Functions
258  
-
259  
-    def read_all(self):
260  
-        return [(self.MSG_OK, self._readvalue(datum)) for datum in self.db_conn.hvals(self.api_id)]
261  
-
262  
-    def read_one(self, shield_id):
263  
-        result = self.db_conn.hget(self.api_id, shield_id)
264  
-        if result:
265  
-            return (self.MSG_OK, self._readvalue(result))
266  
-        return (self.MSG_FAILED, shield_id)
267  
-
268  
-    def read_many(self, shield_ids):
269  
-        message_handler = self._message_factory(self.MSG_FAILED, self.MSG_OK)
270  
-        pipe = self.db_conn.pipeline()
271  
-        for shield_id in shield_ids:
272  
-            pipe.hget(self.api_id, str(shield_id))
273  
-        results = pipe.execute()
274  
-        pipe.reset()
275  
-        return zip(imap(message_handler, results), map(self._readvalue, results))
276  
-
277  
-    ### Update Functions
278  
-
279  
-    def update_one(self, shield):
280  
-        shield_key = str(getattr(shield, self.api_id))
281  
-        message_handler = self._message_factory(self.MSG_UPDATED, self.MSG_CREATED)
282  
-        status = message_handler(self.db_conn.hset(self.api_id, shield_key, self._setvalue(shield)))
283  
-        return (status, shield)
284  
-
285  
-    def update_many(self, shields):
286  
-        message_handler = self._message_factory(self.MSG_UPDATED, self.MSG_CREATED)
287  
-        pipe = self.db_conn.pipeline()
288  
-        for shield in shields:
289  
-            pipe.hset(self.api_id, str(getattr(shield, self.api_id)), self._setvalue(shield))
290  
-        results = pipe.execute()
291  
-        pipe.reset()
292  
-        return zip(imap(message_handler, results), shields)
293  
-
294  
-    ### Destroy Functions
295  
-
296  
-    def destroy_one(self, shield_id):
297  
-        pipe = self.db_conn.pipeline()
298  
-        pipe.hget(self.api_id, shield_id)
299  
-        pipe.hdel(self.api_id, shield_id)
300  
-        result = pipe.execute()
301  
-        if result[1]:
302  
-            return (self.MSG_UPDATED, self._readvalue(result[0]))
303  
-        return self.MSG_NOTFOUND
304  
-
305  
-    def destroy_many(self, ids):
306  
-        # TODO: how to handle missing fields, currently returning self.MSG_FAILED
307  
-        message_handler = self._message_factory(self.MSG_FAILED, self.MSG_UPDATED)
308  
-        pipe = self.db_conn.pipeline()
309  
-        for _id in ids:
310  
-            pipe.hget(self.api_id, _id)
311  
-        values_results = pipe.execute()
312  
-        for _id in ids:
313  
-            pipe.hdel(self.api_id, _id)
314  
-        delete_results = pipe.execute()
315  
-        pipe.reset()
316  
-        return zip(imap(message_handler, delete_results), map(self._readvalue, values_results))
317  
-
4  brubeck/queryset/__init__.py
... ...
@@ -0,0 +1,4 @@
  1
+from brubeck.queryset.base import AbstractQueryset
  2
+from brubeck.queryset.dict import DictQueryset
  3
+from brubeck.queryset.redis import RedisQueryset
  4
+
119  brubeck/queryset/base.py
... ...
@@ -0,0 +1,119 @@
  1
+from brubeck.request_handling import FourOhFourException
  2
+
  3
+class AbstractQueryset(object):
  4
+    """The design of the `AbstractQueryset` attempts to map RESTful calls
  5
+    directly to CRUD calls. It also attempts to be compatible with a single
  6
+    item of a list of items, handling multiple statuses gracefully if
  7
+    necessary.
  8
+
  9
+    The querysets then must allow for calls to perform typical CRUD operations
  10
+    on individual items or a list of items.
  11
+
  12
+    By nature of being dependent on complete data models or ids, the system
  13
+    suggests users follow a key-value methodology. Brubeck believes this is
  14
+    what we scale into over time and should just build to this model from the
  15
+    start.
  16
+
  17
+    Implementing the details of particular databases is then to implement the
  18
+    `create_one`, `create_many`, ..., for all the CRUD operations. MySQL,
  19
+    Mongo, Redis, etc should be easy to implement while providing everything
  20
+    necessary for a proper REST API.
  21
+    """
  22
+
  23
+    MSG_OK = 'OK'
  24
+    MSG_UPDATED = 'Updated'
  25
+    MSG_CREATED = 'Created'
  26
+    MSG_NOTFOUND = 'Not Found'
  27
+    MSG_FAILED = 'Failed'
  28
+
  29
+    def __init__(self, db_conn=None, api_id='id'):
  30
+        self.db_conn = db_conn
  31
+        self.api_id = api_id
  32
+
  33
+    ###
  34
+    ### CRUD Operations
  35
+    ###
  36
+
  37
+    ### Section TODO:
  38
+    ### * Pagination
  39
+    ### * Hook in authentication
  40
+    ### * Key filtering (owner / public)
  41
+    ### * Make model instantiation an option
  42
+
  43
+    def create(self, shields):
  44
+        """Commits a list of new shields to the database
  45
+        """
  46
+        if isinstance(shields, list):
  47
+            return self.create_many(shields)
  48
+        else:
  49
+            return self.create_one(shields)
  50
+
  51
+    def read(self, ids):
  52
+        """Returns a list of items that match ids
  53
+        """
  54
+        if not ids:
  55
+            return self.read_all()
  56
+        elif isinstance(ids, list):
  57
+            return self.read_many(ids)
  58
+        else:
  59
+            return self.read_one(ids)
  60
+
  61
+    def update(self, shields):
  62
+        if isinstance(shields, list):
  63
+            return self.update_many(shields)
  64
+        else:
  65
+            return self.update_one(shields)
  66
+
  67
+    def destroy(self, item_ids):
  68
+        """ Removes items from the datastore
  69
+        """
  70
+        if isinstance(item_ids, list):
  71
+            return self.destroy_many(item_ids)
  72
+        else:
  73
+            return self.destroy_one(item_ids)
  74
+
  75
+    ###
  76
+    ### CRUD Implementations
  77
+    ###
  78
+
  79
+    ### Create Functions
  80
+
  81
+    def create_one(self, shield):
  82
+        raise NotImplementedError
  83
+
  84
+    def create_many(self, shields):
  85
+        raise NotImplementedError
  86
+
  87
+    ### Read Functions
  88
+
  89
+    def read_all(self):
  90
+        """Returns a list of objects in the db
  91
+        """
  92
+        raise NotImplementedError
  93
+
  94
+    def read_one(self, iid):
  95
+        """Returns a single item from the db
  96
+        """
  97
+        raise NotImplementedError
  98
+
  99
+    def read_many(self, ids):
  100
+        """Returns a list of objects matching ids from the db
  101
+        """
  102
+        raise NotImplementedError
  103
+
  104
+    ### Update Functions
  105
+
  106
+    def update_one(self, shield):
  107
+        raise NotImplementedError
  108
+
  109
+    def update_many(self, shields):
  110
+        raise NotImplementedError
  111
+
  112
+    ### Destroy Functions
  113
+
  114
+    def destroy_one(self, iid):
  115
+        raise NotImplementedError
  116
+
  117
+    def destroy_many(self, ids):
  118
+        raise NotImplementedError
  119
+
69  brubeck/queryset/dict.py
... ...
@@ -0,0 +1,69 @@
  1
+from brubeck.queryset.base import AbstractQueryset
  2
+
  3
+class DictQueryset(AbstractQueryset):
  4
+    """This class exists as an example of how one could implement a Queryset.
  5
+    This model is an in-memory dictionary and uses the model's id as the key.
  6
+
  7
+    The data stored is the result of calling model's `to_python()` function.
  8
+    """
  9
+    def __init__(self, **kw):
  10
+        """Set the db_conn to a dictionary.
  11
+        """
  12
+        super(DictQueryset, self).__init__(db_conn=dict(), **kw)
  13
+
  14
+    ### Create Functions
  15
+
  16
+    def create_one(self, shield):
  17
+        if shield.id in self.db_conn:
  18
+            status = self.MSG_UPDATED
  19
+        else:
  20
+            status = self.MSG_CREATED
  21
+
  22
+        shield_key = str(getattr(shield, self.api_id))
  23
+        self.db_conn[shield_key] = shield.to_python()
  24
+        return (status, shield)
  25
+
  26
+    def create_many(self, shields):
  27
+        statuses = [self.create_one(shield) for shield in shields]
  28
+        return statuses
  29
+
  30
+    ### Read Functions
  31
+
  32
+    def read_all(self):
  33
+        return [(self.MSG_OK, datum) for datum in self.db_conn.values()]
  34
+
  35
+
  36
+    def read_one(self, iid):
  37
+        iid = str(iid)  # TODO Should be cleaner
  38
+        if iid in self.db_conn:
  39
+            return (self.MSG_OK, self.db_conn[iid])
  40
+        else:
  41
+            return (self.MSG_FAILED, iid)
  42
+
  43
+    def read_many(self, ids):
  44
+        return [self.read_one(iid) for iid in ids]
  45
+
  46
+    ### Update Functions
  47
+    def update_one(self, shield):
  48
+        shield_key = str(getattr(shield, self.api_id))
  49
+        self.db_conn[shield_key] = shield.to_python()
  50
+        return (self.MSG_UPDATED, shield)
  51
+
  52
+    def update_many(self, shields):
  53
+        statuses = [self.update_one(shield) for shield in shields]
  54
+        return statuses
  55
+
  56
+    ### Destroy Functions
  57
+
  58
+    def destroy_one(self, item_id):
  59
+        try:
  60
+            datum = self.db_conn[item_id]
  61
+            del self.db_conn[item_id]
  62
+        except KeyError:
  63
+            raise FourOhFourException
  64
+        return (self.MSG_UPDATED, datum)
  65
+
  66
+    def destroy_many(self, ids):
  67
+        statuses = [self.destroy_one(iid) for iid in ids]
  68
+        return statuses
  69
+
132  brubeck/queryset/redis.py
... ...
@@ -0,0 +1,132 @@
  1
+from brubeck.queryset.base import AbstractQueryset
  2
+from itertools import imap
  3
+import ujson as json
  4
+import zlib
  5
+try:
  6
+    import redis
  7
+except ImportError:
  8
+    pass
  9
+
  10
+class RedisQueryset(AbstractQueryset):
  11
+    """This class uses redis to store the DictShield after 
  12
+    calling it's `to_json()` method. Upon reading from the Redis
  13
+    store, the object is deserialized using json.loads().
  14
+
  15
+    Redis connection uses the redis-py api located here:
  16
+    https://github.com/andymccurdy/redis-py
  17
+    """
  18
+    # TODO: - catch connection exceptions?
  19
+    #       - set Redis EXPIRE and self.expires
  20
+    #       - confirm that the correct status is being returned in 
  21
+    #         each circumstance
  22
+    def __init__(self, compress=False, compress_level=1, **kw):
  23
+        """The Redis connection wiil be passed in **kw and is used below
  24
+        as self.db_conn.
  25
+        """
  26
+        super(RedisQueryset, self).__init__(**kw)
  27
+        self.compress = compress
  28
+        self.compress_level = compress_level
  29
+        
  30
+    def _setvalue(self, shield):
  31
+        if self.compress:
  32
+            return zlib.compress(shield.to_json(), self.compress_level)
  33
+        return shield.to_json()
  34
+
  35
+    def _readvalue(self, value):
  36
+        if self.compress:
  37
+            try:
  38
+                compressed_value = zlib.decompress(value)
  39
+                return json.loads(zlib.decompress(value))
  40
+            except Exception as e:
  41
+                # value is 0 or None from a Redis return value
  42
+                return value
  43
+        if value:
  44
+            return json.loads(value)
  45
+        return None
  46
+
  47
+    def _message_factory(self, fail_status, success_status):
  48
+        """A Redis command often returns some value or 0 after the
  49
+        operation has returned.
  50
+        """
  51
+        return lambda x: success_status if x else fail_status
  52
+
  53
+    ### Create Functions
  54
+
  55
+    def create_one(self, shield):
  56
+        shield_value = self._setvalue(shield)
  57
+        shield_key = str(getattr(shield, self.api_id))        
  58
+        result = self.db_conn.hset(self.api_id, shield_key, shield_value)
  59
+        if result:
  60
+            return (self.MSG_CREATED, shield)
  61
+        return (self.MSG_UPDATED, shield)
  62
+
  63
+    def create_many(self, shields):
  64
+        message_handler = self._message_factory(self.MSG_UPDATED, self.MSG_CREATED)
  65
+        pipe = self.db_conn.pipeline()
  66
+        for shield in shields:
  67
+            pipe.hset(self.api_id, str(getattr(shield, self.api_id)), self._setvalue(shield))
  68
+        results = zip(imap(message_handler, pipe.execute()), shields)
  69
+        pipe.reset()
  70
+        return results
  71
+        
  72
+    ### Read Functions
  73
+
  74
+    def read_all(self):
  75
+        return [(self.MSG_OK, self._readvalue(datum)) for datum in self.db_conn.hvals(self.api_id)]
  76
+
  77
+    def read_one(self, shield_id):
  78
+        result = self.db_conn.hget(self.api_id, shield_id)
  79
+        if result:
  80
+            return (self.MSG_OK, self._readvalue(result))
  81
+        return (self.MSG_FAILED, shield_id)
  82
+
  83
+    def read_many(self, shield_ids):
  84
+        message_handler = self._message_factory(self.MSG_FAILED, self.MSG_OK)
  85
+        pipe = self.db_conn.pipeline()
  86
+        for shield_id in shield_ids:
  87
+            pipe.hget(self.api_id, str(shield_id))
  88
+        results = pipe.execute()
  89
+        pipe.reset()
  90
+        return zip(imap(message_handler, results), map(self._readvalue, results))
  91
+
  92
+    ### Update Functions
  93
+
  94
+    def update_one(self, shield):
  95
+        shield_key = str(getattr(shield, self.api_id))
  96
+        message_handler = self._message_factory(self.MSG_UPDATED, self.MSG_CREATED)
  97
+        status = message_handler(self.db_conn.hset(self.api_id, shield_key, self._setvalue(shield)))
  98
+        return (status, shield)
  99
+
  100
+    def update_many(self, shields):
  101
+        message_handler = self._message_factory(self.MSG_UPDATED, self.MSG_CREATED)
  102
+        pipe = self.db_conn.pipeline()
  103
+        for shield in shields:
  104
+            pipe.hset(self.api_id, str(getattr(shield, self.api_id)), self._setvalue(shield))
  105
+        results = pipe.execute()
  106
+        pipe.reset()
  107
+        return zip(imap(message_handler, results), shields)
  108
+
  109
+    ### Destroy Functions
  110
+
  111
+    def destroy_one(self, shield_id):
  112
+        pipe = self.db_conn.pipeline()
  113
+        pipe.hget(self.api_id, shield_id)
  114
+        pipe.hdel(self.api_id, shield_id)
  115
+        result = pipe.execute()
  116
+        if result[1]:
  117
+            return (self.MSG_UPDATED, self._readvalue(result[0]))
  118
+        return self.MSG_NOTFOUND
  119
+
  120
+    def destroy_many(self, ids):
  121
+        # TODO: how to handle missing fields, currently returning self.MSG_FAILED
  122
+        message_handler = self._message_factory(self.MSG_FAILED, self.MSG_UPDATED)
  123
+        pipe = self.db_conn.pipeline()
  124
+        for _id in ids:
  125
+            pipe.hget(self.api_id, _id)
  126
+        values_results = pipe.execute()
  127
+        for _id in ids:
  128
+            pipe.hdel(self.api_id, _id)
  129
+        delete_results = pipe.execute()
  130
+        pipe.reset()
  131
+        return zip(imap(message_handler, delete_results), map(self._readvalue, values_results))
  132
+
2  setup.py
@@ -8,5 +8,5 @@
8 8
       author='James Dennis',
9 9
       author_email='jdennis@gmail.com',
10 10
       url='http://github.com/j2labs/brubeck',
11  
-      packages=['brubeck'],
  11
+      packages=['brubeck', 'brubeck.queryset'],
12 12
       install_requires=['ujson', 'dictshield'])
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.