new type system?

Issue #526 resolved
Mike Bayer repo owner created an issue

the issue with types is that we are constantly struggling to support two different paradigms. One is the database specific type string that is generated when issuing CREATE TABLE and CAST statements. the other is the bind/result pre/post processing of data. For the latter, there are two types of processing, one which occurs within a database dialect and is used to coerce types from/to a consistent version on the python side to what DBAPI expects, the other which occurs within the base types module and converts an already consistent type further to add functionality, such as PickleType.

current types relies upon inheritance and composition to accomplish this. but the inheritance pattern is very complicated, people seem generally reticent to create their own types even though its pretty easy, possibly because the patterns are too rigid.

The different concerns regarding types should be separated out into distinct non-inheriting classes. we should also make some attempt to address #77.

So consider having base classes such as this:

class Type(object):
   """a generic type."""

class DDLImpl(object):
   """defines the DDL generated for a particular type.

   DDLImpls are created distinctly per-Type and per-Dialect so that 
   they can store state.
   """
   __defined_for__ = None
   __converters__ = [  def get_col_spec(self):
        pass
   def dbapi_type(self, dbapi):
        """given a DBAPI module, return the DBAPI type for which this impl corresponds"""
        pass

class Converter(object):
   """defines bind param/result conversion of values.

   Converters are created distinctly per dialect so that they can
   configure themselves based on dialect options.
   """
   __returned_type__ = None
   def convert_bind_param(self, value):
       pass
   def convert_result_value(self, value):
       pass

So lets look at examples for String.

# a string with no length (we will still do the auto String -> String() thing)
String()

# string with length 30
String(30)

# string with length 30 that will locate an appropriate Converter for unicode 
# python types
String(30, python_type=unicode)

# string with length 30, specific converter specified.  converters are 
# "chained", with the converters indicated by the DDLImpl being the 
# innermost.  add_converters just adds to the chain, "converters" will
# override the defaults.
String(30, add_converters=MyConverter)

So its just Type that gets created at schema instantiation time. When the dialect gets involved, Type will set up its own internal structure mapping dialect instances to DDLImpls and Converters.

PickleType:

  class Pickled(Converter):
        __returned_type__ = object
        def convert_bind_param(self, value):
            return pickle.dumps(value)
        def convert_result_value(self, value):
            return pickle.loads(value)

  class PickleType(Binary):
       def __init__(self, *args, **kwargs):
           super(PickleType, self).__init__(*args, **kwargs)
           self.add_converter(Pickled)

but i want "pickling" to occur for some other type that isnt Binary:

    oracle.CLOB(add_converter=Pickled)

SQLite date type, requires conversion:

class DateConverter(Converter):
   __returned_type__ = date
   def convert_bind_param(self, value):
        # ....

class DateDDLImpl(DDLImpl):
   __defined_for__ = types.Date
   __converters__ = [date](]
)
   def get_col_spec(self):
        return "DATE"
   def dbapi_type(self, dbapi):
        return dbapi.Date

Comments (6)

  1. Mike Bayer reporter

    seems to just use strings for types and i dont see any way for it to be extensible (typestrings just map to a typestring in the DDL...). unless im missing something, i think our current approach is already way ahead of that.

  2. Mike Bayer reporter

    this might be more complicated than what we need. the types system isn't so bad right now, has been cleaned up a lot, and I'm not sure what the real need for a rewrite is at the moment.

  3. Mike Bayer reporter

    what we have in 0.6 for now satisfies this ticket in that it separates DDL generation from in-python behavior.

  4. Log in to comment