basic sql models for inventory app

main
Ryan Rix 2021-09-18 17:19:50 -07:00
commit 000e4dad77
6 changed files with 246 additions and 0 deletions

1
.envrc Normal file
View File

@ -0,0 +1 @@
use nix

15
mach.nix Normal file
View File

@ -0,0 +1,15 @@
# [[file:poka-ijo.org::*=requirements.txt= and mach-nix setup][=requirements.txt= and mach-nix setup:2]]
{ ... }:
let
mach-nix = import (builtins.fetchGit {
url = "https://github.com/DavHau/mach-nix";
ref = "refs/tags/3.3.0";
}) {
pkgs = import <nixpkgs> {};
};
in
mach-nix.mkPythonShell {
requirements = builtins.readFile ./requirements.txt;
_.websockets.patchPhase = ""; #
}
# =requirements.txt= and mach-nix setup:2 ends here

177
poka-ijo.org Normal file
View File

@ -0,0 +1,177 @@
:PROPERTIES:
:ID: 20210918-pokaijo
:ROAM_ALIASES: "FastAPI Personal Inventory" "My Inventory Application"
:END:
#+TITLE: Poka Ijo
#+filetags: :Project:Programming:
Poka Ijo is a catalog of my nearby things. Poka Ijo is [[id:tokipona][Tokipona]] for "nearby things", and it's a simple FastAPI application designed to run on my laptop or server and be used on my phone to quickly capture things in to my inventory, and run queries to determine where things are, and to find things that I should replace, donate, or maintain.
* Frontmatter
:LOGBOOK:
CLOCK: [2021-09-18 Sat 16:33]--[2021-09-18 Sat 16:56] => 0:23
:END:
** =requirements.txt= and mach-nix setup
#+begin_src txt :tangle requirements.txt :comments none
fastapi
uvicorn[standard]
sqlmodel
#+end_src
#+begin_src nix -r :tangle mach.nix
{ ... }:
let
mach-nix = import (builtins.fetchGit {
url = "https://github.com/DavHau/mach-nix";
ref = "refs/tags/3.3.0";
}) {
pkgs = import <nixpkgs> {};
};
in
mach-nix.mkPythonShell {
requirements = builtins.readFile ./requirements.txt;
_.websockets.patchPhase = ""; # (ref:websockets)
}
#+end_src
in [[(websockets)]] reference, [[file:~/.nix-defexpr/channels/nixpkgs/pkgs/development/python-modules/websockets/default.nix::patchPhase = ''][patchPhase in websockets is broken...]]
[[https://github.com/DavHau/mach-nix/issues/324][sqlmodel]] is uninstallable in =mach-nix= right now, just use venv...
#+begin_src nix :tangle shell.nix
let
pkgs = import <nixpkgs> {};
in pkgs.mkShell {
packages = [
pkgs.python3
];
}
#+end_src
** FastAPI Server initialization
#+begin_src :tangle server.py
#+end_src
* Data Models
:LOGBOOK:
CLOCK: [2021-09-18 Sat 16:56]--[2021-09-18 Sat 16:58] => 0:02
:END:
#+begin_src python :tangle poka_ijo/models.py :noweb yes
from typing import Optional
from sqlmodel import Field, List, Relationship, SQLModel
<<ThingTagLink>>
<<Thing>>
<<Tag>>
<<Attachment>>
<<create_db_and_tables>>
#+end_src
** =Thing= is a discrete object or collection in my Inventory
#+NAME: thing-desc
God the definition of what a "thing" is loose-goosey and probably just gets figured out ad-hoc.
If i have "my aa-batteries", i want to be able to say how many i have left without doing something so insane as tracking each one; but a simple "count" field isn't quite so smart unless we also have a "split", which adds all sorts of struggle in the data model.
- name
- serial number
- description
- count of items in the collection
- Things have-many Attachments, usually images but maybe PDF documentation or receipt scans.
These can just go on my disk, in a [[id:cce/syncthing][Syncthing]] share.
- Things have Many-to-Many with Tags which are simple strings for queryin's sake.
#+begin_src python :noweb-ref Thing :noweb yes
class Thing(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str
serial_no: str
description: str
count: int
attachments: List["Attachment"] = Relationship(back_populates="thing")
tags: List["Tag"] = Relationship(back_populates="thing", link_model=ThingTagLink)
#+end_src
** =Tag= is a simple string which can be joined against for a Good Time
#+begin_src python :noweb-ref Tag
class Tag(SQLModel, table=True):
id: Optiona[int] = Field(default=None, primary_key=True)
tag: str
things: List["Thing"] = Relationship(back_populates="thing", link_model=ThingTagLink)
#+end_src
** =ThingTagLink= is a Many-to-Many link between Things and Tags
[[https://sqlmodel.tiangolo.com/tutorial/many-to-many/create-models-with-link/][SQLModel docs]] on many-to-many:
#+begin_src python :noweb-ref ThingTagLink
class ThingTagLink(SQLModel, table=True):
thing_id: Optional[int] = Field(
default=None, foreign_key="thing.id", primary_key=True
)
tag_id: Optional[int] = Field(
default=None, foreign_key="tag.id", primary_key=True
)
#+end_src
** =Attachment= is a file that is relevant to a Thing
They'll be pictures of the thing I am capturing in to the system, they'll be PDFs of documentation or scans of receipts and inserts.
make sure this is relative to a configurable root in configuration for [[id:cce/syncthing][Syncthing]]ability.
#+begin_src python :noweb-ref Attachment
class Attachment(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str
path: str
thing_id: Optional[int] = Field(default=None, foreign_key="thing.id")
thing: Optional[Thing] = Relationship(back_populates="attachments")
#+end_src
** Model table creation
SQLModel gives us this "for free". Eventually this will go in a configuration file.
#+begin_src python :noweb-ref create_db_and_tables
sqlite_file_name = "poka-ijo.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"
engine = create_engine(sqlite_url, echo=True)
def create_db_and_tables():
SQLModel.metadata.create_all(engine)
#+end_src
* NEXT mobile-friendly capture interface
- image upload
- fast metadata creation
- "insert into"
- "move to"
* NEXT index view
* NEXT search field
just a quick name -> thing search, maybe description, too
* NEXT dynamic autocomplete for object names, inline move-to, insert-into.
* NEXT sqlite queries
these can just stay in the notebook and run against the (read-only!!!!!! I promise!!!!) database on my laptop, unless i have mobile usecases for them that can't be solved with a linux shell access on my phone? idonno.
* NEXT org exporter?
things exported with description with links inserted, maybe even local links to the images.

41
poka_ijo/models.py Normal file
View File

@ -0,0 +1,41 @@
# [[file:../poka-ijo.org::*Data Models][Data Models:1]]
from typing import Optional
from sqlmodel import Field, List, Relationship, SQLModel
class ThingTagLink(SQLModel, table=True):
thing_id: Optional[int] = Field(
default=None, foreign_key="thing.id", primary_key=True
)
tag_id: Optional[int] = Field(
default=None, foreign_key="tag.id", primary_key=True
)
class Thing(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str
serial_no: str
description: str
count: int
attachments: List["Attachment"] = Relationship(back_populates="thing")
tags: List["Tag"] = Relationship(back_populates="thing", link_model=ThingTagLink)
class Tag(SQLModel, table=True):
id: Optiona[int] = Field(default=None, primary_key=True)
tag: str
things: List["Thing"] = Relationship(back_populates="thing", link_model=ThingTagLink)
class Attachment(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str
path: str
thing_id: Optional[int] = Field(default=None, foreign_key="thing.id")
thing: Optional[Thing] = Relationship(back_populates="attachments")
sqlite_file_name = "poka-ijo.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"
engine = create_engine(sqlite_url, echo=True)
def create_db_and_tables():
SQLModel.metadata.create_all(engine)
# Data Models:1 ends here

3
requirements.txt Normal file
View File

@ -0,0 +1,3 @@
fastapi
uvicorn[standard]
sqlmodel

9
shell.nix Normal file
View File

@ -0,0 +1,9 @@
# [[file:poka-ijo.org::*=requirements.txt= and mach-nix setup][=requirements.txt= and mach-nix setup:3]]
let
pkgs = import <nixpkgs> {};
in pkgs.mkShell {
packages = [
pkgs.python3
];
}
# =requirements.txt= and mach-nix setup:3 ends here