This commit is contained in:
Waylon Walker 2023-06-06 11:50:49 -05:00
parent 839cbd0dc0
commit a9ee4a2bd8
No known key found for this signature in database
GPG key ID: 66E2BF2B4190EFE4
7 changed files with 199 additions and 31 deletions

View file

@ -1,9 +1,17 @@
FROM python:3.10 FROM python:3.10
ENV DEBIAIN_FRONTEND=noninteractive ENV DEBIAIN_FRONTEND=noninteractive
ENV PATH="$PATH:/root/.local/bin:/root/.cargo/bin" ENV PATH="$PATH:/home/smoke/.local/bin:/home/smoke/.cargo/bin"
ENV SHELL=zsh ENV SHELL=zsh
ENV USER=root ENV USER=smoke
ARG SMOKE_UID=1000
ARG SMOKE_GID=1000
RUN groupadd -f -g ${SMOKE_GID} smoke && \
useradd -d /home/smoke -s /bin/bash -g ${SMOKE_GID} -u ${SMOKE_UID} smoke
RUN mkdir /home/smoke && chown -R smoke:smoke /home/smoke && mkdir /src && chown smoke:smoke /src
WORKDIR /home/smoke
RUN apt update && \ RUN apt update && \
@ -16,19 +24,21 @@ RUN apt update && \
stow \ stow \
zsh zsh
USER smoke
WORKDIR /root/downloads WORKDIR /home/smoke/downloads
RUN wget https://github.com/neovim/neovim/releases/download/nightly/nvim.appimage && \ RUN wget https://github.com/neovim/neovim/releases/download/nightly/nvim.appimage && \
mkdir -p /root/.local/bin && \ mkdir -p /home/smoke/.local/bin && \
chmod u+x /root/downloads/nvim.appimage && \ chmod u+x /home/smoke/downloads/nvim.appimage && \
/root/downloads/nvim.appimage --appimage-extract && \ /home/smoke/downloads/nvim.appimage --appimage-extract && \
rm -rf nvim.appimage && \ rm -rf nvim.appimage && \
ln -s ~/downloads/squashfs-root/usr/bin/nvim ~/.local/bin/nvim && \ ln -s ~/downloads/squashfs-root/usr/bin/nvim ~/.local/bin/nvim && \
cd ~ && \ cd ~ && \
git clone https://github.com/LazyVim/starter ~/.config/nvim && \ git clone https://github.com/LazyVim/starter ~/.config/nvim && \
nvim --headless -c 'quitall' nvim --headless -c 'quitall'
USER root
RUN curl -sS https://starship.rs/install.sh | sh -s -- -y RUN curl -sS https://starship.rs/install.sh | sh -s -- -y
RUN curl -L zellij.dev/launch | sh -s -- help RUN curl -L zellij.dev/launch | sh -s -- help
@ -43,6 +53,8 @@ RUN python3 -m pip install --upgrade pip && \
WORKDIR /app WORKDIR /app
USER smoke
## DUPLICATE from Dockerfile ## DUPLICATE from Dockerfile
## building FROM learn-sql-model will cause the cache to bust for every ## building FROM learn-sql-model will cause the cache to bust for every
## change, it needs to come after the dev installs. ## change, it needs to come after the dev installs.
@ -54,7 +66,7 @@ COPY . .
RUN python3 -m hatch env create && \ RUN python3 -m hatch env create && \
python3 -m hatch shell python3 -m hatch shell
RUN stow bin -t /root/ RUN stow bin -t /home/smoke/
COPY .env.dev.docker /app/.env.dev COPY .env.dev.docker /app/.env.dev

View file

@ -8,7 +8,13 @@ import typer
from learn_sql_model.config import Config, get_config from learn_sql_model.config import Config, get_config
from learn_sql_model.factories.hero import HeroFactory from learn_sql_model.factories.hero import HeroFactory
from learn_sql_model.factories.pet import PetFactory from learn_sql_model.factories.pet import PetFactory
from learn_sql_model.models.hero import Hero, HeroCreate from learn_sql_model.models.hero import (
Hero,
HeroCreate,
HeroDelete,
HeroRead,
HeroUpdate,
)
hero_app = typer.Typer() hero_app = typer.Typer()
@ -26,7 +32,7 @@ def get(
) -> Union[Hero, List[Hero]]: ) -> Union[Hero, List[Hero]]:
"get one hero" "get one hero"
config.init() config.init()
hero = Hero().get(id=id) hero = HeroRead.get(id=id, config=config)
Console().print(hero) Console().print(hero)
return hero return hero
@ -34,10 +40,13 @@ def get(
@hero_app.command() @hero_app.command()
@engorgio(typer=True) @engorgio(typer=True)
def list( def list(
where: Optional[str] = None,
config: Config = None, config: Config = None,
offset: int = 0,
limit: Optional[int] = None,
) -> Union[Hero, List[Hero]]: ) -> Union[Hero, List[Hero]]:
"get one hero" "get one hero"
hero = Hero().get() hero = HeroRead.list(config=config, where=where, offset=offset, limit=limit)
Console().print(hero) Console().print(hero)
return hero return hero
@ -49,9 +58,42 @@ def create(
config: Config = None, config: Config = None,
) -> Hero: ) -> Hero:
"read all the heros" "read all the heros"
config.init() # config.init()
hero = hero.post(config=config) hero = hero.post(config=config)
Console().print(hero) Console().print(hero)
return hero
# config.init()
# with Session(config.database.engine) as session:
# db_hero = Hero.from_orm(hero)
# session.add(db_hero)
# session.commit()
# session.refresh(db_hero)
# return db_hero
@hero_app.command()
@engorgio(typer=True)
def update(
hero: HeroUpdate,
config: Config = None,
) -> Hero:
"read all the heros"
hero = hero.update(config=config)
Console().print(hero)
return hero
@hero_app.command()
@engorgio(typer=True)
def delete(
hero: HeroDelete,
config: Config = None,
) -> Hero:
"read all the heros"
# config.init()
hero = hero.delete(config=config)
return hero
# Console().print(hero)
@hero_app.command() @hero_app.command()

View file

@ -1,6 +1,7 @@
import alembic import alembic
from alembic.config import Config
import typer import typer
from alembic.config import Config
from copier import run_auto
from learn_sql_model.cli.common import verbose_callback from learn_sql_model.cli.common import verbose_callback
@ -19,13 +20,24 @@ def model(
@model_app.command() @model_app.command()
def create_revision( def create(
verbose: bool = typer.Option( verbose: bool = typer.Option(
False, False,
callback=verbose_callback, callback=verbose_callback,
help="show the log messages", help="show the log messages",
), ),
message: str = typer.Option( template=Path('templates/model')
run_auto(template, Path('.'))
@ model_app.command()
def create_revision(
verbose: bool=typer.Option(
False,
callback=verbose_callback,
help="show the log messages",
),
message: str=typer.Option(
prompt=True, prompt=True,
), ),
): ):
@ -39,23 +51,23 @@ def create_revision(
alembic.command.upgrade(config=alembic_cfg, revision="head") alembic.command.upgrade(config=alembic_cfg, revision="head")
@model_app.command() @ model_app.command()
def checkout( def checkout(
verbose: bool = typer.Option( verbose: bool=typer.Option(
False, False,
callback=verbose_callback, callback=verbose_callback,
help="show the log messages", help="show the log messages",
), ),
revision: str = typer.Option("head"), revision: str=typer.Option("head"),
): ):
alembic_cfg = Config("alembic.ini") alembic_cfg = Config("alembic.ini")
alembic.command.upgrade(config=alembic_cfg, revision="head") alembic.command.upgrade(config=alembic_cfg, revision="head")
@model_app.command() @ model_app.command()
def populate( def populate(
verbose: bool = typer.Option( verbose: bool=typer.Option(
False, False,
callback=verbose_callback, callback=verbose_callback,
help="show the log messages", help="show the log messages",

View file

@ -43,7 +43,6 @@ class FastModel(SQLModel):
with config.database.session as session: with config.database.session as session:
if id is None: if id is None:
print("get all")
statement = select(self.__class__) statement = select(self.__class__)
if where is not None: if where is not None:
statement = statement.where(where).options() statement = statement.where(where).options()

View file

@ -1,12 +1,14 @@
from typing import Optional from typing import Optional
from sqlmodel import Field, Relationship from fastapi import HTTPException
from pydantic import BaseModel
from sqlmodel import Field, Relationship, SQLModel, Session, select
from learn_sql_model.models.fast_model import FastModel from learn_sql_model.config import Config
from learn_sql_model.models.pet import Pet from learn_sql_model.models.pet import Pet
class HeroBase(FastModel, table=False): class HeroBase(SQLModel, table=False):
name: str name: str
secret_name: str secret_name: str
age: Optional[int] = None age: Optional[int] = None
@ -23,14 +25,89 @@ class Hero(HeroBase, table=True):
class HeroCreate(HeroBase): 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
class HeroRead(HeroBase): class HeroRead(HeroBase):
id: Optional[int] = Field(default=None, primary_key=True) id: int
@classmethod
def get(
cls,
config: Config,
id: int,
) -> Hero:
with config.database.session as session:
hero = session.get(Hero, id)
if not hero:
raise HTTPException(status_code=404, detail="Hero not found")
return hero
@classmethod
def list(
self,
config: Config,
where=None,
offset=0,
limit=None,
) -> Hero:
with config.database.session as session:
statement = select(Hero)
if where != "None":
from sqlmodel import text
statement = statement.where(text(where))
statement = statement.offset(offset).limit(limit)
heroes = session.exec(statement).all()
return heroes
class HeroUpdate(HeroBase): class HeroUpdate(SQLModel):
... # id is required to get the hero
id: int
# all other fields, must match the model, but with Optional default None
name: Optional[str] = None
secret_name: Optional[str] = None
age: Optional[int] = None
shoe_size: Optional[int] = None
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
class HeroDelete(HeroBase): class HeroDelete(BaseModel):
id: Optional[int] = Field(default=None, primary_key=True) 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}

View file

@ -9,8 +9,27 @@ if TYPE_CHECKING:
from learn_sql_model.models.hero import Hero from learn_sql_model.models.hero import Hero
class Pet(FastModel, table=True): class PetBase(FastModel, table=False):
id: Optional[int] = Field(default=None, primary_key=True)
name: str = "Jim" name: str = "Jim"
birthday: Optional[datetime] = None birthday: Optional[datetime] = None
hero: "Hero" = Relationship(back_populates="pet") hero: "Hero" = Relationship(back_populates="pet")
class Pet(PetBase, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
class PetCreate(PetBase):
...
class PetRead(PetBase):
id: int
class PetUpdate(PetBase):
...
class PetDelete(PetBase):
id: int

View file

@ -0,0 +1,7 @@
_min_copier_version: v6.0.0b0
_exclude:
- README.md
- .git
- copier.yml
name:
type: str