mirror of
https://github.com/bringout/oca-ocb-core.git
synced 2026-04-20 06:12:04 +02:00
19.0 vanilla
This commit is contained in:
parent
0a7ae8db93
commit
991d2234ca
416 changed files with 646602 additions and 300844 deletions
149
odoo-bringout-oca-ocb-base/odoo/orm/utils.py
Normal file
149
odoo-bringout-oca-ocb-base/odoo/orm/utils.py
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
import re
|
||||
import warnings
|
||||
from collections.abc import Set as AbstractSet
|
||||
|
||||
import dateutil.relativedelta
|
||||
|
||||
from odoo.exceptions import AccessError, ValidationError
|
||||
from odoo.tools import SQL
|
||||
|
||||
regex_alphanumeric = re.compile(r'^[a-z0-9_]+$')
|
||||
regex_object_name = re.compile(r'^[a-z0-9_.]+$')
|
||||
regex_pg_name = re.compile(r'^[a-z_][a-z0-9_$]*$', re.IGNORECASE)
|
||||
# match private methods, to prevent their remote invocation
|
||||
regex_private = re.compile(r'^(_.*|init)$')
|
||||
|
||||
# types handled as collections
|
||||
COLLECTION_TYPES = (list, tuple, AbstractSet)
|
||||
# The hard-coded super-user id (a.k.a. root user, or OdooBot).
|
||||
SUPERUSER_ID = 1
|
||||
|
||||
# _read_group stuff
|
||||
READ_GROUP_TIME_GRANULARITY = {
|
||||
'hour': dateutil.relativedelta.relativedelta(hours=1),
|
||||
'day': dateutil.relativedelta.relativedelta(days=1),
|
||||
'week': dateutil.relativedelta.relativedelta(days=7),
|
||||
'month': dateutil.relativedelta.relativedelta(months=1),
|
||||
'quarter': dateutil.relativedelta.relativedelta(months=3),
|
||||
'year': dateutil.relativedelta.relativedelta(years=1)
|
||||
}
|
||||
|
||||
READ_GROUP_NUMBER_GRANULARITY = {
|
||||
'year_number': 'year',
|
||||
'quarter_number': 'quarter',
|
||||
'month_number': 'month',
|
||||
'iso_week_number': 'week', # ISO week number because anything else than ISO is nonsense
|
||||
'day_of_year': 'doy',
|
||||
'day_of_month': 'day',
|
||||
'day_of_week': 'dow',
|
||||
'hour_number': 'hour',
|
||||
'minute_number': 'minute',
|
||||
'second_number': 'second',
|
||||
}
|
||||
|
||||
READ_GROUP_ALL_TIME_GRANULARITY = READ_GROUP_TIME_GRANULARITY | READ_GROUP_NUMBER_GRANULARITY
|
||||
|
||||
|
||||
# SQL operators with spaces around them
|
||||
# hardcoded to avoid changing SQL injection linting
|
||||
SQL_OPERATORS = {
|
||||
"=": SQL(" = "),
|
||||
"!=": SQL(" != "),
|
||||
"in": SQL(" IN "),
|
||||
"not in": SQL(" NOT IN "),
|
||||
"<": SQL(" < "),
|
||||
">": SQL(" > "),
|
||||
"<=": SQL(" <= "),
|
||||
">=": SQL(" >= "),
|
||||
"like": SQL(" LIKE "),
|
||||
"ilike": SQL(" ILIKE "),
|
||||
"=like": SQL(" LIKE "),
|
||||
"=ilike": SQL(" ILIKE "),
|
||||
"not like": SQL(" NOT LIKE "),
|
||||
"not ilike": SQL(" NOT ILIKE "),
|
||||
"not =like": SQL(" NOT LIKE "),
|
||||
"not =ilike": SQL(" NOT ILIKE "),
|
||||
}
|
||||
|
||||
|
||||
def check_method_name(name):
|
||||
""" Raise an ``AccessError`` if ``name`` is a private method name. """
|
||||
warnings.warn("Since 19.0, use odoo.service.model.get_public_method", DeprecationWarning)
|
||||
if regex_private.match(name):
|
||||
raise AccessError('Private methods (such as %s) cannot be called remotely.' % name)
|
||||
|
||||
|
||||
def check_object_name(name):
|
||||
""" Check if the given name is a valid model name.
|
||||
|
||||
The _name attribute in osv and osv_memory object is subject to
|
||||
some restrictions. This function returns True or False whether
|
||||
the given name is allowed or not.
|
||||
|
||||
TODO: this is an approximation. The goal in this approximation
|
||||
is to disallow uppercase characters (in some places, we quote
|
||||
table/column names and in other not, which leads to this kind
|
||||
of errors:
|
||||
|
||||
psycopg2.ProgrammingError: relation "xxx" does not exist).
|
||||
|
||||
The same restriction should apply to both osv and osv_memory
|
||||
objects for consistency.
|
||||
|
||||
"""
|
||||
return regex_object_name.match(name) is not None
|
||||
|
||||
|
||||
def check_pg_name(name):
|
||||
""" Check whether the given name is a valid PostgreSQL identifier name. """
|
||||
if not regex_pg_name.match(name):
|
||||
raise ValidationError("Invalid characters in table name %r" % name)
|
||||
if len(name) > 63:
|
||||
raise ValidationError("Table name %r is too long" % name)
|
||||
|
||||
|
||||
def parse_field_expr(field_expr: str) -> tuple[str, str | None]:
|
||||
if (property_index := field_expr.find(".")) >= 0:
|
||||
property_name = field_expr[property_index + 1:]
|
||||
field_expr = field_expr[:property_index]
|
||||
else:
|
||||
property_name = None
|
||||
if not field_expr:
|
||||
raise ValueError(f"Invalid field expression {field_expr!r}")
|
||||
return field_expr, property_name
|
||||
|
||||
|
||||
def expand_ids(id0, ids):
|
||||
""" Return an iterator of unique ids from the concatenation of ``[id0]`` and
|
||||
``ids``, and of the same kind (all real or all new).
|
||||
"""
|
||||
yield id0
|
||||
seen = {id0}
|
||||
kind = bool(id0)
|
||||
for id_ in ids:
|
||||
if id_ not in seen and bool(id_) == kind:
|
||||
yield id_
|
||||
seen.add(id_)
|
||||
|
||||
|
||||
class OriginIds:
|
||||
""" A reversible iterable returning the origin ids of a collection of ``ids``.
|
||||
Actual ids are returned as is, and ids without origin are not returned.
|
||||
"""
|
||||
__slots__ = ['ids']
|
||||
|
||||
def __init__(self, ids):
|
||||
self.ids = ids
|
||||
|
||||
def __iter__(self):
|
||||
for id_ in self.ids:
|
||||
if id_ := id_ or getattr(id_, 'origin', None):
|
||||
yield id_
|
||||
|
||||
def __reversed__(self):
|
||||
for id_ in reversed(self.ids):
|
||||
if id_ := id_ or getattr(id_, 'origin', None):
|
||||
yield id_
|
||||
|
||||
|
||||
origin_ids = OriginIds
|
||||
Loading…
Add table
Add a link
Reference in a new issue