Browse Source

Merge branch 'newlodel' of git.labocleo.org:lodel2 into newlodel

prieto 9 years ago
parent
commit
34012cd30a
1 changed files with 171 additions and 20 deletions
  1. 171
    20
      lodel/leapi/query.py

+ 171
- 20
lodel/leapi/query.py View File

@@ -1,41 +1,192 @@
1 1
 #-*- coding: utf-8 -*-
2 2
 
3
-from leobject import LeObject
3
+from .leobject import LeObject, LeApiErrors
4 4
 
5 5
 class LeQueryError(Exception):
6 6
     pass
7 7
 
8
-## @brief Handle CRUD operations on datasource
8
+
9 9
 class LeQuery(object):
10
-    
11
-    ## @brief Constructor
12
-    # @param target_class LeObject class or childs : The LeObject child class concerned by this query
10
+
11
+    ## @brief The datasource object used for this query
12
+    _datasource = None
13
+
14
+    ## @brief The available operators used in query definitions
15
+    _query_operators = ['=', '<=', '>=', '!=', '<', '>', ' in ', ' not in ', ' like ', ' not like ']
16
+
13 17
     def __init__(self, target_class):
14 18
         if not issubclass(target_class, LeObject):
15
-            raise TypeError("target_class have to be a child class of LeObject")
19
+            raise TypeError("target class has to be a child class of LeObject")
16 20
         self._target_class = target_class
17 21
 
18
-## @brief Handles insert queries
22
+
19 23
 class LeInsertQuery(LeQuery):
24
+    action = 'insert'
25
+
26
+    def __init__(self, target_class, datas, classname=None):
27
+        targeted_class = target_class if classname is None else LeObject.name2class(classname)
28
+        if not targeted_class:
29
+            raise LeQueryError('Error when inserting', {'error': ValueError("The class '%s' was not found" % classname)})
30
+
31
+        super().__init__(targeted_class)
32
+        self.datas = datas
33
+
34
+    # @todo Reactivate the LodelHooks call when this class is implemented
35
+    def execute(self):
36
+        datas = self.datas  # TODO : replace with LodelHooks.call_hook('leapi_insert_pre', self._target_class, self.datas)
37
+        ret = self.__insert(**datas)
38
+        # ret = LodelHook.call_hook('leapi_insert_post', self._target_class, ret)
39
+        return ret
40
+
41
+    def __insert(self):
42
+        insert_datas = self._target_class.prepare_datas(self.datas, complete=True, allow_internal=True)
43
+        return self._datasource.insert(self._target_class, **insert_datas)
44
+
45
+
46
+class LeFilteredQuery(LeQuery):
20 47
 
21 48
     def __init__(self, target_class):
22 49
         super().__init__(target_class)
23
-        if target_class.is_abstract():
24
-            raise LeQueryError("Target EmClass cannot be abstract for an InsertQuery")
25 50
 
26
-## @brief Handles Le*Query with a query_filter argument
27
-# @see LeGetQuery, LeUpdateQuery, LeDeleteQuery
28
-class LeFilteredQuery(LeQuery):
29
-    pass
51
+    @classmethod
52
+    def validate_query_filters(cls, query_filters):
53
+        for query_filter in query_filters:
54
+            if query_filter[1] not in cls._query_operators:
55
+                raise LeQueryError("The operator %s is not valid." % query_filter[1])
56
+        return True
57
+
30 58
 
31
-## @brief Handles Get queries
32 59
 class LeGetQuery(LeFilteredQuery):
33
-    pass   
34 60
 
35
-## @brief Handles Update queries
61
+    def __init__(self, target_class, target_uid, query_filters, field_list=None, order=None, group=None, limit=None, offset=0, instanciate=True):
62
+        super().__init__(target_class)
63
+        self.query_filters = query_filters
64
+        self.default_field_list = []
65
+        self.field_list = field_list if field_list is not None else self._target_class.fieldnames()
66
+        self.order = order
67
+        self.group = group
68
+        self.limit = limit
69
+        self.offset = offset
70
+        self.instanciate = instanciate
71
+        self.target_object = None  # TODO get an instance of the target_class using a unique id
72
+
73
+    def execute(self):
74
+        datas = self.datas  # TODO : replace with LodelHook.call_hook('leapi_get_pre', self.target_object, self.datas)
75
+        ret = self.__get(**datas)
76
+        # ret = LodelHook.call_hook('leapi_get_post', self.target_object, ret)
77
+        return ret
78
+
79
+    def __get(self, **kwargs):
80
+        field_list = self.__prepare_field_list(self.field_list)  #TODO implement the prepare_field_list method
81
+
82
+        # Preparing order
83
+        if self.order:
84
+            order = self.__prepare_order()
85
+            if isinstance(order, Exception):
86
+                raise order  # can be buffered and raised later, but _prepare_filters raise when fails
87
+
88
+        # Preparing group
89
+        if self.group:
90
+            group = self.__prepare_order()
91
+            if isinstance(group, Exception):
92
+                raise group  # can be buffered and raised later
93
+
94
+        # checks the limit and offset values
95
+        if self.limit is not None and self.limit <= 0:
96
+            raise ValueError('Invalid limit given')
97
+
98
+        if self.offset is not None and self.offset < 0:
99
+            raise ValueError('Invalid offset given : %d' % self.offset)
100
+
101
+        results = self._datasource.select()  # TODO add the correct arguments for the datasource's method call
102
+        return results
103
+
104
+    def __prepare_field_list(self):
105
+        pass
106
+
107
+    def __prepare_filters(self):
108
+        pass
109
+
110
+    def __prepare_order(self):
111
+        errors = dict()
112
+        result = []
113
+        for order_field in self.order:
114
+            if not isinstance(order_field, tuple):
115
+                order_field = (order_field, 'ASC')
116
+            if len(order_field) != 2 or order_field[1].upper() not in ['ASC', 'DESC']:
117
+                errors[order_field] = ValueError("Expected a string or a tuple with (FIELDNAME, ['ASC'|'DESC']) but got : %s" % order_field)
118
+            else:
119
+                ret = self._target_class.check_field(order_field[0])
120
+                if isinstance(ret, Exception):
121
+                    errors[order_field] = ret
122
+            order_field = (order_field[0], order_field[1].upper())
123
+            result.append(order_field)
124
+
125
+        if len(errors) > 0:
126
+            return LeApiErrors("Errors when preparing ordering fields", errors)
127
+        return result
128
+
129
+
36 130
 class LeUpdateQuery(LeFilteredQuery):
37
-    pass
38 131
 
39
-## @biref Handles Delete queries
40
-class LeInsertQuery(LeFilteredQuery):
41
-    pass
132
+    def __init__(self, target_class, target_uid, query_filters):
133
+        super().__init__(target_class)
134
+        self.query_filters = query_filters
135
+        self.target_uid = target_uid
136
+        self.target_object = None  # TODO get an instance of the target_class using a unique id
137
+
138
+    def execute(self):
139
+        # LodelHook.call_hook('leapi_update_pre', self.target_object, None)
140
+        ret = self.__update()
141
+        # ret = LodelHook.call_hook('leapi_update_post', self.target_object, ret)
142
+        return ret
143
+
144
+    ## @brief calls the datasource's update method and the corresponding hooks
145
+    # @return bool
146
+    # @TODO change the behavior in case of error in the update process
147
+    def __update(self):
148
+        updated_datas = self.__prepare()
149
+        ret = self._datasource.update(self.target_uid, **updated_datas)  # TODO add the correct arguments for the datasource's method call
150
+        if ret == 1:
151
+            return True
152
+        else:
153
+            return False
154
+
155
+    ## @brief prepares the query_filters to be used as argument for the datasource's update method
156
+    def __prepare(self):
157
+        datas = dict()
158
+        if super().validate_query_filters(self.query_filters):
159
+            datas['query_filters'] = self.query_filters
160
+
161
+        datas['target_uid'] = self.target_uid
162
+        datas['target_class'] = self._target_class
163
+        return datas
164
+
165
+
166
+class LeDeleteQuery(LeFilteredQuery):
167
+
168
+    def __init__(self, target_class, target_uid, query_filters):
169
+        super().__init__(self._target_class)
170
+        self.target_uid = target_uid
171
+        self.query_filters = query_filters
172
+
173
+    def execute(self):
174
+        # LodelHook.call_hook('leapi_delete_pre', self.target_uid, None)
175
+        ret = self.__delete()
176
+        # ret = LodelHook.call('leapi_delete_post', self.target_object, ret)
177
+        return ret
178
+
179
+    def __delete(self):
180
+        delete_datas = self.__prepare()
181
+        ret = self._datasource.delete(**delete_datas)
182
+        return ret
183
+
184
+    def __prepare(self):
185
+        datas = dict()
186
+        if super().validate_query_filters(self.query_filters):
187
+            datas['query_filters'] = self.query_filters
188
+
189
+        datas['target_uid'] = self.target_uid
190
+        datas['target_class'] = self._target_class
191
+
192
+        return datas

Loading…
Cancel
Save