diff options
| author | CaselIT <cfederico87@gmail.com> | 2019-11-04 17:11:21 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-11-08 15:40:25 -0500 |
| commit | 3a0e0531c179e598c345e5be24e350c375ce7e22 (patch) | |
| tree | 3b0675f216ced73f3d94f825f65ad19d2376e952 /test/sql | |
| parent | 4f5f953b5472790a5ec6c278ec188f9cea035437 (diff) | |
| download | sqlalchemy-3a0e0531c179e598c345e5be24e350c375ce7e22.tar.gz | |
Support for generated columns
Added DDL support for "computed columns"; these are DDL column
specifications for columns that have a server-computed value, either upon
SELECT (known as "virtual") or at the point of which they are INSERTed or
UPDATEd (known as "stored"). Support is established for Postgresql, MySQL,
Oracle SQL Server and Firebird. Thanks to Federico Caselli for lots of work
on this one.
ORM round trip tests included. The ORM makes use of existing
FetchedValue support and no additional ORM logic is present for
the basic feature.
It has been observed that Oracle RETURNING does not return the
new value of a computed column upon UPDATE; it returns the
prior value. As this is very dangerous, a warning is emitted
if a computed column is rendered into the RETURNING clause
of an UPDATE statement.
Fixes: #4894
Closes: #4928
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/4928
Pull-request-sha: d39c521d5ac6ebfb4fb5b53846451de79752e64c
Change-Id: I2610b2999a5b1b127ed927dcdaeee98b769643ce
Diffstat (limited to 'test/sql')
| -rw-r--r-- | test/sql/test_computed.py | 80 | ||||
| -rw-r--r-- | test/sql/test_metadata.py | 2 |
2 files changed, 82 insertions, 0 deletions
diff --git a/test/sql/test_computed.py b/test/sql/test_computed.py new file mode 100644 index 000000000..2999c621c --- /dev/null +++ b/test/sql/test_computed.py @@ -0,0 +1,80 @@ +# coding: utf-8 +from sqlalchemy import Column +from sqlalchemy import Computed +from sqlalchemy import Integer +from sqlalchemy import MetaData +from sqlalchemy import Table +from sqlalchemy.exc import ArgumentError +from sqlalchemy.schema import CreateTable +from sqlalchemy.testing import assert_raises_message +from sqlalchemy.testing import AssertsCompiledSQL +from sqlalchemy.testing import combinations +from sqlalchemy.testing import fixtures +from sqlalchemy.testing import is_ +from sqlalchemy.testing import is_not_ + + +class DDLComputedTest(fixtures.TestBase, AssertsCompiledSQL): + __dialect__ = "default" + + @combinations( + ("no_persisted", "", "ignore"), + ("persisted_none", "", None), + ("persisted_true", " STORED", True), + ("persisted_false", " VIRTUAL", False), + id_="iaa", + ) + def test_column_computed(self, text, persisted): + m = MetaData() + kwargs = {"persisted": persisted} if persisted != "ignore" else {} + t = Table( + "t", + m, + Column("x", Integer), + Column("y", Integer, Computed("x + 2", **kwargs)), + ) + self.assert_compile( + CreateTable(t), + "CREATE TABLE t (x INTEGER, y INTEGER GENERATED " + "ALWAYS AS (x + 2)%s)" % text, + ) + + def test_server_default_onupdate(self): + text = ( + "A generated column cannot specify a server_default or a " + "server_onupdate argument" + ) + + def fn(**kwargs): + m = MetaData() + Table( + "t", + m, + Column("x", Integer), + Column("y", Integer, Computed("x + 2"), **kwargs), + ) + + assert_raises_message(ArgumentError, text, fn, server_default="42") + assert_raises_message(ArgumentError, text, fn, server_onupdate="42") + + def test_tometadata(self): + comp1 = Computed("x + 2") + m = MetaData() + t = Table("t", m, Column("x", Integer), Column("y", Integer, comp1)) + is_(comp1.column, t.c.y) + is_(t.c.y.server_onupdate, comp1) + is_(t.c.y.server_default, comp1) + + m2 = MetaData() + t2 = t.tometadata(m2) + comp2 = t2.c.y.server_default + + is_not_(comp1, comp2) + + is_(comp1.column, t.c.y) + is_(t.c.y.server_onupdate, comp1) + is_(t.c.y.server_default, comp1) + + is_(comp2.column, t2.c.y) + is_(t2.c.y.server_onupdate, comp2) + is_(t2.c.y.server_default, comp2) diff --git a/test/sql/test_metadata.py b/test/sql/test_metadata.py index e08c35bfb..05e5ec3c2 100644 --- a/test/sql/test_metadata.py +++ b/test/sql/test_metadata.py @@ -651,6 +651,8 @@ class MetaDataTest(fixtures.TestBase, ComparesTables): class ToMetaDataTest(fixtures.TestBase, ComparesTables): @testing.requires.check_constraints def test_copy(self): + # TODO: modernize this test + from sqlalchemy.testing.schema import Table meta = MetaData() |
