c9968ffb36cfc9b58f922c27054867075215590c
[doneit] / src / cache_backend.py
1 """
2 @todo Write and eager cache which will then, combined with file_backend, will be the basis of sync
3 """
4
5
6 class LazyCacheBackend(object):
7
8         def __init__(self, backend):
9                 self._backend = backend
10                 self._projects = {}
11                 self._items = {}
12                 self._locations = {}
13                 self._taskIdToProjId = {}
14                 self._noteIdToTaskId = {}
15
16         def save(self):
17                 self._backend.save()
18
19         def load(self):
20                 self._backend.load()
21
22         def add_project(self, name):
23                 projId = self._backend.add_project(name)
24                 self._invalidate_projects()
25                 return projId
26
27         def set_project_name(self, projId, name):
28                 self._backend.set_project_name(projId, name)
29                 self._invalidate_projects()
30
31         def set_project_visibility(self, projId, visibility):
32                 self._backend.set_project_visibility(projId, visibility)
33                 self._invalidate_projects()
34
35         def get_projects(self):
36                 self._populate_projects()
37                 return self._projects.itervalues()
38
39         def get_project(self, projId):
40                 self._populate_projects()
41                 return self._projects[projId]
42
43         def lookup_project(self, projName):
44                 """
45                 From a project's name, returns the project's details
46                 """
47                 self._populate_projects()
48                 todoList = [
49                         projectDetails
50                         for projectDetails in self._projects.itervalues()
51                                 if projectDetails["name"] == projName
52                 ]
53                 assert len(todoList) == 1, "Wrong number of lists found for %s, in %r" % (projName, todoList)
54                 return todoList[0]
55
56         def get_locations(self):
57                 self._populate_locations()
58                 return self._locations.itervalues()
59
60         def get_tasks_with_details(self, projId):
61                 self._populate_tasks(projId)
62                 return self._items[projId].itervalues()
63
64         def get_task_details(self, taskId):
65                 projId = self._taskIdToProjId[taskId]
66                 self._populate_tasks(projId)
67                 return self._items[projId][taskId]
68
69         def add_task(self, projId, taskName):
70                 taskId = self._backend.add_task(projId, taskName)
71                 self._invalidate_projects_tasks(projId)
72                 self._invalidate_metaprojects_tasks()
73                 self._taskIdToProjId[taskId] = projId
74                 return taskId
75
76         def set_project(self, taskId, newProjId):
77                 self._backend.set_project(taskId, newProjId)
78                 projId = self._taskIdToProjId[taskId]
79                 self._invalidate_projects_tasks(projId)
80                 self._invalidate_projects_tasks(newProjId)
81                 self._invalidate_metaprojects_tasks()
82
83         def set_name(self, taskId, name):
84                 self._backend.set_name(taskId, name)
85                 self._invalidate_task(taskId)
86
87         def set_duedate(self, taskId, dueDate):
88                 self._backend.set_duedate(taskId, dueDate)
89                 self._invalidate_task(taskId)
90
91         def set_priority(self, taskId, priority):
92                 self._backend.set_priority(taskId, priority)
93                 self._invalidate_task(taskId)
94
95         def complete_task(self, taskId):
96                 self._backend.complete_task(taskId)
97                 self._invalidate_task(taskId)
98
99         def add_note(self, taskId, noteTitle, noteBody):
100                 noteId = self._backend.add_note(taskId, noteTitle, noteBody)
101                 self._invalidate_task(taskId)
102                 return noteId
103
104         def update_note(self, noteId, noteTitle, noteBody):
105                 self._backend.update_note(noteId, noteTitle, noteBody)
106                 taskId = self._noteIdToTaskId[noteId]
107                 self._invalidate_task(taskId)
108
109         def delete_note(self, noteId):
110                 self._backend.delete_note(noteId)
111                 taskId = self._noteIdToTaskId[noteId]
112                 del self._noteIdToTaskId[noteId]
113                 self._invalidate_task(taskId)
114
115         def _populate_projects(self):
116                 if self._projects:
117                         print "SAVED BY THE CACHE"
118                         return
119                 self._projects = dict((
120                         (proj["id"], proj)
121                         for proj in self._backend.get_projects()
122                 ))
123
124         def _populate_tasks(self, projId):
125                 if projId in self._items:
126                         print "SAVED BY THE CACHE"
127                         return
128                 self._items[projId] = dict((
129                         (task["id"], task)
130                         for task in self._backend.get_tasks_with_details(projId)
131                 ))
132                 for taskId, task in self._items[projId].iteritems():
133                         self._taskIdToProjId[taskId] = task["projId"]
134                         for noteId, note in task["notes"].iteritems():
135                                 self._noteIdToTaskId[noteId] = taskId
136
137         def _populate_locations(self):
138                 if self._locations:
139                         print "SAVED BY THE CACHE"
140                         return
141                 self._locations = dict((
142                         (loc["id"], loc)
143                         for loc in self._backend.get_locations()
144                 ))
145
146         def _invalidate_projects(self):
147                 self._projects.clear()
148
149         def _invalidate_task(self, taskId):
150                 projId = self._taskIdToProjId[taskId]
151                 self._invalidate_projects_tasks(projId)
152                 self._invalidate_metaprojects_tasks()
153
154         def _invalidate_projects_tasks(self, projId):
155                 del self._items[projId]
156
157         def _invalidate_metaprojects_tasks(self):
158                 for projId in self._get_metalists():
159                         self._invalidate_projects_tasks(projId)
160
161         def _get_metalists(self):
162                 return (
163                         list
164                         for list in self._projects.itervalues()
165                                 if not list["isMeta"]
166                 )