first
This commit is contained in:
0
src/personal_info/__init__.py
Normal file
0
src/personal_info/__init__.py
Normal file
19
src/personal_info/app.py
Normal file
19
src/personal_info/app.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
app = FastAPI (
|
||||
title='personal_info',
|
||||
description='Personal Information Service',
|
||||
version='1.0'
|
||||
)
|
||||
|
||||
@app.get('/health')
|
||||
async def health() -> str:
|
||||
return 'ok'
|
||||
|
||||
|
||||
from personal_info.routers import persons
|
||||
|
||||
app.include(persons.router)
|
||||
|
||||
return app
|
||||
15
src/personal_info/config.py
Normal file
15
src/personal_info/config.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from functools import lru_cache
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseSettings, PostgresDsn
|
||||
|
||||
class Settings(BaseSettings):
|
||||
database_url: Optional[PostgresDsn]
|
||||
|
||||
@lru_cache
|
||||
def get_settings() -> Settings:
|
||||
settings = Settings() # type: ignore
|
||||
print('333333333333333333333333333333333333333333')
|
||||
print(settings)
|
||||
#CONTINUE
|
||||
return settings
|
||||
0
src/personal_info/db/__init__.py
Normal file
0
src/personal_info/db/__init__.py
Normal file
17
src/personal_info/db/models.py
Normal file
17
src/personal_info/db/models.py
Normal file
@@ -0,0 +1,17 @@
|
||||
import uuid
|
||||
from typing import Any
|
||||
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy.sql.schema import ForeignKey
|
||||
|
||||
Base: Any = declarative_base()
|
||||
|
||||
class Person(Base):
|
||||
__tablename__ = 'people'
|
||||
|
||||
id = sa.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||
first_name = sa.Column(sa.Text, nullable=False)
|
||||
last_name = sa.Column(sa.Text, nullable=False)
|
||||
1
src/personal_info/db/schemas/__init__.py
Normal file
1
src/personal_info/db/schemas/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .person import *
|
||||
16
src/personal_info/db/schemas/person.py
Normal file
16
src/personal_info/db/schemas/person.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic.types import UUID4
|
||||
|
||||
class Person(BaseModel):
|
||||
id: UUID4
|
||||
first_name: str
|
||||
last_name: str
|
||||
|
||||
class PersonCreate(Person):
|
||||
pass
|
||||
|
||||
class PersonDetail(Person):
|
||||
pass
|
||||
23
src/personal_info/db/session.py
Normal file
23
src/personal_info/db/session.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from functools import lru_cache
|
||||
from typing import Generator
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import scoped_session, sessionmaker
|
||||
|
||||
from personal_info.config import get_settings
|
||||
|
||||
engine = create_engine(get_settings().database_url, pool_pre_ping=True)
|
||||
|
||||
@lru_cache
|
||||
def create_session() -> scoped_session:
|
||||
Session = scoped_session(
|
||||
sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
)
|
||||
return Session
|
||||
|
||||
def get_session() -> Generator[scoped_session, None, None]:
|
||||
Session = create_session()
|
||||
try:
|
||||
yield Session
|
||||
finally:
|
||||
Session.remove()
|
||||
3
src/personal_info/main.py
Normal file
3
src/personal_info/main.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from personal_info.app import create_app
|
||||
|
||||
app = create_app()
|
||||
0
src/personal_info/routers/__init__.py
Normal file
0
src/personal_info/routers/__init__.py
Normal file
27
src/personal_info/routers/persons.py
Normal file
27
src/personal_info/routers/persons.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from fastapi import Depends
|
||||
from fastapi.routing import APIRouter
|
||||
from pydantic.types import UUID4
|
||||
|
||||
from personal_info.db import models
|
||||
from personal_info.db.schemas import Person, PersonDetail
|
||||
from personal_info.services import PersonService, get_persons_service
|
||||
|
||||
router = APIrouter(prefix='/people')
|
||||
|
||||
@router.get('/', response_model=List[Person])
|
||||
async def list_persons(
|
||||
persons_service: PersonService = Depends(get_persons_service),
|
||||
) -> List[models.Person]:
|
||||
return persons_service.list()
|
||||
|
||||
@router.get('/{person_id}', response_model=PersonDetail)
|
||||
async def get_person(
|
||||
person_id: UUID4, persons_service: PersonService = Depends(get_persons_service)
|
||||
) -> Optional[models.Person]:
|
||||
return persons_service.get(person_id)
|
||||
|
||||
@router.post('/', status_code=201, response_model=PersonDetail)
|
||||
async def create_person(
|
||||
person: PersonCreate, persons_service: PersonService = Depends(get_persons_service)
|
||||
) -> models.Person:
|
||||
return persons_service.create(person)
|
||||
11
src/personal_info/services/__init__.py
Normal file
11
src/personal_info/services/__init__.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from fastapi import Depends
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from personal_info.db.session import get_session
|
||||
|
||||
from .people import PersonService
|
||||
|
||||
def get_persons_service(db_session: Session = Depends(get_session)) -> PersonService:
|
||||
return PersonService(db_session)
|
||||
|
||||
__all__ = ('get_persons_service')
|
||||
52
src/personal_info/services/base.py
Normal file
52
src/personal_info/services/base.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from typing import Any, Generic, List, Optional, Type, TypeVar
|
||||
|
||||
import sqlalchemy
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy.orm import Session
|
||||
from starlette.exceptions import HTTPException
|
||||
|
||||
from personal_info.db.models import Base
|
||||
|
||||
ModelType = TypeVar('ModelType', bound=Base)
|
||||
CreateSchemaType = TypeVar('CreateSchemaType', bound=BaseModel)
|
||||
UpdateSchemaType = TypeVar('UpdateSchemaType', bound=BaseModel)
|
||||
|
||||
class BaseService(Generic[ModelType, CreateSchemaType, UpdateSchemaType]):
|
||||
def __init__(self, model: Type[ModelType], db_session: Session):
|
||||
self.model = model
|
||||
self.db_session = db_session
|
||||
|
||||
def get(self, id: Any) -> Optional[ModelType]:
|
||||
obj: Optional[ModelType] = self.db_session.get(self.model, id)
|
||||
if obj is None:
|
||||
raise HTTPException(status_code=404, detail='NotFound')
|
||||
return obj
|
||||
|
||||
def list(self) -> List[ModelType]:
|
||||
objs: List[ModelType] = self.db_session.query(self.model).all()
|
||||
return objs
|
||||
|
||||
def create(self, obj: CreateSchemaType) -> ModelType:
|
||||
db_obj: ModelType = self.model(**obj.dict())
|
||||
self.db_session.add(db_obj)
|
||||
try:
|
||||
self.db_session.commit()
|
||||
except sqlalchemy.exc.IntegrityError as e:
|
||||
self.db_session.rollback()
|
||||
if 'duplicate key' in str(e):
|
||||
raise HTTPException(status_code=409, detail='Conflict Error')
|
||||
else:
|
||||
raise e
|
||||
return db_obj
|
||||
|
||||
def update(self, id: Any, obj: UpdateSchemaType) -> Optional[ModelType]:
|
||||
db_obj = self.get(id)
|
||||
for column, value in obj.dict(exclude_unset=True).items():
|
||||
setattr(db_obj, column, value)
|
||||
self.db_session.commit()
|
||||
return db_obj
|
||||
|
||||
def delete(self, id: Any) -> None:
|
||||
db_obj = self.db_session.get(self.model, id)
|
||||
self.db_session.delete(db_obj)
|
||||
self.db_session.commit()
|
||||
19
src/personal_info/services/people.py
Normal file
19
src/personal_info/services/people.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from personal_info.db.models import Person
|
||||
from personal_info.db.schemas import PersonCreate
|
||||
|
||||
from personal_info.services.base import BaseService
|
||||
|
||||
class PersonService(BaseService[Person, PersonCreate, Any]):
|
||||
def __init__(self, db_session: Session):
|
||||
super(PersonService, self).__init__(Person, db_session)
|
||||
|
||||
def create(self, obj: PersonCreate) -> Person:
|
||||
person: Person = Person()
|
||||
self.db_session.add(person)
|
||||
self.db_session.flush()
|
||||
self.db_session.commit()
|
||||
return person
|
||||
Reference in New Issue
Block a user