Code

Added the "actor" property. Metakit backend not done (still not confident
[roundup.git] / roundup / backends / back_sqlite.py
index 1f1013c285c9302cf373bacea0e6927b38931c13..04100d09316daac2229e5979670148f0cbdc4b30 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: back_sqlite.py,v 1.15 2004-03-12 04:08:59 richard Exp $
+# $Id: back_sqlite.py,v 1.16 2004-03-15 05:50:20 richard Exp $
 '''Implements a backend for SQLite.
 
 See https://pysqlite.sourceforge.net/ for pysqlite info
@@ -48,6 +48,97 @@ class Database(rdbms_common.Database):
             's_last_use varchar, s_user varchar)')
         self.cursor.execute('create index sessions_key_idx on sessions(s_key)')
 
+    def add_actor_column(self):
+        # update existing tables to have the new actor column
+        tables = self.database_schema['tables']
+        for classname, spec in self.classes.items():
+            if tables.has_key(classname):
+                dbspec = tables[classname]
+                self.update_class(spec, dbspec, force=1, adding_actor=1)
+
+    def update_class(self, spec, old_spec, force=0, adding_actor=0):
+        ''' Determine the differences between the current spec and the
+            database version of the spec, and update where necessary.
+
+            If 'force' is true, update the database anyway.
+
+            SQLite doesn't have ALTER TABLE, so we have to copy and
+            regenerate the tables with the new schema.
+        '''
+        new_has = spec.properties.has_key
+        new_spec = spec.schema()
+        new_spec[1].sort()
+        old_spec[1].sort()
+        if not force and new_spec == old_spec:
+            # no changes
+            return 0
+
+        if __debug__:
+            print >>hyperdb.DEBUG, 'update_class FIRING'
+
+        # detect multilinks that have been removed, and drop their table
+        old_has = {}
+        for name,prop in old_spec[1]:
+            old_has[name] = 1
+            if new_has(name) or not isinstance(prop, hyperdb.Multilink):
+                continue
+            # it's a multilink, and it's been removed - drop the old
+            # table. First drop indexes.
+            self.drop_multilink_table_indexes(spec.classname, ml)
+            sql = 'drop table %s_%s'%(spec.classname, prop)
+            if __debug__:
+                print >>hyperdb.DEBUG, 'update_class', (self, sql)
+            self.cursor.execute(sql)
+        old_has = old_has.has_key
+
+        # now figure how we populate the new table
+        if adding_actor:
+            fetch = ['_activity', '_creation', '_creator']
+        else:
+            fetch = ['_actor', '_activity', '_creation', '_creator']
+        properties = spec.getprops()
+        for propname,x in new_spec[1]:
+            prop = properties[propname]
+            if isinstance(prop, hyperdb.Multilink):
+                if force or not old_has(propname):
+                    # we need to create the new table
+                    self.create_multilink_table(spec, propname)
+            elif old_has(propname):
+                # we copy this col over from the old table
+                fetch.append('_'+propname)
+
+        # select the data out of the old table
+        fetch.append('id')
+        fetch.append('__retired__')
+        fetchcols = ','.join(fetch)
+        cn = spec.classname
+        sql = 'select %s from _%s'%(fetchcols, cn)
+        if __debug__:
+            print >>hyperdb.DEBUG, 'update_class', (self, sql)
+        self.cursor.execute(sql)
+        olddata = self.cursor.fetchall()
+
+        # TODO: update all the other index dropping code
+        self.drop_class_table_indexes(cn, old_spec[0])
+
+        # drop the old table
+        self.cursor.execute('drop table _%s'%cn)
+
+        # create the new table
+        self.create_class_table(spec)
+
+        if olddata:
+            # do the insert of the old data - the new columns will have
+            # NULL values
+            args = ','.join([self.arg for x in fetch])
+            sql = 'insert into _%s (%s) values (%s)'%(cn, fetchcols, args)
+            if __debug__:
+                print >>hyperdb.DEBUG, 'update_class', (self, sql, olddata[0])
+            for entry in olddata:
+                self.cursor.execute(sql, tuple(entry))
+
+        return 1
+
     def sql_close(self):
         ''' Squash any error caused by us already having closed the
             connection.