Testys commited on
Commit
2333542
1 Parent(s): 60cc4ec

Making migrations to code after removing huggingface secrets

Browse files
alembic.ini ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # A generic, single database configuration.
2
+
3
+ [alembic]
4
+ # path to migration scripts
5
+ # Use forward slashes (/) also on windows to provide an os agnostic path
6
+ script_location = alembic
7
+
8
+ # template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
9
+ # Uncomment the line below if you want the files to be prepended with date and time
10
+ # see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file
11
+ # for all available tokens
12
+ # file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s
13
+
14
+ # sys.path path, will be prepended to sys.path if present.
15
+ # defaults to the current working directory.
16
+ prepend_sys_path = .
17
+
18
+ # timezone to use when rendering the date within the migration file
19
+ # as well as the filename.
20
+ # If specified, requires the python>=3.9 or backports.zoneinfo library.
21
+ # Any required deps can installed by adding `alembic[tz]` to the pip requirements
22
+ # string value is passed to ZoneInfo()
23
+ # leave blank for localtime
24
+ # timezone =
25
+
26
+ # max length of characters to apply to the "slug" field
27
+ # truncate_slug_length = 40
28
+
29
+ # set to 'true' to run the environment during
30
+ # the 'revision' command, regardless of autogenerate
31
+ # revision_environment = false
32
+
33
+ # set to 'true' to allow .pyc and .pyo files without
34
+ # a source .py file to be detected as revisions in the
35
+ # versions/ directory
36
+ # sourceless = false
37
+
38
+ # version location specification; This defaults
39
+ # to alembic/versions. When using multiple version
40
+ # directories, initial revisions must be specified with --version-path.
41
+ # The path separator used here should be the separator specified by "version_path_separator" below.
42
+ # version_locations = %(here)s/bar:%(here)s/bat:alembic/versions
43
+
44
+ # version path separator; As mentioned above, this is the character used to split
45
+ # version_locations. The default within new alembic.ini files is "os", which uses os.pathsep.
46
+ # If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas.
47
+ # Valid values for version_path_separator are:
48
+ #
49
+ # version_path_separator = :
50
+ # version_path_separator = ;
51
+ # version_path_separator = space
52
+ version_path_separator = os # Use os.pathsep. Default configuration used for new projects.
53
+
54
+ # set to 'true' to search source files recursively
55
+ # in each "version_locations" directory
56
+ # new in Alembic version 1.10
57
+ # recursive_version_locations = false
58
+
59
+ # the output encoding used when revision files
60
+ # are written from script.py.mako
61
+ # output_encoding = utf-8
62
+
63
+ sqlalchemy.url = postgresql://snapfeast_db_owner:4fLiupkCsN5E@ep-fancy-glade-a57hqsn3-pooler.us-east-2.aws.neon.tech/snapdb?sslmode=require
64
+
65
+
66
+ [post_write_hooks]
67
+ # post_write_hooks defines scripts or Python functions that are run
68
+ # on newly generated revision scripts. See the documentation for further
69
+ # detail and examples
70
+
71
+ # format using "black" - use the console_scripts runner, against the "black" entrypoint
72
+ # hooks = black
73
+ # black.type = console_scripts
74
+ # black.entrypoint = black
75
+ # black.options = -l 79 REVISION_SCRIPT_FILENAME
76
+
77
+ # lint with attempts to fix using "ruff" - use the exec runner, execute a binary
78
+ # hooks = ruff
79
+ # ruff.type = exec
80
+ # ruff.executable = %(here)s/.venv/bin/ruff
81
+ # ruff.options = --fix REVISION_SCRIPT_FILENAME
82
+
83
+ # Logging configuration
84
+ [loggers]
85
+ keys = root,sqlalchemy,alembic
86
+
87
+ [handlers]
88
+ keys = console
89
+
90
+ [formatters]
91
+ keys = generic
92
+
93
+ [logger_root]
94
+ level = WARN
95
+ handlers = console
96
+ qualname =
97
+
98
+ [logger_sqlalchemy]
99
+ level = WARN
100
+ handlers =
101
+ qualname = sqlalchemy.engine
102
+
103
+ [logger_alembic]
104
+ level = INFO
105
+ handlers =
106
+ qualname = alembic
107
+
108
+ [handler_console]
109
+ class = StreamHandler
110
+ args = (sys.stderr,)
111
+ level = NOTSET
112
+ formatter = generic
113
+
114
+ [formatter_generic]
115
+ format = %(levelname)-5.5s [%(name)s] %(message)s
116
+ datefmt = %H:%M:%S
alembic/README ADDED
@@ -0,0 +1 @@
 
 
1
+ Generic single-database configuration.
alembic/env.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from logging.config import fileConfig
2
+
3
+ from sqlalchemy import engine_from_config
4
+ from sqlalchemy import pool
5
+
6
+ from alembic import context
7
+ from core.database import Base
8
+
9
+ # this is the Alembic Config object, which provides
10
+ # access to the values within the .ini file in use.
11
+ config = context.config
12
+
13
+ # Interpret the config file for Python logging.
14
+ # This line sets up loggers basically.
15
+ if config.config_file_name is not None:
16
+ fileConfig(config.config_file_name)
17
+
18
+ # add your model's MetaData object here
19
+ # for 'autogenerate' support
20
+ # from myapp import mymodel
21
+ # target_metadata = mymodel.Base.metadata
22
+ from users.models import User, UserEmbeddings
23
+ from orders.models import Meal, Order
24
+ target_metadata = Base.metadata
25
+
26
+ # other values from the config, defined by the needs of env.py,
27
+ # can be acquired:
28
+ # my_important_option = config.get_main_option("my_important_option")
29
+ # ... etc.
30
+
31
+
32
+ def run_migrations_offline() -> None:
33
+ """Run migrations in 'offline' mode.
34
+
35
+ This configures the context with just a URL
36
+ and not an Engine, though an Engine is acceptable
37
+ here as well. By skipping the Engine creation
38
+ we don't even need a DBAPI to be available.
39
+
40
+ Calls to context.execute() here emit the given string to the
41
+ script output.
42
+
43
+ """
44
+ url = config.get_main_option("sqlalchemy.url")
45
+ context.configure(
46
+ url=url,
47
+ target_metadata=target_metadata,
48
+ literal_binds=True,
49
+ dialect_opts={"paramstyle": "named"},
50
+ )
51
+
52
+ with context.begin_transaction():
53
+ context.run_migrations()
54
+
55
+
56
+ def run_migrations_online() -> None:
57
+ """Run migrations in 'online' mode.
58
+
59
+ In this scenario we need to create an Engine
60
+ and associate a connection with the context.
61
+
62
+ """
63
+ connectable = engine_from_config(
64
+ config.get_section(config.config_ini_section, {}),
65
+ prefix="sqlalchemy.",
66
+ poolclass=pool.NullPool,
67
+ )
68
+
69
+ with connectable.connect() as connection:
70
+ context.configure(
71
+ connection=connection, target_metadata=target_metadata
72
+ )
73
+
74
+ with context.begin_transaction():
75
+ context.run_migrations()
76
+
77
+
78
+ if context.is_offline_mode():
79
+ run_migrations_offline()
80
+ else:
81
+ run_migrations_online()
alembic/script.py.mako ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """${message}
2
+
3
+ Revision ID: ${up_revision}
4
+ Revises: ${down_revision | comma,n}
5
+ Create Date: ${create_date}
6
+
7
+ """
8
+ from typing import Sequence, Union
9
+
10
+ from alembic import op
11
+ import sqlalchemy as sa
12
+ ${imports if imports else ""}
13
+
14
+ # revision identifiers, used by Alembic.
15
+ revision: str = ${repr(up_revision)}
16
+ down_revision: Union[str, None] = ${repr(down_revision)}
17
+ branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
18
+ depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
19
+
20
+
21
+ def upgrade() -> None:
22
+ ${upgrades if upgrades else "pass"}
23
+
24
+
25
+ def downgrade() -> None:
26
+ ${downgrades if downgrades else "pass"}
alembic/versions/5dceb6aede3b_initiate_database_migration.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Initiate Database Migration
2
+
3
+ Revision ID: 5dceb6aede3b
4
+ Revises:
5
+ Create Date: 2024-08-20 17:33:42.696641
6
+
7
+ """
8
+ from typing import Sequence, Union
9
+
10
+ from alembic import op
11
+ import sqlalchemy as sa
12
+
13
+
14
+ # revision identifiers, used by Alembic.
15
+ revision: str = '5dceb6aede3b'
16
+ down_revision: Union[str, None] = None
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.create_table('meals',
24
+ sa.Column('id', sa.Integer(), nullable=False),
25
+ sa.Column('name', sa.String(), nullable=False),
26
+ sa.Column('description', sa.String(), nullable=False),
27
+ sa.Column('price', sa.Float(), nullable=False),
28
+ sa.Column('category', sa.String(), nullable=True),
29
+ sa.PrimaryKeyConstraint('id')
30
+ )
31
+ op.create_index(op.f('ix_meals_id'), 'meals', ['id'], unique=False)
32
+ op.create_index(op.f('ix_meals_name'), 'meals', ['name'], unique=True)
33
+ op.create_table('users',
34
+ sa.Column('id', sa.Integer(), nullable=False),
35
+ sa.Column('email', sa.String(), nullable=False),
36
+ sa.Column('username', sa.String(), nullable=False),
37
+ sa.Column('hashed_password', sa.String(), nullable=False),
38
+ sa.Column('first_name', sa.String(), nullable=True),
39
+ sa.Column('last_name', sa.String(), nullable=True),
40
+ sa.Column('age', sa.Integer(), nullable=True),
41
+ sa.Column('preferences', sa.ARRAY(sa.String()), nullable=True),
42
+ sa.Column('is_active', sa.Boolean(), nullable=True),
43
+ sa.Column('is_admin', sa.Boolean(), nullable=True),
44
+ sa.Column('updated_at', sa.DateTime(), nullable=True),
45
+ sa.Column('created_at', sa.DateTime(), nullable=True),
46
+ sa.PrimaryKeyConstraint('id')
47
+ )
48
+ op.create_index(op.f('ix_users_email'), 'users', ['email'], unique=True)
49
+ op.create_index(op.f('ix_users_id'), 'users', ['id'], unique=False)
50
+ op.create_index(op.f('ix_users_username'), 'users', ['username'], unique=True)
51
+ op.create_table('orders',
52
+ sa.Column('id', sa.Integer(), nullable=False),
53
+ sa.Column('user_id', sa.Integer(), nullable=False),
54
+ sa.Column('meal_id', sa.Integer(), nullable=False),
55
+ sa.Column('quantity', sa.Integer(), nullable=False),
56
+ sa.Column('timestamp', sa.DateTime(), nullable=True),
57
+ sa.ForeignKeyConstraint(['meal_id'], ['meals.id'], ),
58
+ sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
59
+ sa.PrimaryKeyConstraint('id')
60
+ )
61
+ op.create_index(op.f('ix_orders_id'), 'orders', ['id'], unique=False)
62
+ op.create_index(op.f('ix_orders_meal_id'), 'orders', ['meal_id'], unique=False)
63
+ op.create_index(op.f('ix_orders_user_id'), 'orders', ['user_id'], unique=False)
64
+ op.create_table('user_embeddings',
65
+ sa.Column('id', sa.Integer(), nullable=False),
66
+ sa.Column('user_id', sa.Integer(), nullable=False),
67
+ sa.Column('embeddings', sa.ARRAY(sa.Float()), nullable=False),
68
+ sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
69
+ sa.PrimaryKeyConstraint('id'),
70
+ sa.UniqueConstraint('user_id')
71
+ )
72
+ op.create_index(op.f('ix_user_embeddings_id'), 'user_embeddings', ['id'], unique=False)
73
+ # ### end Alembic commands ###
74
+
75
+
76
+ def downgrade() -> None:
77
+ # ### commands auto generated by Alembic - please adjust! ###
78
+ op.drop_index(op.f('ix_user_embeddings_id'), table_name='user_embeddings')
79
+ op.drop_table('user_embeddings')
80
+ op.drop_index(op.f('ix_orders_user_id'), table_name='orders')
81
+ op.drop_index(op.f('ix_orders_meal_id'), table_name='orders')
82
+ op.drop_index(op.f('ix_orders_id'), table_name='orders')
83
+ op.drop_table('orders')
84
+ op.drop_index(op.f('ix_users_username'), table_name='users')
85
+ op.drop_index(op.f('ix_users_id'), table_name='users')
86
+ op.drop_index(op.f('ix_users_email'), table_name='users')
87
+ op.drop_table('users')
88
+ op.drop_index(op.f('ix_meals_name'), table_name='meals')
89
+ op.drop_index(op.f('ix_meals_id'), table_name='meals')
90
+ op.drop_table('meals')
91
+ # ### end Alembic commands ###
auth/responses.py CHANGED
@@ -4,4 +4,4 @@ class TokenResponse(BaseModel):
4
  access_token: str
5
  refresh_token: str
6
  token_type: str = "Bearer"
7
- expires_in: int
 
4
  access_token: str
5
  refresh_token: str
6
  token_type: str = "Bearer"
7
+ expires_in: int
core/config.py CHANGED
@@ -8,14 +8,14 @@ load_dotenv()
8
 
9
  class Settings(BaseSettings):
10
  # Database settings
11
- DATABASE_USER: str = os.getenv("PG_USER")
12
- DATABASE_PASSWORD: str = os.getenv("PG_PASSWORD")
13
- DATABASE_HOST: str = os.getenv("PG_HOST")
14
- DATABASE_PORT: str = os.getenv("PG_PORT")
15
- DATABASE_NAME: str = os.getenv("PG_NAME")
 
16
 
17
  # JWT settings
18
- JWT_SECRET_KEY: str = os.getenv("JWT_SECRET")
19
  JWT_ALGORITHM: str = "HS256"
20
  ACCESS_TOKEN_EXPIRE_MINUTES: int = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", "30"))
21
  REFRESH_TOKEN_EXPIRE_DAYS: int = int(os.getenv("REFRESH_TOKEN_EXPIRE_DAYS", "7"))
 
8
 
9
  class Settings(BaseSettings):
10
  # Database settings
11
+ DATABASE_USER: str = os.getenv("PG_USER", "snapfeast_db_owner")
12
+ DATABASE_PASSWORD: str = os.getenv("PG_PASSWORD", "4fLiupkCsN5E")
13
+ DATABASE_HOST: str = os.getenv("PG_HOST", "ep-fancy-glade-a57hqsn3-pooler.us-east-2.aws.neon.tech")
14
+ DATABASE_PORT: int = os.getenv("PG_PORT", 5432)
15
+ DATABASE_NAME: str = os.getenv("PG_DATABASE", "snapdb")
16
+ JWT_SECRET_KEY: str = os.getenv("JWT_SECRET", "EjQFIgOWHqrzjZc23CfcY6RWi2F2yUMr67DRJlpkjSU")
17
 
18
  # JWT settings
 
19
  JWT_ALGORITHM: str = "HS256"
20
  ACCESS_TOKEN_EXPIRE_MINUTES: int = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", "30"))
21
  REFRESH_TOKEN_EXPIRE_DAYS: int = int(os.getenv("REFRESH_TOKEN_EXPIRE_DAYS", "7"))
core/database.py CHANGED
@@ -11,8 +11,7 @@ engine = create_engine(
11
  pool_size=5,
12
  pool_pre_ping=True,
13
  pool_recycle=300,
14
- max_overflow=0
15
-
16
  )
17
 
18
  SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
 
11
  pool_size=5,
12
  pool_pre_ping=True,
13
  pool_recycle=300,
14
+ max_overflow=0
 
15
  )
16
 
17
  SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
orders/models.py CHANGED
@@ -1,25 +1,28 @@
1
  # models.py
2
- from sqlalchemy import Column, ForeignKey, Integer, String, Float, JSON, ARRAY
3
  from sqlalchemy.orm import relationship
4
  from core.database import Base
 
5
 
6
  class Meal(Base):
7
  __tablename__ = "meals"
8
 
9
  id = Column(Integer, primary_key=True, index=True)
10
- name = Column(String, index=True)
11
- description = Column(String)
12
- price = Column(Float)
13
-
14
- orders = relationship("Order", back_populates="meal")
 
15
 
16
  class Order(Base):
17
  __tablename__ = "orders"
18
 
19
  id = Column(Integer, primary_key=True, index=True)
20
- user_id = Column(Integer, ForeignKey("users.id"))
21
- meal_id = Column(Integer, ForeignKey("meals.id"))
22
- quantity = Column(Integer)
 
23
 
24
  user = relationship("User", back_populates="orders")
25
  meal = relationship("Meal", back_populates="orders")
 
1
  # models.py
2
+ from sqlalchemy import Column, ForeignKey, Integer, String, Float, DateTime
3
  from sqlalchemy.orm import relationship
4
  from core.database import Base
5
+ from datetime import datetime
6
 
7
  class Meal(Base):
8
  __tablename__ = "meals"
9
 
10
  id = Column(Integer, primary_key=True, index=True)
11
+ name = Column(String, unique=True, nullable=False, index=True)
12
+ description = Column(String, nullable=False)
13
+ price = Column(Float, nullable=False)
14
+ category = Column(String, nullable=True) # Optional: To classify meals
15
+
16
+ orders = relationship("Order", back_populates="meal", cascade="all, delete-orphan")
17
 
18
  class Order(Base):
19
  __tablename__ = "orders"
20
 
21
  id = Column(Integer, primary_key=True, index=True)
22
+ user_id = Column(Integer, ForeignKey("users.id"), nullable=False, index=True)
23
+ meal_id = Column(Integer, ForeignKey("meals.id"), nullable=False, index=True)
24
+ quantity = Column(Integer, nullable=False)
25
+ timestamp = Column(DateTime, default=datetime.utcnow) # To track when the order was made
26
 
27
  user = relationship("User", back_populates="orders")
28
  meal = relationship("Meal", back_populates="orders")
orders/routes.py CHANGED
@@ -25,33 +25,50 @@ meal_router = APIRouter(
25
  def health_check():
26
  return {"status": "ok"}
27
 
28
- @meal_router.get("/", response_model=MealBase)
 
29
  async def meal_create(data: MealCreate, db: Session = Depends(get_db)):
30
  return create_meal(db, data)
31
 
 
32
  @meal_router.get("/", response_model=List[MealBase])
33
  def meals_get(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
34
  return get_meals(db, skip=skip, limit=limit)
35
 
 
36
  @meal_router.get("/{meal_id}", response_model=MealBase)
37
  def meal_get(meal_id: int, db: Session = Depends(get_db)):
38
- return get_meal(db, meal_id)
 
 
 
 
39
 
40
  @meal_router.put("/{meal_id}", response_model=MealBase)
41
  def meal_update(meal_id: int, data: MealUpdate, db: Session = Depends(get_db)):
42
- return update_meal(db, meal_id, data)
 
 
 
 
43
 
44
  @meal_router.delete("/{meal_id}", response_model=MealBase)
45
  def meal_delete(meal_id: int, db: Session = Depends(get_db)):
46
- return delete_meal(db, meal_id)
 
 
 
 
47
 
48
- @order_router.post("/", response_model=OrderBase)
49
  def create_order(order: OrderCreate, current_user: OrderBase = Depends(get_current_user), db: Session = Depends(get_db)):
50
  return create_user_order(db, order, current_user.id)
51
 
 
52
  @order_router.get("/", response_model=List[OrderBase])
53
- def read_user_orders(skip: int = 0, limit: int = 100, current_user: OrderBase = Depends(get_current_user), db: Session = Depends(get_db)):
54
- return get_user_orders(db, user_id=current_user.id, skip=skip, limit=limit)
 
55
 
56
  @meal_router.get("/recommendations/", response_model=List[MealBase])
57
  async def get_recommendations(current_user: OrderBase = Depends(get_current_user), db: Session = Depends(get_db)):
 
25
  def health_check():
26
  return {"status": "ok"}
27
 
28
+
29
+ @meal_router.post("/", response_model=MealBase, status_code=status.HTTP_201_CREATED)
30
  async def meal_create(data: MealCreate, db: Session = Depends(get_db)):
31
  return create_meal(db, data)
32
 
33
+
34
  @meal_router.get("/", response_model=List[MealBase])
35
  def meals_get(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
36
  return get_meals(db, skip=skip, limit=limit)
37
 
38
+
39
  @meal_router.get("/{meal_id}", response_model=MealBase)
40
  def meal_get(meal_id: int, db: Session = Depends(get_db)):
41
+ meal = get_meal(db, meal_id)
42
+ if not meal:
43
+ raise HTTPException(status_code=404, detail="Meal not found")
44
+ return meal
45
+
46
 
47
  @meal_router.put("/{meal_id}", response_model=MealBase)
48
  def meal_update(meal_id: int, data: MealUpdate, db: Session = Depends(get_db)):
49
+ meal = update_meal(db, meal_id, data)
50
+ if not meal:
51
+ raise HTTPException(status_code=404, detail="Meal not found")
52
+ return meal
53
+
54
 
55
  @meal_router.delete("/{meal_id}", response_model=MealBase)
56
  def meal_delete(meal_id: int, db: Session = Depends(get_db)):
57
+ meal = delete_meal(db, meal_id)
58
+ if not meal:
59
+ raise HTTPException(status_code=404, detail="Meal not found")
60
+ return meal
61
+
62
 
63
+ @order_router.post("/", response_model=OrderBase, status_code=status.HTTP_201_CREATED)
64
  def create_order(order: OrderCreate, current_user: OrderBase = Depends(get_current_user), db: Session = Depends(get_db)):
65
  return create_user_order(db, order, current_user.id)
66
 
67
+
68
  @order_router.get("/", response_model=List[OrderBase])
69
+ def get_orders(current_user: OrderBase = Depends(get_current_user), skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
70
+ return get_user_orders(db, current_user.id, skip=skip, limit=limit)
71
+
72
 
73
  @meal_router.get("/recommendations/", response_model=List[MealBase])
74
  async def get_recommendations(current_user: OrderBase = Depends(get_current_user), db: Session = Depends(get_db)):
orders/schemas.py CHANGED
@@ -1,9 +1,9 @@
1
- from pydantic import BaseModel
2
 
3
  class MealBase(BaseModel):
4
  name: str
5
  description: str
6
- price: float
7
 
8
  class MealCreate(MealBase):
9
  pass
@@ -18,15 +18,15 @@ class Meal(MealBase):
18
  orm_mode = True
19
 
20
  class OrderBase(BaseModel):
21
- quantity: int
22
 
23
  class OrderCreate(OrderBase):
24
  meal_id: int
25
 
26
  class Order(OrderBase):
27
  id: int
28
- user_id: int # Corrected type annotation
29
- meal_id: int # Corrected type annotation
30
 
31
  class Config:
32
  orm_mode = True
 
1
+ from pydantic import BaseModel, Field
2
 
3
  class MealBase(BaseModel):
4
  name: str
5
  description: str
6
+ price: float = Field(..., gt=0, description="Price must be greater than zero")
7
 
8
  class MealCreate(MealBase):
9
  pass
 
18
  orm_mode = True
19
 
20
  class OrderBase(BaseModel):
21
+ quantity: int = Field(..., gt=0, description="Quantity must be greater than zero")
22
 
23
  class OrderCreate(OrderBase):
24
  meal_id: int
25
 
26
  class Order(OrderBase):
27
  id: int
28
+ user_id: int
29
+ meal_id: int
30
 
31
  class Config:
32
  orm_mode = True
orders/services.py CHANGED
@@ -1,44 +1,46 @@
1
  from sqlalchemy.orm import Session
2
- from typing import List
3
  from orders.schemas import MealCreate, MealUpdate, OrderCreate
4
  from orders.models import Meal, Order
5
 
6
- def get_meals(db: Session, skip: int = 0, limit: int = 100):
7
  return db.query(Meal).offset(skip).limit(limit).all()
8
 
9
- def create_meal(db: Session, meal: MealCreate):
10
  db_meal = Meal(**meal.dict())
11
  db.add(db_meal)
12
  db.commit()
13
  db.refresh(db_meal)
14
  return db_meal
15
 
16
- def get_meal(db: Session, meal_id: int):
17
  return db.query(Meal).filter(Meal.id == meal_id).first()
18
 
19
- def update_meal(db: Session, meal_id: int, meal: MealUpdate):
20
  db_meal = db.query(Meal).filter(Meal.id == meal_id).first()
21
- if db_meal:
22
- update_data = meal.dict(exclude_unset=True)
23
- for key, value in update_data.items():
24
- setattr(db_meal, key, value)
25
- db.commit()
26
- db.refresh(db_meal)
 
27
  return db_meal
28
 
29
- def delete_meal(db: Session, meal_id: int):
30
  db_meal = db.query(Meal).filter(Meal.id == meal_id).first()
31
- if db_meal:
32
- db.delete(db_meal)
33
- db.commit()
 
34
  return db_meal
35
 
36
- def create_user_order(db: Session, order: OrderCreate, user_id: int):
37
  db_order = Order(**order.dict(), user_id=user_id)
38
  db.add(db_order)
39
  db.commit()
40
  db.refresh(db_order)
41
  return db_order
42
 
43
- def get_user_orders(db: Session, user_id: int, skip: int = 0, limit: int = 100):
44
  return db.query(Order).filter(Order.user_id == user_id).offset(skip).limit(limit).all()
 
1
  from sqlalchemy.orm import Session
2
+ from typing import List, Optional
3
  from orders.schemas import MealCreate, MealUpdate, OrderCreate
4
  from orders.models import Meal, Order
5
 
6
+ def get_meals(db: Session, skip: int = 0, limit: int = 100) -> List[Meal]:
7
  return db.query(Meal).offset(skip).limit(limit).all()
8
 
9
+ def create_meal(db: Session, meal: MealCreate) -> Meal:
10
  db_meal = Meal(**meal.dict())
11
  db.add(db_meal)
12
  db.commit()
13
  db.refresh(db_meal)
14
  return db_meal
15
 
16
+ def get_meal(db: Session, meal_id: int) -> Optional[Meal]:
17
  return db.query(Meal).filter(Meal.id == meal_id).first()
18
 
19
+ def update_meal(db: Session, meal_id: int, meal: MealUpdate) -> Optional[Meal]:
20
  db_meal = db.query(Meal).filter(Meal.id == meal_id).first()
21
+ if not db_meal:
22
+ return None # Or raise an exception
23
+ update_data = meal.dict(exclude_unset=True)
24
+ for key, value in update_data.items():
25
+ setattr(db_meal, key, value)
26
+ db.commit()
27
+ db.refresh(db_meal)
28
  return db_meal
29
 
30
+ def delete_meal(db: Session, meal_id: int) -> Optional[Meal]:
31
  db_meal = db.query(Meal).filter(Meal.id == meal_id).first()
32
+ if not db_meal:
33
+ return None # Or raise an exception
34
+ db.delete(db_meal)
35
+ db.commit()
36
  return db_meal
37
 
38
+ def create_user_order(db: Session, order: OrderCreate, user_id: int) -> Order:
39
  db_order = Order(**order.dict(), user_id=user_id)
40
  db.add(db_order)
41
  db.commit()
42
  db.refresh(db_order)
43
  return db_order
44
 
45
+ def get_user_orders(db: Session, user_id: int, skip: int = 0, limit: int = 100) -> List[Order]:
46
  return db.query(Order).filter(Order.user_id == user_id).offset(skip).limit(limit).all()
users/models.py CHANGED
@@ -10,10 +10,10 @@ class User(Base):
10
  email = Column(String, unique=True, index=True, nullable=False)
11
  username = Column(String, unique=True, index=True, nullable=False)
12
  hashed_password = Column(String, nullable=False)
13
- first_name = Column(String)
14
- last_name = Column(String)
15
- age = Column(Integer)
16
- preferences = Column(ARRAY(String))
17
  is_active = Column(Boolean, default=True)
18
  is_admin = Column(Boolean, default=False)
19
  updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
@@ -29,4 +29,4 @@ class UserEmbeddings(Base):
29
  user_id = Column(Integer, ForeignKey("users.id"), unique=True, nullable=False)
30
  embeddings = Column(ARRAY(Float), nullable=False)
31
 
32
- user = relationship("User", back_populates="embeddings")
 
10
  email = Column(String, unique=True, index=True, nullable=False)
11
  username = Column(String, unique=True, index=True, nullable=False)
12
  hashed_password = Column(String, nullable=False)
13
+ first_name = Column(String, nullable=True)
14
+ last_name = Column(String, nullable=True)
15
+ age = Column(Integer, nullable=True)
16
+ preferences = Column(ARRAY(String), nullable=True)
17
  is_active = Column(Boolean, default=True)
18
  is_admin = Column(Boolean, default=False)
19
  updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
 
29
  user_id = Column(Integer, ForeignKey("users.id"), unique=True, nullable=False)
30
  embeddings = Column(ARRAY(Float), nullable=False)
31
 
32
+ user = relationship("User", back_populates="embeddings")
users/schemas.py CHANGED
@@ -9,7 +9,6 @@ class UserBase(BaseModel):
9
  email: EmailStr
10
  age: Optional[int] = Field(None, ge=0, le=120)
11
  preferences: Optional[List[str]] = None
12
- is_active: bool = True
13
 
14
  class UserCreate(UserBase):
15
  password: str = Field(..., min_length=8)
@@ -44,4 +43,4 @@ class UserEmbeddings(UserEmbeddingsBase):
44
  user_id: int
45
 
46
  class Config:
47
- orm_mode = True
 
9
  email: EmailStr
10
  age: Optional[int] = Field(None, ge=0, le=120)
11
  preferences: Optional[List[str]] = None
 
12
 
13
  class UserCreate(UserBase):
14
  password: str = Field(..., min_length=8)
 
43
  user_id: int
44
 
45
  class Config:
46
+ orm_mode = True