1 from pyperry.errors import ConfigurationError
2
4 """
5 The C{ModelBridge} class is positioned between the processors and
6 middlewares in the L{adapter's request/response call stack
7 <AbstractAdapter>}. Before the response from an adapter call reaches the
8 C{ModelBridge}, the middlewares can only reliable work with the raw
9 response data. After the C{ModelBridge} handles the response, the
10 processors that follow can now operate on model instances (subclasses of
11 C{pyperry.Base}) instead of the raw response data.
12
13 On adapter reads, the C{ModelBridge} takes the list of records returned by
14 the adapter call and creates a model instance of the appropriate type for
15 each record in the list.
16
17 On adapter writes and deletes, the C{ModelBridge} class updates the state
18 of the model instance being saved or deleted to reflect
19 the data stored in the Response object returned by the adapter call. This
20 includes things like updating a model's C{saved} and C{new_record}
21 attributes in addition to putting error messages on the model if the
22 adapter received an error response. Additionally, the C{ModelBridge} will
23 refresh all of the model's data attributes (specified by calling
24 C{pyperry.Base.attributes(...)}) after a successful write if a read adapter
25 is configured for the model.
26
27 """
28
30 self.next = next
31 self.options = options
32
34 results = self.next(**kwargs)
35 mode = kwargs['mode']
36
37 if mode == 'read':
38 results = self.handle_read(results, **kwargs)
39 elif mode == 'write':
40 results = self.handle_write(results, **kwargs)
41 elif mode == 'delete':
42 results = self.handle_delete(results, **kwargs)
43
44
45 return results
46
48 """Create perry.Base instances from the raw records dictionaries."""
49 if 'relation' in kwargs:
50 relation = kwargs['relation']
51 records = [relation.klass(record, False)
52 for record in records if record]
53 return records
54
64
66 """
67 Updates the model's state attributes and retrieves a fresh version of
68 the data attributes if a read adapter is configured.
69
70 """
71 has_read_adapter = True
72 try:
73 model.adapter('read')
74 except ConfigurationError:
75 has_read_adapter = False
76
77 if model.new_record and has_read_adapter:
78 setattr(model, model.pk_attr(),
79 response.model_attributes()[model.pk_attr()])
80
81 if has_read_adapter:
82 model.reload()
83
84 model.saved = True
85 model.new_record = False
86
88 """Updates the model instance when a save fails"""
89 model.saved = False
90 self.add_errors(response, model, 'record not saved')
91
93 """Updates the model instance after a delete"""
94 if 'model' in kwargs:
95 model = kwargs['model']
96 if response.success:
97 model.freeze()
98 else:
99 self.add_errors(response, model, 'record not deleted')
100 return response
101
102 - def add_errors(self, response, model, default_message):
103 """
104 Copies the response errors to the model or uses a default error
105 message if the response errors are empty.
106
107 """
108 errors = response.errors()
109 if len(errors) == 0:
110 errors = { 'base': default_message }
111 model.errors = errors
112