This commit is contained in:
Waylon Walker 2023-06-09 16:04:58 -05:00
parent 1a0bf1adb9
commit c3db85a209
No known key found for this signature in database
GPG key ID: 66E2BF2B4190EFE4
21 changed files with 647 additions and 658 deletions

View file

@ -1,18 +1,9 @@
from typing import Annotated
from fastapi import APIRouter, Depends, HTTPException
from sqlmodel import SQLModel, Session
from fastapi import APIRouter, Depends
from sqlmodel import SQLModel
from learn_sql_model.api.user import oauth2_scheme
from learn_sql_model.api.websocket_connection_manager import manager
from learn_sql_model.config import Config, get_config
from learn_sql_model.models.hero import (
Hero,
HeroCreate,
HeroDelete,
HeroRead,
HeroUpdate,
)
from learn_sql_model.config import get_config, get_session
from learn_sql_model.models.hero import Hero, HeroCreate, HeroRead, HeroUpdate
hero_router = APIRouter()
@ -22,52 +13,73 @@ def on_startup() -> None:
SQLModel.metadata.create_all(get_config().database.engine)
@hero_router.get("/items/")
async def read_items(token: Annotated[str, Depends(oauth2_scheme)]):
return {"token": token}
@hero_router.get("/hero/{id}")
async def get_hero(id: int, config: Config = Depends(get_config)) -> Hero:
@hero_router.get("/hero/{hero_id}")
async def get_hero(
*,
session: Session = Depends(get_session),
hero_id: int,
) -> HeroRead:
"get one hero"
return Hero().get(id=id, config=config)
@hero_router.get("/h/{id}")
async def get_h(id: int, config: Config = Depends(get_config)) -> Hero:
"get one hero"
return Hero().get(id=id, config=config)
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero
@hero_router.post("/hero/")
async def post_hero(hero: HeroCreate) -> HeroRead:
async def post_hero(
*,
session: Session = Depends(get_session),
hero: HeroCreate,
) -> HeroRead:
"read all the heros"
config = get_config()
hero = hero.post(config=config)
db_hero = Hero.from_orm(hero)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
await manager.broadcast({hero.json()}, id=1)
return hero
return db_hero
@hero_router.patch("/hero/")
async def patch_hero(hero: HeroUpdate) -> HeroRead:
async def patch_hero(
*,
session: Session = Depends(get_session),
hero: HeroUpdate,
) -> HeroRead:
"read all the heros"
config = get_config()
hero = hero.update(config=config)
db_hero = session.get(Hero, hero.id)
if not db_hero:
raise HTTPException(status_code=404, detail="Hero not found")
for key, value in hero.dict(exclude_unset=True).items():
setattr(db_hero, key, value)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
await manager.broadcast({hero.json()}, id=1)
return hero
return db_hero
@hero_router.delete("/hero/{hero_id}")
async def delete_hero(hero_id: int):
async def delete_hero(
*,
session: Session = Depends(get_session),
hero_id: int,
):
"read all the heros"
hero = HeroDelete(id=hero_id)
config = get_config()
hero = hero.delete(config=config)
hero = session.get(Hero, hero_id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
await manager.broadcast(f"deleted hero {hero_id}", id=1)
return hero
return {"ok": True}
@hero_router.get("/heros/")
async def get_heros(config: Config = Depends(get_config)) -> list[Hero]:
async def get_heros(
*,
session: Session = Depends(get_session),
) -> list[Hero]:
"get all heros"
return Hero().get(config=config)
return HeroRead.list(session=session)

View file

@ -1,45 +0,0 @@
from typing import Annotated
from fastapi import APIRouter, Depends
from sqlmodel import SQLModel
from learn_sql_model.api.user import oauth2_scheme
from learn_sql_model.config import Config, get_config
from learn_sql_model.models.new import new
new_router = APIRouter()
@new_router.on_event("startup")
def on_startup() -> None:
SQLModel.metadata.create_all(get_config().database.engine)
@new_router.get("/items/")
async def read_items(token: Annotated[str, Depends(oauth2_scheme)]):
return {"token": token}
@new_router.get("/new/{id}")
def get_new(id: int, config: Config = Depends(get_config)) -> new:
"get one new"
return new().get(id=id, config=config)
@new_router.get("/h/{id}")
def get_h(id: int, config: Config = Depends(get_config)) -> new:
"get one new"
return new().get(id=id, config=config)
@new_router.post("/new/")
def post_new(new: new, config: Config = Depends(get_config)) -> new:
"read all the news"
new.post(config=config)
return new
@new_router.get("/news/")
def get_news(config: Config = Depends(get_config)) -> list[new]:
"get all news"
return new().get(config=config)

View file

@ -69,4 +69,4 @@ async def websocket_endpoint(websocket: WebSocket):
except WebSocketDisconnect:
manager.disconnect(websocket, id)
await manager.broadcast(f"Client #{client_id} left the chat", id)
await manager.broadcast(f"Client #{id} left the chat", id)

View file

@ -1,3 +1,4 @@
import httpx
from rich.console import Console
import typer
import uvicorn
@ -38,15 +39,11 @@ def status(
help="show the log messages",
),
):
import httpx
config = get_config()
host = config.api_server.host
port = config.api_server.port
url = f"http://{host}:{port}/docs"
url = config.api_client.url
try:
r = httpx.get(url)
r = httpx.get(url + "/docs")
if r.status_code == 200:
Console().print(f"[green]API: ([gold1]{url}[green]) is running")
else:
@ -59,7 +56,7 @@ def status(
Console().print(
f"[green]database: ([gold1]{config.database.engine}[green]) is running"
)
except Exception as e:
except Exception:
Console().print(
f"[red]database: ([gold1]{config.database.engine}[red]) is not running"
)

View file

@ -2,13 +2,11 @@ import sys
from typing import List, Optional, Union
from engorgio import engorgio
import httpx
from rich.console import Console
import typer
from learn_sql_model.config import Config, get_config
from learn_sql_model.config import get_config
from learn_sql_model.factories.hero import HeroFactory
from learn_sql_model.factories.pet import PetFactory
from learn_sql_model.models.hero import (
Hero,
HeroCreate,
@ -19,6 +17,8 @@ from learn_sql_model.models.hero import (
hero_app = typer.Typer()
config = get_config()
@hero_app.callback()
def hero():
@ -28,12 +28,10 @@ def hero():
@hero_app.command()
@engorgio(typer=True)
def get(
id: Optional[int] = typer.Argument(default=None),
config: Config = None,
hero_id: Optional[int] = typer.Argument(default=None),
) -> Union[Hero, List[Hero]]:
"get one hero"
config.init()
hero = HeroRead.get(id=id, config=config)
hero = HeroRead.get(id=hero_id)
Console().print(hero)
return hero
@ -42,12 +40,11 @@ def get(
@engorgio(typer=True)
def list(
where: Optional[str] = None,
config: Config = None,
offset: int = 0,
limit: Optional[int] = None,
) -> Union[Hero, List[Hero]]:
"get one hero"
hero = HeroRead.list(config=config, where=where, offset=offset, limit=limit)
"list many heros"
hero = HeroRead.list(where=where, offset=offset, limit=limit)
Console().print(hero)
return hero
@ -56,65 +53,39 @@ def list(
@engorgio(typer=True)
def create(
hero: HeroCreate,
config: Config = None,
) -> Hero:
"read all the heros"
r = httpx.post(
f"{config.api_client.url}/hero/",
json=hero.dict(),
)
if r.status_code != 200:
raise RuntimeError(f"{r.status_code}:\n {r.text}")
# hero = hero.post(config=config)
# Console().print(hero)
# return hero
"create one hero"
hero.post()
@hero_app.command()
@engorgio(typer=True)
def update(
hero: HeroUpdate,
config: Config = None,
) -> Hero:
"read all the heros"
r = httpx.patch(
f"{config.api_client.url}/hero/",
json=hero.dict(),
)
if r.status_code != 200:
raise RuntimeError(f"{r.status_code}:\n {r.text}")
"update one hero"
hero.update()
@hero_app.command()
@engorgio(typer=True)
def delete(
hero: HeroDelete,
config: Config = None,
) -> Hero:
"read all the heros"
r = httpx.delete(
f"{config.api_client.url}/hero/{hero.id}",
)
if r.status_code != 200:
raise RuntimeError(f"{r.status_code}:\n {r.text}")
"delete a hero by id"
hero.delete()
@hero_app.command()
@engorgio(typer=True)
def populate(
hero: Hero,
n: int = 10,
) -> Hero:
"read all the heros"
config = get_config()
"Create n number of heros"
if config.env == "prod":
Console().print("populate is not supported in production")
sys.exit(1)
for hero in HeroFactory().batch(n):
pet = PetFactory().build()
hero.pet = pet
Console().print(hero)
hero.post(config=config)
hero = HeroCreate(**hero.dict())
hero.post()

View file

@ -44,7 +44,6 @@ def create_revision(
prompt=True,
),
):
alembic_cfg = Config("alembic.ini")
alembic.command.revision(
config=alembic_cfg,
@ -63,7 +62,6 @@ def checkout(
),
revision: str = typer.Option("head"),
):
alembic_cfg = Config("alembic.ini")
alembic.command.upgrade(config=alembic_cfg, revision="head")

View file

@ -1,107 +0,0 @@
import sys
from typing import List, Optional, Union
from engorgio import engorgio
from rich.console import Console
import typer
from learn_sql_model.config import Config, get_config
from learn_sql_model.factories.new import newFactory
from learn_sql_model.factories.pet import PetFactory
from learn_sql_model.models.new import (
new,
newCreate,
newDelete,
newRead,
newUpdate,
)
new_app = typer.Typer()
@new_app.callback()
def new():
"model cli"
@new_app.command()
@engorgio(typer=True)
def get(
id: Optional[int] = typer.Argument(default=None),
config: Config = None,
) -> Union[new, List[new]]:
"get one new"
config.init()
new = newRead.get(id=id, config=config)
Console().print(new)
return new
@new_app.command()
@engorgio(typer=True)
def list(
where: Optional[str] = None,
config: Config = None,
offset: int = 0,
limit: Optional[int] = None,
) -> Union[new, List[new]]:
"get one new"
new = newRead.list(config=config, where=where, offset=offset, limit=limit)
Console().print(new)
return new
@new_app.command()
@engorgio(typer=True)
def create(
new: newCreate,
config: Config = None,
) -> new:
"read all the news"
# config.init()
new = new.post(config=config)
Console().print(new)
return new
@new_app.command()
@engorgio(typer=True)
def update(
new: newUpdate,
config: Config = None,
) -> new:
"read all the news"
new = new.update(config=config)
Console().print(new)
return new
@new_app.command()
@engorgio(typer=True)
def delete(
new: newDelete,
config: Config = None,
) -> new:
"read all the news"
# config.init()
new = new.delete(config=config)
return new
@new_app.command()
@engorgio(typer=True)
def populate(
new: new,
n: int = 10,
) -> new:
"read all the news"
config = get_config()
if config.env == "prod":
Console().print("populate is not supported in production")
sys.exit(1)
for new in newFactory().batch(n):
pet = PetFactory().build()
new.pet = pet
Console().print(new)
new.post(config=config)

View file

@ -30,7 +30,6 @@ class ApiClient(BaseModel):
class Database:
def __init__(self, config: "Config" = None) -> None:
if config is None:
self.config = get_config()
else:
self.config = config
@ -71,17 +70,26 @@ class Config(BaseSettings):
def get_database(config: Config = None) -> Database:
if config is None:
config = get_config()
return Database(config)
def get_config(overrides: dict = {}) -> Config:
raw_config = load("learn_sql_model")
config = Config(**raw_config, **overrides)
return config
def get_session(config: Config = None) -> "Session":
with Session(config.database.engine) as session:
yield session
async def reset_db_state(config: Config = None) -> None:
if config is None:
config = get_config()
config.database.db._state._state.set(db_state_default.copy())
config.database.db._state._state.set(config.database.db_state_default.copy())
config.database.db._state.reset()
@ -96,7 +104,4 @@ def get_db(config: Config = None, reset_db_state=Depends(reset_db_state)):
config.database.db.close()
def get_config(overrides: dict = {}) -> Config:
raw_config = load("learn_sql_model")
config = Config(**raw_config, **overrides)
return config
config = get_config()

View file

@ -1,14 +0,0 @@
from faker import Faker
from polyfactory.factories.pydantic_factory import ModelFactory
from learn_sql_model.models.new import new
class newFactory(ModelFactory[new]):
__model__ = new
__faker__ = Faker(locale="en_US")
__set_as_default_factory_for_type__ = True
id = None
__random_seed__ = 10

View file

@ -21,7 +21,6 @@ class FastModel(SQLModel):
def post(self, config: "Config" = None) -> None:
if config is None:
config = get_config()
self.pre_post()
@ -36,7 +35,6 @@ class FastModel(SQLModel):
self, id: int = None, config: "Config" = None, where=None
) -> Optional["FastModel"]:
if config is None:
config = get_config()
self.pre_get()

View file

@ -1,10 +1,11 @@
from typing import Optional
from fastapi import HTTPException
import httpx
from pydantic import BaseModel
from sqlmodel import Field, Relationship, SQLModel, Session, select
from learn_sql_model.config import Config
from learn_sql_model.config import config, get_session
from learn_sql_model.models.pet import Pet
@ -25,14 +26,13 @@ class Hero(HeroBase, table=True):
class HeroCreate(HeroBase):
...
def post(self, config: Config) -> Hero:
config.init()
with Session(config.database.engine) as session:
db_hero = Hero.from_orm(self)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero
def post(self) -> Hero:
r = httpx.post(
f"{config.api_client.url}/hero/",
json=self.dict(),
)
if r.status_code != 200:
raise RuntimeError(f"{r.status_code}:\n {r.text}")
class HeroRead(HeroBase):
@ -41,10 +41,8 @@ class HeroRead(HeroBase):
@classmethod
def get(
cls,
config: Config,
id: int,
) -> Hero:
with config.database.session as session:
hero = session.get(Hero, id)
if not hero:
@ -54,25 +52,25 @@ class HeroRead(HeroBase):
@classmethod
def list(
self,
config: Config,
where=None,
offset=0,
limit=None,
session: Session = get_session,
) -> Hero:
# with config.database.session as session:
with config.database.session as session:
statement = select(Hero)
if where != "None":
from sqlmodel import text
statement = select(Hero)
if where != "None" and where is not None:
from sqlmodel import text
statement = statement.where(text(where))
statement = statement.offset(offset).limit(limit)
heroes = session.exec(statement).all()
statement = statement.where(text(where))
statement = statement.offset(offset).limit(limit)
heroes = session.exec(statement).all()
return heroes
class HeroUpdate(SQLModel):
# id is required to get the hero
# id is required to update the hero
id: int
# all other fields, must match the model, but with Optional default None
@ -84,30 +82,22 @@ class HeroUpdate(SQLModel):
pet_id: Optional[int] = Field(default=None, foreign_key="pet.id")
pet: Optional[Pet] = Relationship(back_populates="hero")
def update(self, config: Config) -> Hero:
with Session(config.database.engine) as session:
db_hero = session.get(Hero, self.id)
if not db_hero:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = self.dict(exclude_unset=True)
for key, value in hero_data.items():
if value is not None:
setattr(db_hero, key, value)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero
def update(self) -> Hero:
r = httpx.patch(
f"{config.api_client.url}/hero/",
json=self.dict(),
)
if r.status_code != 200:
raise RuntimeError(f"{r.status_code}:\n {r.text}")
class HeroDelete(BaseModel):
id: int
def delete(self, config: Config) -> Hero:
config.init()
with Session(config.database.engine) as session:
hero = session.get(Hero, self.id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
session.delete(hero)
session.commit()
return {"ok": True}
def delete(self) -> Hero:
r = httpx.delete(
f"{config.api_client.url}/hero/{self.id}",
)
if r.status_code != 200:
raise RuntimeError(f"{r.status_code}:\n {r.text}")
return {"ok": True}

View file

@ -1,99 +0,0 @@
from typing import Optional
from fastapi import HTTPException
from pydantic import BaseModel
from sqlmodel import Field, Relationship, SQLModel, Session, select
from learn_sql_model.config import Config
from learn_sql_model.models.pet import Pet
class newBase(SQLModel, table=False):
class new(newBase, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
class newCreate(newBase):
...
def post(self, config: Config) -> new:
config.init()
with Session(config.database.engine) as session:
db_new = new.from_orm(self)
session.add(db_new)
session.commit()
session.refresh(db_new)
return db_new
class newRead(newBase):
id: int
@classmethod
def get(
cls,
config: Config,
id: int,
) -> new:
with config.database.session as session:
new = session.get(new, id)
if not new:
raise HTTPException(status_code=404, detail="new not found")
return new
@classmethod
def list(
self,
config: Config,
where=None,
offset=0,
limit=None,
) -> new:
with config.database.session as session:
statement = select(new)
if where != "None":
from sqlmodel import text
statement = statement.where(text(where))
statement = statement.offset(offset).limit(limit)
newes = session.exec(statement).all()
return newes
class newUpdate(SQLModel):
# id is required to get the new
id: int
# all other fields, must match the model, but with Optional default None
def update(self, config: Config) -> new:
with Session(config.database.engine) as session:
db_new = session.get(new, self.id)
if not db_new:
raise HTTPException(status_code=404, detail="new not found")
new_data = self.dict(exclude_unset=True)
for key, value in new_data.items():
if value is not None:
setattr(db_new, key, value)
session.add(db_new)
session.commit()
session.refresh(db_new)
return db_new
class newDelete(BaseModel):
id: int
def delete(self, config: Config) -> new:
config.init()
with Session(config.database.engine) as session:
new = session.get(new, self.id)
if not new:
raise HTTPException(status_code=404, detail="new not found")
session.delete(new)
session.commit()
return {"ok": True}