diff options
| author | Adrien Berchet <adrien.berchet@gmail.com> | 2019-04-15 13:59:18 -0400 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-04-29 17:24:32 -0400 |
| commit | a10a4ea1248902349d789de7f5470bb8e437a584 (patch) | |
| tree | 536acae15894ae8f60ac2aedd784e37575ccba39 /test/sql/test_functions.py | |
| parent | 64865304051b2af1ee4f90c6bf5e93378d4f302c (diff) | |
| download | sqlalchemy-a10a4ea1248902349d789de7f5470bb8e437a584.tar.gz | |
Add case insensitivity feature to GenericFunction.
The :class:`.GenericFunction` namespace is being migrated so that function
names are looked up in a case-insensitive manner, as SQL functions do not
collide on case sensitive differences nor is this something which would
occur with user-defined functions or stored procedures. Lookups for
functions declared with :class:`.GenericFunction` now use a case
insensitive scheme, however a deprecation case is supported which allows
two or more :class:`.GenericFunction` objects with the same name of
different cases to exist, which will cause case sensitive lookups to occur
for that particular name, while emitting a warning at function registration
time. Thanks to Adrien Berchet for a lot of work on this complicated
feature.
Fixes: #4569
Closes: #4570
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/4570
Pull-request-sha: 37d4f3322b6bace88c99b959cb1916dbbc57610e
Change-Id: Ief07c6eb55bf398f6aad85b60ef13ee6d1173109
Diffstat (limited to 'test/sql/test_functions.py')
| -rw-r--r-- | test/sql/test_functions.py | 58 |
1 files changed, 55 insertions, 3 deletions
diff --git a/test/sql/test_functions.py b/test/sql/test_functions.py index 5fb4bc2e4..b03b156bc 100644 --- a/test/sql/test_functions.py +++ b/test/sql/test_functions.py @@ -1,3 +1,4 @@ +from copy import deepcopy import datetime import decimal @@ -39,6 +40,7 @@ from sqlalchemy.testing import engines from sqlalchemy.testing import eq_ from sqlalchemy.testing import fixtures from sqlalchemy.testing import is_ +from sqlalchemy.testing.assertions import expect_warnings from sqlalchemy.testing.engines import all_dialects @@ -53,8 +55,14 @@ table1 = table( class CompileTest(fixtures.TestBase, AssertsCompiledSQL): __dialect__ = "default" - def tear_down(self): - functions._registry.clear() + def setup(self): + self._registry = deepcopy(functions._registry) + self._case_sensitive_registry = deepcopy( + functions._case_sensitive_registry) + + def teardown(self): + functions._registry = self._registry + functions._case_sensitive_registry = self._case_sensitive_registry def test_compile(self): for dialect in all_dialects(exclude=("sybase",)): @@ -87,6 +95,9 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL): dialect=dialect, ) + functions._registry['_default'].pop('fake_func') + functions._case_sensitive_registry['_default'].pop('fake_func') + def test_use_labels(self): self.assert_compile( select([func.foo()], use_labels=True), "SELECT foo() AS foo_1" @@ -100,7 +111,7 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL): def test_uppercase(self): # for now, we need to keep case insensitivity - self.assert_compile(func.NOW(), "NOW()") + self.assert_compile(func.UNREGISTERED_FN(), "UNREGISTERED_FN()") def test_uppercase_packages(self): # for now, we need to keep case insensitivity @@ -219,6 +230,37 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL): assert isinstance(func.myfunc().type, DateTime) + def test_case_sensitive(self): + class MYFUNC(GenericFunction): + type = DateTime + + assert isinstance(func.MYFUNC().type, DateTime) + assert isinstance(func.MyFunc().type, DateTime) + assert isinstance(func.mYfUnC().type, DateTime) + assert isinstance(func.myfunc().type, DateTime) + + def test_replace_function(self): + class replaceable_func(GenericFunction): + type = Integer + identifier = 'replaceable_func' + + assert isinstance(func.Replaceable_Func().type, Integer) + assert isinstance(func.RePlAcEaBlE_fUnC().type, Integer) + assert isinstance(func.replaceable_func().type, Integer) + + with expect_warnings( + "The GenericFunction 'replaceable_func' is already registered and " + "is going to be overriden.", + regex=False + ): + class replaceable_func_override(GenericFunction): + type = DateTime + identifier = 'replaceable_func' + + assert isinstance(func.Replaceable_Func().type, DateTime) + assert isinstance(func.RePlAcEaBlE_fUnC().type, DateTime) + assert isinstance(func.replaceable_func().type, DateTime) + def test_custom_w_custom_name(self): class myfunc(GenericFunction): name = "notmyfunc" @@ -267,9 +309,19 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL): type = Integer identifier = "buf3" + class GeoBufferFour(GenericFunction): + type = Integer + name = "BufferFour" + identifier = "Buf4" + self.assert_compile(func.geo.buf1(), "BufferOne()") self.assert_compile(func.buf2(), "BufferTwo()") self.assert_compile(func.buf3(), "BufferThree()") + self.assert_compile(func.Buf4(), "BufferFour()") + self.assert_compile(func.BuF4(), "BufferFour()") + self.assert_compile(func.bUf4(), "BufferFour()") + self.assert_compile(func.bUf4_(), "BufferFour()") + self.assert_compile(func.buf4(), "BufferFour()") def test_custom_args(self): class myfunc(GenericFunction): |
