141 lines
4.1 KiB
Python
Executable File
141 lines
4.1 KiB
Python
Executable File
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
|
# this repository contains the full copyright notices and license terms.
|
|
import hashlib
|
|
from weakref import WeakKeyDictionary
|
|
|
|
from trytond.transaction import Transaction
|
|
|
|
|
|
class TableHandlerInterface(object):
|
|
'''
|
|
Define generic interface to handle database table
|
|
'''
|
|
namedatalen = None
|
|
index_translators = None
|
|
__handlers = WeakKeyDictionary()
|
|
|
|
def __new__(cls, model, history=False):
|
|
transaction = Transaction()
|
|
handlers = cls.__handlers.setdefault(transaction, {})
|
|
key = (model.__name__, history)
|
|
if key not in handlers:
|
|
instance = handlers[key] = super().__new__(cls)
|
|
instance._init(model, history=history)
|
|
return handlers[key]
|
|
|
|
def _init(self, model, history=False):
|
|
'''
|
|
:param model: the Model linked to the table
|
|
:param module_name: the module name
|
|
:param history: a boolean to define if it is a history table
|
|
'''
|
|
super(TableHandlerInterface, self).__init__()
|
|
if history:
|
|
self.table_name = model._table + '__history'
|
|
else:
|
|
self.table_name = model._table
|
|
self.object_name = model.__name__
|
|
if history:
|
|
self.sequence_name = self.table_name + '___id_seq'
|
|
else:
|
|
self.sequence_name = self.table_name + '_id_seq'
|
|
self.history = history
|
|
|
|
@classmethod
|
|
def table_exist(cls, table_name):
|
|
raise NotImplementedError
|
|
|
|
@classmethod
|
|
def table_rename(cls, old_name, new_name):
|
|
raise NotImplementedError
|
|
|
|
def column_exist(self, column_name):
|
|
raise NotImplementedError
|
|
|
|
def column_rename(self, old_name, new_name):
|
|
raise NotImplementedError
|
|
|
|
def alter_size(self, column_name, column_type):
|
|
raise NotImplementedError
|
|
|
|
def alter_type(self, column_name, column_type):
|
|
raise NotImplementedError
|
|
|
|
def column_is_type(self, column_name, type_, *, size=-1):
|
|
raise NotImplementedError
|
|
|
|
def db_default(self, column_name, value):
|
|
raise NotImplementedError
|
|
|
|
def add_column(self, column_name, abstract_type, default=None, comment=''):
|
|
raise NotImplementedError
|
|
|
|
def add_fk(self, columns, reference, ref_columns=None, on_delete=None):
|
|
raise NotImplementedError
|
|
|
|
def drop_fk(self, columns, ref_columns=None, table=None):
|
|
raise NotImplementedError
|
|
|
|
def not_null_action(self, column_name, action='add'):
|
|
raise NotImplementedError
|
|
|
|
def add_constraint(self, ident, constraint):
|
|
raise NotImplementedError
|
|
|
|
def drop_constraint(self, ident, table=None):
|
|
raise NotImplementedError
|
|
|
|
def create_index(self, index):
|
|
raise NotImplementedError
|
|
|
|
def drop_column(self, column_name):
|
|
raise NotImplementedError
|
|
|
|
@classmethod
|
|
def drop_table(cls, model, table, cascade=False):
|
|
raise NotImplementedError
|
|
|
|
@classmethod
|
|
def convert_name(cls, name, reserved=0):
|
|
if cls.namedatalen:
|
|
length = cls.namedatalen - reserved
|
|
if length <= 0:
|
|
raise ValueError
|
|
if len(name) >= length:
|
|
if isinstance(name, str):
|
|
name = name.encode('utf-8')
|
|
name = hashlib.sha256(name).hexdigest()[:length - 1]
|
|
return name
|
|
|
|
def set_indexes(self, indexes, concurrently=False):
|
|
raise NotImplementedError
|
|
|
|
def index_translator_for(self, index):
|
|
return next(
|
|
filter(
|
|
lambda t: t.score(index) > 0,
|
|
sorted(
|
|
self.index_translators, key=lambda t: t.score(index),
|
|
reverse=True)),
|
|
None)
|
|
|
|
|
|
class IndexTranslatorInterface:
|
|
|
|
@classmethod
|
|
def _get_name(cls, query, params):
|
|
def hash_(s):
|
|
return hashlib.shake_128(s.encode('utf-8')).hexdigest(16)
|
|
names = [str(query)]
|
|
if params:
|
|
names.append(str(params))
|
|
return '_'.join(map(hash_, names))
|
|
|
|
@classmethod
|
|
def definition(cls, index):
|
|
raise NotImplementedError
|
|
|
|
@classmethod
|
|
def score(cls, index):
|
|
raise NotImplementedError
|