Ver código fonte

Add task model

theenglishway (time) 6 anos atrás
pai
commit
988cba001c

+ 38 - 0
pyplanner/cli.py

@@ -1,3 +1,5 @@
+from datetime import datetime
+
 import click
 from .database import Database
 from .output import TerminalOutput
@@ -79,6 +81,42 @@ def edit(ctx, short_uuid):
         click.echo(Term.failure(f"Could not find UUID {short_uuid}"))
 
 
+@main.command()
+@click.argument('short_uuid')
+@click.pass_context
+def start(ctx, short_uuid):
+    """Start a task"""
+    db = ctx.obj['db']
+    obj = db.search(short_uuid)
+    if obj:
+        if not isinstance(obj, Item):
+            click.echo(Term.failure(f"Cannot start task on {obj.__class__.__qualname__}"))
+
+        data = {'item': obj}
+        task = db.create(Task, data)
+
+        click.echo(Term.success(f"Successfully start task {task.short_uuid} on item {short_uuid}"))
+    else:
+        click.echo(Term.failure(f"Could not find UUID {short_uuid}"))
+
+
+@main.command()
+@click.argument('short_uuid')
+@click.pass_context
+def stop(ctx, short_uuid):
+    """Stop a task"""
+    db = ctx.obj['db']
+    obj = db.search(short_uuid)
+    if obj:
+        data = obj.attrs
+        data.update({'date_finished': datetime.utcnow()})
+        task = db.edit(Task, data)
+
+        click.echo(Term.success(f"Successfully stopped task {task.short_uuid} on item {short_uuid}"))
+    else:
+        click.echo(Term.failure(f"Could not find UUID {short_uuid}"))
+
+
 @main.group()
 @click.pass_context
 def milestone(ctx):

+ 2 - 2
pyplanner/database.py

@@ -1,5 +1,5 @@
 from sqlalchemy import create_engine
-from sqlalchemy.orm import sessionmaker
+from sqlalchemy.orm import sessionmaker, scoped_session
 from sqlalchemy.ext.declarative import declarative_base
 import inspect
 import uuid
@@ -11,7 +11,7 @@ SQLABase = declarative_base()
 class Database:
     def __init__(self, db_url):
         self.engine = create_engine(db_url)
-        self.session_factory = sessionmaker(bind=self.engine)
+        self.session_factory = scoped_session(sessionmaker(bind=self.engine))
 
         SQLABase.metadata.create_all(self.engine)
         self.models = {

+ 16 - 5
pyplanner/models/__init__.py

@@ -1,5 +1,5 @@
 from datetime import datetime
-from sqlalchemy import Column, DateTime
+from sqlalchemy import Column, DateTime, inspect
 from pydantic import ValidationError
 
 
@@ -19,18 +19,27 @@ class Base:
 
     @classmethod
     def to_yaml(cls, representer, node):
-        return representer.represent_data(
-            {k: v for k, v in node.__dict__.items() if k != '_sa_instance_state'}
-        )
+        return representer.represent_data(node.attrs)
 
     @classmethod
     def from_yaml(cls, constructor, node):
         return cls()
 
+    @classmethod
+    def column_properties(cls):
+        ins = inspect(cls)
+        return [p.key for p in ins.iterate_properties if hasattr(p, 'columns')]
+
     @property
     def short_uuid(self):
         return self.uuid[:8]
 
+    @property
+    def attrs(self):
+        return {
+            k: getattr(self, k) for k in self.column_properties()
+        }
+
 
 class BaseEnum:
     @classmethod
@@ -54,6 +63,7 @@ from .planned import (PlannedItem, PlannedItemType,
 from .unplanned import (UnplannedItem, UnplannedItemType,
                         Idea, Experimentation)
 from .comments import Comment
+from .tasks import Task
 
 
 __all__ = [
@@ -66,5 +76,6 @@ __all__ = [
     'ItemPriority', 'Length',
     'UnplannedItem', 'UnplannedItemType',
     'Experimentation', 'Idea',
-    'Comment'
+    'Comment',
+    'Task'
 ]

+ 11 - 1
pyplanner/models/items.py

@@ -25,4 +25,14 @@ class Item(SQLABase, Base):
         'polymorphic_on': _type,
         'polymorphic_identity': 'none',
         'with_polymorphic': '*'
-    }
+    }
+
+    @classmethod
+    def __get_validators__(cls):
+        yield cls.validate
+
+    @classmethod
+    def validate(cls, v):
+        if not isinstance(v, Item):
+            raise ValueError(f'strict string: Item expected not {type(v)}')
+        return v

+ 30 - 0
pyplanner/models/tasks.py

@@ -0,0 +1,30 @@
+from datetime import datetime
+
+from sqlalchemy import Column, Integer, String, DateTime, ForeignKey
+from sqlalchemy.orm import relationship, backref
+from pydantic import BaseModel
+
+from pyplanner.database import SQLABase
+from . import Base, Item
+
+
+class SchemaTask(BaseModel):
+    item: Item
+    uuid: str
+
+    date_started: datetime = None
+    date_finished: datetime = None
+
+
+class Task(SQLABase, Base):
+    _schema = SchemaTask
+
+    __tablename__ = 'tasks'
+    id = Column(Integer, primary_key=True)
+    uuid = Column(String)
+
+    date_started = Column(DateTime, default=datetime.utcnow)
+    date_finished = Column(DateTime, nullable=True)
+
+    item_id = Column(Integer, ForeignKey('items.id'), unique=True)
+    item = relationship('Item', backref=backref('tasks'), foreign_keys=[item_id])