Browse Source

Implémentation requete

prieto 8 years ago
parent
commit
ab2bbee191
1 changed files with 130 additions and 21 deletions
  1. 130
    21
      lodel/leapi/query.py

+ 130
- 21
lodel/leapi/query.py View File

@@ -5,11 +5,30 @@ from .leobject import LeObject, LeApiErrors, LeApiDataCheckError
5 5
 from lodel.plugin.hooks import LodelHook
6 6
 
7 7
 class LeQueryError(Exception):
8
-    pass
8
+    ##@brief Instanciate a new exceptions handling multiple exceptions
9
+    # @param msg str : Exception message
10
+    # @param exceptions dict : A list of data check Exception with concerned field (or stuff) as key
11
+    def __init__(self, msg = "Unknow error", exceptions = None):
12
+        self._msg = msg
13
+        self._exceptions = dict() if exceptions is None else exceptions
14
+
15
+    def __repr__(self):
16
+        return self.__str__()
17
+
18
+    def __str__(self):
19
+        msg = self._msg
20
+        for_iter = self._exceptions.items() if isinstance(self._exceptions, dict) else enumerate(self.__exceptions)
21
+        for obj, expt in for_iter:
22
+            msg += "\n\t{expt_obj} : ({expt_name}) {expt_msg}; ".format(
23
+                    expt_obj = obj,
24
+                    expt_name=expt.__class__.__name__,
25
+                    expt_msg=str(expt)
26
+            )
27
+        return msg
9 28
 
10 29
 class LeQuery(object):
11 30
     
12
-    ##@brief Hookname preffix
31
+    ##@brief Hookname prefix
13 32
     _hook_prefix = None
14 33
     ##@brief arguments for the LeObject.check_data_value()
15 34
     _data_check_args = { 'complete': False, 'allow_internal': False }
@@ -18,7 +37,7 @@ class LeQuery(object):
18 37
     # @param target_class LeObject : class of object the query is about
19 38
     def __init__(self, target_class):
20 39
         if hook_prefix is None:
21
-            raise NotImplementedError("Asbtract class")
40
+            raise NotImplementedError("Abstract class")
22 41
         if not issubclass(target_class, LeObject):
23 42
             raise TypeError("target class has to be a child class of LeObject")
24 43
         self.__target_class = target_class
@@ -61,29 +80,82 @@ class LeFilteredQuery(LeQuery):
61 80
                         '!=',
62 81
                         '<',
63 82
                         '>',
64
-                        ' in ',
65
-                        ' not in ',
66
-                        ' like ',
67
-                        ' not like ']
83
+                        'in',
84
+                        'not in',
85
+                        'like',
86
+                        'not like']
68 87
 
69 88
     ##@brief Abtract constructor for queries with filter
70 89
     # @param target_class LeObject : class of object the query is about
71
-    # @param query_filters list : list of string of query filters (or tuple 
72
-    #(FIELD, OPERATOR, VALUE) )
90
+    # @param query_filters list : with a tuple (only one filter) or a list of tuple
91
+    #   or a dict: {OP,list(filters)} with OP = 'OR' or 'AND
92
+    #   For tuple (FIELD,OPERATOR,VALUE)
73 93
     def __init__(self, target_class, query_filter):
74 94
         super().__init__(target_class)
75 95
         ##@brief The query filter
76 96
         self.__query_filter = None
77
-        self.set_qeury_filter(query_filter)
97
+        self.set_query_filter(query_filter)
78 98
     
79 99
     ##@brief Set the query filter for a query
80 100
     def set_query_filter(self, query_filter):
81 101
         #
82
-        #   Query filter check & prepare should be done here
83
-        #
84
-        self.__query_filter = query_filter
102
+        #   Query filter check & prepare 
103
+        #   query_filters can be a tuple (only one filter), a list of tuple
104
+        #   or a dict: {OP,list(filters)} with OP = 'OR' or 'AND
105
+        #   For tuple (FIELD,OPERATOR,VALUE)
106
+        #   FIELD has to be in the field_names list of target class
107
+        #   OPERATOR in query_operator attribute
108
+        #   VALUE has to be a correct value for FIELD
109
+
110
+        fieldnames = self.__target_class.fieldnames()
111
+        # Recursive method which checks filters
112
+        def check_tuple(tupl, fieldnames, target_class):
113
+            if isinstance(tupl, tuple):
114
+                if tupl[0] not in fieldnames:
115
+                    return False
116
+                if tupl[1] not in self.query_operators:
117
+                    return False
118
+                if not isinstance(tupl[2], target_class.datahandler(tupl[0])):
119
+                    return False
120
+                return True
121
+            elif isinstance(tupl,dict):
122
+                return check_tuple(tupl[1])
123
+            elif isinstance(tupl,list):
124
+                for tup in tupl:
125
+                    return check_tuple(tup)
126
+            else: 
127
+                raise TypeError("Wrong filters for query")
128
+
129
+        check_ok=check_tuple(query_filter, fieldnames, self.__target_class)
130
+        if check_ok:            
131
+            self.__query_filter = query_filter
132
+            
133
+        # try to check if a query string is a simple condition like 'fieldname operator value'
134
+    def simple_cond(cond, target_class):
135
+            # cond is the where clause
85 136
 
86
-##@brief A query for insert a new object
137
+        if 'AND' in cond.upper():
138
+            return False
139
+        if 'OR' in cond.upper():
140
+            return False
141
+        
142
+        n_ops = 0
143
+        for op in target_class.query_operators:
144
+            if op in cond:
145
+                q_op=op
146
+                n_ops+=1
147
+        if n_ops > 1 or n_ops==0:
148
+            raise TypeError("%s isn't a valid sql condition" % cond)
149
+        tupl=cond.partition(q_op)
150
+
151
+        if tupl[0].strip() not in target_class.fieldnames:
152
+            raise TypeError("%s isn't a valid fieldname" % tupl[0].strip())
153
+        if not isinstance(tupl[2].strip(), target_class.datahandler(tupl[0].strip())):
154
+            raise TypeError("%s is not of a valid type for fieldname % s" % tupl[0],tupl[2])
155
+        return True
156
+    
157
+
158
+##@brief A query to insert a new object
87 159
 class LeInsertQuery(LeQuery):
88 160
     
89 161
     _hook_prefix = 'leapi_insert_'
@@ -92,11 +164,18 @@ class LeInsertQuery(LeQuery):
92 164
     def __init__(self, target_class):
93 165
         super().__init__(target_class)
94 166
     
95
-    ## @brief Implements an insert query operations
167
+    ## @brief Implements an insert query operation
96 168
     # @param **datas : datas to be inserted
97 169
     def __query(self, datasource, **datas):
98
-        pass
170
+        nb_inserted = datasource.insert(self.__target_class,**datas)
171
+        if nb_inserted < 0:
172
+            raise LeQueryError("Insertion error")
173
+        return nb_inserted
99 174
 
175
+    ## @brief Execute the insert query
176
+    def execute(self, datasource):
177
+        super().execute()
178
+        
100 179
 ##@brief A query to update datas for a given object
101 180
 class LeUpdateQuery(LeFilteredQuery):
102 181
     
@@ -108,8 +187,20 @@ class LeUpdateQuery(LeFilteredQuery):
108 187
     
109 188
     ##@brief Implements an update query
110 189
     # @param **datas : datas to update
190
+    # @returns the number of updated items
191
+    # @exception when the number of updated items is not as expected
111 192
     def __query(self, datasource, **datas):
112
-        pass
193
+        # select _uid corresponding to query_filter
194
+        l_uids=datasource.select(self.__target_class,list(self.__target_class.getuid()),query_filter,None, None, None, None, 0, False)
195
+        # list of dict l_uids : _uid(s) of the objects to be updated, corresponding datas
196
+        nb_updated = datasource.update(self.__target_class,l_uids, **datas)
197
+        if (nb_updated != len(l_uids):
198
+            raise LeQueryError("Number of updated items: %d is not as expected: %d " % (nb_updated, len(l_uids)))
199
+        return nb_updated
200
+    
201
+    ## @brief Execute the update query
202
+    def execute(self, datasource):
203
+        super().execute()
113 204
 
114 205
 ##@brief A query to delete an object
115 206
 class LeDeleteQuery(LeFilteredQuery):
@@ -124,8 +215,16 @@ class LeDeleteQuery(LeFilteredQuery):
124 215
         super().execute()
125 216
     
126 217
     ##@brief Implements delete query operations
218
+    # @returns the number of deleted items
219
+    # @exception when the number of deleted items is not as expected
127 220
     def __query(self, datasource):
128
-        pass
221
+        # select _uid corresponding to query_filter
222
+        l_uids=datasource.select(self.__target_class,list(self.__target_class.getuid()),query_filter,None, None, None, None, 0, False)
223
+        # list of dict l_uids : _uid(s) of the objects to be deleted
224
+        nb_deleted = datasource.update(self.__target_class,l_uids, **datas)
225
+        if (nb_deleted != len(l_uids):
226
+            raise LeQueryError("Number of deleted items %d is not as expected %d " % (nb_deleted, len(l_uids)))
227
+        return nb_deleted
129 228
 
130 229
 class LeGetQuery(LeFilteredQuery):
131 230
     
@@ -133,8 +232,8 @@ class LeGetQuery(LeFilteredQuery):
133 232
 
134 233
     ##@brief Instanciate a new get query
135 234
     # @param target_class LeObject : class of object the query is about
136
-    # @param query_filters list : list of string of query filters (or tuple 
137
-    #(FIELD, OPERATOR, VALUE) )
235
+    # @param query_filters dict : {OP, list of query filters }
236
+    #        or tuple (FIELD, OPERATOR, VALUE) )
138 237
     # @param field_list list|None : list of string representing fields see @ref leobject_filters
139 238
     # @param order list : A list of field names or tuple (FIELDNAME, [ASC | DESC])
140 239
     # @param group list : A list of field names or tuple (FIELDNAME, [ASC | DESC])
@@ -161,7 +260,7 @@ class LeGetQuery(LeFilteredQuery):
161 260
 
162 261
         if 'field_list' not in kwargs:
163 262
             #field_list = target_class.get_field_list
164
-            pass
263
+            field_list = target_class.fieldnames()
165 264
         else:
166 265
             #target_class.check_fields(kwargs['field_list'])
167 266
             field_list = kwargs['field_list']
@@ -190,3 +289,13 @@ class LeGetQuery(LeFilteredQuery):
190 289
     def execute(self, datasource):
191 290
         super().execute(datasource)
192 291
 
292
+    ##@brief Implements select query operations
293
+    # @returns a list containing the item(s)
294
+
295
+    def __query(self, datasource):
296
+        # select _uid corresponding to query_filter
297
+        l_datas=datasource.select(self.__target_class,list(self.field_list),self.query_filter,None, self.__order, self.__group, self.__limit, self.offset, False)
298
+        return l_datas
299
+        
300
+
301
+

Loading…
Cancel
Save