Skip to content

Commit 3c1f7c4

Browse files
authored
✨ Add created_at field to User and Item models and update endpoints (#2144)
1 parent 2720308 commit 3c1f7c4

File tree

6 files changed

+78
-2
lines changed

6 files changed

+78
-2
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""Add created_at to User and Item
2+
3+
Revision ID: fe56fa70289e
4+
Revises: 1a31ce608336
5+
Create Date: 2026-01-23 15:50:37.171462
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 = 'fe56fa70289e'
15+
down_revision = '1a31ce608336'
16+
branch_labels = None
17+
depends_on = None
18+
19+
20+
def upgrade():
21+
# ### commands auto generated by Alembic - please adjust! ###
22+
op.add_column('item', sa.Column('created_at', sa.DateTime(timezone=True), nullable=True))
23+
op.add_column('user', sa.Column('created_at', sa.DateTime(timezone=True), nullable=True))
24+
# ### end Alembic commands ###
25+
26+
27+
def downgrade():
28+
# ### commands auto generated by Alembic - please adjust! ###
29+
op.drop_column('user', 'created_at')
30+
op.drop_column('item', 'created_at')
31+
# ### end Alembic commands ###

backend/app/api/routes/items.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ def read_items(
2121
if current_user.is_superuser:
2222
count_statement = select(func.count()).select_from(Item)
2323
count = session.exec(count_statement).one()
24-
statement = select(Item).offset(skip).limit(limit)
24+
statement = (
25+
select(Item).order_by(Item.created_at.desc()).offset(skip).limit(limit)
26+
)
2527
items = session.exec(statement).all()
2628
else:
2729
count_statement = (
@@ -33,6 +35,7 @@ def read_items(
3335
statement = (
3436
select(Item)
3537
.where(Item.owner_id == current_user.id)
38+
.order_by(Item.created_at.desc())
3639
.offset(skip)
3740
.limit(limit)
3841
)

backend/app/api/routes/users.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def read_users(session: SessionDep, skip: int = 0, limit: int = 100) -> Any:
4242
count_statement = select(func.count()).select_from(User)
4343
count = session.exec(count_statement).one()
4444

45-
statement = select(User).offset(skip).limit(limit)
45+
statement = select(User).order_by(User.created_at.desc()).offset(skip).limit(limit)
4646
users = session.exec(statement).all()
4747

4848
return UsersPublic(data=users, count=count)

backend/app/models.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
import uuid
2+
from datetime import datetime, timezone
23

34
from pydantic import EmailStr
5+
from sqlalchemy import DateTime
46
from sqlmodel import Field, Relationship, SQLModel
57

68

9+
def get_datetime_utc() -> datetime:
10+
return datetime.now(timezone.utc)
11+
12+
713
# Shared properties
814
class UserBase(SQLModel):
915
email: EmailStr = Field(unique=True, index=True, max_length=255)
@@ -43,12 +49,17 @@ class UpdatePassword(SQLModel):
4349
class User(UserBase, table=True):
4450
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
4551
hashed_password: str
52+
created_at: datetime | None = Field(
53+
default_factory=get_datetime_utc,
54+
sa_type=DateTime(timezone=True), # type: ignore
55+
)
4656
items: list["Item"] = Relationship(back_populates="owner", cascade_delete=True)
4757

4858

4959
# Properties to return via API, id is always required
5060
class UserPublic(UserBase):
5161
id: uuid.UUID
62+
created_at: datetime | None = None
5263

5364

5465
class UsersPublic(SQLModel):
@@ -75,6 +86,10 @@ class ItemUpdate(ItemBase):
7586
# Database model, database table inferred from class name
7687
class Item(ItemBase, table=True):
7788
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
89+
created_at: datetime | None = Field(
90+
default_factory=get_datetime_utc,
91+
sa_type=DateTime(timezone=True), # type: ignore
92+
)
7893
owner_id: uuid.UUID = Field(
7994
foreign_key="user.id", nullable=False, ondelete="CASCADE"
8095
)
@@ -85,6 +100,7 @@ class Item(ItemBase, table=True):
85100
class ItemPublic(ItemBase):
86101
id: uuid.UUID
87102
owner_id: uuid.UUID
103+
created_at: datetime | None = None
88104

89105

90106
class ItemsPublic(SQLModel):

frontend/src/client/schemas.gen.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,18 @@ export const ItemPublicSchema = {
126126
type: 'string',
127127
format: 'uuid',
128128
title: 'Owner Id'
129+
},
130+
created_at: {
131+
anyOf: [
132+
{
133+
type: 'string',
134+
format: 'date-time'
135+
},
136+
{
137+
type: 'null'
138+
}
139+
],
140+
title: 'Created At'
129141
}
130142
},
131143
type: 'object',
@@ -352,6 +364,18 @@ export const UserPublicSchema = {
352364
type: 'string',
353365
format: 'uuid',
354366
title: 'Id'
367+
},
368+
created_at: {
369+
anyOf: [
370+
{
371+
type: 'string',
372+
format: 'date-time'
373+
},
374+
{
375+
type: 'null'
376+
}
377+
],
378+
title: 'Created At'
355379
}
356380
},
357381
type: 'object',

frontend/src/client/types.gen.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export type ItemPublic = {
2323
description?: (string | null);
2424
id: string;
2525
owner_id: string;
26+
created_at?: (string | null);
2627
};
2728

2829
export type ItemsPublic = {
@@ -75,6 +76,7 @@ export type UserPublic = {
7576
is_superuser?: boolean;
7677
full_name?: (string | null);
7778
id: string;
79+
created_at?: (string | null);
7880
};
7981

8082
export type UserRegister = {

0 commit comments

Comments
 (0)