[IMP] ir_sequence: add support for PostgreSQL sequence.
This is partly inspired by openlabs' Sequence Postgres module. Untested yet. bzr revid: vmt@openerp.com-20110928091309-098red2biba5uq73
This commit is contained in:
parent
0a8fe1e3b5
commit
5f4ebc7b1c
|
@ -79,10 +79,51 @@ class ir_sequence(openerp.osv.osv.osv):
|
|||
|
||||
def create(self, cr, uid, values, context=None):
|
||||
values = self._add_missing_default_values(cr, uid, values, context)
|
||||
go = super(ir_sequence, self).create \
|
||||
if values['implementation'] == 'standard' else self.create_nogap
|
||||
go = super(ir_sequence, self).create_postgres \
|
||||
if values['implementation'] == 'standard' else self.create
|
||||
return go(cr, uid, values, context)
|
||||
|
||||
def create_postgres(self, cr, uid, values, context=None):
|
||||
""" Create a fast, gaps-allowed PostgreSQL sequence.
|
||||
|
||||
:param values: same argument than for ``create()`` but the keys
|
||||
``number_increment`` and ``number_next`` must be present.
|
||||
``_add_missing_default_values()`` can be used to this effect.
|
||||
:return: id of the newly created record
|
||||
"""
|
||||
id = super(ir_sequence, self).create(cr, uid, values, context)
|
||||
self._create_sequence(cr,
|
||||
values['number_increment'], values['number_next'])
|
||||
return id
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
super(ir_sequence, self).unlink(cr, uid, ids, context)
|
||||
self._drop_sequence(cr, ids)
|
||||
|
||||
def write(self, cr, uid, ids, values, context=None):
|
||||
ids = ids if isinstance(ids, (list, tuple)) else [ids]
|
||||
new_implementation = values.get('implementation')
|
||||
rows = self.read(cr, uid, ids, ['id,' 'implementation',
|
||||
'number_increment', 'number_next'], context)
|
||||
super(ir_sequence, self).write(cr, uid, ids, values, context)
|
||||
|
||||
for row in rows:
|
||||
# 4 cases: we test the previous impl. against the new one.
|
||||
if row['implementation'] == 'standard':
|
||||
i = values.get('number_increment', row['number_increment'])
|
||||
n = values.get('number_next', row['number_next'])
|
||||
if new_implementation in ('standard', None):
|
||||
self._alter_sequence(cr, row['id'], i, n)
|
||||
else:
|
||||
self._drop_sequence(cr, row['id'])
|
||||
else:
|
||||
if new_implementation in ('no_gap', None):
|
||||
pass
|
||||
else:
|
||||
self._create_sequence(cr, row['id'], i, n)
|
||||
|
||||
return True
|
||||
|
||||
def _interpolate(self, s, d):
|
||||
return s % d if s else ''
|
||||
|
||||
|
@ -110,30 +151,34 @@ class ir_sequence(openerp.osv.osv.osv):
|
|||
argument, which can be a code or an id (as controlled by the
|
||||
``code_or_id`` argument.
|
||||
"""
|
||||
assert code_or_id in ('code', 'id')
|
||||
company_ids = self.pool.get('res.company').search(cr, uid, [], context=context)
|
||||
cr.execute('''
|
||||
SELECT id, number_next, prefix, suffix, padding
|
||||
FROM ir_sequence
|
||||
WHERE %s=%%s
|
||||
AND active=true
|
||||
AND (company_id in %%s or company_id is NULL)
|
||||
ORDER BY company_id, id
|
||||
LIMIT 1
|
||||
FOR UPDATE NOWAIT''' % code_or_id,
|
||||
(sequence_code_or_id, tuple(company_ids)))
|
||||
res = cr.dictfetchone()
|
||||
if res:
|
||||
d = self._interpolation_dict()
|
||||
interpolated_prefix = self._interpolate(res['prefix'], d)
|
||||
interpolated_suffix = self._interpolate(res['suffix'], d)
|
||||
cr.execute('UPDATE ir_sequence SET number_next=number_next+number_increment WHERE id=%s', (res['id'],))
|
||||
if res['number_next']:
|
||||
return interpolated_prefix + '%%0%sd' % res['padding'] % res['number_next'] + interpolated_suffix
|
||||
else:
|
||||
# TODO what is this case used for ?
|
||||
return interpolated_prefix + interpolated_suffix
|
||||
return False
|
||||
# TODO there is no access rights check on the sequence itself.
|
||||
res = self._select_by_code_or_id(cr, uid, sequence_code_or_id,
|
||||
code_or_id, context)
|
||||
|
||||
if not res:
|
||||
return False
|
||||
|
||||
if res['implementation'] == 'standard':
|
||||
cr.execute("""
|
||||
SELECT nextval('ir_sequence_%03d')
|
||||
""", (res['id'],))
|
||||
res['number_next'] = cr.fetchone()
|
||||
else:
|
||||
cr.execute("""
|
||||
UPDATE ir_sequence
|
||||
SET number_next=number_next+number_increment
|
||||
WHERE id=%s
|
||||
""", (res['id'],))
|
||||
|
||||
d = self._interpolation_dict()
|
||||
interpolated_prefix = self._interpolate(res['prefix'], d)
|
||||
interpolated_suffix = self._interpolate(res['suffix'], d)
|
||||
if res['number_next']:
|
||||
return interpolated_prefix + '%%0%sd' % res['padding'] % \
|
||||
res['number_next'] + interpolated_suffix
|
||||
else:
|
||||
# TODO what is this case used for ?
|
||||
return interpolated_prefix + interpolated_suffix
|
||||
|
||||
def get(self, cr, uid, code, context=None):
|
||||
""" Draw an interpolated string using the specified sequence.
|
||||
|
@ -142,5 +187,60 @@ class ir_sequence(openerp.osv.osv.osv):
|
|||
"""
|
||||
return self.get_id(cr, uid, code, 'code', context)
|
||||
|
||||
def _select_by_code_or_id(self, cr, uid, sequence_code_or_id, code_or_id, context=None):
|
||||
""" Read a sequence object.
|
||||
|
||||
There is no access rights check on the sequence itself.
|
||||
"""
|
||||
assert code_or_id in ('code', 'id')
|
||||
res_company = self.pool.get('res.company')
|
||||
company_ids = res_company.search(cr, uid, [], context=context)
|
||||
cr.execute("""
|
||||
SELECT id, number_next, prefix, suffix, padding, implementation
|
||||
FROM ir_sequence
|
||||
WHERE %s=%%s
|
||||
AND active=true
|
||||
AND (company_id in %%s or company_id is NULL)
|
||||
ORDER BY company_id, id
|
||||
LIMIT 1
|
||||
FOR UPDATE NOWAIT
|
||||
""" % code_or_id, (sequence_code_or_id, tuple(company_ids)))
|
||||
return cr.dictfetchone()
|
||||
|
||||
def _create_sequence(self, cr, number_increment, number_next):
|
||||
""" Create a PostreSQL sequence.
|
||||
|
||||
There is no access rights check.
|
||||
"""
|
||||
cr.execute("""
|
||||
CREATE SEQUENCE ir_sequence_%03d INCREMENT BY %s START WITH %s
|
||||
""", (id, number_increment, number_next))
|
||||
|
||||
def _drop_sequence(self, cr, ids):
|
||||
""" Drop the PostreSQL sequence if it exists.
|
||||
|
||||
There is no access rights check.
|
||||
"""
|
||||
|
||||
ids = ids if isinstance(ids, (list, tuple)) else [ids]
|
||||
assert all(isinstance(i, (int, long)) for i in ids), \
|
||||
"Only ids in (int, long) allowed."
|
||||
names = ','.join('ir_sequence_%03d' % i for i in ids)
|
||||
|
||||
# RESTRICT is the default; it prevents dropping the sequence if an
|
||||
# object depends on it.
|
||||
cr.execute("""
|
||||
DROP SEQUENCE IF EXISTS %s RESTRICT
|
||||
""" % names)
|
||||
|
||||
def _alter_sequence(self, cr, id, number_increment, number_next):
|
||||
""" Alter a PostreSQL sequence.
|
||||
|
||||
There is no access rights check.
|
||||
"""
|
||||
cr.execute("""
|
||||
ALTER SEQUENCE ir_sequence_%03d INCREMENT BY %s RESTART WITH %s
|
||||
""", (id, number_increment, number_next))
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
Loading…
Reference in New Issue