refactor ordering

This commit is contained in:
Damien Elmes 2011-04-10 05:10:01 +09:00
parent 291bd399b7
commit efe6177c7a
4 changed files with 64 additions and 100 deletions

View file

@ -632,9 +632,9 @@ update facts set tags = :t, mod = :n where id = :id""", [fix(row) for row in res
# Finding cards # Finding cards
########################################################################## ##########################################################################
def findCards(self, query): def findCards(self, query, sort=None):
import anki.find import anki.find
return anki.find.Finder(self).findCards(query) return anki.find.Finder(self).findCards(query, sort)
def findReplace(self, *args, **kwargs): def findReplace(self, *args, **kwargs):
import anki.find import anki.find

View file

@ -20,15 +20,61 @@ class Finder(object):
def __init__(self, deck): def __init__(self, deck):
self.deck = deck self.deck = deck
def findCards(self, query): def findCards(self, query, sort=None):
"Return a list of card ids for QUERY."
self.query = query self.query = query
(q, args) = self.findCardsWhere() self._findLimits()
query = "select id from cards" if not self.lims['valid']:
if q: return []
query += " where " + q (q, args) = self._whereClause()
print query, args query = self._orderedSelect(sort, q)
return self.deck.db.list(query, **args) return self.deck.db.list(query, **args)
def _whereClause(self):
x = []
if self.lims['fact']:
x.append("fid in (select id from facts where %s)" % " and ".join(
self.lims['fact']))
if self.lims['card']:
x.extend(self.lims['card'])
q = " and ".join(x)
if not q:
q = "1"
return q, self.lims['args']
def _orderedSelect(self, type, lim):
if not type:
return "select id from cards where " + lim
elif type.startswith("fact"):
if type == "factCrt":
sort = "f.crt"
elif type == "factMod":
sort = "f.mod"
elif type == "factFld":
sort = "f.sfld collate nocase"
else:
raise Exception()
return """
select c.id from cards c, facts f where %s and c.id=f.id
order by %s""" % (lim, sort)
elif type.startswith("card"):
if type == "cardMod":
sort = "c.mod"
elif type == "cardReps":
sort = "c.reps"
elif type == "cardDue":
sort = "c.due"
elif type == "cardEase":
sort = "c.ease"
elif type == "cardLapses":
sort = "c.lapses"
else:
raise Exception()
return "select c.id from cards c where %s order by %s" % (
lim, sort)
else:
raise Exception()
def _findLimits(self): def _findLimits(self):
"Generate a list of fact/card limits for the query." "Generate a list of fact/card limits for the query."
self.lims = { self.lims = {
@ -142,19 +188,6 @@ where mid in %s and flds like ? escape '\\'""" % (
extra = "not" if isNeg else "" extra = "not" if isNeg else ""
self.lims['fact'].append("id %s in %s" % (extra, ids2str(fids))) self.lims['fact'].append("id %s in %s" % (extra, ids2str(fids)))
def findCardsWhere(self):
self._findLimits()
if not self.lims['valid']:
return "0", {}
x = []
if self.lims['fact']:
x.append("fid in (select id from facts where %s)" % " and ".join(
self.lims['fact']))
if self.lims['card']:
x.extend(self.lims['card'])
q = " and ".join(x)
return q, self.lims['args']
def _fieldNames(self): def _fieldNames(self):
fields = set() fields = set()
for m in self.deck.models().values(): for m in self.deck.models().values():
@ -323,81 +356,3 @@ def findDuplicates(deck, fmids):
else: else:
vals[val].append(fid) vals[val].append(fid)
return [(k,v) for (k,v) in vals.items() if len(v) > 1] return [(k,v) for (k,v) in vals.items() if len(v) > 1]
# Find & sort
##########################################################################
# copied from ankiqt and trivially changed; will not work at the moment
# if idx == 0:
# self.sortKey = "question"
# elif idx == 1:
# self.sortKey = "answer"
# elif idx == 2:
# self.sortKey = "created"
# elif idx == 3:
# self.sortKey = "modified"
# elif idx == 4:
# self.sortKey = "combinedDue"
# elif idx == 5:
# self.sortKey = "interval"
# elif idx == 6:
# self.sortKey = "reps"
# elif idx == 7:
# self.sortKey = "factor"
# elif idx == 8:
# self.sortKey = "fact"
# elif idx == 9:
# self.sortKey = "noCount"
# elif idx == 10:
# self.sortKey = "firstAnswered"
# else:
# self.sortKey = ("field", self.sortFields[idx-11])
def findSorted(deck, query, sortKey):
# sorting
if not query.strip():
ads = ""
else:
ids = self.deck.findCards(query)
ads = "cards.id in %s" % ids2str(ids)
sort = ""
if isinstance(sortKey, types.StringType):
# card property
if sortKey == "fact":
sort = "order by facts.created, cards.created"
else:
sort = "order by cards." + sortKey
if sortKey in ("question", "answer"):
sort += " collate nocase"
if sortKey == "fact":
query = """
select cards.id from cards, facts
where cards.fid = facts.id """
if ads:
query += "and " + ads + " "
else:
query = "select id from cards "
if ads:
query += "where %s " % ads
query += sort
else:
# field value
ret = self.deck.db.all(
"select id, numeric from fields where name = :name",
name=sortKey[1])
fields = ",".join([str(x[0]) for x in ret])
# if multiple models have the same field, use the first numeric bool
numeric = ret[0][1]
if numeric:
order = "cast(fdata.value as real)"
else:
order = "fdata.value collate nocase"
if ads:
ads = " and " + ads
query = ("select cards.id "
"from fdata, cards where fdata.fmid in (%s) "
"and fdata.fid = cards.fid" + ads +
" order by cards.ordinal, %s") % (fields, order)
# run the query
self.cards = self.deck.db.all(query)

View file

@ -99,7 +99,7 @@ create table if not exists facts (
mod integer not null, mod integer not null,
tags text not null, tags text not null,
flds text not null, flds text not null,
sfld text not null, sfld integer not null,
data text not null data text not null
); );

View file

@ -18,6 +18,7 @@ def test_findCards():
f['Front'] = u'cat' f['Front'] = u'cat'
f['Back'] = u'sheep' f['Back'] = u'sheep'
deck.addFact(f) deck.addFact(f)
catCard = f.cards()[0]
f = deck.newFact() f = deck.newFact()
f['Front'] = u'template test' f['Front'] = u'template test'
f['Back'] = u'foo bar' f['Back'] = u'foo bar'
@ -56,6 +57,8 @@ def test_findCards():
c.flush() c.flush()
assert deck.findCards("is:due") == [c.id] assert deck.findCards("is:due") == [c.id]
c.queue = -1 c.queue = -1
# ensure this card gets a later mod time
import time; time.sleep(1)
c.flush() c.flush()
assert deck.findCards("is:suspended") == [c.id] assert deck.findCards("is:suspended") == [c.id]
# fids # fids
@ -75,3 +78,9 @@ def test_findCards():
assert len(deck.findCards("back:sheep")) == 2 assert len(deck.findCards("back:sheep")) == 2
assert len(deck.findCards("-back:sheep")) == 3 assert len(deck.findCards("-back:sheep")) == 3
assert len(deck.findCards("front:")) == 5 assert len(deck.findCards("front:")) == 5
# ordering
assert deck.findCards("front:", sort="factCrt")[-1] == c.id
assert deck.findCards("", sort="factCrt")[-1] == c.id
assert deck.findCards("", sort="factFld")[0] == catCard.id
assert deck.findCards("", sort="factFld")[-1] == c.id
assert deck.findCards("", sort="cardMod")[-1] == c.id