1 """
2 Adapter Overview
3 ================
4
5 Adapters provide the bridge between the mapped object and the data store.
6 There are several layers to an adapter request and response::
7
8 Req Resp
9 pyperry.base.Base
10 | ^
11 V |
12 Processors
13 | ^
14 V |
15 Model Bridge
16 | ^
17 V |
18 Middlewares
19 | ^
20 V |
21 Adapter
22 \/
23 Database
24
25 The request is initiated by the L{pyperry.base.Base} class and passes through
26 the adapter stack returning a response. Within the stack the request goes
27 through a series of configurable stack items: processors, and middlewares
28 before being passed to the appropriate adapter method. That adapter method
29 then executes the requested action and returns the results back through the
30 stack until returning to Base.
31
32 Processors and middlewares are ways of customizing requests and responses.
33 There is a middleware that is always installed called the ModelBridge. It
34 takes the raw response of the adapter and converts it to mapped objects. The
35 only difference between a middleware and a processor is that the objects
36 returned to a processor are always instantiated records whereas middlewares
37 receive the raw response.
38
39 """
40 from copy import copy
41 import socket
42
43 import pyperry
44 from pyperry import errors
45 from pyperry.middlewares.model_bridge import ModelBridge
48 """
49 Simple class that takes kwargs or a dictionary in initializer and sets
50 values to the class dictionary. Any values set as lambdas will be
51 evaluated when they are accessed.
52 """
53
55 """Set values in kwargs to attributes"""
56 if not kwargs and len(args) is 1:
57 kwargs = args[0]
58
59 for k, v in kwargs.items():
60 self.__dict__[k] = v
61
63 attr = object.__getattribute__(self, key)
64 if type(attr).__name__ == 'function':
65 attr = attr()
66 return attr
67
70 """The base class for all adapters"""
71
72 adapter_types = ['read', 'write']
73
74 - def __init__(self, config, mode=None, middlewares=None, processors=[]):
101
102 @property
104 """
105 Setup the stack plumbing with the configured stack items
106
107 Wrap each stack item (processors and middleware) in reverse order
108 around the call to the adapter method. This will allow stack items to
109 intercept requests, modify query information and pass it along, do
110 things with the results of the query or any combination of these
111 things.
112
113 """
114 if self._stack: return self._stack
115
116 self._stack = self.execute
117 stack_items = copy(self.processors) + copy(self.middlewares)
118 stack_items.reverse()
119
120 for (klass, config) in stack_items:
121 self._stack = klass(self._stack, config)
122
123 return self._stack
124
126 """Clear out the stack causing it to be rebuilt on the next request"""
127 self._stack = None
128
130 """Makes a request to the stack"""
131 pyperry.logger.info('%s: %s' % (self.mode, kwargs.keys()))
132 if 'mode' not in kwargs:
133 kwargs.update(mode=self.mode)
134 result = self.stack(**kwargs)
135
136 if self.mode is 'read' and not hasattr(result, '__iter__'):
137 raise errors.BrokenAdapterStack(
138 "The adapter stack failed to return an iterable object" )
139
140 return result
141
143 """Call read, write, or delete according to the mode kwarg."""
144 return getattr(self, kwargs['mode'])(**kwargs)
145
146 - def read(self, **kwargs):
147 """Read from the datastore with the provided options"""
148 raise NotImplementedError("You must define this method in subclasses")
149
150 - def write(self, **kwargs):
151 """Write object's attributes to the datastore"""
152 raise NotImplementedError("You must define this method in subclasses")
153
155 """Delete the object from the datastore"""
156 raise NotImplementedError("You must define this method in subclasses")
157