Contact: fumanchu@aminus.org

Log in as guest/dejavu to create tickets

I think I've seen this ORM somewhere before...

Changeset 232

Show
Ignore:
Timestamp:
07/20/06 22:31:17
Author:
fumanchu
Message:

Work on MySQL, SQLite stores in preparation for moving the typeadapters into the dbmodel layer.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/storage/storemysql.py

    r231 r232  
    137137        else: 
    138138            typename = "INTEGER" 
    139         if isinstance(cls.sequencer, dejavu.UnitSequencerInteger): 
    140             if key in cls.identifiers: 
    141                 typename += " AUTO_INCREMENT" 
    142139        return typename 
    143140 
     
    157154     
    158155    indexsetclass = MySQLIndexSet 
     156     
     157    def __setitem__(self, key, column): 
     158        t = self.table 
     159         
     160        dbtype = column.dbtype 
     161        if column.autoincrement: 
     162            dbtype += " AUTO_INCREMENT" 
     163        else: 
     164            default = column.default or "" 
     165            if default: 
     166                default = self.adaptertosql.coerce(default) 
     167                dbtype = "%s DEFAULT %s" % (dbtype, default) 
     168         
     169        t.db.execute("ALTER TABLE %s ADD COLUMN %s %s;" % 
     170                     (t.qname, column.qname, dbtype)) 
     171        dict.__setitem__(self, key, column) 
    159172     
    160173    def _rename(self, oldcol, newcol): 
     
    203216         
    204217        fields = [] 
     218        incr_fields = [] 
    205219        pk = [] 
    206220        for colname, col in table.columns.iteritems(): 
     
    208222            dbtype = col.dbtype 
    209223             
    210             default = col.default or "" 
    211             if default: 
    212                 default = " DEFAULT %s" % self.adaptertosql.coerce(default) 
    213              
    214             f = '%s %s%s' % (qname, dbtype, default) 
    215             fields.append(f) 
     224            if col.autoincrement: 
     225                dbtype += " AUTO_INCREMENT" 
     226                # INSERT INTO t (c) VALUES(0) doesn't work for some reason 
     227                if col.default > 1: 
     228                    incr_fields.append(col) 
     229            else: 
     230                default = col.default or "" 
     231                if default: 
     232                    default = self.adaptertosql.coerce(default) 
     233                    dbtype = "%s DEFAULT %s" % (dbtype, default) 
     234             
     235            fields.append('%s %s' % (qname, dbtype)) 
    216236             
    217237            # See create_storage for the other half of this hack. 
    218             if colname in table.mysql_identifiers: 
     238            if col.name in table.mysql_identifiers: 
    219239                if dbtype.endswith('BLOB') or dbtype == 'TEXT': 
    220                     # MySQL won't allow indexes on a BLOB field 
    221                     # without a specific length
     240                    # MySQL won't allow indexes on a BLOB field without a 
     241                    # specific index prefix length. We choose 255 just for fun
    222242                    qname = "%s(255)" % qname 
    223243                pk.append(qname) 
    224244         
    225         pk = ", ".join(pk) 
    226245        if pk: 
    227             pk = ", PRIMARY KEY (%s)" % pk 
     246            pk = ", PRIMARY KEY (%s)" % ", ".join(pk) 
    228247         
    229248        self.execute('CREATE TABLE %s (%s%s);' % 
    230249                     (table.qname, ", ".join(fields), pk)) 
    231250         
    232         seq = getattr(table, "mysql_sequencer", None) 
    233         if seq: 
    234             # Wow, what a hack. We have to INSERT a dummy row 
    235             # to set the autoincrement initial value, and we 
    236             # can't delete it until after the CREATE INDEX 
    237             # statements (or the counter will revert). 
    238             colname, initial = seq 
     251        if incr_fields: 
     252            # Wow, what a hack. We have to INSERT a dummy row to set the 
     253            # autoincrement initial value(s), and we can't delete it until 
     254            # after the CREATE INDEX statements (or the counter will revert). 
     255            fields = ", ".join([col.qname for col in incr_fields]) 
     256            values = ", ".join([str(col.default - 1) for col in incr_fields]) 
    239257            self.execute("INSERT INTO %s (%s) VALUES (%s);" 
    240                          % (table.qname, q(colname), initial - 1)) 
     258                         % (table.qname, fields, values)) 
    241259         
    242260        for k, index in table.columns.indices.iteritems(): 
    243261            dbtype = table.columns[k].dbtype 
    244262            if dbtype.endswith('BLOB') or dbtype == 'TEXT': 
    245                 # MySQL won't allow indexes on a BLOB field 
    246                 # without a specific length
     263                # MySQL won't allow indexes on a BLOB field without a 
     264                # specific index prefix length. We choose 255 just for fun
    247265                self.execute('CREATE INDEX %s ON %s (%s(255));' % 
    248266                             (index.qname, table.qname, q(index.colname))) 
     
    251269                             (index.qname, table.qname, q(index.colname))) 
    252270         
    253         if seq
     271        if incr_fields
    254272            self.execute("DELETE FROM %s" % table.qname) 
    255273         
     
    295313                c.default = self.python_type(dbtype)(row[4]) 
    296314             
    297             if row[5]
    298                 # Usually auto_increment 
    299                 dbtype += " " + row[5] 
     315            if "auto_increment" in row[5].lower()
     316                c.autoincrement = True 
     317             
    300318            c.dbtype = dbtype 
    301319             
     
    324342        """Return a Python type which can store values of the given dbtype.""" 
    325343        dbtype = dbtype.upper() 
    326         dbtype = dbtype.replace(" AUTO_INCREMENT", "") 
    327344        parenpos = dbtype.find("(") 
    328345        if parenpos > -1: 
     
    435452        for key in cls.properties: 
    436453            col = t.columns[key] 
    437             if col.dbtype.endswith("AUTO_INCREMENT")
     454            if col.autoincrement
    438455                # Skip this field, since we're using a sequencer 
    439456                continue 
     
    462479        fields = [] 
    463480        for key in cls.properties: 
    464             dbtype = self.typeAdapter.coerce(cls, key) 
    465              
    466             col = self.db.make_column(cls.__name__, key, dbtype) 
    467              
    468             prop = cls.property(key) 
    469             col.default = prop.default 
    470             col.hints = prop.hints.copy() 
    471              
    472481            # Use the superclass call to avoid ALTER TABLE. 
    473             dict.__setitem__(t.columns, key, col
     482            dict.__setitem__(t.columns, key, self._make_column(cls, key)
    474483             
    475484            if key in indices: 
     
    479488         
    480489        # Hack to get PRIMARY KEY right. See MySQLTableSet.__setitem__ 
    481         t.mysql_identifiers = cls.identifiers 
    482          
    483         # Hack to get AUTO_INCREMENT right where initial > 1. 
    484         # See MySQLTableSet.__setitem__ 
    485         if isinstance(cls.sequencer, dejavu.UnitSequencerInteger): 
    486             i = cls.sequencer.initial 
    487             if i > 1: 
    488                 t.mysql_sequencer = (t.columns[cls.identifiers[0]].name, i) 
     490        t.mysql_identifiers = [t.columns[i].name for i in cls.identifiers] 
    489491         
    490492        # Attach to self.db, which should call CREATE TABLE. 
    491493        self.db[cls.__name__] = t 
    492  
     494     
     495    def _make_column(self, cls, key): 
     496        dbtype = self.typeAdapter.coerce(cls, key) 
     497        col = self.db.make_column(cls.__name__, key, dbtype) 
     498        prop = getattr(cls, key) 
     499        col.default = prop.default 
     500        col.hints = prop.hints.copy() 
     501         
     502        if key in cls.identifiers: 
     503            if isinstance(cls.sequencer, dejavu.UnitSequencerInteger): 
     504                col.autoincrement = True 
     505                col.default = cls.sequencer.initial 
     506        return col 
  • trunk/storage/storesqlite.py

    r231 r232  
    166166    def coerce(self, cls, key): 
    167167        """coerce(cls, key) -> SQL typename for valuetype.""" 
    168         if _autoincrement_support: 
    169             prop = cls.property(key) 
    170             if prop.type is int and key in cls.identifiers: 
    171                 if isinstance(cls.sequencer, dejavu.UnitSequencerInteger): 
    172                     return "INTEGER PRIMARY KEY AUTOINCREMENT" 
    173          
    174168        if self.db.typeless: 
    175169            # SQLite can be 'typeless' (but we lose the type introspection) 
     
    213207    def __setitem__(self, key, column): 
    214208        t = self.table 
     209        if key in self: 
     210            del self[key] 
    215211         
    216212        if _add_column_support: 
     213            dbtype = column.dbtype 
     214            if column.autoincrement: 
     215                dbtype = "INTEGER PRIMARY KEY AUTOINCREMENT" 
     216            else: 
     217                default = column.default or "" 
     218                if not isinstance(default, str): 
     219                    default = t.db.adaptertosql.coerce(default) 
     220                if default: 
     221                    dbtype += " DEFAULT %s" % default 
     222             
    217223            t.db.execute("ALTER TABLE %s ADD COLUMN %s %s;" % 
    218                          (t.qname, column.qname, column.dbtype)) 
     224                         (t.qname, column.qname, dbtype)) 
    219225            dict.__setitem__(self, key, column) 
    220226        else: 
     
    250256            # Drop the intermediate table. 
    251257            t.db[temptable.name] 
     258         
     259        if column.autoincrement: 
     260            self._set_initials(t.name, col.default) 
    252261     
    253262    def __delitem__(self, key): 
     
    399408         
    400409        return str 
     410     
     411    def _set_initials(self, tablename, initial): 
     412        # SQLite AUTOINCREMENT columns start at 1 by default. 
     413        # Manhandle the special SQLITE_SEQUENCE table to include 
     414        # the value of sequencer.initial - 1. 
     415        prev = initial - 1 
     416        data, coldefs = self.fetch("SELECT * FROM SQLITE_SEQUENCE " 
     417                                   "WHERE name = '%s'" % tablename) 
     418        if data: 
     419            self.execute("UPDATE SQLITE_SEQUENCE SET seq = %s " 
     420                         "WHERE name = '%s'" % (prev, tablename)) 
     421        else: 
     422            self.execute("INSERT INTO SQLITE_SEQUENCE (seq, name) " 
     423                         "VALUES (%s, '%s')" % (prev, tablename)) 
     424     
     425    def __setitem__(self, key, table): 
     426        if key in self: 
     427            del self[key] 
     428         
     429        fields = [] 
     430        autoincr_initial = None 
     431        for column in table.columns.itervalues(): 
     432            dbtype = column.dbtype 
     433            if column.autoincrement: 
     434                dbtype = "INTEGER PRIMARY KEY AUTOINCREMENT" 
     435                autoincr_initial = column.default 
     436            else: 
     437                default = column.default or "" 
     438                if not isinstance(default, str): 
     439                    default = table.db.adaptertosql.coerce(default) 
     440                if default: 
     441                    dbtype = " DEFAULT %s" % default 
     442            fields.append('%s %s' % (column.qname, dbtype)) 
     443         
     444        self.execute('CREATE TABLE %s (%s);' % 
     445                     (table.qname, ", ".join(fields))) 
     446         
     447        for index in table.columns.indices.itervalues(): 
     448            self.execute('CREATE INDEX %s ON %s (%s);' % 
     449                         (index.qname, table.qname, 
     450                          self.quote(index.colname))) 
     451         
     452        if autoincr_initial: 
     453            self._set_initials(table.name, autoincr_initial) 
     454         
     455        dict.__setitem__(self, key, table) 
    401456     
    402457    def _rename(self, oldtable, newtable): 
     
    562617        values = [] 
    563618        for key in cls.properties: 
    564             if "AUTOINCREMENT" in self.typeAdapter.coerce(cls, key): 
     619            col = t.columns[key] 
     620            if col.autoincrement: 
    565621                # Skip this field, since we're using AUTOINCREMENT 
    566622                continue 
    567623            val = self.db.adaptertosql.coerce(getattr(unit, key)) 
    568             fields.append(t.columns[key].qname) 
     624            fields.append(col.qname) 
    569625            values.append(val) 
    570626         
     
    583639    #                               Schemas                               # 
    584640     
    585     def create_storage(self, cls): 
    586         """Create storage for the given class.""" 
    587         db.StorageManagerDB.create_storage(self, cls) 
    588          
    589         typename = self.typeAdapter.coerce 
    590          
    591         for key in cls.properties: 
    592             if "AUTOINCREMENT" in typename(cls, key): 
    593                 # SQLite AUTOINCREMENT columns start at 1 by default. 
    594                 # Manhandle the special SQLITE_SEQUENCE table to include 
    595                 # the value of sequencer.initial - 1. 
    596                 prev = cls.sequencer.initial - 1 
    597                 tablename = self.db[cls.__name__].name 
    598                 d, c = self.db.fetch("SELECT * FROM SQLITE_SEQUENCE " 
    599                                      "WHERE name = '%s'" % tablename) 
    600                 if d: 
    601                     self.db.execute("UPDATE SQLITE_SEQUENCE SET seq = %s " 
    602                                     "WHERE name = '%s'" % (prev, tablename)) 
    603                 else: 
    604                     self.db.execute("INSERT INTO SQLITE_SEQUENCE (seq, name) " 
    605                                     "VALUES (%s, '%s')" % (prev, tablename)) 
    606  
     641    def _make_column(self, cls, key): 
     642        col = db.StorageManagerDB._make_column(self, cls, key) 
     643        if (_autoincrement_support and key in cls.identifiers and 
     644                isinstance(cls.sequencer, dejavu.UnitSequencerInteger)): 
     645            col.autoincrement = True 
     646            col.default = cls.sequencer.initial 
     647        return col 
     648