summaryrefslogtreecommitdiff
path: root/model.py
diff options
context:
space:
mode:
authorRené 'Necoro' Neumann <necoro@necoro.net>2013-02-13 12:54:53 +0100
committerRené 'Necoro' Neumann <necoro@necoro.net>2013-02-13 12:54:53 +0100
commit458b4e7a1135df8859e94b10e316d3f8c5c5a561 (patch)
tree449fc7eb3d5d17740eb3cc6cb97e6fe2349005a2 /model.py
parentec4b54dd0f27e59087c5f087dedf5fee51fd9000 (diff)
downloadkosten-458b4e7a1135df8859e94b10e316d3f8c5c5a561.tar.gz
kosten-458b4e7a1135df8859e94b10e316d3f8c5c5a561.tar.bz2
kosten-458b4e7a1135df8859e94b10e316d3f8c5c5a561.zip
Remove dependency on elixir
Diffstat (limited to '')
-rw-r--r--model.py124
1 files changed, 79 insertions, 45 deletions
diff --git a/model.py b/model.py
index cf8c593..7a07ff0 100644
--- a/model.py
+++ b/model.py
@@ -1,42 +1,68 @@
-import elixir
-from elixir import Field, ManyToOne, OneToMany, OneToOne, ColumnProperty, using_options, using_options_defaults
from sqlalchemy import types as T
-from sqlalchemy import sql, Index
+from sqlalchemy import sql, Index, Column, ForeignKey, create_engine
+from sqlalchemy.orm import relationship, backref, scoped_session, sessionmaker,\
+ column_property
+from sqlalchemy.ext.declarative import declarative_base, declared_attr
+from sqlalchemy.ext.hybrid import hybrid_property
import datetime
+import decimal
from functools import partial
from collections import namedtuple
-__all__ = ["Category", "SingleExpense", "ConstExpense", "CatExpense", "MonthExpense"]
+__all__ = ["Category", "SingleExpense", "ConstExpense", "CatExpense", "MonthExpense",
+ "Session"]
#
# DB Setup
#
-elixir.metadata.bind = "sqlite:///test.sqlite"
-elixir.metadata.bind.echo = True
+engine = create_engine("sqlite:///test.sqlite")
+engine.echo = True
+
+Session = scoped_session(sessionmaker(bind=engine))
#
# Global definitions
#
-ReqField = partial(Field, required = True)
-ExpNum = T.Numeric(scale = 2, precision = 10)
+class Base(object):
+ @declared_attr
+ def __tablename__ (cls):
+ return cls.__name__.lower()
+
+ id = Column(T.Integer, primary_key=True)
+
+ query = Session.query_property()
+
+ @classmethod
+ def get_by (cls, *args, **kwargs):
+ return cls.query.filter_by(*args, **kwargs).first()
+
+ @classmethod
+ def get (cls, *args, **kwargs):
+ return cls.query.get(*args, **kwargs)
+
-class Entity (elixir.Entity):
- using_options(abstract = True)
+Base = declarative_base(cls=Base)
+
+ReqColumn = partial(Column, nullable = False)
+ExpNum = T.Numeric(scale = 2, precision = 10)
- using_options_defaults(shortnames = True)
+def to_exp(d):
+ """Converts decimal into expense"""
+ return d.quantize(decimal.Decimal('.01'), rounding = decimal.ROUND_UP)
#
# Database Entities
#
-class Category (Entity):
- name = Field(T.Unicode(50), unique = True)
+class Category (Base):
+ name = ReqColumn(T.Unicode(50), unique = True)
+ parent_id = Column(T.Integer, ForeignKey('category.id'))
- parent = ManyToOne('Category')
- children = OneToMany('Category')
+ children = relationship('Category',
+ backref=backref('parent', remote_side="Category.id"))
def __repr__ (self):
if self.parent:
@@ -44,17 +70,24 @@ class Category (Entity):
else:
return '<Category "%s">' % self.name
-class Expense (Entity):
- using_options(abstract = True)
+class Expense (Base):
+ __abstract__ = True
- description = Field(T.Unicode(50))
- expense = ReqField(ExpNum)
- category = ManyToOne('Category', required = True, innerjoin = True)
+ description = Column(T.Unicode(50))
+ expense = ReqColumn(ExpNum)
+
+ @declared_attr
+ def category_id(cls):
+ return ReqColumn(T.Integer, ForeignKey(Category.id))
+
+ @declared_attr
+ def category(cls):
+ return relationship(Category, innerjoin = True)
class SingleExpense (Expense):
- year = ReqField(T.Integer)
- month = ReqField(T.SmallInteger)
- day = ReqField(T.SmallInteger)
+ year = ReqColumn(T.Integer)
+ month = ReqColumn(T.SmallInteger)
+ day = ReqColumn(T.SmallInteger)
@classmethod
def of_month (cls, month, year):
@@ -75,14 +108,17 @@ class SingleExpense (Expense):
self.day = d.day
class ConstExpense (Expense):
- months = ReqField(T.SmallInteger)
- start = ReqField(T.Date, index = True)
- end = ReqField(T.Date, index = True)
+ months = ReqColumn(T.SmallInteger)
+ start = ReqColumn(T.Date, index = True)
+ end = ReqColumn(T.Date, index = True)
+ prev_id = Column(T.Integer, ForeignKey('constexpense.id'))
- prev = ManyToOne('ConstExpense', ondelete = "SET NULL")
- next = OneToOne('ConstExpense', inverse = 'prev')
-
- monthly = ColumnProperty(lambda c: sql.cast(c.expense / c.months, ExpNum))
+ prev = relationship('ConstExpense', remote_side = "ConstExpense.id", uselist = False,
+ backref=backref('next', uselist = False))
+
+ @property
+ def monthly(self):
+ return to_exp(self.expense / self.months)
@classmethod
def of_month (cls, month, year):
@@ -100,16 +136,22 @@ class CatExpense (namedtuple('CatExpense', 'cat expense exps')):
return self.exps.order_by(SingleExpense.day).all()
class MonthExpense (namedtuple('MonthExpense', 'date catexps')):
- __slots__ = ()
- @property
- def constsum (self):
- c = ConstExpense.of_month(self.date.month, self.date.year)
- return c.value(sql.functions.sum(ConstExpense.monthly)) or 0
+ def __init__ (self, *args, **kwargs):
+ self._consts = None
+ super(MonthExpense, self).__init__(*args, **kwargs)
@property
def consts (self):
- return ConstExpense.of_month(self.date.month, self.date.year).all()
+ if self._consts is None:
+ self._consts = ConstExpense.of_month(self.date.month, self.date.year).all()
+
+ return self._consts
+
+ @property
+ def constsum (self):
+ s = sum(c.monthly for c in self.consts)
+ return s or 0
@property
def sum (self):
@@ -123,14 +165,6 @@ class MonthExpense (namedtuple('MonthExpense', 'date catexps')):
return '<MonthExpense of "%s": %s>' % (self.date, self.sum)
#
-# Rest
-#
-
-elixir.setup_all()
-
-session = elixir.session
-
-#
# Extra indizes have to be here
#
@@ -138,4 +172,4 @@ Index('idx_single_date', SingleExpense.year, SingleExpense.month)
Index('idx_start_end', ConstExpense.start, ConstExpense.end)
if __name__ == "__main__":
- elixir.create_all()
+ Base.metadata.create_all(engine)