from sqlalchemy.testing import expect_warnings
from sqlalchemy.testing import fixtures
from sqlalchemy.testing import is_
+from sqlalchemy.testing import is_true
from sqlalchemy.testing import mock
from sqlalchemy.types import Boolean
from sqlalchemy.types import Date
eq_(res, ["sqlitetempview"])
finally:
connection.exec_driver_sql("DROP VIEW sqlitetempview")
+
+
+class ComputedReflectionTest(fixtures.TestBase):
+ __only_on__ = "sqlite"
+ __backend__ = True
+
+ @classmethod
+ def setup_test_class(cls):
+ tables = [
+ """CREATE TABLE test1 (
+ s VARCHAR,
+ x VARCHAR GENERATED ALWAYS AS (s || 'x')
+ );""",
+ """CREATE TABLE test2 (
+ s VARCHAR,
+ x VARCHAR GENERATED ALWAYS AS (s || 'x'),
+ y VARCHAR GENERATED ALWAYS AS (s || 'y')
+ );""",
+ """CREATE TABLE test3 (
+ s VARCHAR,
+ x INTEGER GENERATED ALWAYS AS (INSTR(s, ","))
+ );""",
+ """CREATE TABLE test4 (
+ s VARCHAR,
+ x INTEGER GENERATED ALWAYS AS (INSTR(s, ",")),
+ y INTEGER GENERATED ALWAYS AS (INSTR(x, ",")));""",
+ """CREATE TABLE test5 (
+ s VARCHAR,
+ x VARCHAR GENERATED ALWAYS AS (s || 'x') STORED
+ );""",
+ """CREATE TABLE test6 (
+ s VARCHAR,
+ x VARCHAR GENERATED ALWAYS AS (s || 'x') STORED,
+ y VARCHAR GENERATED ALWAYS AS (s || 'y') STORED
+ );""",
+ """CREATE TABLE test7 (
+ s VARCHAR,
+ x INTEGER GENERATED ALWAYS AS (INSTR(s, ",")) STORED
+ );""",
+ """CREATE TABLE test8 (
+ s VARCHAR,
+ x INTEGER GENERATED ALWAYS AS (INSTR(s, ",")) STORED,
+ y INTEGER GENERATED ALWAYS AS (INSTR(x, ",")) STORED
+ );""",
+ ]
+
+ with testing.db.begin() as conn:
+ for ct in tables:
+ conn.exec_driver_sql(ct)
+
+ @classmethod
+ def teardown_test_class(cls):
+ with testing.db.begin() as conn:
+ for tn in cls.res:
+ conn.exec_driver_sql(f"DROP TABLE {tn}")
+
+ res = {
+ "test1": {"x": {"text": "s || 'x'", "stored": False}},
+ "test2": {
+ "x": {"text": "s || 'x'", "stored": False},
+ "y": {"text": "s || 'y'", "stored": False},
+ },
+ "test3": {"x": {"text": 'INSTR(s, ",")', "stored": False}},
+ "test4": {
+ "x": {"text": 'INSTR(s, ",")', "stored": False},
+ "y": {"text": 'INSTR(x, ",")', "stored": False},
+ },
+ "test5": {"x": {"text": "s || 'x'", "stored": True}},
+ "test6": {
+ "x": {"text": "s || 'x'", "stored": True},
+ "y": {"text": "s || 'y'", "stored": True},
+ },
+ "test7": {"x": {"text": 'INSTR(s, ",")', "stored": True}},
+ "test8": {
+ "x": {"text": 'INSTR(s, ",")', "stored": True},
+ "y": {"text": 'INSTR(x, ",")', "stored": True},
+ },
+ }
+
+ def test_reflection(self, connection):
+ meta = MetaData()
+ meta.reflect(connection)
+ eq_(len(meta.tables), len(self.res))
+ for tbl in meta.tables.values():
+ data = self.res[tbl.name]
+ seen = set()
+ for col in tbl.c:
+ if col.name not in data:
+ is_(col.computed, None)
+ else:
+ info = data[col.name]
+ seen.add(col.name)
+ msg = f"{tbl.name}-{col.name}"
+ is_true(bool(col.computed))
+ eq_(col.computed.sqltext.text, info["text"], msg)
+ eq_(col.computed.persisted, info["stored"], msg)
+ eq_(seen, data.keys())