1
1
from typing import Dict , List
2
+ from collections import defaultdict
2
3
3
4
from django .core .exceptions import ImproperlyConfigured , ObjectDoesNotExist
4
5
from django .db .transaction import atomic
@@ -27,6 +28,8 @@ class AtomicOperationView(APIView):
27
28
sequential = True
28
29
response_data : List [Dict ] = []
29
30
31
+ lid_to_id = defaultdict (dict )
32
+
30
33
# TODO: proof how to check permissions for all operations
31
34
# permission_classes = TODO
32
35
# call def check_permissions for `add` operation
@@ -94,8 +97,15 @@ def post(self, request, *args, **kwargs):
94
97
95
98
def handle_sequential (self , serializer , operation_code ):
96
99
if operation_code in ["add" , "update" , "update-relationship" ]:
100
+ lid = serializer .initial_data .get ("lid" , None )
101
+
97
102
serializer .is_valid (raise_exception = True )
98
103
serializer .save ()
104
+
105
+ if operation_code == "add" and lid :
106
+ resource_type = serializer .initial_data ["type" ]
107
+ self .lid_to_id [resource_type ][lid ] = serializer .data ["id" ]
108
+
99
109
if operation_code != "update-relationship" :
100
110
self .response_data .append (serializer .data )
101
111
else :
@@ -139,6 +149,36 @@ def handle_bulk(self, serializer, current_operation_code, bulk_operation_data):
139
149
bulk_operation_data ["serializer_collection" ][0 ], current_operation_code )
140
150
bulk_operation_data ["serializer_collection" ] = []
141
151
152
+ def substitute_lids (self , data , idx , should_raise_unknown_lid_error ):
153
+ if not isinstance (data , dict ):
154
+ return
155
+
156
+ try :
157
+ lid = data .get ("lid" , None )
158
+ if lid :
159
+ resource_type = data ["type" ]
160
+ data ["id" ] = self .lid_to_id [resource_type ][lid ]
161
+ except KeyError :
162
+ if should_raise_unknown_lid_error :
163
+ raise UnprocessableEntity ([
164
+ {
165
+ "id" : "unknown-lid" ,
166
+ "detail" : f'Object with lid `{ lid } ` received for operation with index `{ idx } ` does not exist' ,
167
+ "source" : {
168
+ "pointer" : f"/{ ATOMIC_OPERATIONS } /{ idx } /data/lid"
169
+ },
170
+ "status" : "422"
171
+ }
172
+ ])
173
+
174
+ for _ , value in data .items ():
175
+ if isinstance (value , dict ):
176
+ self .substitute_lids (value , idx , should_raise_unknown_lid_error = True )
177
+ elif isinstance (value , list ):
178
+ [self .substitute_lids (value , idx , should_raise_unknown_lid_error = True ) for value in value ]
179
+
180
+ return data
181
+
142
182
def perform_operations (self , parsed_operations : List [Dict ]):
143
183
self .response_data = [] # reset local response data storage
144
184
@@ -154,6 +194,9 @@ def perform_operations(self, parsed_operations: List[Dict]):
154
194
operation_code = next (iter (operation ))
155
195
obj = operation [operation_code ]
156
196
197
+ should_raise_unknown_lid_error = operation_code != "add"
198
+ self .substitute_lids (obj , idx , should_raise_unknown_lid_error )
199
+
157
200
serializer = self .get_serializer (
158
201
idx = idx ,
159
202
data = obj ,
0 commit comments