From 84a43c5cf9698287ea303701a9e865b2ca4570e6 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 27 Feb 2006 15:36:48 +0000 Subject: [PATCH] Added code to make foreignkey on ActiveMapper accept a string and create the ForeignKey object on the fly. Also added ability to pass args and kwargs to Column constructor. ActiveMapper columns can have keyword args indexed and unique which will automatically create a index or a unique index. dburi in AutoConnectEngine can be a callable. --- lib/sqlalchemy/ext/activemapper.py | 34 ++++++++--- lib/sqlalchemy/ext/proxy.py | 6 +- test/autoconnect_engine.py | 90 ++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 10 deletions(-) create mode 100644 test/autoconnect_engine.py diff --git a/lib/sqlalchemy/ext/activemapper.py b/lib/sqlalchemy/ext/activemapper.py index 8b3387eaea..e5b3e4929c 100644 --- a/lib/sqlalchemy/ext/activemapper.py +++ b/lib/sqlalchemy/ext/activemapper.py @@ -1,10 +1,10 @@ from sqlalchemy import objectstore, create_engine, assign_mapper, relation, mapper from sqlalchemy import and_, or_ -from sqlalchemy import Table, Column +from sqlalchemy import Table, Column, ForeignKey from sqlalchemy.ext.proxy import ProxyEngine import inspect - +import sys # # the "proxy" to the database engine... this can be swapped out at runtime @@ -17,13 +17,18 @@ engine = ProxyEngine() # declarative column declaration - this is so that we can infer the colname # class column(object): - def __init__(self, coltype, colname=None, foreign_key=None, primary_key=False): + def __init__(self, coltype, colname=None, foreign_key=None, + primary_key=False, *args, **kwargs): + if isinstance( foreign_key, basestring ): + foreign_key= ForeignKey( foreign_key ) self.coltype = coltype self.colname = colname self.foreign_key = foreign_key self.primary_key = primary_key - - + self.unique = kwargs.pop( 'unique', False ) + self.indexed = kwargs.pop( 'indexed', self.unique ) + self.kwargs = kwargs + self.args = args # # declarative relationship declaration @@ -89,6 +94,7 @@ class ActiveMapperMeta(type): table_name = clsname.lower() columns = [] relations = {} + _engine = getattr( sys.modules[cls.__module__], "__engine__", engine ) if 'mapping' in dict: members = inspect.getmembers(dict.get('mapping')) @@ -97,6 +103,10 @@ class ActiveMapperMeta(type): table_name = value continue + if '__engine__' == name: + _engine= value + continue + if name.startswith('__'): continue if isinstance(value, column): @@ -104,18 +114,24 @@ class ActiveMapperMeta(type): col = Column(value.colname or name, value.coltype, value.foreign_key, - primary_key=value.primary_key) + primary_key=value.primary_key, + *value.args, **value.kwargs) else: col = Column(value.colname or name, value.coltype, - primary_key=value.primary_key) + primary_key=value.primary_key, + *value.args, **value.kwargs) columns.append(col) + if value.indexed: + # create a Index object for the column + index= Index( "%s_idx" % (value.colname or name), + col, unique= value.unique ) continue if isinstance(value, relationship): relations[name] = value - - cls.table = Table(table_name, engine, *columns) + assert _engine is not None, "No engine specified" + cls.table = Table(table_name, _engine, *columns) assign_mapper(cls, cls.table) cls.relations = relations ActiveMapperMeta.classes[clsname] = cls diff --git a/lib/sqlalchemy/ext/proxy.py b/lib/sqlalchemy/ext/proxy.py index dc02606086..d9a830c66e 100644 --- a/lib/sqlalchemy/ext/proxy.py +++ b/lib/sqlalchemy/ext/proxy.py @@ -65,7 +65,11 @@ class AutoConnectEngine(BaseProxyEngine): def get_engine(self): if self._engine is None: - self._engine= create_engine( self.dburi, self.opts, **self.kwargs ) + if callable(self.dburi): + dburi= self.dburi() + else: + dburi= self.dburi + self._engine= create_engine( dburi, self.opts, **self.kwargs ) return self._engine def set_engine(self, engine): diff --git a/test/autoconnect_engine.py b/test/autoconnect_engine.py new file mode 100644 index 0000000000..39bcf3e536 --- /dev/null +++ b/test/autoconnect_engine.py @@ -0,0 +1,90 @@ +from sqlalchemy import * +from sqlalchemy.ext.proxy import AutoConnectEngine + +from testbase import PersistTest +import testbase +import os + +# +# Define an engine, table and mapper at the module level, to show that the +# table and mapper can be used with different real engines in multiple threads +# + + +module_engine = AutoConnectEngine( testbase.db_uri ) +users = Table('users', module_engine, + Column('user_id', Integer, primary_key=True), + Column('user_name', String(16)), + Column('password', String(20)) + ) + +class User(object): + pass + + +class AutoConnectEngineTest1(PersistTest): + + def setUp(self): + clear_mappers() + objectstore.clear() + + def test_engine_connect(self): + users.create() + assign_mapper(User, users) + try: + trans = objectstore.begin() + + user = User() + user.user_name='fred' + user.password='*' + trans.commit() + + # select + sqluser = User.select_by(user_name='fred')[0] + assert sqluser.user_name == 'fred' + + # modify + sqluser.user_name = 'fred jones' + + # commit - saves everything that changed + objectstore.commit() + + allusers = [ user.user_name for user in User.select() ] + assert allusers == [ 'fred jones' ] + finally: + users.drop() + + + + +if __name__ == "__main__": + testbase.main() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- 2.47.2