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

Reply via email to