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
##########################################################################
def findCards(self, query):
def findCards(self, query, sort=None):
import anki.find
return anki.find.Finder(self).findCards(query)
return anki.find.Finder(self).findCards(query, sort)
def findReplace(self, *args, **kwargs):
import anki.find

View file

@ -20,15 +20,61 @@ class Finder(object):
def __init__(self, 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
(q, args) = self.findCardsWhere()
query = "select id from cards"
if q:
query += " where " + q
print query, args
self._findLimits()
if not self.lims['valid']:
return []
(q, args) = self._whereClause()
query = self._orderedSelect(sort, q)
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):
"Generate a list of fact/card limits for the query."
self.lims = {
@ -142,19 +188,6 @@ where mid in %s and flds like ? escape '\\'""" % (
extra = "not" if isNeg else ""
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):
fields = set()
for m in self.deck.models().values():
@ -323,81 +356,3 @@ def findDuplicates(deck, fmids):
else:
vals[val].append(fid)
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,
tags text not null,
flds text not null,
sfld text not null,
sfld integer not null,
data text not null
);

View file

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