Rules for Migrating TypeEngine classes to 0.6
|
---------------------------------------------
|
|
1. the TypeEngine classes are used for:
|
|
a. Specifying behavior which needs to occur for bind parameters
|
or result row columns.
|
|
b. Specifying types that are entirely specific to the database
|
in use and have no analogue in the sqlalchemy.types package.
|
|
c. Specifying types where there is an analogue in sqlalchemy.types,
|
but the database in use takes vendor-specific flags for those
|
types.
|
|
d. If a TypeEngine class doesn't provide any of this, it should be
|
*removed* from the dialect.
|
|
2. the TypeEngine classes are *no longer* used for generating DDL. Dialects
|
now have a TypeCompiler subclass which uses the same visit_XXX model as
|
other compilers.
|
|
3. the "ischema_names" and "colspecs" dictionaries are now required members on
|
the Dialect class.
|
|
4. The names of types within dialects are now important. If a dialect-specific type
|
is a subclass of an existing generic type and is only provided for bind/result behavior,
|
the current mixed case naming can remain, i.e. _PGNumeric for Numeric - in this case,
|
end users would never need to use _PGNumeric directly. However, if a dialect-specific
|
type is specifying a type *or* arguments that are not present generically, it should
|
match the real name of the type on that backend, in uppercase. E.g. postgresql.INET,
|
mysql.ENUM, postgresql.ARRAY.
|
|
Or follow this handy flowchart:
|
|
is the type meant to provide bind/result is the type the same name as an
|
behavior to a generic type (i.e. MixedCase) ---- no ---> UPPERCASE type in types.py ?
|
type in types.py ? | |
|
| no yes
|
yes | |
|
| | does your type need special
|
| +<--- yes --- behavior or arguments ?
|
| | |
|
| | no
|
name the type using | |
|
_MixedCase, i.e. v V
|
_OracleBoolean. it name the type don't make a
|
stays private to the dialect identically as that type, make sure the dialect's
|
and is invoked *only* via within the DB, base.py imports the types.py
|
the colspecs dict. using UPPERCASE UPPERCASE name into its namespace
|
| (i.e. BIT, NCHAR, INTERVAL).
|
| Users can import it.
|
| |
|
v v
|
subclass the closest is the name of this type
|
MixedCase type types.py, identical to an UPPERCASE
|
i.e. <--- no ------- name in types.py ?
|
class _DateTime(types.DateTime),
|
class DATETIME2(types.DateTime), |
|
class BIT(types.TypeEngine). yes
|
|
|
v
|
the type should
|
subclass the
|
UPPERCASE
|
type in types.py
|
(i.e. class BLOB(types.BLOB))
|
|
|
Example 1. pysqlite needs bind/result processing for the DateTime type in types.py,
|
which applies to all DateTimes and subclasses. It's named _SLDateTime and
|
subclasses types.DateTime.
|
|
Example 2. MS-SQL has a TIME type which takes a non-standard "precision" argument
|
that is rendered within DDL. So it's named TIME in the MS-SQL dialect's base.py,
|
and subclasses types.TIME. Users can then say mssql.TIME(precision=10).
|
|
Example 3. MS-SQL dialects also need special bind/result processing for date
|
But its DATE type doesn't render DDL differently than that of a plain
|
DATE, i.e. it takes no special arguments. Therefore we are just adding behavior
|
to types.Date, so it's named _MSDate in the MS-SQL dialect's base.py, and subclasses
|
types.Date.
|
|
Example 4. MySQL has a SET type, there's no analogue for this in types.py. So
|
MySQL names it SET in the dialect's base.py, and it subclasses types.String, since
|
it ultimately deals with strings.
|
|
Example 5. PostgreSQL has a DATETIME type. The DBAPIs handle dates correctly,
|
and no special arguments are used in PG's DDL beyond what types.py provides.
|
PostgreSQL dialect therefore imports types.DATETIME into its base.py.
|
|
Ideally one should be able to specify a schema using names imported completely from a
|
dialect, all matching the real name on that backend:
|
|
from sqlalchemy.dialects.postgresql import base as pg
|
|
t = Table('mytable', metadata,
|
Column('id', pg.INTEGER, primary_key=True),
|
Column('name', pg.VARCHAR(300)),
|
Column('inetaddr', pg.INET)
|
)
|
|
where above, the INTEGER and VARCHAR types are ultimately from sqlalchemy.types,
|
but the PG dialect makes them available in its own namespace.
|
|
5. "colspecs" now is a dictionary of generic or uppercased types from sqlalchemy.types
|
linked to types specified in the dialect. Again, if a type in the dialect does not
|
specify any special behavior for bind_processor() or result_processor() and does not
|
indicate a special type only available in this database, it must be *removed* from the
|
module and from this dictionary.
|
|
6. "ischema_names" indicates string descriptions of types as returned from the database
|
linked to TypeEngine classes.
|
|
a. The string name should be matched to the most specific type possible within
|
sqlalchemy.types, unless there is no matching type within sqlalchemy.types in which
|
case it points to a dialect type. *It doesn't matter* if the dialect has its
|
own subclass of that type with special bind/result behavior - reflect to the types.py
|
UPPERCASE type as much as possible. With very few exceptions, all types
|
should reflect to an UPPERCASE type.
|
|
b. If the dialect contains a matching dialect-specific type that takes extra arguments
|
which the generic one does not, then point to the dialect-specific type. E.g.
|
mssql.VARCHAR takes a "collation" parameter which should be preserved.
|
|
5. DDL, or what was formerly issued by "get_col_spec()", is now handled exclusively by
|
a subclass of compiler.GenericTypeCompiler.
|
|
a. your TypeCompiler class will receive generic and uppercase types from
|
sqlalchemy.types. Do not assume the presence of dialect-specific attributes on
|
these types.
|
|
b. the visit_UPPERCASE methods on GenericTypeCompiler should *not* be overridden with
|
methods that produce a different DDL name. Uppercase types don't do any kind of
|
"guessing" - if visit_TIMESTAMP is called, the DDL should render as TIMESTAMP in
|
all cases, regardless of whether or not that type is legal on the backend database.
|
|
c. the visit_UPPERCASE methods *should* be overridden with methods that add additional
|
arguments and flags to those types.
|
|
d. the visit_lowercase methods are overridden to provide an interpretation of a generic
|
type. E.g. visit_large_binary() might be overridden to say "return self.visit_BIT(type_)".
|
|
e. visit_lowercase methods should *never* render strings directly - it should always
|
be via calling a visit_UPPERCASE() method.
|