Contact: fumanchu@aminus.org

Log in as guest/geniusql to create tickets

Changeset 13

Show
Ignore:
Timestamp:
02/17/07 04:11:06
Author:
fumanchu
Message:

Package reorganization.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/geniusql/__init__.py

    r12 r13  
    109109 
    110110 
    111 import threading 
    112  
    113 from dejavu import logic 
    114  
    115111from geniusql import errors, typerefs 
    116  
    117 from geniusql.adapters import * 
    118 from geniusql.conn import * 
    119 from geniusql.isolation import * 
    120 from geniusql.select import * 
    121  
     112from geniusql import adapters 
     113from geniusql import conns 
     114from geniusql import isolation 
     115from geniusql import select 
    122116from geniusql import providers 
     117from geniusql.objects import * 
    123118 
    124119 
     
    133128    return providers.registry.open(provider, **options) 
    134129 
    135  
    136 class Index: 
    137     """An index on a table column (or columns) in a database.""" 
    138      
    139     def __init__(self, name, qname, tablename, colname, unique=True): 
    140         self.name = name 
    141         self.qname = qname 
    142         self.tablename = tablename 
    143         self.colname = colname 
    144         self.unique = unique 
    145      
    146     def __repr__(self): 
    147         return ("%s.%s(%r, %r, %r, %r, unique=%r)" % 
    148                 (self.__module__, self.__class__.__name__, 
    149                  self.name, self.qname, self.tablename, 
    150                  self.colname, self.unique)) 
    151      
    152     def __copy__(self): 
    153         return self.__class__(self.name, self.qname, self.tablename, 
    154                               self.colname, self.unique) 
    155     copy = __copy__ 
    156  
    157  
    158 class IndexSet(dict): 
    159      
    160     def __new__(cls, table): 
    161         return dict.__new__(cls) 
    162      
    163     def __init__(self, table): 
    164         dict.__init__(self) 
    165         self.table = table 
    166      
    167     def alias(self, oldname, newname): 
    168         """Add a new key for the Index with the given, existing key. 
    169          
    170         Consumer code should call this method when user-supplied index 
    171         names do not match the names in the database. This does not 
    172         remove the old key; both keys may be used to refer to the same 
    173         Index object. 
    174         """ 
    175         if oldname == newname: 
    176             return 
    177         obj = self[oldname] 
    178         if newname in self: 
    179             dict.__delitem__(self, newname) 
    180         dict.__delitem__(self, oldname) 
    181         dict.__setitem__(self, newname, obj) 
    182      
    183     def __setitem__(self, key, index): 
    184         """Create the specified index.""" 
    185         t = self.table 
    186         if t.created: 
    187             t.schema.db.execute_ddl('CREATE INDEX %s ON %s (%s);' % 
    188                                     (index.qname, t.qname, 
    189                                      t.schema.db.quote(index.colname))) 
    190         dict.__setitem__(self, key, index) 
    191      
    192     def __delitem__(self, key): 
    193         """Drop the specified index.""" 
    194         t = self.table 
    195         if t.created: 
    196             t.schema.db.execute_ddl('DROP INDEX %s ON %s;' % 
    197                              (self[key].qname, t.qname)) 
    198         dict.__delitem__(self, key) 
    199  
    200  
    201 class Column: 
    202     """A column in a table in a database. 
    203      
    204     name: the SQL name for this table (unquoted). 
    205     qname: the SQL name for this table (quoted). 
    206     pytype: the Python type (the actual type object, not its name). 
    207     dbtype: the database type name (as used in a CREATE TABLE statement). 
    208     default: default Python value for this column for new rows. 
    209     hints: a dict of implementation hints, such as precision, scale, or bytes. 
    210     key: True if this column is part of the table's primary key. 
    211      
    212     imperfect_type: if True, signals that we are deliberately using a 
    213         database type other than the default (usually in order to handle 
    214         irregular values, such as huge numbers). When comparing imperfect 
    215         column values with constant values in SQL, the database must be 
    216         able to cast the column value to the constant's type. If that 
    217         cannot be done for the given types, then the query will be marked 
    218         imperfect. 
    219     autoincrement: if True, uses the database's built-in sequencing. 
    220     sequence_name: for databases that use separate statements to create and 
    221         drop sequences, this stores the name of the sequence. 
    222     initial: if autoincrement, holds the initial value for the sequence. 
    223     """ 
    224      
    225     def __init__(self, pytype, dbtype, default=None, hints=None, key=False, 
    226                  name=None, qname=None): 
    227         self.pytype = pytype 
    228         self.dbtype = dbtype 
    229         self.name = name 
    230         self.qname = qname 
    231         self.default = default 
    232         if hints is None: 
    233             hints = {} 
    234         else: 
    235             hints = hints.copy() 
    236         self.hints = hints 
    237         self.key = key 
    238          
    239         # If autoincrement, the initial value should be put in self.initial. 
    240         self.autoincrement = False 
    241         self.sequence_name = None 
    242         self.initial = 1 
    243          
    244         self.imperfect_type = False 
    245      
    246     def __repr__(self): 
    247         return ("%s.%s(%r, %r, default=%r, hints=%r, key=%r, name=%r, qname=%r)" % 
    248                 (self.__module__, self.__class__.__name__, 
    249                  self.pytype, self.dbtype, 
    250                  self.default, self.hints, self.key, 
    251                  self.name, self.qname) 
    252                 ) 
    253      
    254     def __copy__(self): 
    255         newcol = self.__class__(self.pytype, self.dbtype, 
    256                                 self.default, self.hints, self.key, 
    257                                 self.name, self.qname) 
    258         newcol.autoincrement = self.autoincrement 
    259         newcol.initial = self.initial 
    260         newcol.imperfect_type = self.imperfect_type 
    261         return newcol 
    262     copy = __copy__ 
    263  
    264  
    265 class Table(dict): 
    266     """A table in a database; a dict of Column objects. 
    267      
    268     Values in this dict must be instances of Column (or a subclass of it). 
    269     Keys should be consumer-friendly names for each Column value. 
    270      
    271     name: the SQL name for this table (unquoted). 
    272     qname: the SQL name for this table (quoted). 
    273     schema: the schema for this table. 
    274     created: whether or not this Table has a concrete implementation in the 
    275         database. If False (the default), then changes to Table items can be 
    276         made with impunity. If True, then appropriate ALTER TABLE commands 
    277         are executed whenever a consumer adds or deletes items from the 
    278         Table, or calls methods like 'rename'. 
    279     indices: a dict-like IndexSet of Index objects. 
    280     references: a dict of the form: {name: (nearColKey, farTableKey, farColKey)}. 
    281     """ 
    282      
    283     def __new__(cls, name, qname, schema, created=False): 
    284         return dict.__new__(cls) 
    285      
    286     def __init__(self, name, qname, schema, created=False): 
    287         dict.__init__(self) 
    288          
    289         self.name = name 
    290         self.qname = qname 
    291         self.schema = schema 
    292         self.created = created 
    293          
    294         self.indices = schema.indexsetclass(self) 
    295         self.references = {} 
    296      
    297     def __repr__(self): 
    298         name = getattr(self, "name", "<unknown>") 
    299         qname = getattr(self, "qname", "<unknown>") 
    300         return ("%s.%s(%r, %r)" % 
    301                 (self.__module__, self.__class__.__name__, name, qname)) 
    302      
    303     def __copy__(self): 
    304         # Don't set 'created' when copying! 
    305         newtable = self.__class__(self.name, self.qname, self.schema) 
    306         for key, c in self.iteritems(): 
    307             dict.__setitem__(newtable, key, c.copy()) 
    308         for key, i in self.indices.iteritems(): 
    309             dict.__setitem__(newtable.indices, key, i.copy()) 
    310         return newtable 
    311     copy = __copy__ 
    312      
    313     def alias(self, oldname, newname): 
    314         """Add a new key for the Column with the given, existing key. 
    315          
    316         Consumer code should call this method when user-supplied column 
    317         names do not match the names in the database. This does not 
    318         remove the old key; both keys may be used to refer to the same 
    319         Column object. 
    320         """ 
    321         if oldname == newname: 
    322             return 
    323          
    324         obj = self[oldname] 
    325         if newname in self: 
    326             dict.__delitem__(self, newname) 
    327         dict.__delitem__(self, oldname) 
    328         dict.__setitem__(self, newname, obj) 
    329      
    330     def _add_column(self, column): 
    331         """Internal function to add the column to the database.""" 
    332         coldef = self.schema.columnclause(column) 
    333         self.schema.db.execute("ALTER TABLE %s ADD COLUMN %s;" % 
    334                                (self.qname, coldef)) 
    335      
    336     def __setitem__(self, key, column): 
    337         if column.name is None: 
    338             column.name = self.schema._column_name(self.name, key) 
    339             column.qname = self.schema.db.quote(column.name) 
    340          
    341         if not self.created: 
    342             dict.__setitem__(self, key, column) 
    343             return 
    344          
    345         if key in self: 
    346             del self[key] 
    347          
    348         if column.autoincrement: 
    349             # This may or may not be a no-op, depending on the DB. 
    350             self.schema.create_sequence(self, column) 
    351         self._add_column(column) 
    352         dict.__setitem__(self, key, column) 
    353      
    354     def _drop_column(self, column): 
    355         """Internal function to drop the column from the database.""" 
    356         self.schema.db.execute_ddl("ALTER TABLE %s DROP COLUMN %s;" % 
    357                                    (self.qname, column.qname)) 
    358      
    359     def __delitem__(self, key): 
    360         if key in self.indices: 
    361             del self.indices[key] 
    362          
    363         if not self.created: 
    364             dict.__delitem__(self, key) 
    365             return 
    366          
    367         column = self[key] 
    368         self._drop_column(column) 
    369         if column.autoincrement: 
    370             # This may or may not be a no-op, depending on the DB. 
    371             self.schema.drop_sequence(column) 
    372         dict.__delitem__(self, key) 
    373      
    374     def _rename(self, oldcol, newcol): 
    375         # Override this to do the actual rename at the DB level. 
    376         self.schema.db.execute_ddl("ALTER TABLE %s RENAME COLUMN %s TO %s;" % 
    377                                    (self.qname, oldcol.qname, newcol.qname)) 
    378      
    379     def rename(self, oldkey, newkey): 
    380         """Rename a Column. This will change the table name in the database.""" 
    381         oldcol = self[oldkey] 
    382          
    383         if not self.created: 
    384             dict.__delitem__(self, oldkey) 
    385             dict.__setitem__(self, newkey, oldcol) 
    386             return 
    387          
    388         oldname = oldcol.name 
    389         newname = self.schema._column_name(self.name, newkey) 
    390          
    391         if oldname != newname: 
    392             newcol = oldcol.copy() 
    393             newcol.name = newname 
    394             newcol.qname = self.schema.db.quote(newname) 
    395             self._rename(oldcol, newcol) 
    396          
    397         # Use the superclass calls to avoid DROP COLUMN/ADD COLUMN. 
    398         dict.__delitem__(self, oldkey) 
    399         dict.__setitem__(self, newkey, newcol) 
    400      
    401     def add_index(self, columnkey): 
    402         """Add and return a new Index for the given column key. 
    403          
    404         The new Index object will possess the same key as the column. 
    405         In general, the actual SQL name of the new Index will be of 
    406         the form: "i" + table.name + column.name. 
    407         """ 
    408         colname = self[columnkey].name 
    409         name = self.schema.table_name("i" + self.name + colname) 
    410         i = Index(name, self.schema.db.quote(name), self.name, colname) 
    411         self.indices[columnkey] = i 
    412         return i 
    413      
    414      
    415     # ---------------------------- OLTP/CRUD ---------------------------- # 
    416      
    417     def whereclause(self, **inputs): 
    418         """Return an SQL WHERE clause for the given input fields. 
    419          
    420         If the given clause is imperfect, a ValueError is raised. 
    421         """ 
    422         tpair = [(self.qname, self)] 
    423         decom = self.schema.db.decompiler(tpair, logic.filter(**inputs), 
    424                                           self.schema.db.adaptertosql) 
    425         code = decom.code() 
    426         if decom.imperfect: 
    427             raise ValueError("The given inputs could not safely be translated " 
    428                              "to SQL.", inputs, code) 
    429         return code 
    430      
    431     def id_clause(self, **inputs): 
    432         """Return an SQL expression for the identifiers of the given table.""" 
    433         for key in inputs.keys(): 
    434             if not self[key].key: 
    435                 inputs.pop(key) 
    436         return self.whereclause(**inputs) 
    437      
    438     def insert(self, **inputs): 
    439         """Insert a row and return {idcolkey: newid}.""" 
    440         coerce_out = self.schema.db.adaptertosql.coerce 
    441         coerce_in = self.schema.db.adapterfromdb.coerce 
    442          
    443         fields = [] 
    444         idkeys = [] 
    445         values = [] 
    446         for key, col in self.iteritems(): 
    447             if col.autoincrement: 
    448                 # Skip this field, since we're using a sequencer 
    449                 idkeys.append(key) 
    450                 continue 
    451             if key in inputs: 
    452                 val = coerce_out(inputs[key], col.dbtype) 
    453                 fields.append(col.qname) 
    454                 values.append(val) 
    455          
    456         conn = self.schema.db.connections.get() 
    457          
    458         fields = ", ".join(fields) 
    459         values = ", ".join(values) 
    460         self.schema.db.execute('INSERT INTO %s (%s) VALUES (%s);' % 
    461                                (self.qname, fields, values), conn) 
    462          
    463         if idkeys: 
    464             newids = self._grab_new_ids(idkeys, conn) 
    465             for key in newids.keys(): 
    466                 col = self[key] 
    467                 newids[key] = coerce_in(newids[key], col.dbtype, col.pytype) 
    468             return newids 
    469         else: 
    470             return {} 
    471      
    472     def _grab_new_ids(self, idkeys, conn): 
    473         # Override this to fetch and return new autoincrement values. 
    474         raise NotImplementedError 
    475      
    476     def save(self, **inputs): 
    477         """Update a row using the given inputs.""" 
    478         parms = [] 
    479         coerce = self.schema.db.adaptertosql.coerce 
    480         for key, val in inputs.iteritems(): 
    481             col = self[key] 
    482             if col.autoincrement: 
    483                 # Skip this field, since we're using a sequencer 
    484                 pass 
    485             else: 
    486                 val = coerce(val, col.dbtype) 
    487                 parms.append('%s = %s' % (col.qname, val)) 
    488          
    489         if parms: 
    490             sql = ('UPDATE %s SET %s WHERE %s;' % 
    491                    (self.qname, ", ".join(parms), self.id_clause(**inputs))) 
    492             self.schema.db.execute(sql) 
    493      
    494     use_asterisk_to_delete_all = False 
    495      
    496     def delete(self, **inputs): 
    497         """Delete all rows matching the given identifier inputs.""" 
    498         if self.use_asterisk_to_delete_all: 
    499             star = " *" 
    500         else: 
    501             star = "" 
    502         self.schema.db.execute('DELETE%s FROM %s WHERE %s;' % 
    503                                (star, self.qname, self.id_clause(**inputs))) 
    504      
    505     def delete_all(self, **inputs): 
    506         """Delete all rows matching the given inputs.""" 
    507         if self.use_asterisk_to_delete_all: 
    508             star = " *" 
    509         else: 
    510             star = "" 
    511         self.schema.db.execute('DELETE%s FROM %s WHERE %s;' % 
    512                                (star, self.qname, 
    513                                 self.whereclause(**inputs))) 
    514      
    515     def select_all(self, restriction=None, **kwargs): 
    516         """Yield data dicts matching the given restriction.""" 
    517         if restriction and not isinstance(restriction, logic.Expression): 
    518             restriction = logic.Expression(restriction) 
    519         if kwargs: 
    520             f = logic.filter(**kwargs) 
    521             if restriction: 
    522                 restriction += f 
    523             else: 
    524                 restriction = f 
    525          
    526         attrs = self.keys() 
    527         data = self.schema.db.select(self, attrs, restriction) 
    528         for row in data: 
    529             row = dict(zip(attrs, row)) 
    530             if restriction and data.imperfect: 
    531                 # Run a dummy object through our restriction before yielding. 
    532                 if not restriction(ImperfectDummy(**row)): 
    533                     continue 
    534             yield row 
    535      
    536     def select_one(self, restriction=None, **kwargs): 
    537         """Return a single data dict matching the given restriction (or None).""" 
    538         try: 
    539             return self.select_all(restriction, **kwargs).next() 
    540         except StopIteration: 
    541             return None 
    542  
    543  
    544 class ImperfectDummy(object): 
    545     """A dummy object for resolving imperfect queries.""" 
    546     def __init__(self, **kwargs): 
    547         for k, v in kwargs.iteritems(): 
    548             setattr(self, k, v) 
    549  
    550  
    551 class Schema(dict): 
    552     """A dict for managing a set of tables. 
    553      
    554     Values in this dict must be instances of Table. Keys should be 
    555     consumer-friendly names for each Table value. For example, it's 
    556     easiest to use all lowercase table names in MySQL; however, a 
    557     geniusql consumer might want their code to use TitledNames to 
    558     refer to each table. 
    559      
    560     When a consumer adds and deletes items from a Schema object, 
    561     appropriate CREATE TABLE/DROP TABLE commands are executed. 
    562     This means that a Table object to be added should have all 
    563     of its columns populated before adding it to the Schema. 
    564     """ 
    565      
    566     tableclass = Table 
    567     indexsetclass = IndexSet 
    568      
    569     def __new__(cls, db, name): 
    570         return dict.__new__(cls) 
    571      
    572     def __init__(self, db, name): 
    573         dict.__init__(self) 
    574          
    575         self.db = db 
    576         self.name = self.db.sql_name(name) 
    577         self.qname = self.db.quote(self.name) 
    578         self._discover_lock = threading.Lock() 
    579         self.discover_dbinfo() 
    580      
    581     def __repr__(self): 
    582         name = getattr(self, "name", "<unknown>") 
    583         return "%s.%s(%r)" % (self.__module__, self.__class__.__name__, name) 
    584      
    585     #                              Discovery                              # 
    586      
    587     def _get_dbinfo(self, conn=None): 
    588         return {} 
    589      
    590     def discover_dbinfo(self, conn=None): 
    591         """Set attributes on self with actual DB metadata, where possible.""" 
    592         for k, v in self._get_dbinfo().iteritems(): 
    593             setattr(self, k, v) 
    594      
    595     def _get_tables(self, conn=None): 
    596         raise NotImplementedError 
    597      
    598     def _get_table(self, tablename, conn=None): 
    599         # Fallback behavior. This is slow and should be optimized by each DB. 
    600         for t in self._get_tables(): 
    601             if t.name == tablename: 
    602                 return t 
    603         raise errors.MappingError(tablename) 
    604      
    605     def _get_columns(self, tablename, conn=None): 
    606         raise NotImplementedError 
    607      
    608     def _get_indices(self, tablename, conn=None): 
    609         raise NotImplementedError 
    610      
    611     def _discover_table(self, table, conn=None): 
    612         """Populate the columns and indices of the given Table object.""" 
    613         for col in self._get_columns(table.name, conn): 
    614             # Use the superclass call to avoid ALTER TABLE 
    615             if col.name in table: 
    616                 dict.__delitem__(table, col.name) 
    617             dict.__setitem__(table, col.name, col) 
    618          
    619         for idx in self._get_indices(table.name, conn): 
    620             # Use the superclass call to avoid CREATE INDEX 
    621             if idx.name in table.indices: 
    622                 dict.__delitem__(table.indices, idx.name) 
    623             dict.__setitem__(table.indices, idx.name, idx) 
    624      
    625     def discover(self, tablename, conn=None): 
    626         """Attach a new Table from the underlying DB to self (and return it). 
    627          
    628         Table objects (and their Column and Index subobjects) will be 
    629         added to self using keys that match the database's names. 
    630         Consumers should call the "alias(oldname, newname)" method 
    631         of Schema, Table, and IndexSet in order to re-map the 
    632         discovered objects using consumer-friendly names. 
    633          
    634         If no such table exists, a MappingError should be raised. 
    635         """ 
    636         self._discover_lock.acquire() 
    637         try: 
    638             table = self._get_table(tablename) 
    639             self._discover_table(table, conn) 
    640              
    641             # Use the superclass calls to avoid CREATE TABLE 
    642             if table.name in self: 
    643                 dict.__delitem__(self, table.name) 
    644             dict.__setitem__(self, table.name, table) 
    645              
    646             return table 
    647         finally: 
    648             self._discover_lock.release() 
    649      
    650     def discover_all(self, conn=None): 
    651         """(Re-)populate self (all table items) from the underlying DB. 
    652          
    653         Table objects (and their Column and Index subobjects) will be 
    654         added to self using keys that match the database's names. 
    655         Consumers should call the "alias(oldname, newname)" method 
    656         of Schema, Table, and IndexSet in order to re-map the 
    657         discovered objects using consumer-friendly names. 
    658          
    659         This method is idempotent, but that doesn't mean cheap. Try not 
    660         to call it very often (once at app startup is usually enough). 
    661         If you already know the names of all the tables you want to 
    662         discover, it's often faster to skip this method and just use 
    663         the discover(tablename) method for each known name instead. 
    664         """ 
    665         self._discover_lock.acquire() 
    666         try: 
    667             for table in self._get_tables(conn): 
    668                 self._discover_table(table, conn) 
    669                  
    670                 # Use the superclass calls to avoid CREATE TABLE 
    671                 if table.name in self: 
    672                     dict.__delitem__(self, table.name) 
    673                 dict.__setitem__(self, table.name, table) 
    674         finally: 
    675             self._discover_lock.release() 
    676      
    677     def alias(self, oldname, newname): 
    678         """Add a new key for the Table with the given, existing key. 
    679          
    680         Consumer code should call this method when user-supplied table 
    681         names do not match the names in the database. This does not 
    682         remove the old key; both keys may be used to refer to the same 
    683         Table object. 
    684         """ 
    685         if oldname == newname: 
    686             return 
    687          
    688         obj = self[oldname] 
    689         if newname in self: 
    690             dict.__delitem__(self, newname) 
    691         dict.__delitem__(self, oldname) 
    692         dict.__setitem__(self, newname, obj) 
    693      
    694     def _column_name(self, tablename, columnkey): 
    695         "Return the SQL column name for the given table name and column key." 
    696         # If you want to use a map from your ORM's property names 
    697         # to DB column names, override this method (that's why 
    698         # the tablename must be included in the args). 
    699         return self.db.sql_name(columnkey) 
    700      
    701     def column(self, pytype=unicode, dbtype=None, default=None, hints=None, 
    702                key=False, autoincrement=False): 
    703         """Return a Column object from the given arguments.""" 
    704         col = Column(pytype, dbtype, default, hints, key) 
    705         col.autoincrement = autoincrement 
    706          
    707         if dbtype is None: 
    708             col.dbtype = self.db.typeadapter.coerce(col, pytype) 
    709         pytype2 = self.db.python_type(col.dbtype) 
    710         col.imperfect_type = not self.db.isrelatedtype(pytype, pytype2) 
    711          
    712         return col 
    713      
    714     prefix = "" 
    715      
    716     def table_name(self, key): 
    717         """Return the SQL table name for the given key.""" 
    718         # If you want to use a map from your ORM's class names 
    719         # to DB table names, override this method. 
    720         return self.db.sql_name(self.prefix + key) 
    721      
    722     def table(self, name): 
    723         """Create and return a Table object for the given name.""" 
    724         name = self.table_name(name) 
    725         return self.tableclass(name, self.db.quote(name), self) 
    726      
    727     def create_sequence(self, table, column): 
    728         """Create a SEQUENCE for the given column and set its sequence_name.""" 
    729         # By default, this does nothing. Databases which require a separate 
    730         # statement to create a sequence generator should override this. 
    731         pass 
    732      
    733     def drop_sequence(self, column): 
    734         """Drop a SEQUENCE for the given column and remove its sequence_name.""" 
    735         # By default, this does nothing. Databases which require a separate 
    736         # statement to drop a sequence generator should override this. 
    737         pass 
    738      
    739     def columnclause(self, column): 
    740         """Return a clause for the given column for CREATE or ALTER TABLE. 
    741          
    742         This will be of the form "name type [DEFAULT x]". 
    743          
    744         Most subclasses will override this to add autoincrement support. 
    745         """ 
    746         dbtype = column.dbtype 
    747          
    748         default = column.default or "" 
    749         if default: 
    750             default = self.db.adaptertosql.coerce(default, dbtype) 
    751             default = " DEFAULT %s" % default 
    752          
    753         return "%s %s%s" % (column.qname, dbtype, default) 
    754      
    755     def __setitem__(self, key, table): 
    756         if key in self: 
    757             del self[key] 
    758          
    759         # Set table.created to True, which should "turn on" 
    760         # any future ALTER TABLE statements. 
    761         table.created = True 
    762          
    763         fields = [] 
    764         pk = [] 
    765         for column in table.itervalues(): 
    766             if column.autoincrement: 
    767                 # This may or may not be a no-op, depending on the DB. 
    768                 self.create_sequence(table, column) 
    769              
    770             fields.append(self.columnclause(column)) 
    771             if column.key: 
    772                 pk.append(column.qname) 
    773          
    774         if pk: 
    775             pk = ", PRIMARY KEY (%s)" % ", ".join(pk) 
    776         else: 
    777             pk = "" 
    778          
    779         self.db.execute_ddl('CREATE TABLE %s (%s%s);' % 
    780                             (table.qname, ", ".join(fields), pk)) 
    781          
    782         for index in table.indices.itervalues(): 
    783             self.db.execute_ddl('CREATE INDEX %s ON %s (%s);' % 
    784                                 (index.qname, table.qname, 
    785                                  self.db.quote(index.colname))) 
    786          
    787         dict.__setitem__(self, key, table) 
    788      
    789     def __delitem__(self, key): 
    790         table = self[key] 
    791         self.db.execute_ddl('DROP TABLE %s;' % table.qname) 
    792         for col in table.itervalues(): 
    793             if col.autoincrement: 
    794                 self.drop_sequence(col) 
    795         dict.__delitem__(self, key) 
    796      
    797     def _rename(self, oldtable, newtable): 
    798         # Override this to do the actual rename at the DB level. 
    799         raise NotImplementedError 
    800         newtable.created = True 
    801      
    802     def rename(self, oldkey, newkey): 
    803         """Rename a Table.""" 
    804         oldtable = self[oldkey] 
    805         oldname = oldtable.name 
    806         newname = self.db.table_name(newkey) 
    807          
    808         if oldname != newname: 
    809             newtable = oldtable.copy() 
    810             newtable.schema = self.schema 
    811             newtable.name = newname 
    812             newtable.qname = self.db.quote(newname) 
    813             self._rename(oldtable, newname) 
    814          
    815         # Use the superclass calls to avoid DROP TABLE/CREATE TABLE. 
    816         dict.__delitem__(self, oldkey) 
    817         dict.__setitem__(self, newkey, newtable) 
    818      
    819     def create_database(self): 
    820         self.db.execute_ddl("CREATE DATABASE %s;" % self.qname) 
    821         self.clear() 
    822      
    823     def drop_database(self): 
    824         # Must shut down all connections to avoid 
    825         # "being accessed by other users" error. 
    826         self.db.connections.shutdown() 
    827         self.db.execute_ddl("DROP DATABASE %s;" % self.qname) 
    828         self.clear() 
    829  
    830  
    831 class Database(object): 
    832      
    833     __metaclass__ = _AttributeDocstrings 
    834      
    835     adaptertosql = AdapterToSQL() 
    836     adapterfromdb = AdapterFromDB() 
    837     typeadapter = TypeAdapter() 
    838     decompiler = SQLDecompiler 
    839     joinwrapper = TableWrapper 
    840     selectwriter = SelectWriter 
    841     connectionmanager = ConnectionManager 
    842     schemaclass = Schema 
    843      
    844     multischema = True 
    845     multischema__doc = """If True, instances of this Database class may 
    846     spawn multiple Schema instances. This is False, for example, when 
    847     the underlying Database engine binds connections to individual files. 
    848     In most applications (that use a single schema) this presents no 
    849     problems; applications that need to handle more than one schema 
    850     at a time should inspect this value to determine whether they 
    851     need a separate Database instance per Schema instance. 
    852     """ 
    853      
    854     def __init__(self, **kwargs): 
    855         for k, v in kwargs.iteritems(): 
    856             setattr(self, k, v) 
    857          
    858         poolsize = kwargs.get('poolsize', 10) 
    859         self.connections = self.connectionmanager(self, poolsize) 
    860      
    861     def version(self): 
    862         """Return a string containing version info for this database.""" 
    863         raise NotImplementedError 
    864      
    865     def log(self, msg): 
    866         pass 
    867      
    868     def python_type(self, dbtype): 
    869         """Return a Python type which can store values of the given dbtype.""" 
    870         raise TypeError("Database type %r could not be converted " 
    871                         "to a Python type." % dbtype) 
    872      
    873     def isrelatedtype(self, pytype1, pytype2): 
    874         """If values of both types are expressed with the same SQL, return True.""" 
    875         if issubclass(pytype1, pytype2) or issubclass(pytype2, pytype1): 
    876             return True 
    877         if issubclass(pytype1, basestring) and issubclass(pytype2, basestring): 
    878             return True 
    879         if ((issubclass(pytype1, int) or issubclass(pytype1, long)) and 
    880             (issubclass(pytype2, int) or issubclass(pytype2, long))): 
    881             return True 
    882         if typerefs.fixedpoint: 
    883             if typerefs.decimal: 
    884                 if ((issubclass(pytype1, typerefs.fixedpoint.FixedPoint) 
    885                      or issubclass(pytype1, typerefs.decimal.Decimal)) and 
    886                     (issubclass(pytype2, typerefs.fixedpoint.FixedPoint) 
    887                      or issubclass(pytype2, typerefs.decimal.Decimal))): 
    888                     return True 
    889             else: 
    890                 if (issubclass(pytype1, typerefs.fixedpoint.FixedPoint) and 
    891                     issubclass(pytype2, typerefs.fixedpoint.FixedPoint)): 
    892                     return True 
    893         else: 
    894             if typerefs.decimal: 
    895                 if (issubclass(pytype1, typerefs.decimal.Decimal) and 
    896                     issubclass(pytype2, typerefs.decimal.Decimal)): 
    897                     return True 
    898         return False 
    899      
    900     #                               Naming                               # 
    901      
    902     sql_name_max_length = 64 
    903     sql_name_caseless = False 
    904      
    905     def quote(self, name): 
    906         """Return name, quoted for use in an SQL statement.""" 
    907         # This base class doesn't use "quote", 
    908         # but most subclasses will. 
    909         return name 
    910      
    911     def sql_name(self, key): 
    912         """Return the native SQL version of key.""" 
    913         if self.sql_name_caseless: 
    914             key = key.lower() 
    915          
    916         maxlen = self.sql_name_max_length 
    917         if maxlen and len(key) > maxlen: 
    918             errors.warn("The name '%s' is longer than the maximum of " 
    919                         "%s characters." % (key, maxlen)) 
    920             key = key[:maxlen] 
    921          
    922         return key 
    923      
    924     def is_timeout_error(self, exc): 
    925         """If the given exception instance is a lock timeout, return True. 
    926          
    927         This should return True for errors which arise from locking 
    928         timeouts; for example, if the database prevents 'dirty reads' 
    929         by raising an error. 
    930         """ 
    931         # You should definitely override this for your database. 
    932         return False 
    933      
    934     def execute(self, query, conn=None): 
    935         """Return a native response for the given query.""" 
    936         if conn is None: 
    937             conn = self.connections.get() 
    938         if isinstance(query, unicode): 
    939             query = query.encode(self.adaptertosql.encoding) 
    940         self.log(query) 
    941         return conn.query(query) 
    942      
    943     def execute_ddl(self, query, conn=None): 
    944         """Return a native response for the given DDL statement. 
    945          
    946         In general, DDL statements should lock out other statements 
    947         (especially those isolated in other transactions). Use this 
    948         method to perform a locked DDL statement. 
    949         """ 
    950         self.connections.lock("Transaction denied due to DDL: %r" % query) 
    951         try: 
    952 ##            # Must shut down all connections to avoid 
    953 ##            # "being accessed by other users" error? 
    954 ##            self.connections.shutdown() 
    955             if conn is None: 
    956                 # Important: use _factory(), not get(), to avoid the lock 
    957                 conn = self.connections._factory() 
    958             self.execute(query, conn) 
    959         finally: 
    960             self.connections.unlock() 
    961      
    962     def fetch(self, query, conn=None): 
    963         """Return rowdata, columns (name, type) for the given query. 
    964          
    965         query should be a SQL query in string format 
    966         rowdata will be an iterable of iterables containing the result values. 
    967         columns will be an iterable of (column name, data type) pairs. 
    968          
    969         This base class uses _sqlite syntax. 
    970         """ 
    971         res = self.execute(query, conn) 
    972         return res.row_list, res.col_defs 
    973      
    974     def select(self, relation, attributes, restriction=None, distinct=False): 
    975         """Yield matching data, coerced to Python types (where known).""" 
    976         sel = self.selectwriter(self, relation, attributes, restriction) 
    977         data, _ = self.fetch(sel.sql(distinct)) 
    978         return ResultSet(data, sel.columns, sel.imperfect) 
    979      
    980     def schema(self, name): 
    981         return self.schemaclass(self, name) 
    982  
    983  
    984 class ResultSet: 
    985      
    986     def __init__(self, data, columns, imperfect): 
    987         self.data = data 
    988         self.columns = columns 
    989         self.imperfect = imperfect 
    990         self.cursor = 0 
    991      
    992     def __iter__(self): 
    993         return self 
    994      
    995     def next(self): 
    996         try: 
    997             row = self.data[self.cursor] 
    998             self.cursor += 1 
    999         except IndexError: 
    1000             raise StopIteration 
    1001          
    1002         coerced_row = [] 
    1003         for i, (table, col, qname) in enumerate(self.columns): 
    1004             val = row[i] 
    1005             if table and col: 
    1006                 val = table.schema.db.adapterfromdb.coerce(val, col.dbtype, col.pytype) 
    1007             coerced_row.append(val) 
    1008         return coerced_row 
    1009  
  • trunk/geniusql/providers/ado.py

    r12 r13  
    3737 
    3838import geniusql 
    39 from geniusql import errors, typerefs 
     39from geniusql import adapters, conns, errors, select, typerefs 
     40from geniusql import isolation as _isolation 
    4041 
    4142adOpenForwardOnly = 0 
     
    130131 
    131132 
    132 class AdapterFromADO(geniusql.AdapterFromDB): 
     133class AdapterFromADO(adapters.AdapterFromDB): 
    133134    """Coerce incoming values from ADO to Python datatypes.""" 
    134135     
     
    230231 
    231232 
    232 class ADOSQLDecompiler(geniusql.SQLDecompiler): 
     233class ADOSQLDecompiler(select.SQLDecompiler): 
    233234     
    234235    def visit_COMPARE_OP(self, lo, hi): 
    235236        op2, op1 = self.stack.pop(), self.stack.pop() 
    236         if op1 is geniusql.cannot_represent or op2 is geniusql.cannot_represent: 
    237             self.stack.append(geniusql.cannot_represent) 
     237        if op1 is select.cannot_represent or op2 is select.cannot_represent: 
     238            self.stack.append(select.cannot_represent) 
    238239            return 
    239240         
     
    267268                op1, op2 = self._compare_constants(op1, op2) 
    268269            except TypeError: 
    269                 self.stack.append(geniusql.cannot_represent) 
     270                self.stack.append(select.cannot_represent) 
    270271                self.imperfect = True 
    271272                return 
    272273             
    273             if (isinstance(op2, geniusql.ConstWrapper) 
     274            if (isinstance(op2, select.ConstWrapper) 
    274275                and isinstance(op2.basevalue, basestring)): 
    275276                atom = self._compare_strings(op1, op, op2) 
     
    300301    def containedby(self, op1, op2): 
    301302        self.imperfect = True 
    302         if isinstance(op1, ConstWrapper): 
     303        if isinstance(op1, select.ConstWrapper): 
    303304            # Looking for text in a field. Use Like (reverse terms). 
    304305            return op2 + " LIKE '%" + self.adapter.escape_like(op1) + "%'" 
     
    313314     
    314315    def dejavu_icontainedby(self, op1, op2): 
    315         if isinstance(op1, geniusql.ConstWrapper): 
     316        if isinstance(op1, select.ConstWrapper): 
    316317            # Looking for text in a field. Use Like (reverse terms). 
    317318            # LIKE is already case-insensitive in MS SQL Server; 
     
    388389 
    389390 
    390 class ADOConnectionManager(geniusql.ConnectionManager): 
     391class ADOConnectionManager(conns.ConnectionManager): 
    391392     
    392393    # the amount of time to try to close the db connection 
     
    785786 
    786787 
    787 class AdapterToADOSQL_SQLServer(geniusql.AdapterToSQL): 
     788class AdapterToADOSQL_SQLServer(adapters.AdapterToSQL): 
    788789     
    789790    encoding = 'ISO-8859-1' 
     
    809810 
    810811 
    811 class TypeAdapter_SQLServer(geniusql.TypeAdapter): 
     812class TypeAdapter_SQLServer(adapters.TypeAdapter): 
    812813     
    813814    # Hm. Docs say 38, but I can't seem to get more than 12 working. 
     
    10021003 
    10031004 
    1004 class TypeAdapter_MSAccess(geniusql.TypeAdapter): 
     1005class TypeAdapter_MSAccess(adapters.TypeAdapter): 
    10051006    # http://msdn2.microsoft.com/en-us/library/ms714540.aspx 
    10061007    # http://office.microsoft.com/en-us/access/HP010322481033.aspx 
     
    10391040 
    10401041 
    1041 class AdapterToADOSQL_MSAccess(geniusql.AdapterToSQL): 
     1042class AdapterToADOSQL_MSAccess(adapters.AdapterToSQL): 
    10421043    """Coerce Expression constants to ADO SQL.""" 
    10431044     
     
    10821083        # to be a commit timeout. See http://support.microsoft.com/kb/200300 
    10831084        # for additional synchronization issues. 
    1084         self._factory = geniusql.SingleConnection(self._get_conn, self._del_conn) 
     1085        self._factory = conns.SingleConnection(self._get_conn, self._del_conn) 
    10851086     
    10861087    def isolate(self, conn, isolation=None): 
     
    10981099            isolation = self.default_isolation 
    10991100         
    1100         if isinstance(isolation, geniusql.IsolationLevel): 
     1101        if isinstance(isolation, _isolation.IsolationLevel): 
    11011102            # Map the given IsolationLevel object to a native value. 
    11021103            isolation = isolation.name 
  • trunk/geniusql/providers/firebird.py

    r12 r13  
    77 
    88import geniusql 
    9 from geniusql import errors, typerefs 
     9from geniusql import adapters, conns, errors, select, typerefs 
     10from geniusql import isolation as _isolation 
    1011 
    1112import kinterbasdb 
     
    1516 
    1617 
    17 class AdapterToFireBirdSQL(geniusql.AdapterToSQL): 
     18class AdapterToFireBirdSQL(adapters.AdapterToSQL): 
    1819     
    1920    # Notice these are ordered pairs. Escape \ before introducing new ones. 
     
    4647 
    4748 
    48 class AdapterFromFirebirdDB(geniusql.AdapterFromDB): 
     49class AdapterFromFirebirdDB(adapters.AdapterFromDB): 
    4950     
    5051    def coerce_any_to_decimal(self, value): 
     
    104105 
    105106 
    106 class TypeAdapterFirebird(geniusql.TypeAdapter): 
     107class TypeAdapterFirebird(adapters.TypeAdapter): 
    107108    """Return the SQL typename of a DB column.""" 
    108109     
     
    139140 
    140141 
    141 class FirebirdSQLDecompiler(geniusql.SQLDecompiler): 
     142class FirebirdSQLDecompiler(select.SQLDecompiler): 
    142143     
    143144    # --------------------------- Dispatchees --------------------------- # 
     
    150151     
    151152    def containedby(self, op1, op2): 
    152         if isinstance(op1, geniusql.ConstWrapper): 
     153        if isinstance(op1, select.ConstWrapper): 
    153154            # Looking for text in a field. Use Like (reverse terms). 
    154155            return op2 + " LIKE '%" + self.adapter.escape_like(op1) + "%' ESCAPE '\\'" 
     
    163164     
    164165    def dejavu_icontainedby(self, op1, op2): 
    165         if isinstance(op1, geniusql.ConstWrapper): 
     166        if isinstance(op1, select.ConstWrapper): 
    166167            return op2 + " CONTAINING " + op1 
    167168        else: 
     
    198199 
    199200 
    200 class FirebirdSelectWriter(geniusql.SelectWriter): 
     201class FirebirdSelectWriter(select.SelectWriter): 
    201202     
    202203    def wrap(self, join): 
     
    204205        t1, t2 = join.table1, join.table2 
    205206         
    206         if isinstance(t1, geniusql.Join): 
     207        if isinstance(t1, select.Join): 
    207208            wt1 = self.wrap(t1) 
    208209        else: 
     
    215216            self.seen[t1.name] = None 
    216217         
    217         if isinstance(t2, geniusql.Join): 
     218        if isinstance(t2, select.Join): 
    218219            wt2 = self.wrap(t2) 
    219220        else: 
     
    224225            self.seen[t2.name] = None 
    225226         
    226         newjoin = geniusql.Join(wt1, wt2, join.leftbiased) 
     227        newjoin = select.Join(wt1, wt2, join.leftbiased) 
    227228        # if the original Join had a custom reference path, 
    228229        # copy it to the new Join instance 
     
    292293 
    293294 
    294 class FirebirdConnectionManager(geniusql.ConnectionManager): 
     295class FirebirdConnectionManager(conns.ConnectionManager): 
    295296     
    296297    default_isolation = kinterbasdb.isc_tpb_read_committed 
     
    328329            isolation = self.default_isolation 
    329330         
    330         if isinstance(isolation, geniusql.IsolationLevel): 
     331        if isinstance(isolation, _isolation.IsolationLevel): 
    331332            # Map the given IsolationLevel object to a native value. 
    332333            # This base class uses the four ANSI names as native values. 
  • trunk/geniusql/providers/mysql.py

    r12 r13  
    1717 
    1818import geniusql 
    19 from geniusql import errors, typerefs, provider
    20  
    21  
    22 class AdapterToMySQL(geniusql.AdapterToSQL): 
     19from geniusql import adapters, conns, errors, providers, select, typeref
     20 
     21 
     22class AdapterToMySQL(adapters.AdapterToSQL): 
    2323     
    2424    escapes = [("'", "''"), ("\\", r"\\")] 
     
    4141 
    4242 
    43 class AdapterFromMySQL(geniusql.AdapterFromDB): 
     43class AdapterFromMySQL(adapters.AdapterFromDB): 
    4444     
    4545    def coerce_any_to_bool(self, value): 
     
    5050 
    5151 
    52 class MySQLDecompiler(geniusql.SQLDecompiler): 
     52class MySQLDecompiler(select.SQLDecompiler): 
    5353     
    5454    def dejavu_today(self): 
     
    6363     
    6464    def dejavu_icontainedby(self, op1, op2): 
    65         if isinstance(op1, geniusql.ConstWrapper): 
     65        if isinstance(op1, select.ConstWrapper): 
    6666            # Looking for text in a field. Use Like (reverse terms). 
    6767            return ("CONVERT("+ op2 + " USING utf8) LIKE '%" + 
     
    8484 
    8585 
    86 class TypeAdapterMySQL(geniusql.TypeAdapter): 
     86class TypeAdapterMySQL(adapters.TypeAdapter): 
    8787     
    8888    numeric_max_precision = 16 
     
    166166            ] 
    167167 
    168 class MySQLConnectionManager(geniusql.ConnectionManager): 
     168class MySQLConnectionManager(conns.ConnectionManager): 
    169169     
    170170    # InnoDB default 
  • trunk/geniusql/providers/postgres.py

    r12 r13  
    1313 
    1414import geniusql 
    15 from geniusql import errors, typerefs 
    16  
    17  
    18 class AdapterToPgSQL(geniusql.AdapterToSQL): 
     15from geniusql import adapters, errors, select, typerefs 
     16 
     17 
     18class AdapterToPgSQL(adapters.AdapterToSQL): 
    1919     
    2020    like_escapes = [("%", r"\\%"), ("_", r"\\_")] 
     
    7070 
    7171 
    72 class AdapterFromPg(geniusql.AdapterFromDB): 
     72class AdapterFromPg(adapters.AdapterFromDB): 
    7373     
    7474    def coerce_any_to_str(self, value): 
     
    8181 
    8282 
    83 class PgDecompiler(geniusql.SQLDecompiler): 
     83class PgDecompiler(select.SQLDecompiler): 
    8484     
    8585    def dejavu_icontainedby(self, op1, op2): 
    86         if isinstance(op1, geniusql.ConstWrapper): 
     86        if isinstance(op1, select.ConstWrapper): 
    8787            # Looking for text in a field. Use ILike (reverse terms). 
    8888            return op2 + " ILIKE '%" + self.adapter.escape_like(op1) + "%'" 
  • trunk/geniusql/providers/psycopg.py

    r12 r13  
    99 
    1010import geniusql 
    11 from geniusql import errors 
     11from geniusql import conns, errors 
    1212from geniusql.providers import postgres 
    1313 
     
    2525 
    2626 
    27 class PsycoPgConnectionManager(geniusql.ConnectionManager): 
     27class PsycoPgConnectionManager(conns.ConnectionManager): 
    2828     
    2929    default_isolation = "READ COMMITTED" 
  • trunk/geniusql/providers/pypgsql.py

    r12 r13  
    33 
    44import geniusql 
    5 from geniusql import errors, typerefs 
     5from geniusql import conns, errors, typerefs 
    66from geniusql.providers import postgres 
    77 
    88 
    9 class PyPgConnectionManager(geniusql.ConnectionManager): 
     9class PyPgConnectionManager(conns.ConnectionManager): 
    1010     
    1111    default_isolation = "READ COMMITTED" 
  • trunk/geniusql/providers/sqlite.py

    r12 r13  
    44 
    55import geniusql 
    6 from geniusql import errors, typerefs, providers 
     6from geniusql import adapters, conns, errors, providers, select, typerefs 
     7from geniusql import isolation as _isolation 
    78 
    89try: 
     
    3839 
    3940 
    40 class AdapterToSQLite(geniusql.AdapterToSQL): 
     41class AdapterToSQLite(adapters.AdapterToSQL): 
    4142     
    4243    # C-style backslash escapes are not supported. 
     
    6465 
    6566 
    66 class AdapterFromSQLite(geniusql.AdapterFromDB): 
     67class AdapterFromSQLite(adapters.AdapterFromDB): 
    6768     
    6869    def coerce_any_to_bool(self, value): 
     
    7475 
    7576 
    76 class SQLiteDecompiler(geniusql.SQLDecompiler): 
     77class SQLiteDecompiler(select.SQLDecompiler): 
    7778     
    7879    def visit_COMPARE_OP(self, lo, hi): 
     
    8788            # comparison. 
    8889            for i, op in enumerate((op1, op2)): 
    89                 if (isinstance(op, geniusql.ConstWrapper) and 
     90                if (isinstance(op, select.ConstWrapper) and 
    9091                    isinstance(op.basevalue, (datetime.date, datetime.datetime))): 
    9192                    op1 = "julianday(" + op1 + ")" 
     
    104105            self.stack.append(op2) 
    105106         
    106         geniusql.SQLDecompiler.visit_COMPARE_OP(self, lo, hi) 
     107        select.SQLDecompiler.visit_COMPARE_OP(self, lo, hi) 
    107108     
    108109    def attr_startswith(self, tos, arg): 
     
    125126     
    126127    def containedby(self, op1, op2): 
    127         if isinstance(op1, geniusql.ConstWrapper): 
     128        if isinstance(op1, select.ConstWrapper): 
    128129            # Looking for text in a field. Use Like (reverse terms). 
    129130            if _escape_support: 
     
    140141     
    141142    def dejavu_icontainedby(self, op1, op2): 
    142         if isinstance(op1, geniusql.ConstWrapper): 
     143        if isinstance(op1, select.ConstWrapper): 
    143144            # Looking for text in a field. Use Like (reverse terms). 
    144145            if _escape_support: 
     
    185186        else: 
    186187            self.imperfect = True 
    187             return geniusql.cannot_represent 
     188            return select.cannot_represent 
    188189     
    189190    dejavu_today = dejavu_now 
     
    194195        else: 
    195196            self.imperfect = True 
    196             return geniusql.cannot_represent 
     197            return select.cannot_represent 
    197198     
    198199    def dejavu_month(self, x): 
     
    201202        else: 
    202203            self.imperfect = True 
    203             return geniusql.cannot_represent 
     204            return select.cannot_represent 
    204205     
    205206    def dejavu_day(self, x): 
     
    208209        else: 
    209210            self.imperfect = True 
    210             return geniusql.cannot_represent 
    211  
    212  
    213 class TypeAdapterSQLite(geniusql.TypeAdapter): 
     211            return select.cannot_represent 
     212 
     213 
     214class TypeAdapterSQLite(adapters.TypeAdapter): 
    214215    """For a column and Python type, return a database type. 
    215216     
     
    266267 
    267268 
    268 class TypeAdapterSQLiteTypeless(geniusql.TypeAdapter): 
     269class TypeAdapterSQLiteTypeless(adapters.TypeAdapter): 
    269270     
    270271    def coerce(self, col, pytype): 
     
    415416 
    416417 
    417 class SQLiteSelectWriter(geniusql.SelectWriter): 
     418class SQLiteSelectWriter(select.SelectWriter): 
    418419     
    419420    def _joinclause(self, join): 
     
    421422         
    422423        t1, t2 = join.table1, join.table2 
    423         if isinstance(t1, geniusql.Join): 
     424        if isinstance(t1, select.Join): 
    424425            name1, oc = self._joinclause(t1) 
    425426            on_clauses.extend(oc) 
     
    430431            tlist1 = [t1] 
    431432         
    432         if isinstance(t2, geniusql.Join): 
     433        if isinstance(t2, select.Join): 
    433434            name2, oc = self._joinclause(t2) 
    434435            on_clauses.extend(oc) 
     
    473474 
    474475 
    475 class SQLiteConnectionManager(geniusql.ConnectionManager): 
     476class SQLiteConnectionManager(conns.ConnectionManager): 
    476477     
    477478    default_isolation = "SERIALIZABLE" 
     
    490491            # http://www.sqlite.org/cvstrac/wiki?p=InMemoryDatabase 
    491492            # So we need to give :memory: databases a SingleConnection. 
    492             self._factory = geniusql.SingleConnection(self._get_conn, self._del_conn) 
    493         else: 
    494             geniusql.ConnectionManager._set_factory(self) 
     493            self._factory = conns.SingleConnection(self._get_conn, self._del_conn) 
     494        else: 
     495            conns.ConnectionManager._set_factory(self) 
    495496     
    496497    if _cursor_required: 
     
    525526            isolation = self.default_isolation 
    526527         
    527         if isinstance(isolation, geniusql.IsolationLevel): 
     528        if isinstance(isolation, _isolation.IsolationLevel): 
    528529            # Map the given IsolationLevel object to a native value. 
    529530            # This base class uses the four ANSI names as native values.