diff --git a/CHANGES.txt b/CHANGES.txt index 6d080add0..329270844 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -11,6 +11,7 @@ Unreleased that SQL statement clauses like ``LIMIT -1`` could have been generated. Both PostgreSQL and CrateDB only accept ``LIMIT ALL`` instead. +- Added support for computed columns in the SQLAlchemy ORM 2022/10/10 0.27.2 ================= diff --git a/src/crate/client/sqlalchemy/compiler.py b/src/crate/client/sqlalchemy/compiler.py index a747bbe58..b55e53434 100644 --- a/src/crate/client/sqlalchemy/compiler.py +++ b/src/crate/client/sqlalchemy/compiler.py @@ -108,8 +108,23 @@ def get_column_specification(self, column, **kwargs): colspec = self.preparer.format_column(column) + " " + \ self.dialect.type_compiler.process(column.type) # TODO: once supported add default / NOT NULL here + + if column.computed is not None: + colspec += " " + self.process(column.computed) + return colspec + def visit_computed_column(self, generated): + if generated.persisted is False: + raise sa.exc.CompileError( + "Virtual computed columns are not supported, set " + "'persisted' to None or True" + ) + + return "GENERATED ALWAYS AS (%s)" % self.sql_compiler.process( + generated.sqltext, include_table=False, literal_binds=True + ) + def post_create_table(self, table): special_options = '' clustered_options = defaultdict(str) diff --git a/src/crate/client/sqlalchemy/tests/create_table_test.py b/src/crate/client/sqlalchemy/tests/create_table_test.py index 0a7dbe8b7..bee6b9295 100644 --- a/src/crate/client/sqlalchemy/tests/create_table_test.py +++ b/src/crate/client/sqlalchemy/tests/create_table_test.py @@ -97,6 +97,28 @@ class DummyTable(self.Base): ') CLUSTERED BY (p)\n\n'), ()) + def test_with_computed_column(self): + class DummyTable(self.Base): + __tablename__ = 't' + ts = sa.Column(sa.BigInteger, primary_key=True) + p = sa.Column(sa.BigInteger, sa.Computed("date_trunc('day', ts)")) + self.Base.metadata.create_all() + fake_cursor.execute.assert_called_with( + ('\nCREATE TABLE t (\n\t' + 'ts LONG, \n\t' + 'p LONG GENERATED ALWAYS AS (date_trunc(\'day\', ts)), \n\t' + 'PRIMARY KEY (ts)\n' + ')\n\n'), + ()) + + def test_with_virtual_computed_column(self): + class DummyTable(self.Base): + __tablename__ = 't' + ts = sa.Column(sa.BigInteger, primary_key=True) + p = sa.Column(sa.BigInteger, sa.Computed("date_trunc('day', ts)", persisted=False)) + with self.assertRaises(sa.exc.CompileError): + self.Base.metadata.create_all() + def test_with_partitioned_by(self): class DummyTable(self.Base): __tablename__ = 't'