Ensure all SQL functions are supported by the backend's
issue8942 review270751002
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
import datetime
|
||||
import logging
|
||||
import math
|
||||
import os
|
||||
import random
|
||||
import threading
|
||||
import time
|
||||
from decimal import Decimal
|
||||
@@ -230,6 +232,10 @@ class SQLiteTrim(Trim):
|
||||
return function + '(%s, %s)' % (
|
||||
format(self.string), format(self.characters))
|
||||
|
||||
@property
|
||||
def params(self):
|
||||
return [self.string, self.characters]
|
||||
|
||||
|
||||
def sign(value):
|
||||
if value > 0:
|
||||
@@ -256,6 +262,18 @@ def least(*args):
|
||||
return None
|
||||
|
||||
|
||||
def cbrt(value):
|
||||
return math.pow(value, 1 / 3)
|
||||
|
||||
|
||||
def div(a, b):
|
||||
return a // b
|
||||
|
||||
|
||||
def trunc(value, digits):
|
||||
return math.trunc(value * 10 ** digits) / 10 ** digits
|
||||
|
||||
|
||||
MAPPING = {
|
||||
Extract: SQLiteExtract,
|
||||
Position: SQLitePosition,
|
||||
@@ -333,16 +351,40 @@ class Database(DatabaseInterface):
|
||||
self._conn.create_function('extract', 2, SQLiteExtract.extract)
|
||||
self._conn.create_function('date_trunc', 2, date_trunc)
|
||||
self._conn.create_function('split_part', 3, split_part)
|
||||
self._conn.create_function('position', 2, SQLitePosition.position)
|
||||
self._conn.create_function('to_char', 2, to_char)
|
||||
self._conn.create_function('overlay', 3, SQLiteOverlay.overlay)
|
||||
self._conn.create_function('overlay', 4, SQLiteOverlay.overlay)
|
||||
if sqlite.sqlite_version_info < (3, 3, 14):
|
||||
self._conn.create_function('replace', 3, replace)
|
||||
self._conn.create_function('now', 0, now)
|
||||
self._conn.create_function('sign', 1, sign)
|
||||
self._conn.create_function('greatest', -1, greatest)
|
||||
self._conn.create_function('least', -1, least)
|
||||
|
||||
# Mathematical functions
|
||||
self._conn.create_function('cbrt', 1, cbrt)
|
||||
self._conn.create_function('ceil', 1, math.ceil)
|
||||
self._conn.create_function('degrees', 1, math.degrees)
|
||||
self._conn.create_function('div', 2, div)
|
||||
self._conn.create_function('exp', 1, math.exp)
|
||||
self._conn.create_function('floor', 1, math.floor)
|
||||
self._conn.create_function('ln', 1, math.log)
|
||||
self._conn.create_function('log', 1, math.log10)
|
||||
self._conn.create_function('mod', 2, math.fmod)
|
||||
self._conn.create_function('pi', 0, lambda: math.pi)
|
||||
self._conn.create_function('power', 2, math.pow)
|
||||
self._conn.create_function('radians', 1, math.radians)
|
||||
self._conn.create_function('sign', 1, sign)
|
||||
self._conn.create_function('sqrt', 1, math.sqrt)
|
||||
self._conn.create_function('trunc', 1, math.trunc)
|
||||
self._conn.create_function('trunc', 2, trunc)
|
||||
|
||||
# Random functions
|
||||
self._conn.create_function('random', 0, random.random)
|
||||
self._conn.create_function('setseed', 1, random.seed)
|
||||
|
||||
# String functions
|
||||
self._conn.create_function('overlay', 3, SQLiteOverlay.overlay)
|
||||
self._conn.create_function('overlay', 4, SQLiteOverlay.overlay)
|
||||
self._conn.create_function('position', 2, SQLitePosition.position)
|
||||
|
||||
if (hasattr(self._conn, 'set_trace_callback')
|
||||
and logger.isEnabledFor(logging.DEBUG)):
|
||||
self._conn.set_trace_callback(logger.debug)
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
# 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 datetime
|
||||
import math
|
||||
import unittest
|
||||
|
||||
from sql import Select
|
||||
from sql import functions
|
||||
from sql.functions import CurrentTimestamp, ToChar
|
||||
|
||||
from trytond.tests.test_tryton import activate_module, with_transaction
|
||||
@@ -84,6 +86,64 @@ class BackendTestCase(unittest.TestCase):
|
||||
|
||||
self.assertEqual(text, today.strftime('%Y-%m-%d'))
|
||||
|
||||
@with_transaction()
|
||||
def test_functions(self):
|
||||
"Test functions"
|
||||
cursor = Transaction().connection.cursor()
|
||||
tests = [
|
||||
(functions.Abs(-1), 1),
|
||||
(functions.Cbrt(27), 3),
|
||||
(functions.Ceil(-42.8), -42),
|
||||
(functions.Degrees(0.5), 28.6478897565412),
|
||||
(functions.Div(9, 4), 2),
|
||||
(functions.Exp(1.), math.e),
|
||||
(functions.Floor(-42.8), -43),
|
||||
(functions.Ln(2.), 0.693147180559945),
|
||||
(functions.Log(100.0), 2),
|
||||
(functions.Mod(9, 4), 1),
|
||||
(functions.Pi(), math.pi),
|
||||
(functions.Power(9, 3), 729),
|
||||
(functions.Radians(45.), math.pi / 4),
|
||||
(functions.Round(42.4), 42),
|
||||
(functions.Round(42.4382, 2), 42.44),
|
||||
(functions.Sign(-8.4), -1),
|
||||
(functions.Sqrt(2.), 1.4142135623731),
|
||||
(functions.Trunc(42.8), 42),
|
||||
(functions.Trunc(42.4348, 2), 42.43),
|
||||
(functions.CharLength('jose'), 4),
|
||||
(functions.Lower('TOM'), 'tom'),
|
||||
(functions.Overlay('Txxxxas', 'hom', 2, 4), 'Thomas'),
|
||||
(functions.Position('om', 'Thomas'), 3),
|
||||
(functions.Substring('Thomas', 2, 3), 'hom'),
|
||||
# (functions.Substring('Thomas', '...$'), 'mas'),
|
||||
# (functions.Substring('Thomas', '%#"o_a#"_', '#'), 'oma'),
|
||||
(functions.Trim('yxTomxx', 'BOTH', 'xyz'), 'Tom'),
|
||||
(functions.Upper('tom'), 'TOM'),
|
||||
]
|
||||
for func, result in tests:
|
||||
with self.subTest(func=str(func)):
|
||||
cursor.execute(*Select([func]))
|
||||
value, = cursor.fetchone()
|
||||
if isinstance(result, str):
|
||||
self.assertEqual(value, result)
|
||||
else:
|
||||
self.assertAlmostEqual(float(value), float(result))
|
||||
|
||||
@with_transaction()
|
||||
def test_function_random(self):
|
||||
"Test RANDOM function"
|
||||
cursor = Transaction().connection.cursor()
|
||||
cursor.execute(*Select([functions.Random()]))
|
||||
value, = cursor.fetchone()
|
||||
self.assertGreaterEqual(value, 0)
|
||||
self.assertLessEqual(value, 1)
|
||||
|
||||
@with_transaction()
|
||||
def test_function_setseed(self):
|
||||
"Test SETSEED function"
|
||||
cursor = Transaction().connection.cursor()
|
||||
cursor.execute(*Select([functions.SetSeed(1)]))
|
||||
|
||||
|
||||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromTestCase(BackendTestCase)
|
||||
|
||||
Reference in New Issue
Block a user