Skip to content

Commit 714bdd2

Browse files
add user and request + test (#179)
* add user and request + test * fix * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fix * add foreign key * fix * fix * fix * fix for adding ner user * change type to string * update to use uuid * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * add migrations --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 079340e commit 714bdd2

File tree

5 files changed

+194
-0
lines changed

5 files changed

+194
-0
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"""empty message
2+
3+
Revision ID: d92996388b65
4+
Revises: caea7b5cf249
5+
Create Date: 2023-05-11 15:07:43.373248
6+
7+
"""
8+
import sqlalchemy as sa
9+
from alembic import op
10+
from sqlalchemy.dialects import postgresql
11+
12+
# revision identifiers, used by Alembic.
13+
revision = "d92996388b65"
14+
down_revision = "caea7b5cf249"
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade(): # noqa
20+
# ### commands auto generated by Alembic - please adjust! ###
21+
op.create_table(
22+
"user",
23+
sa.Column(
24+
"uuid", postgresql.UUID(), server_default=sa.text("gen_random_uuid()"), nullable=False
25+
),
26+
sa.Column("email", sa.String(), nullable=True),
27+
sa.PrimaryKeyConstraint("uuid"),
28+
)
29+
op.create_table(
30+
"api_request",
31+
sa.Column("created_utc", sa.DateTime(timezone=True), nullable=True),
32+
sa.Column(
33+
"uuid", postgresql.UUID(), server_default=sa.text("gen_random_uuid()"), nullable=False
34+
),
35+
sa.Column("url", sa.String(), nullable=True),
36+
sa.Column("user_uuid", postgresql.UUID(), nullable=True),
37+
sa.ForeignKeyConstraint(
38+
["user_uuid"],
39+
["user.uuid"],
40+
),
41+
sa.PrimaryKeyConstraint("uuid"),
42+
)
43+
op.create_index(op.f("ix_api_request_user_uuid"), "api_request", ["user_uuid"], unique=False)
44+
# ### end Alembic commands ###
45+
46+
47+
def downgrade(): # noqa
48+
# ### commands auto generated by Alembic - please adjust! ###
49+
op.drop_index(op.f("ix_api_request_user_uuid"), table_name="api_request")
50+
op.drop_table("api_request")
51+
op.drop_table("user")
52+
# ### end Alembic commands ###

nowcasting_datamodel/models/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
The primary keys could be 'gsp_id' and 'target_datetime_utc'.
2121
"""
2222

23+
from .api import * # noqa F403
2324
from .forecast import * # noqa F403
2425
from .gsp import * # noqa F403
2526
from .metric import * # noqa F403

nowcasting_datamodel/models/api.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
""" Pydantic and Sqlalchemy models for the database
2+
3+
The following class are made
4+
1. User
5+
2. APIRequest
6+
7+
"""
8+
9+
from typing import Optional
10+
11+
from pydantic import Field
12+
from sqlalchemy import (
13+
Column,
14+
ForeignKey,
15+
String,
16+
func,
17+
)
18+
from sqlalchemy.dialects.postgresql import UUID
19+
from sqlalchemy.orm import relationship
20+
21+
from nowcasting_datamodel.models.base import Base_Forecast
22+
from nowcasting_datamodel.models.utils import CreatedMixin, EnhancedBaseModel
23+
24+
25+
########
26+
# 1. User
27+
########
28+
class UserSQL(Base_Forecast):
29+
"""ML model that is being used"""
30+
31+
__tablename__ = "user"
32+
33+
uuid = Column(UUID, primary_key=True, server_default=func.gen_random_uuid())
34+
email = Column(String)
35+
36+
api_request = relationship("APIRequestSQL", back_populates="user")
37+
38+
39+
class User(EnhancedBaseModel):
40+
"""ML model that is being used"""
41+
42+
email: Optional[str] = Field(..., description="The name of the model", index=True)
43+
44+
def to_orm(self) -> UserSQL:
45+
"""Change model to MLModelSQL"""
46+
return UserSQL(
47+
email=self.email,
48+
)
49+
50+
51+
########
52+
# 2. APIRequest
53+
########
54+
class APIRequestSQL(Base_Forecast, CreatedMixin):
55+
"""Information about what API route was called"""
56+
57+
__tablename__ = "api_request"
58+
59+
uuid = Column(UUID, primary_key=True, server_default=func.gen_random_uuid())
60+
url = Column(String)
61+
62+
user_uuid = Column(UUID, ForeignKey("user.uuid"), index=True)
63+
user = relationship("UserSQL", back_populates="api_request")
64+
65+
66+
class APIRequest(EnhancedBaseModel):
67+
"""Information about the input data that was used to create the forecast"""
68+
69+
url: str = Field(..., description="The url that was called")
70+
user: Optional[User] = Field(
71+
None,
72+
description="The user associated with this api call",
73+
)
74+
75+
def to_orm(self) -> APIRequestSQL:
76+
"""Change model to APIRequestSQL"""
77+
return APIRequestSQL(
78+
url=self.url,
79+
user=self.user.to_orm() if self.user is not None else None,
80+
)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
""" Read user"""
2+
import logging
3+
4+
from sqlalchemy.orm.session import Session
5+
6+
from nowcasting_datamodel.models.api import UserSQL
7+
8+
logger = logging.getLogger(__name__)
9+
10+
11+
def get_user(session: Session, email: str) -> UserSQL:
12+
"""
13+
Get metric object from database
14+
15+
:param session: database session
16+
:param email: email of user
17+
18+
return: One Metric SQl object
19+
20+
"""
21+
22+
# start main query
23+
query = session.query(UserSQL)
24+
25+
# filter on name
26+
query = query.filter(UserSQL.email == email)
27+
28+
# get all results
29+
users = query.all()
30+
31+
if len(users) == 0:
32+
logger.debug(f"User for name {email} does not exist so going to add it")
33+
34+
user = UserSQL(email=email)
35+
36+
session.add(user)
37+
session.commit()
38+
39+
else:
40+
user = users[0]
41+
42+
return user

tests/read/test_read_user.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from nowcasting_datamodel.models import UserSQL
2+
from nowcasting_datamodel.read.read_user import get_user
3+
4+
5+
def test_get_user(db_session):
6+
db_session.add(UserSQL(email="[email protected]"))
7+
8+
user = get_user(session=db_session, email="[email protected]")
9+
assert user.email == "[email protected]"
10+
assert len(db_session.query(UserSQL).all()) == 1
11+
12+
13+
def test_get_new_metric(db_session):
14+
assert len(db_session.query(UserSQL).all()) == 0
15+
16+
_ = get_user(session=db_session, email="[email protected]")
17+
user = get_user(session=db_session, email="[email protected]")
18+
assert user.email == "[email protected]"
19+
assert len(db_session.query(UserSQL).all()) == 1

0 commit comments

Comments
 (0)