Skip to content

Commit d421c90

Browse files
authored
🗃️ Add max_length validation for database models and input data (#1233)
1 parent df66c1d commit d421c90

4 files changed

Lines changed: 99 additions & 33 deletions

File tree

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
"""Add max length for string(varchar) fields in User and Items models
2+
3+
Revision ID: 9c0a54914c78
4+
Revises: e2412789c190
5+
Create Date: 2024-06-17 14:42:44.639457
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
import sqlmodel.sql.sqltypes
11+
12+
13+
# revision identifiers, used by Alembic.
14+
revision = '9c0a54914c78'
15+
down_revision = 'e2412789c190'
16+
branch_labels = None
17+
depends_on = None
18+
19+
20+
def upgrade():
21+
# Adjust the length of the email field in the User table
22+
op.alter_column('user', 'email',
23+
existing_type=sa.String(),
24+
type_=sa.String(length=255),
25+
existing_nullable=False)
26+
27+
# Adjust the length of the full_name field in the User table
28+
op.alter_column('user', 'full_name',
29+
existing_type=sa.String(),
30+
type_=sa.String(length=255),
31+
existing_nullable=True)
32+
33+
# Adjust the length of the title field in the Item table
34+
op.alter_column('item', 'title',
35+
existing_type=sa.String(),
36+
type_=sa.String(length=255),
37+
existing_nullable=False)
38+
39+
# Adjust the length of the description field in the Item table
40+
op.alter_column('item', 'description',
41+
existing_type=sa.String(),
42+
type_=sa.String(length=255),
43+
existing_nullable=True)
44+
45+
46+
def downgrade():
47+
# Revert the length of the email field in the User table
48+
op.alter_column('user', 'email',
49+
existing_type=sa.String(length=255),
50+
type_=sa.String(),
51+
existing_nullable=False)
52+
53+
# Revert the length of the full_name field in the User table
54+
op.alter_column('user', 'full_name',
55+
existing_type=sa.String(length=255),
56+
type_=sa.String(),
57+
existing_nullable=True)
58+
59+
# Revert the length of the title field in the Item table
60+
op.alter_column('item', 'title',
61+
existing_type=sa.String(length=255),
62+
type_=sa.String(),
63+
existing_nullable=False)
64+
65+
# Revert the length of the description field in the Item table
66+
op.alter_column('item', 'description',
67+
existing_type=sa.String(length=255),
68+
type_=sa.String(),
69+
existing_nullable=True)

backend/app/models.py

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,40 @@
1+
from pydantic import EmailStr
12
from sqlmodel import Field, Relationship, SQLModel
23

34

45
# Shared properties
5-
# TODO replace email str with EmailStr when sqlmodel supports it
66
class UserBase(SQLModel):
7-
email: str = Field(unique=True, index=True)
7+
email: EmailStr = Field(unique=True, index=True, max_length=255)
88
is_active: bool = True
99
is_superuser: bool = False
10-
full_name: str | None = None
10+
full_name: str | None = Field(default=None, max_length=255)
1111

1212

1313
# Properties to receive via API on creation
1414
class UserCreate(UserBase):
15-
password: str
15+
password: str = Field(min_length=8, max_length=40)
1616

1717

18-
# TODO replace email str with EmailStr when sqlmodel supports it
1918
class UserRegister(SQLModel):
20-
email: str
21-
password: str
22-
full_name: str | None = None
19+
email: EmailStr = Field(max_length=255)
20+
password: str = Field(min_length=8, max_length=40)
21+
full_name: str | None = Field(default=None, max_length=255)
2322

2423

2524
# Properties to receive via API on update, all are optional
26-
# TODO replace email str with EmailStr when sqlmodel supports it
2725
class UserUpdate(UserBase):
28-
email: str | None = None # type: ignore
29-
password: str | None = None
26+
email: EmailStr | None = Field(default=None, max_length=255) # type: ignore
27+
password: str | None = Field(default=None, min_length=8, max_length=40)
3028

3129

32-
# TODO replace email str with EmailStr when sqlmodel supports it
3330
class UserUpdateMe(SQLModel):
34-
full_name: str | None = None
35-
email: str | None = None
31+
full_name: str | None = Field(default=None, max_length=255)
32+
email: EmailStr | None = Field(default=None, max_length=255)
3633

3734

3835
class UpdatePassword(SQLModel):
39-
current_password: str
40-
new_password: str
36+
current_password: str = Field(min_length=8, max_length=40)
37+
new_password: str = Field(min_length=8, max_length=40)
4138

4239

4340
# Database model, database table inferred from class name
@@ -59,24 +56,24 @@ class UsersPublic(SQLModel):
5956

6057
# Shared properties
6158
class ItemBase(SQLModel):
62-
title: str
63-
description: str | None = None
59+
title: str = Field(min_length=1, max_length=255)
60+
description: str | None = Field(default=None, max_length=255)
6461

6562

6663
# Properties to receive on item creation
6764
class ItemCreate(ItemBase):
68-
title: str
65+
title: str = Field(min_length=1, max_length=255)
6966

7067

7168
# Properties to receive on item update
7269
class ItemUpdate(ItemBase):
73-
title: str | None = None # type: ignore
70+
title: str | None = Field(default=None, min_length=1, max_length=255) # type: ignore
7471

7572

7673
# Database model, database table inferred from class name
7774
class Item(ItemBase, table=True):
7875
id: int | None = Field(default=None, primary_key=True)
79-
title: str
76+
title: str = Field(max_length=255)
8077
owner_id: int | None = Field(default=None, foreign_key="user.id", nullable=False)
8178
owner: User | None = Relationship(back_populates="items")
8279

@@ -110,4 +107,4 @@ class TokenPayload(SQLModel):
110107

111108
class NewPassword(SQLModel):
112109
token: str
113-
new_password: str
110+
new_password: str = Field(min_length=8, max_length=40)

backend/poetry.lock

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jinja2 = "^3.1.4"
2020
alembic = "^1.12.1"
2121
httpx = "^0.25.1"
2222
psycopg = {extras = ["binary"], version = "^3.1.13"}
23-
sqlmodel = "^0.0.16"
23+
sqlmodel = "^0.0.19"
2424
# Pin bcrypt until passlib supports the latest
2525
bcrypt = "4.0.1"
2626
pydantic-settings = "^2.2.1"

0 commit comments

Comments
 (0)