Browse Source

Updated version of the sqlwrapper

Yann Weber 9 years ago
parent
commit
a25e97607c
2 changed files with 269 additions and 446 deletions
  1. 67
    0
      Database/sqlobject.py
  2. 202
    446
      Database/sqlwrapper.py

+ 67
- 0
Database/sqlobject.py View File

1
+# -*- coding: utf-8 -*-
2
+
3
+import os
4
+import logging as logger
5
+
6
+import sqlalchemy as sql
7
+
8
+from Database.sqlwrapper import SqlWrapper
9
+
10
+class SqlObject(object):
11
+    """ Object that make aliases with sqlalchemy
12
+        
13
+        Example usage of object that inherite from SqlObject :
14
+        
15
+        class foo(SlqObject,...):
16
+            def __init__(self, ...):
17
+                self.__class__.tname = 'foo_table'
18
+
19
+        f = foo(...)
20
+        req = f.where(f.col.id == 42)
21
+        res = f.rexec(req)
22
+
23
+        e = bar(...)
24
+        req = f.join(e.col.id == f.col.id)
25
+        res = f.rexec(req)
26
+
27
+    """
28
+
29
+    def __init__(self, tname):
30
+        self.tname = tname
31
+
32
+    @property
33
+    def table(self):
34
+        return sql.Table(self.tname, sql.MetaData())
35
+
36
+    @property
37
+    def col(self):
38
+        return self.table.c
39
+    
40
+    @property
41
+    def sel(self):
42
+        return sql.select(self.table)
43
+
44
+    @property
45
+    def where(self):
46
+        return self.sel.where
47
+
48
+    @property
49
+    def join(self):
50
+        return self.sel.join
51
+
52
+    @property
53
+    def rconn(self):
54
+        return SqlWrapper.rconn()
55
+
56
+    @property
57
+    def wconn(self):
58
+        return SqlWrapper.wconn()
59
+
60
+    def sFetchAll(self, sel):
61
+        return self.rexec(sel).fetchall()
62
+
63
+    def rexec(self, o):
64
+        return self.rconn.execute(o)
65
+
66
+    def wexec(self, o):
67
+        return self.wconn.execute(o)

+ 202
- 446
Database/sqlwrapper.py View File

1
 # -*- coding: utf-8 -*-
1
 # -*- coding: utf-8 -*-
2
+import os
3
+import logging as logger
2
 
4
 
3
-from sqlalchemy import * # TODO ajuster les classes à importer
4
-from Database.sqlsettings import SQLSettings as sqlsettings
5
+import sqlalchemy as sqla
5
 from django.conf import settings
6
 from django.conf import settings
6
-import re
7
 
7
 
8
-import logging as logger #TODO hack to replace the standarts use of logging in django
8
+#Logger config
9
 logger.getLogger().setLevel('DEBUG')
9
 logger.getLogger().setLevel('DEBUG')
10
+#To be able to use dango confs
11
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Lodel.settings")
10
 
12
 
11
 class SqlWrapper(object):
13
 class SqlWrapper(object):
12
-
13
-    def __init__(self, log=False):
14
+    """ A wrapper class to sqlalchemy 
15
+        Usefull to provide a standart API
16
+    """
17
+
18
+    ##Read Engine
19
+    rengine = None
20
+    ##Write Engine
21
+    wengine = None
22
+
23
+    ##Read connection
24
+    rconn = None
25
+    ##Write connection
26
+    wconn = None
27
+
28
+    ##Configuration dict alias for class access
29
+    config=settings.LODEL2SQLWRAPPER
30
+    ##SqlAlchemy logging
31
+    sqla_logging = False
32
+
33
+    def __init__(self, alchemy_logs=None):
14
         """ Instanciate a new SqlWrapper
34
         """ Instanciate a new SqlWrapper
15
-            @param log bool: If true activate sqlalchemy logger
16
-        """
17
-        # TODO Passer ces deux éléments dans les settings django (au niveau de l'init de l'appli)
18
-        self.read_engine = self.get_engine(sqlsettings.DB_READ_CONNECTION_NAME, log)
19
-        self.write_engine = self.get_engine(sqlsettings.DB_WRITE_CONNECTION_NAME, log)
20
-
21
-    def get_engine(self, connection_name, log=False):
22
-        """ Crée un moteur logique sur une base de données
23
-
24
-            @param connection_name str: Connection name as defined is django settings
25
-            @param log bool: If true this engine will have logging enabled
26
-            @return Engine
27
-        """
28
-
29
-        connection_params = settings.DATABASES[connection_name]
30
-
31
-        if 'ENGINE' not in connection_params:
32
-            raise NameError('Missing ENGINE in configuration file')
33
-
34
-        if connection_params['ENGINE'] not in sqlsettings.dbms_list:
35
-            raise NameError('Wrong ENGINE "'+connection_params['ENGINE']+'" in configuration files')
36
-        dialect = connection_params['ENGINE']
37
-
38
-        if 'driver' not in sqlsettings.dbms_list[dialect]:
39
-            raise NameError('Wrong ENGINE "'+dialect+'" in configuration files')
40
-        driver = sqlsettings.dbms_list[dialect]['driver']
41
-
42
-        if 'NAME' not in connection_params:
43
-            raise NameError('Missing database name in configuration files')
44
-        database = connection_params['NAME']
45
-
46
-        if 'USER' in connection_params:
47
-            user = connection_params['USER']
48
-            if 'PASSWORD' in connection_params:
49
-                user += ':'+connection_params['PASSWORD']
35
+            @param alchemy_logs bool: If true activate sqlalchemy logger
36
+        """
37
+        
38
+        if (alchemy_logs != None and \
39
+            bool(alchemy_logs) != self.__class__.sqla_logging):
40
+            #logging config changed for sqlalchemy
41
+            self.__class__.restart()
42
+
43
+        if not self.__class__.started():
44
+            self.__class__.start()
45
+        
46
+        pass
47
+
48
+    @classmethod
49
+    def table(c, o):
50
+        """ Return a SqlAlchemy Table object
51
+            @param o str: Table name
52
+        """
53
+        if isinstance(o, str):
54
+            return sqla.Table(o, sqla.MetaData())
55
+        return None
56
+
57
+    @classmethod
58
+    def connect(c,read = None):
59
+        
60
+        if read == None:
61
+            return c.connect(True) and c.coonect(False)
62
+        elif read:
63
+            c.rconn = c.rengine.connect()
50
         else:
64
         else:
51
-            user = ''
52
-
53
-        hostname = connection_params['HOST'] if 'HOST' in connection_params else sqlsettings.DEFAULT_HOSTNAME
54
-        port = connection_params['PORT'] if 'PORT' in connection_params else ''
55
-        host = hostname if port=='' else '%s:%s' % (hostname, port)
65
+            c.wconn = c.wengine.connect()
66
+        return True #TODO attention c'est pas checké...
56
 
67
 
57
-
58
-        if dialect == 'sqlite':
59
-            connection_string = '%s+%s:///%s' % (dialect, driver, database)
68
+    @classmethod   
69
+    def conn(c, read=True):
70
+        if read:
71
+            res = c.rconn
60
         else:
72
         else:
61
-            connection_string = '%s+%s://%s@%s/%s' % (dialect, driver, user, host, database)
62
-
63
-        engine = create_engine(connection_string, encoding=sqlsettings.dbms_list[dialect]['encoding'], echo=log)
64
-        return engine
65
-
66
-    def get_read_engine(self):
67
-        return self.read_engine
68
-
69
-    def get_write_engine(self):
70
-        return self.write_engine
71
-
72
-    def execute(self, queries, action_type):
73
-        """ Exécute une série de requêtes en base
74
-
75
-            @param queries list: une liste de requêtes
76
-            @param action_type str: le type d'action ( 'read'|'write' )
77
-            @return List. Tableau de résultats sous forme de tuples (requête, résultat)
78
-        """
79
-
80
-        db = self.get_write_engine() if action_type==sqlsettings.ACTION_TYPE_WRITE else self.get_read_engine()
81
-        connection = db.connect()
82
-        transaction= connection.begin()
83
-        result = []
84
-
85
-        queries = queries if isinstance(queries, list) else [queries]
86
-
87
-
88
-        try:
89
-            for query in queries:
90
-                result.append((query, connection.execute(query)))
91
-            transaction.commit()
92
-            connection.close()
93
-        except:
94
-            transaction.rollback()
95
-            connection.close()
96
-            result = None
97
-            raise
98
-
99
-        return result
100
-
101
-    def create_foreign_key_constraint_object(self, localcol, remotecol, constraint_name=None):
102
-        """ Génère une contrainte Clé étrangère
103
-
104
-            @param localcol str: Colonne locale
105
-            @param remotecol str: Colonne distante (syntaxe : Table.col)
106
-            @param constraint_name str: Nom de la contrainte (par défaut : fk_localcol_remotecol)
107
-
108
-        Returns:
109
-            ForeignKeyConstraint.
110
-        """
111
-
112
-        foreignkeyobj = ForeignKeyConstraint([localcol], [remotecol], name=constraint_name)
113
-        return foreignkeyobj
114
-
115
-    def create_column_object(self, column_name, column_type, column_extra=None):
116
-        """ Génère un objet colonne
117
-
118
-            Exemple de dictionnaire pour column_extra : { "primarykey":True, "nullable":False, "default":"test" ... }
119
-            @param column_name str: Nom de la colonne
120
-            @param column_type str: Type de la colonne
121
-            @param column_extra dict : Objet json contenant les paramètres optionnels comme PRIMARY KEY, NOT NULL, etc ...
122
-
123
-            @return Column. La méthode renvoie "None" si l'opération échoue
124
-
125
-        """
126
-
127
-        # Traitement du type (mapping avec les types SQLAlchemy)
128
-        # TODO créer une méthode qui fait un mapping plus complet
129
-        column = None
130
-        if column_type=='INTEGER':
131
-            column = Column(column_name, INTEGER)
132
-        elif 'VARCHAR' in column_type:
133
-            check_length = re.search(re.compile('VARCHAR\(([\d]+)\)', re.IGNORECASE), column_type)
134
-            column_length = int(check_length.groups()[0]) if check_length else None
135
-            column = Column(column_name, VARCHAR(length=column_length))
136
-        elif column_type=='TEXT':
137
-            column = Column(column_name, TEXT)
138
-        elif column_type=='DATE':
139
-            column = Column(column_name, DATE)
140
-        elif column_type=='BOOLEAN':
141
-            column = Column(column_name, BOOLEAN)
142
-
143
-        if column is not None and column_extra:
144
-            if 'nullable' in column_extra:
145
-                column.nullable = column_extra['nullable']
146
-            if 'primarykey' in column_extra:
147
-                column.primary_key = column_extra['primarykey']
148
-            if 'default' in column_extra:
149
-                column.default = ColumnDefault(column_extra['default'])
150
-            if 'foreignkey' in column_extra:
151
-                column.append_foreign_key(ForeignKey(column_extra['foreignkey']))
152
-
153
-
154
-        return column
155
-
156
-    def create_table(self, tableparams):
157
-        """ Crée une nouvelle table
158
-
159
-            Les paramètres de la tables sont passés via un dictionnaire dont voici la description :
160
-            { 'name':'<nom_table>', 'columns': [ <col1>, <col2>, <coln> ], 'constraints': dict(...) }
161
-            Avec <colX> : { 'name': '<name_colX>', 'type': '<type_colX>', 'extra': dict(...) }
162
-            A noter que les types de col (<type_colX>) sont des chaines representant un type SQL (ex: "VARCHAR(50)")
163
-            Les deux champs "name" et "columns" seulement sont obligatoires.
164
-            Le champ "extra" de la définition des colonnes est facultatif.
165
-
166
-            @args tableparams dict: Dictionnaire avec les paramétrages de la table
167
-
168
-            @return bool. True si le process est allé au bout, False si on a rencontré une erreur.
169
-
170
-        """
171
-
172
-        metadata = MetaData()
173
-        table = Table(tableparams['name'], metadata)
174
-        columns = tableparams['columns']
175
-        for column in columns:
176
-            column_extra = column['extra'] if 'extra' in column else None
177
-            table.append_column(self.create_column_object(column['name'], column['type'], column_extra))
178
-
179
-        try:
180
-            table.create(self.get_write_engine())
181
-            return True
182
-        except Exception as e:
183
-            # TODO Ajuster le code d'erreur à retourner
184
-            logger.warning("Error creating table : "+str(e))
73
+            res = c.wconn
74
+
75
+        if res == None:
76
+            if not c.connect(read):
77
+                raise RuntimeError('Unable to connect to Db')
78
+            return self.conn(read)
79
+
80
+        return c.rconn
81
+
82
+    @classmethod
83
+    def rc(c): return c.conn(True)
84
+    @classmethod
85
+    def wc(c): return c.conn(False)
86
+
87
+    @classmethod
88
+    def start(c, sqlalogging = None):
89
+        """ Load engines
90
+            Open connections to databases
91
+            @param sqlalogging bool: overwrite class parameter about sqlalchemy logging
92
+            @return False if already started
93
+        """
94
+        c.checkConf()
95
+        if c.started():
96
+            logger.warning('Starting SqlWrapper but it is allready \
97
+started')
185
             return False
98
             return False
186
 
99
 
100
+        c.rengine = c._getEngine(read=True, sqlaloggingi=None)
101
+        c.wengine = c._getEngine(read=False, sqlalogging=None)
102
+        return True
187
 
103
 
188
-    def get_table(self, table_name, action_type=sqlsettings.ACTION_TYPE_WRITE):
189
-        """ Récupère une table dans un objet Table
104
+    @classmethod
105
+    def stop(c): c.rengine = c.wengine = None; pass
106
+    @classmethod
107
+    def restart(c): c.stop(); c.start(); pass
108
+    @classmethod
109
+    def started(c): return (c.rengine != None and c.rengine != None)
110
+    
111
+    @classmethod
112
+    def _sqllog(c,sqlalogging = None):
113
+        return bool(sqlalogging) if sqlalogging != None else c.sqlalogging
114
+
115
+    @classmethod
116
+    def _getEngine(c, read=True, sqlalogging = None):
117
+        """ Return a sqlalchemy engine
118
+            @param read bool: If True return the read engine, else 
119
+            return the write one
120
+            @return a sqlachemy engine instance
121
+
122
+            @todo Put the check on db config in SqlWrapper.checkConf()
123
+        """
124
+        #Loading confs
125
+        connconf = 'dbread' if read else 'dbwrite'
126
+        dbconf = connconf if connconf in c.config['db'] else 'default'
127
+
128
+        if dbconf not in c.config['db']: #This check should not be here
129
+            raise NameError('Configuration error no db "'+dbconf+'" in \
130
+configuration files')
131
+        
132
+        cfg = c.config['db'][dbconf] #Database config
133
+        
134
+        edata = c.config['engines'][cfg['ENGINE']] #engine infos
135
+        conn_str = cfg['ENGINE']+'+'+edata['driver']+'://'
136
+
137
+        if cfg['ENGINE'] == 'sqlite':
138
+            #Sqlite connection string
139
+            conn_str = '%s+%s:///%s'%( cfg['ENGINE'],
140
+                edata['driver'],
141
+                cfg['NAME'])
142
+        else:
143
+            #Mysql and Postgres connection string
144
+            user = cfg['USER']
145
+            user += (':'+cfg['PASSWORD'] if 'PASSWORD' in cfg else '')
190
             
146
             
191
-            @param table_name str: Nom de la table
192
-            @param action_type str: Type d'action (read|write) (par défaut : "write")
193
-            @return Table.
194
-        """
195
-        db = self.get_write_engine() if action_type == sqlsettings.ACTION_TYPE_WRITE else self.get_read_engine()
196
-        metadata = MetaData()
197
-
198
-        return Table(table_name, metadata, autoload=True, autoload_with=db)
199
-
147
+            if 'HOST' not in cfg:
148
+                logger.info('Not HOST in configuration, using \
149
+localhost')
150
+                host = 'localhost'
151
+            else:
152
+                host = cfg['HOST']
200
 
153
 
201
-    def drop_table(self, table_name):
202
-        """ Supprime une table
203
-            @param table_name str: Nom de la table
204
-            @return bool. True si le process est allé au bout. False si on a rencontré une erreur
205
-        """
154
+            host += (':'+cfg['PORT'] if 'PORT' in cfg else '')
206
 
155
 
207
-        try:
208
-            db = self.get_write_engine().connect()
209
-            metadata = MetaData()
210
-            table = Table(table_name, metadata, autoload=True, autoload_with=db)
211
-            # Pour le drop, on utilise checkfirst qui permet de demander la suppression préalable des contraintes liées à la table
212
-            table.drop(db, checkfirst=True)
213
-            db.close()
214
-            return True
215
-        except Exception as e:
216
-            # TODO ajuster le code d'erreur
217
-            logger.warning("Error droping table : "+str(e))
218
-            return False
156
+            conn_str = '%s+%s://'%(cfg['ENGINE'], edata['driver'])
157
+            conn_str += '%s@%s/%s'%(user,host,cfg['NAME'])
219
 
158
 
159
+        return sqla.create_engine(   conn_str, encoding=edata['encoding'],
160
+                                echo=c._sqllog(sqlalogging))
220
 
161
 
221
-    def get_querystring(self, action, dialect):
222
-        """ Renvoit un modèle de requete selon un dialect et une action
162
+    @classmethod
163
+    def checkConf(c):
164
+        """ Class method that check the configuration
223
             
165
             
224
-            @param action str: Peut être 'add_column' 'alter_column' 'drop_column'
225
-            @param dialect str: Pour le moment seul 'default', 'mysql' et 'postgresql' sont supportés
226
-
227
-            @return str: Un modèle de requète
228
-        """
229
-        string_dialect = dialect if dialect in sqlsettings.querystrings[action] else 'default'
230
-        querystring = sqlsettings.querystrings[action][string_dialect]
231
-        return querystring
232
-
233
-    def add_column(self, table_name, column):
234
-        """ Ajoute une colonne à une table existante
235
-
236
-            @param table_name str: nom de la table
237
-            @param column dict: la colonne - {"name":"<nom de la colonne>", "type":"<type de la colonne>"}
238
-
239
-            @return bool. True si le process est allé au bout, False si on a rencontré une erreur
240
-        """
241
-
242
-        sqlquery = self.get_querystring('add_column', self.get_write_engine().dialect) % (table_name, column['name'], column['type'])
243
-        sqlresult = self.execute(sqlquery, sqlsettings.ACTION_TYPE_WRITE)
244
-        return True if sqlresult else False
245
-
246
-    def alter_column(self, table_name, column):
247
-        """ Modifie le type d'une colonne
248
-
249
-            @param table_name str: nom de la table
250
-            @param column_name dict: la colonne - {"name":"<nom de la colonne>","type":"<nouveau type de la colonne>"}
251
-
252
-            @return bool. True si le process est allé au bout. False si on a rencontré une erreur
253
-        """
254
-
255
-        sqlquery = self.get_querystring('alter_column', self.get_write_engine().dialect) % (table_name, column['name'], column['type'])
256
-        sqlresult = self.execute(sqlquery, sqlsettings.ACTION_TYPE_WRITE)
257
-        return True if sqlresult else False
258
-
259
-    def insert(self, table_name, newrecord):
260
-        """ Insère un nouvel enregistrement
261
-
262
-            @param table_name str: nom de la table
263
-            @param newrecord dict: dictionnaire contenant les informations sur le nouvel enregistrement à insérer - {"column1":"value1", "column2":"value2", etc ...)
264
-
265
-            @return int. Nombre de lignes insérées
266
-        """
267
-        sqlresult = self.execute(self.get_table(table_name).insert().values(newrecord), sqlsettings.ACTION_TYPE_WRITE)
268
-        return sqlresult.rowcount
269
-
270
-    def delete(self, table_name, whereclauses):
271
-        """ Supprime un enregistrement
272
-
273
-            @param table_name str: nom de la table
274
-            @param whereclauses list: liste des conditions sur les enregistrements (sous forme de textes SQL)
275
-
276
-            @return int. Nombre de lignes supprimées
277
-        """
278
-
279
-        deleteobject = self.get_table(table_name).delete()
280
-
281
-        for whereclause in whereclauses:
282
-            deleteobject = deleteobject.where(whereclause)
283
-
284
-        sqlresult = self.execute(deleteobject, sqlsettings.ACTION_TYPE_WRITE)
285
-        return sqlresult.rowcount
286
-
287
-    def update(self, table_name, whereclauses, newvalues):
288
-        """ Met à jour des enregistrements
289
-
290
-            @param table_name str: nom de la table
291
-            @param whereclauses list: liste des conditions sur les enregistrements (sous forme de textes SQL)
292
-            @param newvalues dict: dictionnaire contenant les nouvelles valeurs à insérer - {"colonne1":"valeur1", "colonne2":"valeur2", etc ...}
293
-
294
-            @return int. Nombre de lignes modifiées
295
-
296
-            @throw DataError. Incompatibilité entre la valeur insérée et le type de colonne dans la table
297
-        """
298
-
299
-        table = self.get_table(table_name)
300
-        update_object = table.update()
301
-
302
-        updated_lines_count = 0
303
-
304
-        try:
305
-            for whereclause in whereclauses:
306
-                update_object = update_object.where(whereclause)
307
-
308
-            update_object = update_object.values(newvalues)
309
-
310
-            sqlresult = self.execute(update_object, sqlsettings.ACTION_TYPE_WRITE)
311
-            updated_lines_count = sqlresult.rowcount
312
-
313
-        except DataError as e:
314
-            # TODO Voir si on garde "-1" ou si on place un "None" ou un "False"
315
-            logger.warning("Error updating database : "+str(e))
316
-            updated_lines_count = -1
317
-
318
-        return updated_lines_count
319
-
320
-    def select(self, select_params):
321
-        """ Récupère un jeu d'enregistrements
322
-
323
-            Champs de select_params :
324
-            - "what":"<liste des colonnes>",
325
-            - "from":"<liste des tables>",
326
-            - "where":"<liste des conditions>",
327
-            - "distinct":True|False,
328
-            - "join":{"left":"table_de_gauche.champ","right":"table_de_droite.champ", "options":{"outer":True|False}}
329
-            - ...
330
-
331
-            Les listes sont supportées sous deux formats :
332
-            - texte SQL : "colonne1, colonne2, ..."
333
-            - liste Python : ["colonne1", "colonne2", ...]
334
-
335
-            @param select_params list: liste de dictionnaire permettant de caractériser la requête.
336
-
337
-            @return list. Liste des dictionnaires représentant les différents enregistrements.
338
-        """
339
-
340
-        if not 'what' in select_params or not 'from' in select_params:
341
-            # TODO Lever une exception à ce niveau
342
-            raise
343
-
344
-        query_what = select_params['what'] if isinstance(select_params['what'], list) else select_params['what'].replace(' ', '').split(',')
345
-        query_from = select_params['from'] if isinstance(select_params['from'], list) else select_params['from'].replace(' ', '').split(',')
346
-        query_where= select_params['where'] if isinstance(select_params['where'], list) else select_params['where'].replace(' ', '').split(',')
347
-        query_distinct = select_params['distinct'] if 'distinct' in select_params else False
348
-        query_limit = select_params['limit'] if 'limit' in select_params else False
349
-        query_offset = select_params['offset'] if 'offset' in select_params else False
350
-        query_orderby = select_params['order_by'] if 'order_by' in select_params else False
351
-        query_groupby = select_params['group_by'] if 'group_by' in select_params else False
352
-        query_having = select_params['having'] if 'having' in select_params else False
353
-
354
-        columns_list = []
355
-        if len(query_from) > 1:
356
-            for column_id in query_what:
357
-                # Il y a plusieurs tables, les colonnes sont donc nommées sur le format suivant : <nom de la table>.<nom du champ>
358
-                column_id_array = column_id.split('.')
359
-                columns_list.append(getattr(self.get_table(column_id_array[0]).c, column_id_array[1]))
166
+            Configuration looks like
167
+            - db (mandatory)
168
+             - ENGINE (mandatory)
169
+             - NAME (mandatory)
170
+             - USER
171
+             - PASSWORD
172
+            - engines (mandatory)
173
+             - driver (mandatory)
174
+             - encoding (mandatory)
175
+            - dbread (mandatory if no default db)
176
+            - dbwrite (mandatory if no default db)
177
+        """
178
+        return True #TODO desactivate because buggy
179
+        err = []
180
+        if 'db' not in c.config:
181
+            err.append('Missing "db" in configuration')
360
         else:
182
         else:
361
-            table = self.get_table(query_from[0])
362
-
363
-
364
-        select_object = select(columns=columnslist)
365
-
366
-        selected_lines = []
367
-
368
-        try:
369
-            # Traitement des différents paramètres de la requête
370
-            for query_where_item in query_where:
371
-                select_object = select_object.where(query_where_item)
372
-
373
-            select_object = select_object.distinct(True) if query_distinct else select_object
374
-            select_object = select_object.limit(query_limit) if query_limit else select_object
375
-            select_object = select_object.offset(query_offset) if query_offset else select_object
376
-
377
-            if query_orderby:
378
-                for query_orderby_column, query_orderby_direction in query_orderby:
379
-                    select_object = select_object.order_by("%s %s" % (query_orderby_column, query_orderby_direction))
380
-
381
-            #Traitement de la jointure
382
-            if 'join' in select_params:
383
-                select_join = self.create_join_object(select_params['join'])
384
-                if select_join:
385
-                    select_object = select_object.select_from(select_join)
183
+            if 'default' not in c.config['db']:
184
+                if 'dbread' not in c.config:
185
+                    err.append('Missing "dbread" in configuration and\
186
+ no "default" db declared')
187
+                if 'dbwrite' not in c.config:
188
+                    err.append('Missing "dbwrite" in configuration and\
189
+ no "default" db declared')
190
+            for db in c.config['db']:
191
+                if 'ENGINE' not in db:
192
+                    err.append('Missing "ENGINE" in database "'+db+'"')
386
                 else:
193
                 else:
387
-                    raise # TODO Ajuster l'exception à lever (ici :"Données de jointure invalides ou manquantes")
388
-
389
-            #Traitement du group_by
390
-            if query_groupby:
391
-                for group_by_clause in query_groupby:
392
-                    select_object = select_object.group_by(self.get_table_column_from_sql_string(group_by_clause))
393
-
394
-            # Traitement du having
395
-            if query_groupby and query_having:
396
-                for having_clause in query_having:
397
-                    select_object = select_object.having(having_clause)
398
-
399
-            # Exécution de la requête
400
-            sqlresult = self.execute(select_object, sqlsettings.ACTION_TYPE_READ)
401
-
402
-            # Transformation du résultat en une liste de dictionnaires
403
-            records = sqlresult.fetchall()
404
-            for record in records:
405
-                selected_lines.append(dict(zip(record.keys(), record)))
406
-        except Exception as e:
407
-            logger.debug("Error selecting in database : "+str(e))
408
-            selected_lines = None
409
-
410
-        return selected_lines
411
-
412
-    def get_table_column_from_sql_string(self,sql_string):
413
-
414
-        sql_string_array = sql_string.split('.')
415
-        table_name = sql_string_array[0]
416
-        column_name = sql_string_array[1]
417
-        table_object = self.get_table(table_name,sqlsettings.ACTION_TYPE_READ)
418
-        column_object = getattr(table_object.c, column_name)
419
-
420
-        return column_object
421
-
422
-
423
-    def create_join_object(self, join_params):
424
-        """Génère un objet "Jointure" pour le greffer dans une requête
425
-
426
-            Format des dictionnaires de description des jointures :
427
-            - Format1 liste de champs
428
-             - "left":"table.champ",
429
-             - "right":"table.champ",
430
-             - "options":{"outer":True|False}
431
-            - Format2 liste de champs
432
-             - "left":{"table":"nom de la table","field":"nom du champ"},
433
-             - "right":{"table":"nom de la table","field":"nom du champ"},
434
-             - "options":{"outer":True|False}
435
-    
436
-            @param join_params (dict) : dictionnaire de données sur la jointure.
437
-            @return join.
438
-        """
439
-
440
-        join_object = None
441
-
442
-        if 'left' in join_params and 'right' in join_params:
443
-            if isinstance(join_params['left'], dict):
444
-                join_left_table_name = join_params['left']['table']
445
-                join_left_field_name = join_params['left']['field']
446
-            else:
447
-                join_left_array = join_params['left'].split('.')
448
-                join_left_table_name = join_left_array[0]
449
-                join_left_field_name = join_left_array[1]
450
-
451
-            if isinstance(join_params['right'], dict):
452
-                join_right_table_name = join_params['right']['table']
453
-                join_right_field_name = join_params['right']['field']
454
-            else:
455
-                join_right_array = join_params['right'].split('.')
456
-                join_right_table_name = join_right_array[0]
457
-                join_right_field_name = join_right_array[1]
458
-
459
-            left_table = self.get_table(join_left_table_name, sqlsettings.ACTION_TYPE_READ)
460
-            left_field = getattr(left_table.c, join_left_field_name)
461
-
462
-            right_table = self.get_table(join_right_table_name, sqlsettings.ACTION_TYPE_READ)
463
-            right_field = getattr(right_table.c, join_right_field_name)
464
-
465
-            join_option_isouter = True if 'options' in join_params and 'outer' in join_params and join_params['outer']==True else False
466
-
467
-            join_object = join(left_table, right_table, left_field == right_field,isouter=join_option_isouter)
194
+                    if db['ENGINE'] != 'sqlite' and 'USER' not in db:
195
+                        err.append('Missing "USER" in database "\
196
+'+db+'"')
197
+                if 'NAME' not in db:
198
+                    err.append('Missing "NAME" in database "'+db+'"')
199
+        
200
+        if len(c.config['engines']) == 0:
201
+            err.append('Missing "engines" in configuration')
202
+        for ename in c.config['engines']:
203
+            engine = c.config['engines'][ename]
204
+            if 'driver' not in engine:
205
+                err.append('Missing "driver" in database engine "\
206
+'+ename+'"')
207
+            if 'encoding' not in engine:
208
+                err.append('Missing "encoding" in database engine "\
209
+'+ename+'"')
210
+
211
+        if len(err)>0:
212
+            err_str = ""
213
+            for e in err:
214
+                err_str += e+"\n"
215
+            raise NameError('Configuration errors in LODEL2SQLWRAPPER\
216
+:'+err_str)
217
+                
218
+
219
+    @property
220
+    def cfg(self):
221
+        """ Get the dict of options for the wrapper
222
+            Its an alias to the classes property SqlWrapper.config
223
+            @return a dict containing the Db settings"""
224
+        return self.__class__.config
468
 
225
 
469
-        return join_object

Loading…
Cancel
Save