diff --git a/anki/deck.py b/anki/deck.py index 6747afc42..6d317be67 100644 --- a/anki/deck.py +++ b/anki/deck.py @@ -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 diff --git a/anki/find.py b/anki/find.py index d3548e62a..7c271fb2c 100644 --- a/anki/find.py +++ b/anki/find.py @@ -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) diff --git a/anki/storage.py b/anki/storage.py index 5e05c9053..849a5b3ed 100644 --- a/anki/storage.py +++ b/anki/storage.py @@ -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 ); diff --git a/tests/test_find.py b/tests/test_find.py index c91dfe278..d25f01c5e 100644 --- a/tests/test_find.py +++ b/tests/test_find.py @@ -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