Praneeth Yerrapragada commited on
Commit
a4ec216
·
1 Parent(s): f92858b

feat: transactions router

Browse files
Dockerfile CHANGED
@@ -25,4 +25,7 @@ COPY . .
25
  # Make port 8000 available to the world outside this container
26
  EXPOSE 8000
27
 
 
 
 
28
  CMD ["python", "main.py"]
 
25
  # Make port 8000 available to the world outside this container
26
  EXPOSE 8000
27
 
28
+ # Run migrations
29
+ RUN alembic upgrade head
30
+
31
  CMD ["python", "main.py"]
app/api/routers/transaction.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List
2
+ from fastapi import APIRouter, Depends, HTTPException, status
3
+ from sqlalchemy.ext.asyncio import AsyncSession
4
+ from app.model.transaction import Transaction as TransactionModel
5
+ from app.schema.index import TransactionOutput
6
+ from app.engine.postgresdb import get_db_session
7
+
8
+ transaction_router = r = APIRouter(prefix="/api/v1/transactions", tags=["transactions"])
9
+
10
+
11
+ @r.get(
12
+ "/{user_id}",
13
+ response_model=List[TransactionOutput],
14
+ responses={
15
+ 200: {"description": "New user created"},
16
+ 400: {"description": "Bad request"},
17
+ 204: {"description": "No content"},
18
+ 500: {"description": "Internal server error"},
19
+ },
20
+ )
21
+ async def get_transactions(user_id: int, db: AsyncSession = Depends(get_db_session)):
22
+ """
23
+ Retrieve all transactions.
24
+ """
25
+ result = await TransactionModel.get_by_user(db, user_id)
26
+ if len(result) == 0:
27
+ raise HTTPException(status_code=status.HTTP_204_NO_CONTENT)
28
+ return result.scalars().all()
app/model/transaction.py CHANGED
@@ -1,6 +1,9 @@
1
  from datetime import datetime
 
2
  from sqlalchemy import ForeignKey
3
  from sqlalchemy.orm import relationship, Mapped, mapped_column
 
 
4
 
5
  from app.model.base import BaseModel
6
  from app.engine.postgresdb import Base
@@ -16,3 +19,29 @@ class Transaction(Base, BaseModel):
16
 
17
  user_id = mapped_column(ForeignKey("users.id"))
18
  user = relationship("User", back_populates="transactions")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from datetime import datetime
2
+ from typing import List
3
  from sqlalchemy import ForeignKey
4
  from sqlalchemy.orm import relationship, Mapped, mapped_column
5
+ from sqlalchemy.sql import expression as sql
6
+ from sqlalchemy.ext.asyncio import AsyncSession
7
 
8
  from app.model.base import BaseModel
9
  from app.engine.postgresdb import Base
 
19
 
20
  user_id = mapped_column(ForeignKey("users.id"))
21
  user = relationship("User", back_populates="transactions")
22
+
23
+ @classmethod
24
+ async def create(cls: "type[Transaction]", db: AsyncSession, **kwargs) -> "Transaction":
25
+ query = sql.insert(cls).values(**kwargs).returning(cls.id)
26
+ transactions = await db.execute(query)
27
+ await db.commit()
28
+ return transactions.first()
29
+
30
+ @classmethod
31
+ async def update(cls: "type[Transaction]", db: AsyncSession, id: int, **kwargs) -> "Transaction":
32
+ query = (
33
+ sql.update(cls)
34
+ .where(cls.id == id)
35
+ .values(**kwargs)
36
+ .execution_options(synchronize_session="fetch")
37
+ .returning(cls.id)
38
+ )
39
+ transactions = await db.execute(query)
40
+ await db.commit()
41
+ return transactions.first()
42
+
43
+ @classmethod
44
+ async def get_by_user(cls: "type[Transaction]", db: AsyncSession, user_id: int) -> "List[Transaction]":
45
+ query = sql.select(cls).where(cls.user_id == user_id)
46
+ transactions = await db.execute(query)
47
+ return transactions
app/schema/index.py CHANGED
@@ -24,10 +24,13 @@ class User(BaseModel):
24
  transactions: "List[Transaction]" = []
25
 
26
 
27
- class Transaction(BaseModel):
28
  transaction_date: datetime
29
  category: str
30
  name_description: str
31
  amount: float
32
  type: TransactionType
 
 
 
33
  user: User
 
24
  transactions: "List[Transaction]" = []
25
 
26
 
27
+ class TransactionOutput(BaseModel):
28
  transaction_date: datetime
29
  category: str
30
  name_description: str
31
  amount: float
32
  type: TransactionType
33
+
34
+
35
+ class Transaction(TransactionOutput):
36
  user: User
main.py CHANGED
@@ -7,6 +7,7 @@ from fastapi.middleware.cors import CORSMiddleware
7
  from fastapi.responses import RedirectResponse
8
  from app.api.routers.chat import chat_router
9
  from app.api.routers.user import user_router
 
10
  from app.settings import init_settings
11
  from fastapi.staticfiles import StaticFiles
12
  from alembic.config import Config
@@ -61,6 +62,7 @@ def init_app():
61
  app.mount("/api/data", StaticFiles(directory="data"), name="static")
62
  app.include_router(chat_router, prefix="/api/chat")
63
  app.include_router(user_router)
 
64
 
65
  return app
66
 
 
7
  from fastapi.responses import RedirectResponse
8
  from app.api.routers.chat import chat_router
9
  from app.api.routers.user import user_router
10
+ from app.api.routers.transaction import transaction_router
11
  from app.settings import init_settings
12
  from fastapi.staticfiles import StaticFiles
13
  from alembic.config import Config
 
62
  app.mount("/api/data", StaticFiles(directory="data"), name="static")
63
  app.include_router(chat_router, prefix="/api/chat")
64
  app.include_router(user_router)
65
+ app.include_router(transaction_router)
66
 
67
  return app
68
 
migration/env.py CHANGED
@@ -22,7 +22,8 @@ if config.config_file_name is not None:
22
  fileConfig(config.config_file_name)
23
 
24
  # Import all models so they're registered with SQLAlchemy.
25
- from app.model import *
 
26
 
27
  # add your model's MetaData object here
28
  # for 'autogenerate' support
 
22
  fileConfig(config.config_file_name)
23
 
24
  # Import all models so they're registered with SQLAlchemy.
25
+ import app.model.transaction
26
+ import app.model.user
27
 
28
  # add your model's MetaData object here
29
  # for 'autogenerate' support
migration/versions/8feaedca36f9_users_datatype_updates.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Remove_Transactions_From_Users
2
+
3
+ Revision ID: 8feaedca36f9
4
+ Revises: cd515c44401d
5
+ Create Date: 2024-06-02 01:26:54.731002
6
+
7
+ """
8
+ from typing import Sequence, Union
9
+
10
+ from alembic import op
11
+ import sqlalchemy as sa
12
+ from sqlalchemy.dialects import postgresql
13
+
14
+ # revision identifiers, used by Alembic.
15
+ revision: str = '8feaedca36f9'
16
+ down_revision: Union[str, None] = 'cd515c44401d'
17
+ branch_labels: Union[str, Sequence[str], None] = None
18
+ depends_on: Union[str, Sequence[str], None] = None
19
+
20
+
21
+ def upgrade() -> None:
22
+ # ### commands auto generated by Alembic - please adjust! ###
23
+ op.alter_column('transactions', 'transaction_date',
24
+ existing_type=postgresql.TIMESTAMP(),
25
+ nullable=False)
26
+ op.alter_column('transactions', 'category',
27
+ existing_type=sa.VARCHAR(),
28
+ nullable=False)
29
+ op.alter_column('transactions', 'name_description',
30
+ existing_type=sa.VARCHAR(),
31
+ nullable=False)
32
+ op.alter_column('transactions', 'amount',
33
+ existing_type=sa.DOUBLE_PRECISION(precision=53),
34
+ nullable=False)
35
+ op.alter_column('transactions', 'type',
36
+ existing_type=sa.VARCHAR(),
37
+ nullable=False)
38
+ op.add_column('users', sa.Column('hashed_password', sa.String(), nullable=False))
39
+ op.add_column('users', sa.Column('is_deleted', sa.Boolean(), nullable=False))
40
+ op.alter_column('users', 'name',
41
+ existing_type=sa.VARCHAR(),
42
+ nullable=False)
43
+ op.alter_column('users', 'email',
44
+ existing_type=sa.VARCHAR(),
45
+ nullable=False)
46
+ # ### end Alembic commands ###
47
+
48
+
49
+ def downgrade() -> None:
50
+ # ### commands auto generated by Alembic - please adjust! ###
51
+ op.alter_column('users', 'email',
52
+ existing_type=sa.VARCHAR(),
53
+ nullable=True)
54
+ op.alter_column('users', 'name',
55
+ existing_type=sa.VARCHAR(),
56
+ nullable=True)
57
+ op.drop_column('users', 'is_deleted')
58
+ op.drop_column('users', 'hashed_password')
59
+ op.alter_column('transactions', 'type',
60
+ existing_type=sa.VARCHAR(),
61
+ nullable=True)
62
+ op.alter_column('transactions', 'amount',
63
+ existing_type=sa.DOUBLE_PRECISION(precision=53),
64
+ nullable=True)
65
+ op.alter_column('transactions', 'name_description',
66
+ existing_type=sa.VARCHAR(),
67
+ nullable=True)
68
+ op.alter_column('transactions', 'category',
69
+ existing_type=sa.VARCHAR(),
70
+ nullable=True)
71
+ op.alter_column('transactions', 'transaction_date',
72
+ existing_type=postgresql.TIMESTAMP(),
73
+ nullable=True)
74
+ # ### end Alembic commands ###