db backend
This commit is contained in:
commit
ccc7eb22b2
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.pyc
|
||||
*.db
|
17
pyproject.toml
Normal file
17
pyproject.toml
Normal file
@ -0,0 +1,17 @@
|
||||
[project]
|
||||
name = "tt"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
"peewee>=3.17.8",
|
||||
"textual>=1.0.0",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
hello = "tt:hello"
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
2
src/tt/__init__.py
Normal file
2
src/tt/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
def hello() -> None:
|
||||
print("Hello from tt!")
|
81
src/tt/controller.py
Normal file
81
src/tt/controller.py
Normal file
@ -0,0 +1,81 @@
|
||||
from datetime import datetime
|
||||
from peewee import fn
|
||||
from .db import Task, Category, TaskStatus, db
|
||||
|
||||
|
||||
def add_task(
|
||||
text: str,
|
||||
category: str,
|
||||
status: str = TaskStatus.ZERO.value,
|
||||
due: datetime | None = None,
|
||||
type: str | None = None,
|
||||
) -> Task:
|
||||
"""
|
||||
Add a new task to the database.
|
||||
Returns the created task instance.
|
||||
"""
|
||||
with db.atomic():
|
||||
category_id = None
|
||||
if category:
|
||||
category, _ = Category.get_or_create(name=category)
|
||||
category_id = category.id
|
||||
task = Task.create(
|
||||
text=text, type=type, status=status, due=due, category_id=category_id
|
||||
)
|
||||
return task
|
||||
|
||||
|
||||
def update_task(
|
||||
task_id: int,
|
||||
text: str | None,
|
||||
type: str | None,
|
||||
status: str | None = None,
|
||||
due: datetime | None = None,
|
||||
) -> Task:
|
||||
with db.atomic():
|
||||
task = Task.get_by_id(task_id)
|
||||
|
||||
update_dict = {
|
||||
"text": text,
|
||||
"type": type,
|
||||
"due": due,
|
||||
"status": status,
|
||||
}
|
||||
if status not in [s.value for s in TaskStatus]:
|
||||
raise ValueError(f"Invalid status: {status}")
|
||||
|
||||
query = Task.update(update_dict).where(Task.id == task_id)
|
||||
query.execute()
|
||||
task = Task.get_by_id(task_id)
|
||||
return task
|
||||
|
||||
|
||||
def get_tasks(
|
||||
search_text: str | None = None,
|
||||
category: int | None = None,
|
||||
status: str | None = None,
|
||||
include_done: bool = False,
|
||||
) -> list[Task]:
|
||||
query = Task.select()
|
||||
|
||||
if search_text:
|
||||
query = query.where(fn.Lower(Task.text).contains(search_text.lower()))
|
||||
if category:
|
||||
query = query.where(Task.category == Category.get(name=category))
|
||||
if status:
|
||||
query = query.where(Task.status == status)
|
||||
|
||||
if not include_done:
|
||||
# by default, exclude done tasks
|
||||
query = query.where(Task.status != TaskStatus.DONE.value)
|
||||
|
||||
# order by due date (null last) and created date
|
||||
query = query.order_by(
|
||||
fn.COALESCE(Task.due, datetime(3000, 12, 31)), Task.created_at
|
||||
)
|
||||
|
||||
return list(query)
|
||||
|
||||
|
||||
def get_categories() -> list[Category]:
|
||||
return list(Category.select().order_by(Category.name))
|
58
src/tt/db.py
Normal file
58
src/tt/db.py
Normal file
@ -0,0 +1,58 @@
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from peewee import (
|
||||
Model,
|
||||
SqliteDatabase,
|
||||
CharField,
|
||||
TextField,
|
||||
DateTimeField,
|
||||
ForeignKeyField,
|
||||
)
|
||||
|
||||
db = SqliteDatabase("tasks.db")
|
||||
|
||||
|
||||
class TaskStatus(Enum):
|
||||
ZERO = "zero"
|
||||
WIP = "wip"
|
||||
BLOCKED = "blocked"
|
||||
DONE = "done"
|
||||
|
||||
|
||||
class BaseModel(Model):
|
||||
class Meta:
|
||||
database = db
|
||||
|
||||
|
||||
class Category(BaseModel):
|
||||
name = CharField(unique=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class Task(BaseModel):
|
||||
text = TextField()
|
||||
status = CharField(
|
||||
choices=[(status.value, status.name) for status in TaskStatus],
|
||||
default=TaskStatus.ZERO.value,
|
||||
)
|
||||
due = DateTimeField(null=True)
|
||||
category = ForeignKeyField(Category, backref="tasks", null=True)
|
||||
type = CharField()
|
||||
created_at = DateTimeField(default=datetime.now)
|
||||
updated_at = DateTimeField(default=datetime.now)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.updated_at = datetime.now()
|
||||
return super(Task, self).save(*args, **kwargs)
|
||||
|
||||
|
||||
def initialize_db():
|
||||
db.connect()
|
||||
db.create_tables([Category, Task])
|
||||
db.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
initialize_db()
|
141
uv.lock
generated
Normal file
141
uv.lock
generated
Normal file
@ -0,0 +1,141 @@
|
||||
version = 1
|
||||
requires-python = ">=3.10"
|
||||
|
||||
[[package]]
|
||||
name = "linkify-it-py"
|
||||
version = "2.0.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "uc-micro-py" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/2a/ae/bb56c6828e4797ba5a4821eec7c43b8bf40f69cda4d4f5f8c8a2810ec96a/linkify-it-py-2.0.3.tar.gz", hash = "sha256:68cda27e162e9215c17d786649d1da0021a451bdc436ef9e0fa0ba5234b9b048", size = 27946 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/04/1e/b832de447dee8b582cac175871d2f6c3d5077cc56d5575cadba1fd1cccfa/linkify_it_py-2.0.3-py3-none-any.whl", hash = "sha256:6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79", size = 19820 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markdown-it-py"
|
||||
version = "3.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "mdurl" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
linkify = [
|
||||
{ name = "linkify-it-py" },
|
||||
]
|
||||
plugins = [
|
||||
{ name = "mdit-py-plugins" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mdit-py-plugins"
|
||||
version = "0.4.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "markdown-it-py" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/19/03/a2ecab526543b152300717cf232bb4bb8605b6edb946c845016fa9c9c9fd/mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5", size = 43542 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/f7/7782a043553ee469c1ff49cfa1cdace2d6bf99a1f333cf38676b3ddf30da/mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636", size = 55316 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mdurl"
|
||||
version = "0.1.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peewee"
|
||||
version = "3.17.8"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b4/dc/832bcf4ea5ee2ebc4ea42ef36e44a451de5d80f8b9858bf2066e30738c67/peewee-3.17.8.tar.gz", hash = "sha256:ce1d05db3438830b989a1b9d0d0aa4e7f6134d5f6fd57686eeaa26a3e6485a8c", size = 948249 }
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "4.3.6"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.18.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8e/62/8336eff65bcbc8e4cb5d05b55faf041285951b6e80f33e2bff2024788f31/pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", size = 4891905 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", size = 1205513 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rich"
|
||||
version = "13.9.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "markdown-it-py" },
|
||||
{ name = "pygments" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textual"
|
||||
version = "1.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "markdown-it-py", extra = ["linkify", "plugins"] },
|
||||
{ name = "platformdirs" },
|
||||
{ name = "rich" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1f/b6/59b1de04bb4dca0f21ed7ba0b19309ed7f3f5de4396edf20cc2855e53085/textual-1.0.0.tar.gz", hash = "sha256:bec9fe63547c1c552569d1b75d309038b7d456c03f86dfa3706ddb099b151399", size = 1532733 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ac/bb/5fb6656c625019cd653d5215237d7cd6e0b12e7eae4195c3d1c91b2136fc/textual-1.0.0-py3-none-any.whl", hash = "sha256:2d4a701781c05104925e463ae370c630567c70c2880e92ab838052e3e23c986f", size = 660456 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tt"
|
||||
version = "0.1.0"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "peewee" },
|
||||
{ name = "textual" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "peewee", specifier = ">=3.17.8" },
|
||||
{ name = "textual", specifier = ">=1.0.0" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.12.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uc-micro-py"
|
||||
version = "1.0.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/91/7a/146a99696aee0609e3712f2b44c6274566bc368dfe8375191278045186b8/uc-micro-py-1.0.3.tar.gz", hash = "sha256:d321b92cff673ec58027c04015fcaa8bb1e005478643ff4a500882eaab88c48a", size = 6043 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/37/87/1f677586e8ac487e29672e4b17455758fce261de06a0d086167bb760361a/uc_micro_py-1.0.3-py3-none-any.whl", hash = "sha256:db1dffff340817673d7b466ec86114a9dc0e9d4d9b5ba229d9d60e5c12600cd5", size = 6229 },
|
||||
]
|
Loading…
Reference in New Issue
Block a user