sqlacodegen
Advanced tools
@@ -13,3 +13,3 @@ name: test suite | ||
| matrix: | ||
| python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] | ||
| python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] | ||
| runs-on: ubuntu-latest | ||
@@ -16,0 +16,0 @@ steps: |
@@ -19,3 +19,3 @@ # This is the configuration file for pre-commit (https://pre-commit.com/). | ||
| - repo: https://github.com/astral-sh/ruff-pre-commit | ||
| rev: v0.12.11 | ||
| rev: v0.13.3 | ||
| hooks: | ||
@@ -27,3 +27,3 @@ - id: ruff | ||
| - repo: https://github.com/pre-commit/mirrors-mypy | ||
| rev: v1.17.1 | ||
| rev: v1.18.2 | ||
| hooks: | ||
@@ -41,1 +41,4 @@ - id: mypy | ||
| - id: rst-inline-touching-normal | ||
| ci: | ||
| autoupdate_schedule: quarterly |
+11
-0
| Version history | ||
| =============== | ||
| **3.2.0** | ||
| - Dropped support for Python 3.9 | ||
| - Fix Postgres ``DOMAIN`` adaptation regression introduced in SQLAlchemy 2.0.42 (PR by @sheinbergon) | ||
| - Support disabling special naming logic for single column many-to-one and one-to-one relationships | ||
| (PR by @Henkhogan, revised by @sheinbergon) | ||
| - Add ``include_dialect_options`` option to render ``Table`` and ``Column`` | ||
| dialect-specific kwargs and ``info`` in generated code. (PR by @jaogoy) | ||
| - Add ``keep_dialect_types`` option to preserve dialect-specific column types instead of | ||
| adapting to generic SQLAlchemy types. (PR by @jaogoy) | ||
| **3.1.1** | ||
@@ -5,0 +16,0 @@ |
+8
-6
| Metadata-Version: 2.4 | ||
| Name: sqlacodegen | ||
| Version: 3.1.1 | ||
| Version: 3.2.0 | ||
| Summary: Automatic model code generator for SQLAlchemy | ||
@@ -18,3 +18,2 @@ Author-email: Alex Grönholm <alex.gronholm@nextday.fi> | ||
| Classifier: Programming Language :: Python :: 3 | ||
| Classifier: Programming Language :: Python :: 3.9 | ||
| Classifier: Programming Language :: Python :: 3.10 | ||
@@ -24,9 +23,8 @@ Classifier: Programming Language :: Python :: 3.11 | ||
| Classifier: Programming Language :: Python :: 3.13 | ||
| Requires-Python: >=3.9 | ||
| Classifier: Programming Language :: Python :: 3.14 | ||
| Requires-Python: >=3.10 | ||
| Description-Content-Type: text/x-rst | ||
| License-File: LICENSE | ||
| Requires-Dist: SQLAlchemy<2.0.42,>=2.0.29 | ||
| Requires-Dist: SQLAlchemy>=2.0.29 | ||
| Requires-Dist: inflect>=4.0.0 | ||
| Requires-Dist: importlib_metadata; python_version < "3.10" | ||
| Requires-Dist: stdlib-list; python_version < "3.10" | ||
| Provides-Extra: test | ||
@@ -153,2 +151,6 @@ Requires-Dist: sqlacodegen[geoalchemy2,pgvector,sqlmodel]; extra == "test" | ||
| * ``noindexes``: ignore indexes | ||
| * ``noidsuffix``: prevent the special naming logic for single column many-to-one | ||
| and one-to-one relationships (see `Relationship naming logic`_ for details) | ||
| * ``include_dialect_options``: render a table' dialect options, such as ``starrocks_partition`` for StarRocks' specific options. | ||
| * ``keep_dialect_types``: preserve dialect-specific column types instead of adapting to generic SQLAlchemy types. | ||
@@ -155,0 +157,0 @@ * ``declarative`` |
+4
-6
@@ -24,3 +24,2 @@ [build-system] | ||
| "Programming Language :: Python :: 3", | ||
| "Programming Language :: Python :: 3.9", | ||
| "Programming Language :: Python :: 3.10", | ||
@@ -30,9 +29,8 @@ "Programming Language :: Python :: 3.11", | ||
| "Programming Language :: Python :: 3.13", | ||
| "Programming Language :: Python :: 3.14", | ||
| ] | ||
| requires-python = ">=3.9" | ||
| requires-python = ">=3.10" | ||
| dependencies = [ | ||
| "SQLAlchemy >= 2.0.29,<2.0.42", | ||
| "SQLAlchemy >= 2.0.29", | ||
| "inflect >= 4.0.0", | ||
| "importlib_metadata; python_version < '3.10'", | ||
| "stdlib-list; python_version < '3.10'" | ||
| ] | ||
@@ -100,3 +98,3 @@ dynamic = ["version"] | ||
| [tool.tox] | ||
| env_list = ["py39", "py310", "py311", "py312", "py313"] | ||
| env_list = ["py310", "py311", "py312", "py313", "py314"] | ||
| skip_missing_interpreters = true | ||
@@ -103,0 +101,0 @@ |
+4
-0
@@ -106,2 +106,6 @@ .. image:: https://github.com/agronholm/sqlacodegen/actions/workflows/test.yml/badge.svg | ||
| * ``noindexes``: ignore indexes | ||
| * ``noidsuffix``: prevent the special naming logic for single column many-to-one | ||
| and one-to-one relationships (see `Relationship naming logic`_ for details) | ||
| * ``include_dialect_options``: render a table' dialect options, such as ``starrocks_partition`` for StarRocks' specific options. | ||
| * ``keep_dialect_types``: preserve dialect-specific column types instead of adapting to generic SQLAlchemy types. | ||
@@ -108,0 +112,0 @@ * ``declarative`` |
| Metadata-Version: 2.4 | ||
| Name: sqlacodegen | ||
| Version: 3.1.1 | ||
| Version: 3.2.0 | ||
| Summary: Automatic model code generator for SQLAlchemy | ||
@@ -18,3 +18,2 @@ Author-email: Alex Grönholm <alex.gronholm@nextday.fi> | ||
| Classifier: Programming Language :: Python :: 3 | ||
| Classifier: Programming Language :: Python :: 3.9 | ||
| Classifier: Programming Language :: Python :: 3.10 | ||
@@ -24,9 +23,8 @@ Classifier: Programming Language :: Python :: 3.11 | ||
| Classifier: Programming Language :: Python :: 3.13 | ||
| Requires-Python: >=3.9 | ||
| Classifier: Programming Language :: Python :: 3.14 | ||
| Requires-Python: >=3.10 | ||
| Description-Content-Type: text/x-rst | ||
| License-File: LICENSE | ||
| Requires-Dist: SQLAlchemy<2.0.42,>=2.0.29 | ||
| Requires-Dist: SQLAlchemy>=2.0.29 | ||
| Requires-Dist: inflect>=4.0.0 | ||
| Requires-Dist: importlib_metadata; python_version < "3.10" | ||
| Requires-Dist: stdlib-list; python_version < "3.10" | ||
| Provides-Extra: test | ||
@@ -153,2 +151,6 @@ Requires-Dist: sqlacodegen[geoalchemy2,pgvector,sqlmodel]; extra == "test" | ||
| * ``noindexes``: ignore indexes | ||
| * ``noidsuffix``: prevent the special naming logic for single column many-to-one | ||
| and one-to-one relationships (see `Relationship naming logic`_ for details) | ||
| * ``include_dialect_options``: render a table' dialect options, such as ``starrocks_partition`` for StarRocks' specific options. | ||
| * ``keep_dialect_types``: preserve dialect-specific column types instead of adapting to generic SQLAlchemy types. | ||
@@ -155,0 +157,0 @@ * ``declarative`` |
@@ -1,8 +0,4 @@ | ||
| SQLAlchemy<2.0.42,>=2.0.29 | ||
| SQLAlchemy>=2.0.29 | ||
| inflect>=4.0.0 | ||
| [:python_version < "3.10"] | ||
| importlib_metadata | ||
| stdlib-list | ||
| [citext] | ||
@@ -9,0 +5,0 @@ sqlalchemy-citext>=1.7.0 |
@@ -7,2 +7,3 @@ from __future__ import annotations | ||
| from contextlib import ExitStack | ||
| from importlib.metadata import entry_points, version | ||
| from typing import Any, TextIO | ||
@@ -28,8 +29,3 @@ | ||
| if sys.version_info < (3, 10): | ||
| from importlib_metadata import entry_points, version | ||
| else: | ||
| from importlib.metadata import entry_points, version | ||
| def _parse_engine_arg(arg_str: str) -> tuple[str, Any]: | ||
@@ -36,0 +32,0 @@ if "=" not in arg_str: |
@@ -122,3 +122,9 @@ from __future__ import annotations | ||
| class TablesGenerator(CodeGenerator): | ||
| valid_options: ClassVar[set[str]] = {"noindexes", "noconstraints", "nocomments"} | ||
| valid_options: ClassVar[set[str]] = { | ||
| "noindexes", | ||
| "noconstraints", | ||
| "nocomments", | ||
| "include_dialect_options", | ||
| "keep_dialect_types", | ||
| } | ||
| stdlib_module_names: ClassVar[set[str]] = get_stdlib_module_names() | ||
@@ -139,2 +145,9 @@ | ||
| # Render SchemaItem.info and dialect kwargs (Table/Column) into output | ||
| self.include_dialect_options_and_info: bool = ( | ||
| "include_dialect_options" in self.options | ||
| ) | ||
| # Keep dialect-specific types instead of adapting to generic SQLAlchemy types | ||
| self.keep_dialect_types: bool = "keep_dialect_types" in self.options | ||
| @property | ||
@@ -398,2 +411,6 @@ def views_supported(self) -> bool: | ||
| # add info + dialect kwargs for callable context (opt-in) | ||
| if self.include_dialect_options_and_info: | ||
| self._add_dialect_kwargs_and_info(table, kwargs, values_for_dict=False) | ||
| return render_callable("Table", *args, kwargs=kwargs, indentation=" ") | ||
@@ -504,2 +521,6 @@ | ||
| # add column info + dialect kwargs for callable context (opt-in) | ||
| if self.include_dialect_options_and_info: | ||
| self._add_dialect_kwargs_and_info(column, kwargs, values_for_dict=False) | ||
| return self.render_column_callable(is_table, *args, **kwargs) | ||
@@ -622,2 +643,47 @@ | ||
| def _add_dialect_kwargs_and_info( | ||
| self, obj: Any, target_kwargs: dict[str, object], *, values_for_dict: bool | ||
| ) -> None: | ||
| """ | ||
| Merge SchemaItem-like object's .info and .dialect_kwargs into target_kwargs. | ||
| - values_for_dict=True: keep raw values so pretty-printer emits repr() (for __table_args__ dict) | ||
| - values_for_dict=False: set values to repr() strings (for callable kwargs) | ||
| """ | ||
| info_dict = getattr(obj, "info", None) | ||
| if info_dict: | ||
| target_kwargs["info"] = info_dict if values_for_dict else repr(info_dict) | ||
| dialect_keys: list[str] | ||
| try: | ||
| dialect_keys = sorted(getattr(obj, "dialect_kwargs")) | ||
| except Exception: | ||
| return | ||
| dialect_kwargs = getattr(obj, "dialect_kwargs", {}) | ||
| for key in dialect_keys: | ||
| try: | ||
| value = dialect_kwargs[key] | ||
| except Exception: | ||
| continue | ||
| # Render values: | ||
| # - callable context (values_for_dict=False): produce a string expression. | ||
| # primitives use repr(value); custom objects stringify then repr(). | ||
| # - dict context (values_for_dict=True): pass raw primitives / str; | ||
| # custom objects become str(value) so pformat quotes them. | ||
| if values_for_dict: | ||
| if isinstance(value, type(None) | bool | int | float): | ||
| target_kwargs[key] = value | ||
| elif isinstance(value, str | dict | list): | ||
| target_kwargs[key] = value | ||
| else: | ||
| target_kwargs[key] = str(value) | ||
| else: | ||
| if isinstance( | ||
| value, type(None) | bool | int | float | str | dict | list | ||
| ): | ||
| target_kwargs[key] = repr(value) | ||
| else: | ||
| target_kwargs[key] = repr(str(value)) | ||
| def should_ignore_table(self, table: Table) -> bool: | ||
@@ -688,6 +754,7 @@ # Support for Alembic and sqlalchemy-migrate -- never expose the schema version | ||
| for column in table.c: | ||
| try: | ||
| column.type = self.get_adapted_type(column.type) | ||
| except CompileError: | ||
| pass | ||
| if not self.keep_dialect_types: | ||
| try: | ||
| column.type = self.get_adapted_type(column.type) | ||
| except CompileError: | ||
| continue | ||
@@ -727,2 +794,16 @@ # PostgreSQL specific fix: detect sequences from server_default | ||
| # Hack to fix Postgres DOMAIN type adaptation, broken as of SQLAlchemy 2.0.42 | ||
| # For additional information - https://github.com/agronholm/sqlacodegen/issues/416#issuecomment-3417480599 | ||
| if supercls is DOMAIN: | ||
| if coltype.default: | ||
| kw["default"] = coltype.default | ||
| if coltype.constraint_name is not None: | ||
| kw["constraint_name"] = coltype.constraint_name | ||
| if coltype.not_null: | ||
| kw["not_null"] = coltype.not_null | ||
| if coltype.check is not None: | ||
| kw["check"] = coltype.check | ||
| if coltype.create_type: | ||
| kw["create_type"] = coltype.create_type | ||
| try: | ||
@@ -762,2 +843,3 @@ new_coltype = coltype.adapt(supercls) | ||
| "nobidi", | ||
| "noidsuffix", | ||
| } | ||
@@ -1099,3 +1181,3 @@ | ||
| # preceding part as the relationship name | ||
| if relationship.constraint: | ||
| if relationship.constraint and "noidsuffix" not in self.options: | ||
| is_source = relationship.source.table is relationship.constraint.table | ||
@@ -1190,3 +1272,3 @@ if is_source or relationship.type not in ( | ||
| args: list[str] = [] | ||
| kwargs: dict[str, str] = {} | ||
| kwargs: dict[str, object] = {} | ||
@@ -1217,2 +1299,6 @@ # Render constraints | ||
| # add info + dialect kwargs for dict context (__table_args__) (opt-in) | ||
| if self.include_dialect_options_and_info: | ||
| self._add_dialect_kwargs_and_info(table, kwargs, values_for_dict=True) | ||
| if kwargs: | ||
@@ -1219,0 +1305,0 @@ formatted_kwargs = pformat(kwargs) |
@@ -5,3 +5,3 @@ from __future__ import annotations | ||
| from enum import Enum, auto | ||
| from typing import Any, Union | ||
| from typing import Any | ||
@@ -56,3 +56,3 @@ from sqlalchemy.sql.schema import Column, ForeignKeyConstraint, Table | ||
| JoinType = tuple[Model, Union[ColumnAttribute, str], Model, Union[ColumnAttribute, str]] | ||
| JoinType = tuple[Model, ColumnAttribute | str, Model, ColumnAttribute | str] | ||
@@ -59,0 +59,0 @@ |
@@ -114,2 +114,176 @@ from __future__ import annotations | ||
| @pytest.mark.parametrize("generator", [["include_dialect_options"]], indirect=True) | ||
| def test_include_dialect_options_and_info_table_and_column( | ||
| generator: CodeGenerator, | ||
| ) -> None: | ||
| from .test_generator_tables import _PartitionInfo | ||
| Table( | ||
| "t_opts", | ||
| generator.metadata, | ||
| Column("id", INTEGER, primary_key=True, starrocks_is_agg_key=True), | ||
| Column("name", VARCHAR, starrocks_agg_type="REPLACE"), | ||
| starrocks_aggregate_key="id", | ||
| starrocks_partition_by=_PartitionInfo("RANGE(id)"), | ||
| starrocks_security="DEFINER", | ||
| starrocks_PROPERTIES={"replication_num": "3", "storage_medium": "SSD"}, | ||
| info={ | ||
| "table_kind": "MATERIALIZED VIEW", | ||
| "definition": "SELECT id, name FROM t_opts_base_table", | ||
| }, | ||
| ) | ||
| validate_code( | ||
| generator.generate(), | ||
| """\ | ||
| from typing import Optional | ||
| from sqlalchemy import Integer, String | ||
| from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column | ||
| class Base(DeclarativeBase): | ||
| pass | ||
| class TOpts(Base): | ||
| __tablename__ = 't_opts' | ||
| __table_args__ = {'info': {'definition': 'SELECT id, name FROM t_opts_base_table', | ||
| 'table_kind': 'MATERIALIZED VIEW'}, | ||
| 'starrocks_PROPERTIES': {'replication_num': '3', 'storage_medium': 'SSD'}, | ||
| 'starrocks_aggregate_key': 'id', | ||
| 'starrocks_partition_by': 'RANGE(id)', | ||
| 'starrocks_security': 'DEFINER'} | ||
| id: Mapped[int] = mapped_column(Integer, primary_key=True, starrocks_is_agg_key=True) | ||
| name: Mapped[Optional[str]] = mapped_column(String, starrocks_agg_type='REPLACE') | ||
| """, | ||
| ) | ||
| @pytest.mark.parametrize("generator", [["include_dialect_options"]], indirect=True) | ||
| def test_include_dialect_options_and_info_with_hyphen(generator: CodeGenerator) -> None: | ||
| Table( | ||
| "t_opts2", | ||
| generator.metadata, | ||
| Column("id", INTEGER, primary_key=True), | ||
| mysql_engine="InnoDB", | ||
| info={"table_kind": "View"}, | ||
| ) | ||
| validate_code( | ||
| generator.generate(), | ||
| """\ | ||
| from sqlalchemy import Integer | ||
| from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column | ||
| class Base(DeclarativeBase): | ||
| pass | ||
| class TOpts2(Base): | ||
| __tablename__ = 't_opts2' | ||
| __table_args__ = {'info': {'table_kind': 'View'}, 'mysql_engine': 'InnoDB'} | ||
| id: Mapped[int] = mapped_column(Integer, primary_key=True) | ||
| """, | ||
| ) | ||
| def test_include_dialect_options_not_enabled_skips(generator: CodeGenerator) -> None: | ||
| from .test_generator_tables import _PartitionInfo | ||
| Table( | ||
| "t_plain", | ||
| generator.metadata, | ||
| Column( | ||
| "id", | ||
| INTEGER, | ||
| primary_key=True, | ||
| info={"abc": True}, | ||
| starrocks_is_agg_key=True, | ||
| ), | ||
| starrocks_engine="OLAP", | ||
| starrocks_partition_by=_PartitionInfo("RANGE(id)"), | ||
| ) | ||
| validate_code( | ||
| generator.generate(), | ||
| """\ | ||
| from sqlalchemy import Integer | ||
| from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column | ||
| class Base(DeclarativeBase): | ||
| pass | ||
| class TPlain(Base): | ||
| __tablename__ = 't_plain' | ||
| id: Mapped[int] = mapped_column(Integer, primary_key=True) | ||
| """, | ||
| ) | ||
| def test_keep_dialect_types_adapts_mysql_integer_default( | ||
| generator: CodeGenerator, | ||
| ) -> None: | ||
| from sqlalchemy.dialects.mysql import INTEGER as MYSQL_INTEGER | ||
| Table( | ||
| "num", | ||
| generator.metadata, | ||
| Column("id", INTEGER, primary_key=True), | ||
| Column("val", MYSQL_INTEGER(), nullable=False), | ||
| ) | ||
| validate_code( | ||
| generator.generate(), | ||
| """\ | ||
| from sqlalchemy import Integer | ||
| from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column | ||
| class Base(DeclarativeBase): | ||
| pass | ||
| class Num(Base): | ||
| __tablename__ = 'num' | ||
| id: Mapped[int] = mapped_column(Integer, primary_key=True) | ||
| val: Mapped[int] = mapped_column(Integer, nullable=False) | ||
| """, | ||
| ) | ||
| @pytest.mark.parametrize("generator", [["keep_dialect_types"]], indirect=True) | ||
| def test_keep_dialect_types_keeps_mysql_integer(generator: CodeGenerator) -> None: | ||
| from sqlalchemy.dialects.mysql import INTEGER as MYSQL_INTEGER | ||
| Table( | ||
| "num2", | ||
| generator.metadata, | ||
| Column("id", INTEGER, primary_key=True), | ||
| Column("val", MYSQL_INTEGER(), nullable=False), | ||
| ) | ||
| validate_code( | ||
| generator.generate(), | ||
| """\ | ||
| from sqlalchemy import INTEGER | ||
| from sqlalchemy.dialects.mysql import INTEGER | ||
| from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column | ||
| class Base(DeclarativeBase): | ||
| pass | ||
| class Num2(Base): | ||
| __tablename__ = 'num2' | ||
| id: Mapped[int] = mapped_column(INTEGER, primary_key=True) | ||
| val: Mapped[int] = mapped_column(INTEGER, nullable=False) | ||
| """, | ||
| ) | ||
| def test_onetomany(generator: CodeGenerator) -> None: | ||
@@ -1567,2 +1741,58 @@ Table( | ||
| @pytest.mark.parametrize("generator", [["noidsuffix"]], indirect=True) | ||
| def test_named_foreign_key_constraints_with_noidsuffix( | ||
| generator: CodeGenerator, | ||
| ) -> None: | ||
| Table( | ||
| "simple_items", | ||
| generator.metadata, | ||
| Column("id", INTEGER, primary_key=True), | ||
| Column("container_id", INTEGER), | ||
| ForeignKeyConstraint( | ||
| ["container_id"], ["simple_containers.id"], name="foreignkeytest" | ||
| ), | ||
| ) | ||
| Table( | ||
| "simple_containers", | ||
| generator.metadata, | ||
| Column("id", INTEGER, primary_key=True), | ||
| ) | ||
| validate_code( | ||
| generator.generate(), | ||
| """\ | ||
| from typing import Optional | ||
| from sqlalchemy import ForeignKeyConstraint, Integer | ||
| from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship | ||
| class Base(DeclarativeBase): | ||
| pass | ||
| class SimpleContainers(Base): | ||
| __tablename__ = 'simple_containers' | ||
| id: Mapped[int] = mapped_column(Integer, primary_key=True) | ||
| simple_items: Mapped[list['SimpleItems']] = relationship('SimpleItems', \ | ||
| back_populates='simple_containers') | ||
| class SimpleItems(Base): | ||
| __tablename__ = 'simple_items' | ||
| __table_args__ = ( | ||
| ForeignKeyConstraint(['container_id'], ['simple_containers.id'], \ | ||
| name='foreignkeytest'), | ||
| ) | ||
| id: Mapped[int] = mapped_column(Integer, primary_key=True) | ||
| container_id: Mapped[Optional[int]] = mapped_column(Integer) | ||
| simple_containers: Mapped[Optional['SimpleContainers']] = relationship('SimpleContainers', \ | ||
| back_populates='simple_items') | ||
| """, | ||
| ) | ||
| # @pytest.mark.xfail(strict=True) | ||
@@ -1569,0 +1799,0 @@ def test_colname_import_conflict(generator: CodeGenerator) -> None: |
@@ -8,3 +8,4 @@ from __future__ import annotations | ||
| from sqlalchemy import TypeDecorator | ||
| from sqlalchemy.dialects import mysql, postgresql | ||
| from sqlalchemy.dialects import mysql, postgresql, registry | ||
| from sqlalchemy.dialects.mysql.pymysql import MySQLDialect_pymysql | ||
| from sqlalchemy.engine import Engine | ||
@@ -1094,1 +1095,83 @@ from sqlalchemy.schema import ( | ||
| ) | ||
| class MockStarRocksDialect(MySQLDialect_pymysql): | ||
| name = "starrocks" | ||
| construct_arguments = [ | ||
| ( | ||
| Column, | ||
| { | ||
| "is_agg_key": None, | ||
| "agg_type": None, | ||
| "IS_AGG_KEY": None, | ||
| "AGG_TYPE": None, | ||
| }, | ||
| ), | ||
| ( | ||
| Table, | ||
| { | ||
| "primary_key": None, | ||
| "aggregate_key": None, | ||
| "unique_key": None, | ||
| "duplicate_key": None, | ||
| "engine": "OLAP", | ||
| "partition_by": None, | ||
| "order_by": None, | ||
| "security": None, | ||
| "properties": {}, | ||
| "ENGINE": "OLAP", | ||
| "PARTITION_BY": None, | ||
| "ORDER_BY": None, | ||
| "SECURITY": None, | ||
| "PROPERTIES": {}, | ||
| }, | ||
| ), | ||
| ] | ||
| # Register StarRocksDialect | ||
| registry.register("starrocks", __name__, "MockStarRocksDialect") | ||
| class _PartitionInfo: | ||
| def __init__(self, partition_by: str) -> None: | ||
| self.partition_by = partition_by | ||
| def __str__(self) -> str: | ||
| return self.partition_by | ||
| def __repr__(self) -> str: | ||
| return repr(self.partition_by) | ||
| @pytest.mark.parametrize("generator", [["include_dialect_options"]], indirect=True) | ||
| def test_include_dialect_options_starrocks_tables(generator: CodeGenerator) -> None: | ||
| Table( | ||
| "t_starrocks", | ||
| generator.metadata, | ||
| Column("id", INTEGER, primary_key=True, starrocks_is_agg_key=True), | ||
| starrocks_ENGINE="OLAP", | ||
| starrocks_PARTITION_BY=_PartitionInfo("RANGE(id)"), | ||
| starrocks_ORDER_BY="id, name", | ||
| starrocks_PROPERTIES={"replication_num": "3", "storage_medium": "SSD"}, | ||
| ).info = {"table_kind": "TABLE"} | ||
| validate_code( | ||
| generator.generate(), | ||
| """\ | ||
| from sqlalchemy import Column, Integer, MetaData, Table | ||
| metadata = MetaData() | ||
| t_t_starrocks = Table( | ||
| 't_starrocks', metadata, | ||
| Column('id', Integer, primary_key=True, starrocks_is_agg_key=True), | ||
| info={'table_kind': 'TABLE'}, | ||
| starrocks_ENGINE='OLAP', | ||
| starrocks_ORDER_BY='id, name', | ||
| starrocks_PARTITION_BY='RANGE(id)', | ||
| starrocks_PROPERTIES={'replication_num': '3', 'storage_medium': 'SSD'} | ||
| ) | ||
| """, | ||
| ) |
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
236123
6.31%4737
7.24%