rewrite groupCounts()

Instead of collecting the exact number of cards, we just record whether a
group has any reviews or new cards. By not needing to calculate the exact
numbers, it runs a lot faster than before.

Also, changed the group code to ensure parents are automatically created when
a group is added.
This commit is contained in:
Damien Elmes 2011-09-07 03:02:07 +09:00
parent de8a5b69ed
commit 28d045feef
3 changed files with 55 additions and 38 deletions

View file

@ -94,8 +94,9 @@ class GroupManager(object):
# if it's a top level group, it gets the top level config
g = defaultTopConf.copy()
else:
# not top level. calling code should ensure parents already exist?
# not top level; ensure all parents exist
g = {}
self._ensureParents(name)
g['name'] = name
g['conf'] = 1
while 1:
@ -122,6 +123,16 @@ class GroupManager(object):
"A list of all groups."
return self.groups.values()
def _ensureParents(self, name):
path = name.split("::")
s = ""
for p in path[:-1]:
if not s:
s += p
else:
s += "::" + p
self.id(s)
# Group utils
#############################################################
@ -164,8 +175,7 @@ class GroupManager(object):
return
# save the top level group
name = self.groups[str(gid)]['name']
path = name.split("::")
self.deck.conf['topGroup'] = self.id(path[0])
self.deck.conf['topGroup'] = self.topFor(name)
# current group
self.deck.conf['curGroup'] = gid
# and active groups (current + all children)
@ -174,3 +184,8 @@ class GroupManager(object):
if g['name'].startswith(name + "::"):
actv.append(g['id'])
self.deck.conf['activeGroups'] = actv
def topFor(self, name):
"The top level gid for NAME."
path = name.split("::")
return self.id(path[0])

View file

@ -108,15 +108,28 @@ order by due""" % self._groupLimit(),
##########################################################################
def groupCounts(self):
"Returns [groupname, cards, due, new]"
"Returns [groupname, hasDue, hasNew]"
# find groups with 1 or more due cards
gids = {}
for (gid, all, rev, new) in self.deck.db.execute("""
select gid, count(),
sum(case when queue = 2 and due <= ? then 1 else 0 end),
sum(case when queue = 0 then 1 else 0 end)
from cards group by gid""", self.today):
gids[gid] = [all, rev, new]
return [[grp['name'], int(gid)]+gids.get(int(gid), [0, 0, 0])
for g in self.deck.groups.all():
hasDue = self.deck.db.scalar("""
select 1 from cards where gid = ? and
((queue = 2 and due <= ?) or (queue = 1 and due < ?)) limit 1""",
g['id'], self.today, intTime())
top = self.deck.groups.get(
self.deck.groups.topFor(g['name']))
if top['newToday'][0] != self.today:
# it's a new day; reset counts
top['newToday'] = [self.today, 0]
hasNew = max(0, top['newPerDay'] - top['newToday'][1])
if hasNew:
# if the limit hasn't run out, check to see if there are
# actually cards
hasNew = self.deck.db.scalar(
"select 1 from cards where queue = 0 and gid = ? limit 1",
g['id'])
gids[g['id']] = [hasDue or 0, hasNew or 0]
return [[grp['name'], int(gid)]+gids.get(int(gid))
for (gid, grp) in self._orderedGroups()]
def _orderedGroups(self):
@ -145,7 +158,6 @@ from cards group by gid""", self.today):
for (head, tail) in itertools.groupby(grps, key=key):
tail = list(tail)
gid = None
all = 0
rev = 0
new = 0
children = []
@ -153,9 +165,8 @@ from cards group by gid""", self.today):
if len(c[0]) == 1:
# current node
gid = c[1]
all += c[2]
rev += c[3]
new += c[4]
rev += c[2]
new += c[3]
else:
# set new string to tail
c[0] = c[0][1]
@ -163,10 +174,9 @@ from cards group by gid""", self.today):
children = self._groupChildren(children)
# tally up children counts
for ch in children:
all += ch[2]
rev += ch[3]
new += ch[4]
tree.append((head, gid, all, rev, new, children))
rev += ch[2]
new += ch[3]
tree.append((head, gid, rev, new, children))
return tuple(tree)
# Getting the next card

View file

@ -695,32 +695,24 @@ def test_groupCounts():
d.addFact(f)
d.reset()
assert d.sched.counts() == (3, 0, 1)
assert len(d.groups.groups) == 4
assert len(d.groups.groups) == 5
cnts = d.sched.groupCounts()
assert cnts[0] == ["Default", 1, 1, 0, 1]
assert cnts[1] == ["Default::1", default1, 1, 1, 0]
assert cnts[2] == ["foo::bar", foobar, 1, 0, 1]
assert cnts[3] == ["foo::baz", foobaz, 1, 0, 1]
assert cnts[0] == ["Default", 1, 0, 1]
assert cnts[1] == ["Default::1", default1, 1, 0]
assert cnts[2] == ["foo", d.groups.id("foo"), 0, 0]
assert cnts[3] == ["foo::bar", foobar, 0, 1]
assert cnts[4] == ["foo::baz", foobaz, 0, 1]
tree = d.sched.groupCountTree()
assert tree[0][0] == "Default"
# sum of child and parent
assert tree[0][1] == 1
assert tree[0][2] == 2
assert tree[0][2] == 1
assert tree[0][3] == 1
assert tree[0][4] == 1
# child count is just review
assert tree[0][5][0][0] == "1"
assert tree[0][5][0][1] == default1
assert tree[0][5][0][2] == 1
assert tree[0][5][0][3] == 1
assert tree[0][5][0][4] == 0
# event if parent group didn't exist, it should have been created with a
# counts summary, with an empty gid
assert tree[1][0] == "foo"
assert tree[1][1] == None
assert tree[1][2] == 2
assert tree[1][3] == 0
assert tree[1][4] == 2
assert tree[0][4][0][0] == "1"
assert tree[0][4][0][1] == default1
assert tree[0][4][0][2] == 1
assert tree[0][4][0][3] == 0
def test_reorder():
d = getEmptyDeck()