Browse Source

sqlwrapper deletion and sqlsetup enhancement

Moved the database initialisation functionnality to sqlsetup and fixed all the code to handle the sqlwrapper deletion
Yann Weber 10 years ago
parent
commit
a3b9daf319

+ 0
- 85
Database/sqlquerybuilder.py View File

@@ -1,85 +0,0 @@
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 SqlQueryBuilder():
11
-
12
-    def __init__(self, sqlwrapper, table):
13
-        if not type(sqlwrapper) is SqlWrapper:
14
-             logger.error("Unable to instanciate, bad argument...")
15
-             raise TypeError('Excepted a SqlWrapper not a '+str(type(sqlwrapper)))
16
-        self.table = table
17
-        self.sqlwrapper = sqlwrapper
18
-        self.proxy = None
19
-
20
-
21
-    def Select(self, arg):
22
-        """ Alias for select clause
23
-            @param arg iterable: arg must be a Python list or other iterable and contain eather table name/type or colum/literal_column
24
-        """
25
-
26
-        self.proxy = sql.select(arg)
27
-        return self.proxy
28
-
29
-    def Where(self, arg):
30
-        """ Alias for where clause
31
-            @param arg SQL expression object or string
32
-        """
33
-        self.proxy = self.proxy.where(arg)
34
-
35
-    def From(self, arg):
36
-        """ Alias for select_from clause
37
-            @param arg Table or table('tablename') or join clause
38
-        """
39
-        self.proxy = self.proxy.select_from(arg)
40
-
41
-    def Update(self):
42
-        self.proxy = self.table.update()
43
-
44
-    def Insert(self):
45
-        self.proxy = self.table.insert()
46
-
47
-    def Delete(self):
48
-        self.proxy = self.proxy.delete()
49
-
50
-    def Value(self, arg):
51
-        """
52
-        Allow you to specifies the VALUES or SET clause of the statement.
53
-        @param arg: VALUES or SET clause
54
-        """
55
-        self.proxy = self.proxy.values(arg)
56
-
57
-    def Execute(self, bindedparam):
58
-        """
59
-        Execute the sql query constructed in the proxy and return the result.
60
-        If no query then return False.
61
-        @return: query result on success else False
62
-        """
63
-        if(self.proxy.__str__().split() == 'SELECT'):
64
-            if('bindparam' in self.proxy.__str__()):
65
-                #on test separement la présence de la clause bindparam et le type de l'argument correspondant
66
-                #car si la clause est présente mais que l'argument est defectueux on doit renvoyer False et non pas executer la requete
67
-                if(type(bindedparam) is list and type(bindedparam[0]) is dict):
68
-                    return self.sqlwrapper.rconn.execute(self.proxy, bindedparam)
69
-                else:
70
-                    return False
71
-            else:
72
-                return self.sqlwrapper.rconn.execute(self.proxy)
73
-        elif(self.proxy is not None):
74
-            if('bindparam' in self.proxy.__str__()):
75
-                if(type(bindedparam) is list and type(bindedparam[0]) is dict):
76
-                    return self.sqlwrapper.wconn.execute(self.proxy, bindedparam)
77
-                else:
78
-                    return False
79
-            else:
80
-                return self.sqlwrapper.wconn.execute(self.proxy)
81
-        else:
82
-            return False
83
-
84
-
85
-

+ 184
- 113
Database/sqlsetup.py View File

@@ -1,120 +1,191 @@
1 1
 # -*- coding: utf-8 -*-
2 2
 
3
-from Database.sqlwrapper import SqlWrapper
4 3
 import sqlalchemy as sql
5
-
6
-class SQLSetup(object): 
7
-
8
-    def initDb(self, dbconfname = 'default', alchemy_logs=None):
9
-        db = SqlWrapper(read_db = dbconfname, write_db = dbconfname, alchemy_logs=alchemy_logs)
10
-        tables = self.get_schema()
11
-        db.dropAll()
12
-        db.createAllFromConf(tables)
13
-
14
-    def get_schema(self):
15
-        tables = []
16
-
17
-        default_columns = [
18
-            {"name":"uid",          "type":"INTEGER", "extra":{"foreignkey":"uids.uid", "nullable":False, "primarykey":True}},
19
-            {"name":"name",         "type":"VARCHAR(50)", "extra":{"nullable":False, "unique":True}},
20
-            {"name":"string",       "type":"TEXT"},
21
-            {"name":"help",         "type":"TEXT"},
22
-            {"name":"rank",         "type":"INTEGER"},
23
-            {"name":"date_create",  "type":"DATETIME"},
24
-            {"name":"date_update",  "type":"DATETIME"},
25
-        ]
26
-
27
-        # Table listing all objects created by lodel, giving them an unique id
28
-        uids = {
29
-                "name":"uids",
30
-                "columns":[
31
-                    {"name":"uid",          "type":"INTEGER", "extra":{"nullable":False, "primarykey":True, 'autoincrement':True}},
32
-                    {"name":"table",        "type":"VARCHAR(50)"}
33
-                ]
34
-            }
35
-        tables.append(uids)
36
-
37
-
38
-        # Table listing the classes
39
-        em_class = {"name":"em_class"}
40
-        em_class['columns'] = default_columns + [
41
-            {"name":"classtype",    "type":"VARCHAR(50)"},
42
-            {"name":"sortcolumn",   "type":"VARCHAR(50)", "extra":{"default":"rank"}},
43
-            {"name":"icon",         "type":"INTEGER"},
44
-        ]
45
-        tables.append(em_class)
46
-
47
-
48
-        # Table listing the types
49
-        em_type = {"name":"em_type"}
50
-        em_type['columns'] = default_columns + [
51
-            {"name":"class_id",     "type":"INTEGER", "extra":{"foreignkey":"em_class.uid", "nullable":False}},
52
-            {"name":"sortcolumn",   "type":"VARCHAR(50)", "extra":{"default":"rank"}},
53
-            {"name":"icon",         "type":"INTEGER"},
54
-        ]
55
-        tables.append(em_type)
56
-
57
-        # relation between types: which type can be a child of another
58
-        em_type_hierarchy = {"name":"em_type_hierarchy"}
59
-        em_type_hierarchy['columns'] = [
60
-            {"name":"superior_id",    "type":"INTEGER", "extra":{"foreignkey":"em_type.uid", "nullable":False, "primarykey":True}},
61
-            {"name":"subordinate_id", "type":"INTEGER", "extra":{"foreignkey":"em_type.uid", "nullable":False, "primarykey":True}},
62
-            {"name":"nature",         "type":"VARCHAR(50)", "extra":{"primarykey":True}},
63
-        ]
64
-        tables.append(em_type_hierarchy)
65
-
66
-       # Table listing the fieldgroups of a class
67
-        em_fieldgroup = {"name":"em_fieldgroup"}
68
-        em_fieldgroup['columns'] = default_columns + [
69
-            {"name":"class_id",     "type":"INTEGER", "extra":{"foreignkey":"em_class.uid", "nullable":False}},
70
-        ]
71
-        tables.append(em_fieldgroup)
72
-
73
-        # Table listing the fields of a fieldgroup
74
-        em_field = {"name":"em_field"}
75
-        em_field['columns'] = default_columns + [
76
-            {"name":"fieldtype",   "type":"VARCHAR(50)", "extra":{"nullable":False}},
77
-            {"name":"fieldgroup_id",  "type":"INTEGER", "extra":{"foreignkey":"em_fieldgroup.uid", "nullable":False}},
78
-            {"name":"rel_to_type_id", "type":"INTEGER", "extra":{"foreignkey":"em_type.uid", "nullable":True, "server_default": sql.text('NULL')}}, # if relational: type this field refer to
79
-            {"name":"rel_field_id",   "type":"INTEGER", "extra":{"foreignkey":"em_type.uid", "nullable":True, "server_default": sql.text('NULL')}}, # if relational: field that specify the rel_to_type_id
80
-            {"name":"optional",       "type":"BOOLEAN"},
81
-            {"name":"internal",       "type":"BOOLEAN"},
82
-            {"name":"icon",           "type":"INTEGER"},
83
-        ]
84
-        tables.append(em_field)
85
-
86
-        # selected field for each type
87
-        em_field_type = {"name":"em_field_type"}
88
-        em_field_type['columns'] = [
89
-            {"name":"type_id",   "type":"INTEGER", "extra":{"foreignkey":"em_type.uid", "nullable":False, "primarykey":True}},
90
-            {"name":"field_id",  "type":"INTEGER", "extra":{"foreignkey":"em_field.uid", "nullable":False, "primarykey":True}},
91
-        ]
92
-        tables.append(em_field_type)
93
-
94
-        # Table of the objects created by the user (instance of the types)
95
-        objects = {
96
-            "name":"objects",
97
-            "columns":[
98
-                {"name":"uid",         "type":"INTEGER", "extra":{"foreignkey":"uids.uid", "nullable":False, "primarykey":True}},
99
-                {"name":"string",      "type":"VARCHAR(50)"},
100
-                {"name":"class_id",    "type":"INTEGER", "extra":{"foreignkey":"em_class.uid"}},
101
-                {"name":"type_id",     "type":"INTEGER", "extra":{"foreignkey":"em_type.uid"}},
102
-                {"name":"date_create", "type":"DATETIME"},
103
-                {"name":"date_update", "type":"DATETIME"},
104
-                {"name":"history",     "type":"TEXT"}
105
-            ]
106
-        }
107
-        tables.append(objects)
108
-
109
-        # Table listing all files
110
-        # TODO Préciser les colonnes à ajouter
111
-        files = {
112
-            "name":"files",
4
+import re #Converting string to sqlalchemy types
5
+from Database import sqlutils
6
+
7
+
8
+def init_db(dbconfname = 'default', alchemy_logs=None, schema=None):
9
+
10
+    dbe = sqlutils.getEngine(dbconfname, alchemy_logs)
11
+    meta = sqlutils.meta(dbe)
12
+    meta.reflect()
13
+    meta.drop_all(dbe)
14
+    #refresh meta (maybe useless)
15
+    meta = sqlutils.meta(dbe)
16
+    meta.reflect()
17
+    
18
+    if schema is None:
19
+        schema = get_schema()
20
+
21
+    for table in schema:
22
+        topt = table.copy()
23
+        del topt['columns']
24
+        name = topt['name']
25
+        del topt['name']
26
+        cur_table = sql.Table(name, meta, **topt)
27
+        for col in table['columns']:
28
+            cur_col = create_column(**col)
29
+            cur_table.append_column(cur_col)
30
+
31
+    meta.create_all(bind=dbe)
32
+    pass
33
+    
34
+
35
+
36
+def get_schema():
37
+    tables = []
38
+
39
+    default_columns = [
40
+        {"name":"uid",          "type":"INTEGER", "extra":{"foreignkey":"uids.uid", "nullable":False, "primarykey":True}},
41
+        {"name":"name",         "type":"VARCHAR(50)", "extra":{"nullable":False, "unique":True}},
42
+        {"name":"string",       "type":"TEXT"},
43
+        {"name":"help",         "type":"TEXT"},
44
+        {"name":"rank",         "type":"INTEGER"},
45
+        {"name":"date_create",  "type":"DATETIME"},
46
+        {"name":"date_update",  "type":"DATETIME"},
47
+    ]
48
+
49
+    # Table listing all objects created by lodel, giving them an unique id
50
+    uids = {
51
+            "name":"uids",
113 52
             "columns":[
114
-                {"name":"uid",     "type":"INTEGER", "extra":{"foreignkey":"uids.uid", "nullable":False, "primarykey":True}},
115
-                {"name":"field1",  "type":"VARCHAR(50)"}
53
+                {"name":"uid",          "type":"INTEGER", "extra":{"nullable":False, "primarykey":True, 'autoincrement':True}},
54
+                {"name":"table",        "type":"VARCHAR(50)"}
116 55
             ]
117 56
         }
118
-        tables.append(files)
57
+    tables.append(uids)
58
+
59
+
60
+    # Table listing the classes
61
+    em_class = {"name":"em_class"}
62
+    em_class['columns'] = default_columns + [
63
+        {"name":"classtype",    "type":"VARCHAR(50)"},
64
+        {"name":"sortcolumn",   "type":"VARCHAR(50)", "extra":{"default":"rank"}},
65
+        {"name":"icon",         "type":"INTEGER"},
66
+    ]
67
+    tables.append(em_class)
68
+
69
+
70
+    # Table listing the types
71
+    em_type = {"name":"em_type"}
72
+    em_type['columns'] = default_columns + [
73
+        {"name":"class_id",     "type":"INTEGER", "extra":{"foreignkey":"em_class.uid", "nullable":False}},
74
+        {"name":"sortcolumn",   "type":"VARCHAR(50)", "extra":{"default":"rank"}},
75
+        {"name":"icon",         "type":"INTEGER"},
76
+    ]
77
+    tables.append(em_type)
78
+
79
+    # relation between types: which type can be a child of another
80
+    em_type_hierarchy = {"name":"em_type_hierarchy"}
81
+    em_type_hierarchy['columns'] = [
82
+        {"name":"superior_id",    "type":"INTEGER", "extra":{"foreignkey":"em_type.uid", "nullable":False, "primarykey":True}},
83
+        {"name":"subordinate_id", "type":"INTEGER", "extra":{"foreignkey":"em_type.uid", "nullable":False, "primarykey":True}},
84
+        {"name":"nature",         "type":"VARCHAR(50)", "extra":{"primarykey":True}},
85
+    ]
86
+    tables.append(em_type_hierarchy)
87
+
88
+   # Table listing the fieldgroups of a class
89
+    em_fieldgroup = {"name":"em_fieldgroup"}
90
+    em_fieldgroup['columns'] = default_columns + [
91
+        {"name":"class_id",     "type":"INTEGER", "extra":{"foreignkey":"em_class.uid", "nullable":False}},
92
+    ]
93
+    tables.append(em_fieldgroup)
94
+
95
+    # Table listing the fields of a fieldgroup
96
+    em_field = {"name":"em_field"}
97
+    em_field['columns'] = default_columns + [
98
+        {"name":"fieldtype",   "type":"VARCHAR(50)", "extra":{"nullable":False}},
99
+        {"name":"fieldgroup_id",  "type":"INTEGER", "extra":{"foreignkey":"em_fieldgroup.uid", "nullable":False}},
100
+        {"name":"rel_to_type_id", "type":"INTEGER", "extra":{"foreignkey":"em_type.uid", "nullable":True, "server_default": sql.text('NULL')}}, # if relational: type this field refer to
101
+        {"name":"rel_field_id",   "type":"INTEGER", "extra":{"foreignkey":"em_type.uid", "nullable":True, "server_default": sql.text('NULL')}}, # if relational: field that specify the rel_to_type_id
102
+        {"name":"optional",       "type":"BOOLEAN"},
103
+        {"name":"internal",       "type":"BOOLEAN"},
104
+        {"name":"icon",           "type":"INTEGER"},
105
+    ]
106
+    tables.append(em_field)
107
+
108
+    # selected field for each type
109
+    em_field_type = {"name":"em_field_type"}
110
+    em_field_type['columns'] = [
111
+        {"name":"type_id",   "type":"INTEGER", "extra":{"foreignkey":"em_type.uid", "nullable":False, "primarykey":True}},
112
+        {"name":"field_id",  "type":"INTEGER", "extra":{"foreignkey":"em_field.uid", "nullable":False, "primarykey":True}},
113
+    ]
114
+    tables.append(em_field_type)
115
+
116
+    # Table of the objects created by the user (instance of the types)
117
+    objects = {
118
+        "name":"objects",
119
+        "columns":[
120
+            {"name":"uid",         "type":"INTEGER", "extra":{"foreignkey":"uids.uid", "nullable":False, "primarykey":True}},
121
+            {"name":"string",      "type":"VARCHAR(50)"},
122
+            {"name":"class_id",    "type":"INTEGER", "extra":{"foreignkey":"em_class.uid"}},
123
+            {"name":"type_id",     "type":"INTEGER", "extra":{"foreignkey":"em_type.uid"}},
124
+            {"name":"date_create", "type":"DATETIME"},
125
+            {"name":"date_update", "type":"DATETIME"},
126
+            {"name":"history",     "type":"TEXT"}
127
+        ]
128
+    }
129
+    tables.append(objects)
130
+
131
+    # Table listing all files
132
+    # TODO Préciser les colonnes à ajouter
133
+    files = {
134
+        "name":"files",
135
+        "columns":[
136
+            {"name":"uid",     "type":"INTEGER", "extra":{"foreignkey":"uids.uid", "nullable":False, "primarykey":True}},
137
+            {"name":"field1",  "type":"VARCHAR(50)"}
138
+        ]
139
+    }
140
+    tables.append(files)
141
+
142
+    return tables
143
+
144
+def create_column(**kwargs):
145
+    #Converting parameters
146
+    if 'type_' not in kwargs and 'type' in kwargs:
147
+        kwargs['type_'] = _strToSqlAType(kwargs['type'])
148
+        del kwargs['type']
149
+
150
+    if 'extra' in kwargs:
151
+        #put the extra keys in kwargs
152
+        for exname in kwargs['extra']:
153
+            kwargs[exname] = kwargs['extra'][exname]
154
+        del kwargs['extra']
155
+
156
+    if 'foreignkey' in kwargs:
157
+        #Instanciate a fk
158
+        fk = sql.ForeignKey(kwargs['foreignkey'])
159
+        del kwargs['foreignkey']
160
+    else:
161
+        fk = None
162
+
163
+    if 'primarykey' in kwargs:
164
+        #renaming primary_key in primarykey in kwargs
165
+        kwargs['primary_key'] = kwargs['primarykey']
166
+        del kwargs['primarykey']
167
+
168
+    col = sql.Column(**kwargs)
169
+
170
+    if fk != None:
171
+        col.append_foreign_key(fk)
172
+
173
+    return col
174
+
175
+def _strToSqlAType(strtype):
176
+    """ Convert a string to an sqlAlchemy column type """
177
+    if 'VARCHAR' in strtype:
178
+        return _strToVarchar(strtype)
179
+    else:
180
+        try:
181
+            return getattr(sql, strtype)
182
+        except AttributeError:
183
+            raise NameError("Unknown type '"+strtype+"'")
184
+    pass
185
+
186
+def _strToVarchar(vstr):
187
+    """ Convert a string like 'VARCHAR(XX)' (with XX an integer) to a SqlAlchemy varchar type"""
188
+    check_length = re.search(re.compile('VARCHAR\(([\d]+)\)', re.IGNORECASE), vstr)
189
+    column_length = int(check_length.groups()[0]) if check_length else None
190
+    return sql.VARCHAR(length=column_length)
119 191
 
120
-        return tables

+ 1
- 1
Database/sqlutils.py View File

@@ -75,7 +75,7 @@ def getEngine(ename = 'default', sqlalogging = None):
75 75
 # @param engine sqlalchemy.engine : A sqlalchemy engine
76 76
 # @return an sql alechemy MetaData instance bind to engine
77 77
 def meta(engine):
78
-    res = sqla.MetaData()
78
+    res = sqla.MetaData(bind=engine)
79 79
     res.reflect(bind=engine)
80 80
     return res
81 81
 

+ 0
- 515
Database/sqlwrapper.py View File

@@ -1,515 +0,0 @@
1
-# -*- coding: utf-8 -*-
2
-import os
3
-import re
4
-import logging
5
-
6
-import sqlalchemy as sqla
7
-from sqlalchemy.ext.compiler import compiles
8
-from django.conf import settings
9
-
10
-from Database.sqlalter import *
11
-
12
-#Logger config
13
-#logger.getLogger().setLevel('WARNING')
14
-logger = logging.getLogger('lodel2.Database.sqlwrapper')
15
-logger.setLevel('CRITICAL')
16
-logger.propagate = False
17
-#To be able to use dango confs
18
-os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Lodel.settings")
19
-
20
-class SqlWrapper(object):
21
-    """ A wrapper class to sqlalchemy
22
-
23
-        Usefull to provide a standart API
24
-
25
-        __Note__ : This class is not thread safe (sqlAlchemy connections are not). Create a new instance of the class to use in different threads or use SqlWrapper::copy
26
-    """
27
-    ENGINES = {'mysql': {
28
-                    'driver': 'pymysql',
29
-                    'encoding': 'utf8'
30
-                },
31
-                'postgresql': {
32
-                    'driver': 'psycopg2',
33
-                    'encoding': 'utf8',
34
-                },
35
-                'sqlite': {
36
-                    'driver': 'pysqlite',
37
-                    'encoding': 'utf8',
38
-                },
39
-    }
40
-    
41
-    ##Configuration dict alias for class access
42
-    config=settings.LODEL2SQLWRAPPER
43
-    
44
-    ##Wrapper instance list
45
-    wrapinstance = dict()
46
-
47
-    def __init__(self, name=None, alchemy_logs=None, read_db = "default", write_db = "default"):
48
-        """ Instanciate a new SqlWrapper
49
-            @param name str: The wrapper name
50
-            @param alchemy_logs bool: If true activate sqlalchemy logger
51
-            @param read_db str: The name of the db conf
52
-            @param write_db str: The name of the db conf
53
-
54
-            @todo Better use of name (should use self.cfg['wrapper'][name] to get engines configs
55
-            @todo Is it a really good idea to store instance in class scope ? Maybe not !!
56
-        """
57
-        
58
-        self.sqlalogging = False if alchemy_logs == None else bool(alchemy_logs)
59
-
60
-        if name == None:
61
-            self.name = read_db+':'+write_db
62
-        else:
63
-            self.name = name
64
-    
65
-        self.r_dbconf = read_db
66
-        self.w_dbconf = write_db
67
-
68
-        self._checkConf() #raise if errors in configuration
69
-
70
-        if self.name in self.__class__.wrapinstance:
71
-            logger.warning("A SqlWrapper with the name "+self.name+" allready exist. Replacing the old one by the new one")
72
-        SqlWrapper.wrapinstance[self.name] = self
73
-
74
-        #Engine and wrapper initialisation
75
-        self.r_engine = self._getEngine(True, self.sqlalogging)
76
-        self.w_engine = self._getEngine(False, self.sqlalogging)
77
-        self.r_conn = None
78
-        self.w_conn = None
79
-
80
-
81
-        self.metadata = None #TODO : use it to load all db schema in 1 request and don't load it each table instanciation
82
-        self.meta_crea = None
83
-
84
-        logger.debug("New wrapper instance : <"+self.name+" read:"+str(self.r_engine)+" write:"+str(self.w_engine))
85
-        pass
86
-
87
-    @classmethod
88
-    def getEngine(c, ename = 'default', logs = None):
89
-        return c(read_db = ename, write_db = ename, alchemy_logs = logs).r_engine
90
-
91
-    @property
92
-    def cfg(self):
93
-        """ Return the SqlWrapper.config dict """
94
-        return self.__class__.config;
95
-    @property
96
-    def _engines_cfg(self):
97
-        return self.__class__.ENGINES;
98
-
99
-    @property
100
-    def meta(self):
101
-        if self.metadata == None:
102
-            self.renewMetaData()
103
-        return self.metadata
104
-
105
-    def renewMetaData(self):
106
-        """ (Re)load the database schema """
107
-        self.metadata = sqla.MetaData(bind=self.r_engine)
108
-        self.metadata.reflect()
109
-
110
-    @property
111
-    def rconn(self):
112
-        """ Return the read connection
113
-            @warning Do not store the connection, call this method each time you need it
114
-        """
115
-        return self._getConnection(True)
116
-    @property
117
-    def wconn(self):
118
-        """ Return the write connection
119
-            @warning Do not store the connection, call this method each time you need it
120
-        """
121
-        return self._getConnection(False)
122
-
123
-    def _getConnection(self, read):
124
-        """ Return an opened connection
125
-            @param read bool: If true return the reading connection
126
-            @return A sqlAlchemy db connection
127
-            @private
128
-        """
129
-        if read:
130
-            r = self.r_conn
131
-        else:
132
-            r = self.w_conn
133
-
134
-        if r == None:
135
-            #Connection not yet opened
136
-            self.connect(read)
137
-            r = self._getConnection(read) #TODO : Un truc plus safe/propre qu'un appel reccursif ?
138
-        return r
139
-
140
-
141
-    def connect(self, read = None):
142
-        """ Open a connection to a database
143
-            @param read bool|None: If None connect both, if True only connect the read side (False the write side)
144
-            @return None
145
-        """
146
-        if read or read == None:
147
-            if self.r_conn != None:
148
-                logger.debug(' SqlWrapper("'+self.name+'") Unable to connect, already connected')
149
-            else:
150
-                self.r_conn = self.r_engine.connect()
151
-
152
-        if not read or read == None:
153
-            if self.w_conn != None:
154
-                logger.debug(' SqlWrapper("'+self.name+'") Unable to connect, already connected')
155
-            else:
156
-                self.w_conn = self.w_engine.connect()
157
-
158
-    def disconnect(self, read = None):
159
-        """ Close a connection to a database
160
-            @param read bool|None: If None disconnect both, if True only connect the read side (False the write side)
161
-            @return None
162
-        """
163
-        if read or read == None:
164
-            if self.r_conn == None:
165
-                logger.info('Unable to close read connection : connection not opened')
166
-            else:
167
-                self.r_conn.close()
168
-            self.r_conn = None
169
-
170
-        if not read or read == None:
171
-            if self.r_conn == None:
172
-                logger.info('Unable to close write connection : connection not opened')
173
-            else:
174
-                self.w_conn.close()
175
-            self.w_conn = None
176
-
177
-    def reconnect(self, read = None):
178
-        """ Close and reopen a connection to a database
179
-            @param read bool|None: If None disconnect both, if True only connect the read side (False the write side)
180
-            @return None
181
-        """
182
-        self.disconnect(read)
183
-        self.connect(read)
184
-
185
-    @classmethod
186
-    def reconnectAll(c, read = None):
187
-        """ Reconnect all the wrappers 
188
-            @static
189
-        """
190
-        for wname in c.wrapinstance:
191
-            c.wrapinstance[wname].reconnect(read)
192
-            
193
-    def Table(self, tname):
194
-        """ Instanciate a new SqlAlchemy Table
195
-            @param tname str: The table name
196
-            @return A new instance of SqlAlchemy::Table
197
-        """
198
-        if not isinstance(tname, str):
199
-            return TypeError('Excepting a <class str> but got a '+str(type(tname)))
200
-        #return sqla.Table(tname, self.meta, autoload_with=self.r_engine, autoload=True)
201
-        return sqla.Table(tname, self.meta)
202
-
203
-    def _getEngine(self, read=True, sqlalogging = None):
204
-        """ Return a sqlalchemy engine
205
-            @param read bool: If True return the read engine, else 
206
-            return the write one
207
-            @return a sqlachemy engine instance
208
-
209
-            @todo Put the check on db config in SqlWrapper.checkConf()
210
-        """
211
-        #Loading confs
212
-        cfg = self.cfg['db'][self.r_dbconf if read else self.w_dbconf]
213
-
214
-        edata = self._engines_cfg[cfg['ENGINE']] #engine infos
215
-        conn_str = ""
216
-
217
-        if cfg['ENGINE'] == 'sqlite':
218
-            #Sqlite connection string
219
-            conn_str = '%s+%s:///%s'%( cfg['ENGINE'],
220
-                edata['driver'],
221
-                cfg['NAME'])
222
-        else:
223
-            #Mysql and Postgres connection string
224
-            user = cfg['USER']
225
-            user += (':'+cfg['PASSWORD'] if 'PASSWORD' in cfg else '')
226
-            
227
-            if 'HOST' not in cfg:
228
-                logger.info('Not HOST in configuration, using localhost')
229
-                host = 'localhost'
230
-            else:
231
-                host = cfg['HOST']
232
-
233
-            host += (':'+cfg['PORT'] if 'PORT' in cfg else '')
234
-
235
-            conn_str = '%s+%s://'%(cfg['ENGINE'], edata['driver'])
236
-            conn_str += '%s@%s/%s'%(user,host,cfg['NAME'])
237
-
238
-
239
-        ret = sqla.create_engine(conn_str, encoding=edata['encoding'], echo=self.sqlalogging)
240
-
241
-        logger.debug("Getting engine :"+str(ret))
242
-
243
-        return ret
244
-
245
-    @classmethod
246
-    def getWrapper(c, name):
247
-        """ Return a wrapper instance from a wrapper name
248
-            @param name str: The wrapper name
249
-            @return a SqlWrapper instance
250
-
251
-            @throw KeyError
252
-        """
253
-        if name not in c.wrapinstance:
254
-            raise KeyError("No wrapper named '"+name+"' exists")
255
-        return c.wrapinstance[name]
256
-
257
-    def _checkConf(self):
258
-        """ Class method that check the configuration
259
-            
260
-            Configuration looks like
261
-            - db (mandatory)
262
-             - ENGINE (mandatory)
263
-             - NAME (mandatory)
264
-             - USER
265
-             - PASSWORD
266
-            - engines (mandatory)
267
-             - driver (mandatory)
268
-             - encoding (mandatory)
269
-            - dbread (mandatory if no default db)
270
-            - dbwrite (mandatory if no default db)
271
-        """
272
-        err = []
273
-        if 'db' not in self.cfg:
274
-            err.append('Missing "db" in configuration')
275
-        else:
276
-            for dbname in [self.r_dbconf, self.w_dbconf]:
277
-                if dbname not in self.cfg['db']:    
278
-                    err.append('Missing "'+dbname+'" db configuration')
279
-                else:
280
-                    db = self.cfg['db'][dbname]
281
-                    if db['ENGINE'] not in self._engines_cfg:
282
-                        err.append('Unknown engine "'+db['ENGINE']+'"')
283
-                    elif db['ENGINE'] != 'sqlite' and 'USER' not in db:
284
-                        err.append('Missing "User" in configuration of database "'+dbname+'"')
285
-                    if 'NAME' not in db:
286
-                        err.append('Missing "NAME" in database "'+dbname+'"')
287
-                        
288
-        if len(err)>0:
289
-            err_str = "\n"
290
-            for e in err:
291
-                err_str += "\t\t"+e+"\n"
292
-            raise NameError('Configuration errors in LODEL2SQLWRAPPER:'+err_str)
293
-    
294
-    def dropAll(self):
295
-        """ Drop ALL tables from the database """
296
-        if not settings.DEBUG:
297
-            logger.critical("Trying to drop all tables but we are not in DEBUG !!!")
298
-            raise RuntimeError("Trying to drop all tables but we are not in DEBUG !!!")
299
-        meta = sqla.MetaData(bind=self.w_engine)
300
-        meta.reflect()
301
-        meta.drop_all()
302
-        pass
303
-
304
-    def createAllFromConf(self, schema):
305
-        """ Create a bunch of tables from a schema
306
-            @param schema list: A list of table schema
307
-            @see SqlWrapper::createTable()
308
-        """
309
-        self.meta_crea = sqla.MetaData()
310
-
311
-        logger.info("Running function createAllFromConf")
312
-        for i,table in enumerate(schema):
313
-            if not isinstance(table, dict):
314
-                raise TypeError("Excepted a list of dict but got a "+str(type(schema))+" in the list")
315
-            self.createTable(**table)
316
-        
317
-        self.meta_crea.create_all(bind = self.w_engine)
318
-        logger.info("All tables created")
319
-        self.meta_crea = None
320
-        self.renewMetaData()
321
-        pass
322
-            
323
-    def createTable(self, name, columns, **kw):
324
-        """ Create a table
325
-            @param name str: The table name
326
-            @param columns list: A list of columns description dict
327
-            @param extra dict: Extra arguments for table creation
328
-            @see SqlWrapper::createColumn()
329
-        """
330
-
331
-        if self.meta_crea == None:
332
-            self.meta_crea = sqla.MetaData()
333
-            crea_now = True
334
-        else:
335
-            crea_now = False
336
-
337
-        if not isinstance(name, str):
338
-            raise TypeError("<class str> excepted for table name, but got "+type(name))
339
-
340
-        #if not 'mysql_engine' in kw and self.w_engine.dialect.name == 'mysql':
341
-        #    kw['mysql_engine'] = 'InnoDB'
342
-
343
-        res = sqla.Table(name, self.meta_crea, **kw)
344
-        for i,col in enumerate(columns):
345
-            res.append_column(self.createColumn(**col))
346
-
347
-        if crea_now:
348
-            self.meta_crea.create_all(self.w_engine)
349
-            logger.debug("Table '"+name+"' created")
350
-
351
-        pass
352
-
353
-    def createColumn(self, **kwargs):
354
-        """ Create a Column
355
-            
356
-            Accepte named parameters :
357
-                - name : The column name
358
-                - type : see SqlWrapper::_strToSqlAType()
359
-                - extra : a dict like { "primarykey":True, "nullable":False, "default":"test"...}
360
-            @param **kwargs 
361
-        """
362
-        if not 'name' in kwargs or ('type' not in kwargs and 'type_' not in kwargs):
363
-            pass#ERROR
364
-
365
-        #Converting parameters
366
-        if 'type_' not in kwargs and 'type' in kwargs:
367
-            kwargs['type_'] = self._strToSqlAType(kwargs['type'])
368
-            del kwargs['type']
369
-
370
-        if 'extra' in kwargs:
371
-            #put the extra keys in kwargs
372
-            for exname in kwargs['extra']:
373
-                kwargs[exname] = kwargs['extra'][exname]
374
-            del kwargs['extra']
375
-
376
-        if 'foreignkey' in kwargs:
377
-            #Instanciate a fk
378
-            fk = sqla.ForeignKey(kwargs['foreignkey'])
379
-            del kwargs['foreignkey']
380
-        else:
381
-            fk = None
382
-
383
-        if 'primarykey' in kwargs:
384
-            #renaming primary_key in primarykey in kwargs
385
-            kwargs['primary_key'] = kwargs['primarykey']
386
-            del kwargs['primarykey']
387
-
388
-        res = sqla.Column(**kwargs)
389
-
390
-        if fk != None:
391
-            res.append_foreign_key(fk)
392
-
393
-        #logger.debug("Column '"+kwargs['name']+"' created")
394
-        return res
395
-    
396
-    def _strToSqlAType(self, strtype):
397
-        """ Convert a string to an sqlAlchemy column type """
398
-
399
-        if 'VARCHAR' in strtype:
400
-            return self._strToVarchar(strtype)
401
-        else:
402
-            try:
403
-                return getattr(sqla, strtype)
404
-            except AttributeError:
405
-                raise NameError("Unknown type '"+strtype+"'")
406
-        pass
407
-
408
-    def _strToVarchar(self, vstr):
409
-        """ Convert a string like 'VARCHAR(XX)' (with XX an integer) to a SqlAlchemy varchar type"""
410
-        check_length = re.search(re.compile('VARCHAR\(([\d]+)\)', re.IGNORECASE), vstr)
411
-        column_length = int(check_length.groups()[0]) if check_length else None
412
-        return sqla.VARCHAR(length=column_length)
413
-     
414
-
415
-    def dropColumn(self, tname, colname):
416
-        """ Drop a column from a table
417
-            @param tname str|sqlalchemy.Table: The table name or a Table object
418
-            @param colname str|sqlalchemy.Column: The column name or a column object
419
-            @return None
420
-        """
421
-        if tname not in self.meta.tables: #Useless ?
422
-            raise NameError("The table '"+tname+"' dont exist")
423
-        table = self.Table(tname)
424
-        col = sqla.Column(colname)
425
-
426
-        ddl = DropColumn(table, col)
427
-        sql = ddl.compile(dialect=self.w_engine.dialect)
428
-        sql = str(sql)
429
-        logger.debug("Executing SQL  : '"+sql+"'")
430
-        ret = bool(self.w_engine.execute(sql))
431
-
432
-        self.renewMetaData()
433
-        return ret
434
-
435
-    
436
-    def addColumn(self, tname, colname, coltype):
437
-        """ Add a column to a table
438
-            @param tname str: The table name
439
-            @param colname str: The column name
440
-            @param coltype str: The new column type
441
-
442
-            @return True if query success False if it fails
443
-        """
444
-        if tname not in self.meta.tables: #Useless ?
445
-            raise NameError("The table '"+tname+"' dont exist")
446
-        table = self.Table(tname)
447
-        newcol = self.createColumn(name=colname, type_ = coltype)
448
-
449
-        ddl = AddColumn(table, newcol)
450
-        sql = ddl.compile(dialect=self.w_engine.dialect)
451
-        sql = str(sql)
452
-        logger.debug("Executing SQL  : '"+sql+"'")
453
-        ret = bool(self.wconn.execute(sql))
454
-
455
-        self.renewMetaData()
456
-        return ret
457
-
458
-    ## AddColumnObject
459
-    #
460
-    # Adds a column from a SQLAlchemy Column Object
461
-    #
462
-    # @param tname str: Name of the table in which to add the column
463
-    # @param column Column: Column object to add to the table
464
-    # @return True if query is successful, False if it fails
465
-    def addColumnObject(self, tname, column):
466
-        if tname not in self.meta.tables:
467
-            raise NameError("The table '%s' doesn't exist" % tname)
468
-        table = self.Table(tname)
469
-
470
-        ddl = AddColumn(table, column)
471
-        sql = ddl.compile(dialect=self.w_engine.dialect)
472
-        sql = str(sql)
473
-        logger.debug("Executing SQL : '%s'" % sql)
474
-        ret = bool(self.wconn.execute(sql))
475
-        self.renewMetaData()
476
-        return ret
477
-
478
-    def alterColumn(self, tname, colname, col_newtype):
479
-        """ Change the type of a column
480
-            @param tname str: The table name
481
-            @param colname str: The column name
482
-            @param col_newtype str: The column new type
483
-
484
-            @return True if query successs False if it fails
485
-        """
486
-        
487
-        if tname not in self.meta.tables: #Useless ?
488
-            raise NameError("The table '"+tname+"' dont exist")
489
-
490
-        col = self.createColumn(name=colname, type_=col_newtype)
491
-        table = self.Table(tname)
492
-
493
-        ddl = AlterColumn(table, newcol)
494
-        sql = ddl.compile(dialect=self.w_engine.dialect)
495
-        sql = str(sql)
496
-        logger.debug("Executing SQL  : '"+sql+"'")
497
-        ret = bool(self.wconn.execute(sql))
498
-
499
-        self.renewMetaData()
500
-        return ret
501
-
502
-    def _debug__printSchema(self):
503
-        """ Debug function to print the db schema """
504
-        print(self.meta)
505
-        for tname in self.meta.tables:
506
-            self._debug__printTable(tname)
507
-
508
-    def _debug__printTable(self, tname):
509
-        t = self.meta.tables[tname]
510
-        tstr = 'Table : "'+tname+'" :\n'
511
-        for c in t.c:
512
-            tstr += '\t\t"'+c.name+'"('+str(c.type)+') \n'
513
-        print(tstr)
514
-            
515
-

+ 1
- 2
EditorialModel/components.py View File

@@ -175,8 +175,7 @@ class EmComponent(object):
175 175
         dbe = cls.db_engine()
176 176
         conn = dbe.connect()
177 177
 
178
-        #kwargs['rank'] = cls.get_max_rank(kwargs[cls.ranked_in]) + 1 #Warning !!!
179
-        kwargs['rank'] = -1
178
+        kwargs['rank'] = -1 #Warning !!!
180 179
 
181 180
         table = sql.Table(cls.table, sqlutils.meta(dbe))
182 181
         req = table.insert(kwargs)

+ 2
- 4
EditorialModel/test/test_classes.py View File

@@ -16,8 +16,7 @@ from EditorialModel.types import EmType
16 16
 from EditorialModel.fields import EmField
17 17
 import EditorialModel.fieldtypes  as fieldTypes
18 18
 
19
-from Database.sqlsetup import SQLSetup
20
-from Database import sqlutils
19
+from Database import sqlutils, sqlsetup
21 20
 import sqlalchemy as sqla
22 21
 
23 22
 
@@ -33,8 +32,7 @@ class ClassesTestCase(TestCase):
33 32
     # run before every instanciation of the class
34 33
     @classmethod
35 34
     def setUpClass(cls):
36
-        sql = SQLSetup()
37
-        sql.initDb()
35
+        sqlsetup.init_db()
38 36
 
39 37
     # run before every function of the class
40 38
     def setUp(self):

+ 5
- 12
EditorialModel/test/test_component.py View File

@@ -21,9 +21,8 @@ from EditorialModel.test.utils import *
21 21
 
22 22
 from Lodel.utils.mlstring import MlString
23 23
 
24
-from Database.sqlsetup import SQLSetup
25
-from Database.sqlwrapper import SqlWrapper
26 24
 from Database import sqlutils
25
+from Database import sqlsetup
27 26
 import sqlalchemy as sqla
28 27
 
29 28
 
@@ -57,8 +56,7 @@ def setUpModule():
57 56
     logging.basicConfig(level=logging.CRITICAL)
58 57
 
59 58
     #testDB setup
60
-    sqls = SQLSetup()
61
-    tables = sqls.get_schema()
59
+    tables = sqlsetup.get_schema()
62 60
     ttest = {   'name':'ttest',
63 61
                 'columns':  [
64 62
                     {"name":"uid",          "type":"INTEGER", "extra":{"foreignkey":"uids.uid", "nullable":False, "primarykey":True}},
@@ -73,7 +71,6 @@ def setUpModule():
73 71
             }
74 72
     tables.append(ttest)
75 73
 
76
-    sqlwrap = globals()['dbwrapper'] = SqlWrapper(read_db='default', write_db = 'default', alchemy_logs=False)
77 74
     globals()['tables'] = tables
78 75
 
79 76
     #Creating db structure
@@ -81,9 +78,9 @@ def setUpModule():
81 78
     initTestDb(TEST_COMPONENT_DBNAME)
82 79
     setDbConf(TEST_COMPONENT_DBNAME)
83 80
 
84
-    sqlwrap.createAllFromConf(tables)
81
+    sqlsetup.init_db('default', False, tables)   
85 82
 
86
-    dbe = sqlwrap.r_engine
83
+    dbe = sqlutils.getEngine('default')
87 84
 
88 85
     # Insertion of testings datas
89 86
     conn = dbe.connect()
@@ -143,16 +140,12 @@ class ComponentTestCase(TestCase):
143 140
         { 'uid': 1025, 'name': 'name', 'string': '{}', 'help': '{}', 'rank': 5},
144 141
     ]
145 142
 
146
-    @property
147
-    def db(self):
148
-        return globals()['dbwrapper']
149 143
     @property
150 144
     def tables(self):
151 145
         return globals()['tables']
152 146
     
153 147
     def setUp(self):
154
-        self.dber = globals()['dbwrapper'].r_engine
155
-        self.dbew = globals()['dbwrapper'].w_engine
148
+        self.dber = sqlutils.getEngine('default')
156 149
         self.test_values = self.__class__.test_values
157 150
         #Db RAZ
158 151
         #shutil.copyfile(TEST_COMPONENT_DBNAME+'_bck', globals()['component_test_dbfilename'])

+ 1
- 5
EditorialModel/test/test_field.py View File

@@ -16,9 +16,6 @@ from EditorialModel.fields_types import Em_Field_Type
16 16
 from EditorialModel.test.utils import *
17 17
 from EditorialModel.fieldtypes import *
18 18
 
19
-from Database.sqlsetup import SQLSetup
20
-from Database.sqlwrapper import SqlWrapper
21
-from Database.sqlquerybuilder import SqlQueryBuilder
22 19
 from Database import sqlutils
23 20
 
24 21
 import sqlalchemy as sqla
@@ -45,8 +42,7 @@ class FieldTestCase(TestCase):
45 42
 
46 43
     @classmethod
47 44
     def setUpClass(cls):
48
-        sqls = SQLSetup()
49
-        sqls.initDb()
45
+        sqlsetup.init_db()
50 46
 
51 47
         # Generation of the test data
52 48
         testclass = EmClass.create("testclass1",EmClassType.entity)

+ 0
- 1
EditorialModel/test/test_fieldgroups.py View File

@@ -18,7 +18,6 @@ from EditorialModel.fieldtypes import *
18 18
 
19 19
 from EditorialModel.test.utils import *
20 20
 
21
-from Database.sqlsetup import SQLSetup
22 21
 from Database import sqlutils
23 22
 
24 23
 import sqlalchemy as sqla

+ 2
- 2
EditorialModel/test/utils.py View File

@@ -3,7 +3,7 @@ import logging
3 3
 import shutil
4 4
 
5 5
 from django.conf import settings
6
-from Database.sqlsetup import SQLSetup
6
+from Database import sqlsetup
7 7
 
8 8
 
9 9
 _TESTDB_DEFAULT_DIR = '/tmp/'
@@ -42,7 +42,7 @@ def initTestDb(dbname = _TESTDB_DEFAULT_NAME, dbdir = _TESTDB_DEFAULT_DIR):
42 42
             'ENGINE': 'sqlite',
43 43
             'NAME': db_default,
44 44
         }
45
-        SQLSetup().initDb(dbconfname = 'dbtest_default')
45
+        sqlsetup.init_db(dbconfname = 'dbtest_default')
46 46
         #Make the backup copy
47 47
         shutil.copyfile(db_default, db_copy)
48 48
     

Loading…
Cancel
Save