Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions docs/models/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,27 @@ explicitly to opt out, or pass a different value to override.
issue `CREATE SCHEMA <name>` (PostgreSQL) or `CREATE DATABASE <name>` (MySQL)
before tables can be created in those schemas.

### Table Comment

You can attach a SQL `COMMENT ON TABLE` value to a model by passing `comment=` to
`OrmarConfig` (or `OrmarConfig.copy()`). The value is forwarded to the underlying
SQLAlchemy `Table` and emitted by `metadata.create_all()` on dialects that
support table comments (PostgreSQL and MySQL; SQLite ignores it).

```python
class Book(ormar.Model):
ormar_config = base_ormar_config.copy(
tablename="books",
comment="Library catalogue entries.",
)

id: int = ormar.Integer(primary_key=True)
title: str = ormar.String(max_length=200)
```

`copy()` inherits the parent config's comment by default; pass `comment=None`
explicitly to opt out, or pass a different value to override.

### Constraints

On a model level you can also set model-wise constraints on sql columns.
Expand Down
7 changes: 7 additions & 0 deletions docs/releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

## Unreleased

### ✨ Features

* Add `OrmarConfig(comment=...)` to attach a SQL `COMMENT ON TABLE` value to a
model — forwarded to the underlying SQLAlchemy `Table` and emitted by
`metadata.create_all()` on dialects that support table comments (PostgreSQL,
MySQL; SQLite ignores it). [#1240](https://github.com/collerek/ormar/issues/1240)

### 🐛 Fixes

* Fix race in `get_or_create` (and the m2m / reverse-fk variant) where
Expand Down
1 change: 1 addition & 0 deletions ormar/models/helpers/sqlalchemy.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ def populate_config_sqlalchemy_table_if_required(config: "OrmarConfig") -> None:
*config.columns,
*config.constraints,
schema=config.schema,
comment=config.comment,
)
config.table = table

Expand Down
8 changes: 8 additions & 0 deletions ormar/models/ormar_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class OrmarConfig:
engine: AsyncEngine
tablename: str
schema: Optional[str]
comment: Optional[str]
order_by: list[str]
abstract: bool
proxy: bool
Expand All @@ -36,6 +37,7 @@ def __init__(
engine: Optional[AsyncEngine] = None,
tablename: Optional[str] = None,
schema: Optional[str] = None,
comment: Optional[str] = None,
order_by: Optional[list[str]] = None,
abstract: bool = False,
proxy: bool = False,
Expand All @@ -50,6 +52,7 @@ def __init__(
self.engine = engine # type: ignore
self.tablename = tablename # type: ignore
self.schema = schema
self.comment = comment
self.orders_by = order_by or []
self.columns: list[sqlalchemy.Column] = []
self.constraints = constraints or []
Expand All @@ -74,6 +77,7 @@ def copy(
engine: Optional[AsyncEngine] = None,
tablename: Optional[str] = None,
schema: Union[str, None, PydanticUndefinedType] = PydanticUndefined,
comment: Union[str, None, PydanticUndefinedType] = PydanticUndefined,
order_by: Optional[list[str]] = None,
abstract: Optional[bool] = None,
proxy: Optional[bool] = None,
Expand All @@ -87,12 +91,16 @@ def copy(
resolved_schema = (
self.schema if isinstance(schema, PydanticUndefinedType) else schema
)
resolved_comment = (
self.comment if isinstance(comment, PydanticUndefinedType) else comment
)
return OrmarConfig(
metadata=metadata or self.metadata,
database=database or self.database,
engine=engine or self.engine,
tablename=tablename,
schema=resolved_schema,
comment=resolved_comment,
order_by=order_by,
abstract=abstract or self.abstract,
proxy=proxy if proxy is not None else self.proxy,
Expand Down
68 changes: 68 additions & 0 deletions tests/test_model_definition/test_table_comment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"""Tests for ``OrmarConfig.comment`` forwarding to ``sqlalchemy.Table``."""

import ormar
from tests.lifespan import init_tests
from tests.settings import create_config

base_ormar_config = create_config()


class CommentedModel(ormar.Model):
ormar_config = base_ormar_config.copy(
tablename="commented_models",
comment="Stores commented things.",
)

id: int = ormar.Integer(primary_key=True)
name: str = ormar.String(max_length=100)


class UncommentedModel(ormar.Model):
ormar_config = base_ormar_config.copy(tablename="uncommented_models")

id: int = ormar.Integer(primary_key=True)


create_test_database = init_tests(base_ormar_config)


def test_comment_forwarded_to_sqlalchemy_table():
assert CommentedModel.ormar_config.table.comment == "Stores commented things."


def test_comment_defaults_to_none():
assert UncommentedModel.ormar_config.comment is None
assert UncommentedModel.ormar_config.table.comment is None


def test_copy_inherits_parent_comment_when_omitted():
parent = ormar.OrmarConfig(
metadata=base_ormar_config.metadata,
database=base_ormar_config.database,
engine=base_ormar_config.engine,
comment="parent comment",
)
child = parent.copy(tablename="child")
assert child.comment == "parent comment"


def test_copy_can_explicitly_clear_parent_comment():
parent = ormar.OrmarConfig(
metadata=base_ormar_config.metadata,
database=base_ormar_config.database,
engine=base_ormar_config.engine,
comment="parent comment",
)
child = parent.copy(tablename="child", comment=None)
assert child.comment is None


def test_copy_can_override_parent_comment():
parent = ormar.OrmarConfig(
metadata=base_ormar_config.metadata,
database=base_ormar_config.database,
engine=base_ormar_config.engine,
comment="parent comment",
)
child = parent.copy(tablename="child", comment="child comment")
assert child.comment == "child comment"