Xavier (Open ERP) has proposed merging
lp:~openerp-dev/openobject-server/trunk-smart-fields-pgtype-xmo into
lp:openobject-server.
Requested reviews:
OpenERP Core Team (openerp)
For more details, see:
https://code.launchpad.net/~openerp-dev/openobject-server/trunk-smart-fields-pgtype-xmo/+merge/109134
--
https://code.launchpad.net/~openerp-dev/openobject-server/trunk-smart-fields-pgtype-xmo/+merge/109134
Your team OpenERP R&D Team is subscribed to branch
lp:~openerp-dev/openobject-server/trunk-smart-fields-pgtype-xmo.
=== modified file 'openerp/osv/fields.py'
--- openerp/osv/fields.py 2012-05-21 07:38:51 +0000
+++ openerp/osv/fields.py 2012-06-07 12:55:24 +0000
@@ -78,6 +78,9 @@
# used to hide a certain field type in the list of field types
_deprecated = False
+ # Postgres data type for the column, returned by pg_type unless overwritten
+ _pg_type = None
+
def __init__(self, string='unknown', required=False, readonly=False, domain=None, context=None, states=None, priority=0, change_default=False, size=None, ondelete=None, translate=False, select=False, manual=False, **args):
"""
@@ -127,6 +130,37 @@
res = obj.read(cr, uid, ids, [name], context=context)
return [x[name] for x in res]
+ @property
+ def pg_type(self):
+ """ Postgres column types for the OpenERP field, fully qualified (e.g.
+ including size for char columns with one)
+
+ :returns: tuple
+ :rtype: (str, str)
+ """
+ return self.pg_type_for(self)
+
+ @classmethod
+ def pg_type_for(cls, field):
+ """ Method actually fetching the postgres type for a field. Has to be
+ a class method in case a column type A needs to delegate to a column
+ type B (e.g. function fields)
+
+ By default, simply returns the value of the _pg_type class attribute.
+
+ :param cls: current column object
+ :param field: current column instance
+ :returns: a pair of (type, type)
+ :rtype: (str, str)
+ """
+ return cls._pg_type
+
+class _varchar(_column):
+ @classmethod
+ def pg_type_for(cls, field):
+ if not field.size:
+ return 'varchar', 'varchar'
+ return 'varchar', 'varchar(%d)' % field.size
# ---------------------------------------------------------
# Simple fields
@@ -137,6 +171,8 @@
_symbol_f = lambda x: x and 'True' or 'False'
_symbol_set = (_symbol_c, _symbol_f)
+ _pg_type = ('bool', 'bool')
+
def __init__(self, string='unknown', required=False, **args):
super(boolean, self).__init__(string=string, required=required, **args)
if required:
@@ -152,6 +188,8 @@
_symbol_set = (_symbol_c, _symbol_f)
_symbol_get = lambda self,x: x or 0
+ _pg_type = ('int4', 'int4')
+
def __init__(self, string='unknown', required=False, **args):
super(integer, self).__init__(string=string, required=required, **args)
if required:
@@ -160,7 +198,7 @@
" `required` has no effect, as NULL values are "
"automatically turned into 0.")
-class reference(_column):
+class reference(_varchar):
_type = 'reference'
_classic_read = False # post-process to handle missing target
@@ -178,7 +216,7 @@
result[value['id']] = False
return result
-class char(_column):
+class char(_varchar):
_type = 'char'
def __init__(self, string, size, **args):
@@ -204,6 +242,8 @@
class text(_column):
_type = 'text'
+ _pg_type = ('text', 'text')
+
import __builtin__
class float(_column):
@@ -213,6 +253,12 @@
_symbol_set = (_symbol_c, _symbol_f)
_symbol_get = lambda self,x: x or 0.0
+ @classmethod
+ def pg_type_for(cls, field):
+ if field.digits:
+ return 'numeric', 'numeric'
+ return 'float8', 'double precision'
+
def __init__(self, string='unknown', digits=None, digits_compute=None, required=False, **args):
_column.__init__(self, string=string, required=required, **args)
self.digits = digits
@@ -236,6 +282,8 @@
class date(_column):
_type = 'date'
+ _pg_type = ('date', 'date')
+
@staticmethod
def today(*args):
""" Returns the current date in a format fit for being a
@@ -281,6 +329,9 @@
class datetime(_column):
_type = 'datetime'
+
+ _pg_type = ('timestamp', 'timestamp')
+
@staticmethod
def now(*args):
""" Returns the current datetime in a format fit for being a
@@ -326,6 +377,8 @@
_type = 'binary'
_symbol_c = '%s'
+ _pg_type = ('bytea', 'bytea')
+
# Binary values may be byte strings (python 2.6 byte array), but
# the legacy OpenERP convention is to transfer and store binaries
# as base64-encoded strings. The base64 string may be provided as a
@@ -368,9 +421,17 @@
res[i] = val
return res
-class selection(_column):
+class selection(_varchar):
_type = 'selection'
+ @classmethod
+ def pg_type_for(cls, field):
+ if (isinstance(field.selection, list) and isinstance(field.selection[0][0], int))\
+ or getattr(field, 'size', None) == -1:
+ return 'int4', 'int4'
+
+ return super(selection, cls).pg_type_for(field)
+
def __init__(self, selection, string='unknown', **args):
_column.__init__(self, string=string, **args)
self.selection = selection
@@ -396,6 +457,8 @@
_symbol_f = lambda x: x or None
_symbol_set = (_symbol_c, _symbol_f)
+ _pg_type = ('int4', 'int4')
+
def __init__(self, obj, string='unknown', **args):
_column.__init__(self, string=string, **args)
self._obj = obj
@@ -1078,6 +1141,12 @@
if self._fnct_inv:
self._fnct_inv(obj, cr, user, id, name, value, self._fnct_inv_arg, context)
+ @classmethod
+ def pg_type_for(cls, field):
+ if field._type == 'selection':
+ return 'varchar', 'varchar'
+ return globals()[field._type].pg_type_for(field)
+
# ---------------------------------------------------------
# Related fields
# ---------------------------------------------------------
@@ -1303,7 +1372,7 @@
def __init__(self, serialization_field, **kwargs):
self.serialization_field = serialization_field
- return super(sparse, self).__init__(self._fnct_read, fnct_inv=self._fnct_write, multi='__sparse_multi', **kwargs)
+ super(sparse, self).__init__(self._fnct_read, fnct_inv=self._fnct_write, multi='__sparse_multi', **kwargs)
@@ -1350,6 +1419,8 @@
_symbol_set = (_symbol_c, _symbol_f)
_symbol_get = _symbol_get_struct
+ _pg_type = ('text', 'text')
+
# TODO: review completly this class for speed improvement
class property(function):
=== modified file 'openerp/osv/orm.py'
--- openerp/osv/orm.py 2012-06-06 14:19:08 +0000
+++ openerp/osv/orm.py 2012-06-07 12:55:24 +0000
@@ -528,71 +528,6 @@
self._cache[model].clear()
self._cache[model].update(cached_ids)
-def pg_varchar(size=0):
- """ Returns the VARCHAR declaration for the provided size:
-
- * If no size (or an empty or negative size is provided) return an
- 'infinite' VARCHAR
- * Otherwise return a VARCHAR(n)
-
- :type int size: varchar size, optional
- :rtype: str
- """
- if size:
- if not isinstance(size, int):
- raise TypeError("VARCHAR parameter should be an int, got %s"
- % type(size))
- if size > 0:
- return 'VARCHAR(%d)' % size
- return 'VARCHAR'
-
-FIELDS_TO_PGTYPES = {
- fields.boolean: 'bool',
- fields.integer: 'int4',
- fields.text: 'text',
- fields.date: 'date',
- fields.datetime: 'timestamp',
- fields.binary: 'bytea',
- fields.many2one: 'int4',
- fields.serialized: 'text',
-}
-
-def get_pg_type(f, type_override=None):
- """
- :param fields._column f: field to get a Postgres type for
- :param type type_override: use the provided type for dispatching instead of the field's own type
- :returns: (postgres_identification_type, postgres_type_specification)
- :rtype: (str, str)
- """
- field_type = type_override or type(f)
-
- if field_type in FIELDS_TO_PGTYPES:
- pg_type = (FIELDS_TO_PGTYPES[field_type], FIELDS_TO_PGTYPES[field_type])
- elif issubclass(field_type, fields.float):
- if f.digits:
- pg_type = ('numeric', 'NUMERIC')
- else:
- pg_type = ('float8', 'DOUBLE PRECISION')
- elif issubclass(field_type, (fields.char, fields.reference)):
- pg_type = ('varchar', pg_varchar(f.size))
- elif issubclass(field_type, fields.selection):
- if (isinstance(f.selection, list) and isinstance(f.selection[0][0], int))\
- or getattr(f, 'size', None) == -1:
- pg_type = ('int4', 'INTEGER')
- else:
- pg_type = ('varchar', pg_varchar(getattr(f, 'size', None)))
- elif issubclass(field_type, fields.function):
- if f._type == 'selection':
- pg_type = ('varchar', pg_varchar())
- else:
- pg_type = get_pg_type(f, getattr(fields, f._type))
- else:
- _logger.warning('%s type not supported!', field_type)
- pg_type = None
-
- return pg_type
-
-
class MetaModel(type):
""" Metaclass for the Model.
@@ -2906,23 +2841,23 @@
self._table, k)
f_obj_type = None
else:
- f_obj_type = get_pg_type(f) and get_pg_type(f)[0]
+ f_obj_type = f.pg_type and f.pg_type[0]
if f_obj_type:
ok = False
casts = [
- ('text', 'char', pg_varchar(f.size), '::%s' % pg_varchar(f.size)),
+ ('text', 'char', f.pg_type[1], '::%s' % f.pg_type[1]),
('varchar', 'text', 'TEXT', ''),
- ('int4', 'float', get_pg_type(f)[1], '::'+get_pg_type(f)[1]),
+ ('int4', 'float', f.pg_type[1], '::'+f.pg_type[1]),
('date', 'datetime', 'TIMESTAMP', '::TIMESTAMP'),
('timestamp', 'date', 'date', '::date'),
- ('numeric', 'float', get_pg_type(f)[1], '::'+get_pg_type(f)[1]),
- ('float8', 'float', get_pg_type(f)[1], '::'+get_pg_type(f)[1]),
+ ('numeric', 'float', f.pg_type[1], '::'+f.pg_type[1]),
+ ('float8', 'float', f.pg_type[1], '::'+f.pg_type[1]),
]
if f_pg_type == 'varchar' and f._type == 'char' and f_pg_size < f.size:
cr.execute('ALTER TABLE "%s" RENAME COLUMN "%s" TO temp_change_size' % (self._table, k))
- cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, pg_varchar(f.size)))
- cr.execute('UPDATE "%s" SET "%s"=temp_change_size::%s' % (self._table, k, pg_varchar(f.size)))
+ cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, f.pg_type[1]))
+ cr.execute('UPDATE "%s" SET "%s"=temp_change_size::%s' % (self._table, k, f.pg_type[1]))
cr.execute('ALTER TABLE "%s" DROP COLUMN temp_change_size CASCADE' % (self._table,))
cr.commit()
_schema.debug("Table '%s': column '%s' (type varchar) changed size from %s to %s",
@@ -2955,7 +2890,7 @@
if f_pg_notnull:
cr.execute('ALTER TABLE "%s" ALTER COLUMN "%s" DROP NOT NULL' % (self._table, k))
cr.execute('ALTER TABLE "%s" RENAME COLUMN "%s" TO "%s"' % (self._table, k, newname))
- cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, get_pg_type(f)[1]))
+ cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, f.pg_type[1]))
cr.execute("COMMENT ON COLUMN %s.\"%s\" IS %%s" % (self._table, k), (f.string,))
_schema.debug("Table '%s': column '%s' has changed type (DB=%s, def=%s), data moved to column %s !",
self._table, k, f_pg_type, f._type, newname)
@@ -3020,10 +2955,10 @@
else:
if not isinstance(f, fields.function) or f.store:
# add the missing field
- cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, get_pg_type(f)[1]))
+ cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, f.pg_type[1]))
cr.execute("COMMENT ON COLUMN %s.\"%s\" IS %%s" % (self._table, k), (f.string,))
_schema.debug("Table '%s': added column '%s' with definition=%s",
- self._table, k, get_pg_type(f)[1])
+ self._table, k, f.pg_type[1])
# initialize it
if not create and k in self._defaults:
_______________________________________________
Mailing list: https://launchpad.net/~openerp-dev-gtk
Post to : [email protected]
Unsubscribe : https://launchpad.net/~openerp-dev-gtk
More help : https://help.launchpad.net/ListHelp