From: Mike Bayer Date: Fri, 5 May 2006 17:23:00 +0000 (+0000) Subject: fixed a _get_criterion mismatch, cleaned up types + updated types doc X-Git-Tag: rel_0_1_7~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6c89f97e45baf5cbda183f0fdda4135545d0ffbc;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git fixed a _get_criterion mismatch, cleaned up types + updated types doc --- diff --git a/doc/build/content/document_base.myt b/doc/build/content/document_base.myt index ed5c937de1..38d13ec811 100644 --- a/doc/build/content/document_base.myt +++ b/doc/build/content/document_base.myt @@ -24,7 +24,7 @@ onepage='documentation' index='index' title='SQLAlchemy Documentation' - version = '0.1.6' + version = '0.1.7' <%method title> diff --git a/doc/build/content/types.txt b/doc/build/content/types.txt index a979035b27..2ed230ac95 100644 --- a/doc/build/content/types.txt +++ b/doc/build/content/types.txt @@ -23,6 +23,7 @@ The standard set of generic types are: class Float(Numeric): def __init__(self, precision=10) + # DateTime, Date, and Time work with Python datetime objects class DateTime(TypeEngine) class Date(TypeEngine) @@ -38,11 +39,11 @@ The standard set of generic types are: # as bind params, raw bytes to unicode as # rowset values, using the unicode encoding # setting on the engine (defaults to 'utf-8') - class Unicode(String) + class Unicode(TypeDecorator) # uses the pickle protocol to serialize data # in/out of Binary columns - class PickleType(Binary) + class PickleType(TypeDecorator) More specific subclasses of these types are available, which various database engines may choose to implement specifically, allowing finer grained control over types: @@ -76,51 +77,23 @@ Type objects are specified to table meta data using either the class itself, or ### Creating your Own Types {@name=custom} -User-defined types can be created, to support either database-specific types, or customized pre-processing of query parameters as well as post-processing of result set data. You can make your own classes to perform these operations. They are specified by subclassing the desired type class: +User-defined types can be created, to support either database-specific types, or customized pre-processing of query parameters as well as post-processing of result set data. You can make your own classes to perform these operations. To augment the behavior of a `TypeEngine` type, such as `String`, the `TypeDecorator` class is used: {python title="Basic Example"} import sqlalchemy.types as types - class MyType(types.String): + class MyType(types.TypeDecorator): """basic type that decorates String, prefixes values with "PREFIX:" on the way in and strips it off on the way out.""" + impl = types.String def convert_bind_param(self, value, engine): return "PREFIX:" + value def convert_result_value(self, value, engine): return value[7:] + +The `Unicode` and `PickleType` classes are instances of `TypeDecorator` already and can be subclassed directly. -A common desire is for a "pickle" type, which overrides a Binary object to provide pickling behavior: - - {python title="Pickle Type"} - import cPickle - - class PickleType(Binary): - def __init__(self, protocol=pickle.HIGHEST_PROTOCOL): - """allows the pickle protocol to be specified""" - self.protocol = protocol - def convert_result_value(self, value, engine): - if value is None: - return None - buf = Binary.convert_result_value(self, value, engine) - return pickle.loads(str(buf)) - def convert_bind_param(self, value, engine): - if value is None: - return None - return Binary.convert_bind_param(self, pickle.dumps(value, self.protocol), engine) - def get_constructor_args(self): - return {} - -Which can be used like: - - {python} - mytable = Table('mytable', engine, - Column('id', Integer, primary_key=True), - Column('data', PickleType())) - - my_object = MyObject() - mytable.insert().execute(data=my_object) - -Another example, which illustrates a fully defined datatype. This just overrides the base type class TypeEngine: +To build a type object from scratch, which will not have a corresponding database-specific implementation, subclass `TypeEngine`: {python} import sqlalchemy.types as types @@ -134,7 +107,4 @@ Another example, which illustrates a fully defined datatype. This just override return value def convert_result_value(self, value, engine): return value - def adapt_args(self): - """allows for the adaptation of this TypeEngine object into a new kind of type depending on its arguments.""" - return self diff --git a/lib/sqlalchemy/mapping/mapper.py b/lib/sqlalchemy/mapping/mapper.py index 15d197a340..7977cae6a6 100644 --- a/lib/sqlalchemy/mapping/mapper.py +++ b/lib/sqlalchemy/mapping/mapper.py @@ -450,6 +450,22 @@ class Mapper(object): self._options[optkey] = mapper return mapper + def _get_criterion(self, key, value): + """used by select_by to match a key/value pair against + local properties, column names, or a matching property in this mapper's + list of relations.""" + if self.props.has_key(key): + return self.props[key].columns[0] == value + elif self.table.c.has_key(key): + return self.table.c[key] == value + else: + for prop in self.props.values(): + c = prop.get_criterion(key, value) + if c is not None: + return c + else: + return None + def __getattr__(self, key): if (key.startswith('select_by_') or key.startswith('get_by_')): return getattr(self.query, key) diff --git a/lib/sqlalchemy/mapping/query.py b/lib/sqlalchemy/mapping/query.py index 2ef23c5606..283e8c1890 100644 --- a/lib/sqlalchemy/mapping/query.py +++ b/lib/sqlalchemy/mapping/query.py @@ -177,7 +177,7 @@ class Query(object): for key, value in params.iteritems(): if value is False: continue - c = self._get_criterion(key, value) + c = self.mapper._get_criterion(key, value) if c is None: raise InvalidRequestError("Cant find criterion for property '"+ key + "'") if clause is None: @@ -261,18 +261,3 @@ class Query(object): value.setup(key, statement, **kwargs) return statement - def _get_criterion(self, key, value): - """used by select_by to match a key/value pair against - local properties, column names, or a matching property in this mapper's - list of relations.""" - if self.props.has_key(key): - return self.props[key].columns[0] == value - elif self.table.c.has_key(key): - return self.table.c[key] == value - else: - for prop in self.props.values(): - c = prop.get_criterion(key, value) - if c is not None: - return c - else: - return None diff --git a/lib/sqlalchemy/types.py b/lib/sqlalchemy/types.py index 40b94bbd8e..bc894184f9 100644 --- a/lib/sqlalchemy/types.py +++ b/lib/sqlalchemy/types.py @@ -67,7 +67,9 @@ class TypeDecorator(AbstractType): def convert_result_value(self, value, engine): return self.impl.convert_result_value(value, engine) def copy(self): - raise NotImplementedError() + instance = self.__class__.__new__(self.__class__) + instance.__dict__.update(self.__dict__) + return instance def to_instance(typeobj): if typeobj is None: @@ -132,8 +134,6 @@ class Unicode(TypeDecorator): return value.decode(engine.encoding) else: return value - def copy(self): - return Unicode(self.impl.length) class Integer(TypeEngine): """integer datatype""" @@ -194,8 +194,6 @@ class PickleType(TypeDecorator): if value is None: return None return self.impl.convert_bind_param(pickle.dumps(value, self.protocol), engine) - def copy(self): - return PickleType(self.protocol) class Boolean(TypeEngine): pass