mirror of
https://github.com/ankitects/anki.git
synced 2025-09-24 16:56:36 -04:00
support matches on card properties
This commit is contained in:
parent
a76d34dc19
commit
3755a8f82d
2 changed files with 66 additions and 1 deletions
40
anki/find.py
40
anki/find.py
|
@ -14,6 +14,7 @@ SEARCH_TEMPLATE = 4
|
||||||
SEARCH_FIELD = 5
|
SEARCH_FIELD = 5
|
||||||
SEARCH_MODEL = 6
|
SEARCH_MODEL = 6
|
||||||
SEARCH_DECK = 7
|
SEARCH_DECK = 7
|
||||||
|
SEARCH_PROP = 8
|
||||||
|
|
||||||
# Tools
|
# Tools
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
@ -119,6 +120,8 @@ and c.nid=n.id %s""" % (q, order)
|
||||||
self._findModel(token, isNeg)
|
self._findModel(token, isNeg)
|
||||||
elif type == SEARCH_DECK:
|
elif type == SEARCH_DECK:
|
||||||
self._findDeck(token, isNeg)
|
self._findDeck(token, isNeg)
|
||||||
|
elif type == SEARCH_PROP:
|
||||||
|
self._findProp(token, isNeg)
|
||||||
else:
|
else:
|
||||||
self._findText(token, isNeg, c)
|
self._findText(token, isNeg, c)
|
||||||
|
|
||||||
|
@ -161,6 +164,40 @@ and c.nid=n.id %s""" % (q, order)
|
||||||
else:
|
else:
|
||||||
self.lims['valid'] = False
|
self.lims['valid'] = False
|
||||||
|
|
||||||
|
def _findProp(self, val, neg):
|
||||||
|
# extract
|
||||||
|
m = re.match("(^.+?)(<=|>=|=|<|>)(.+?$)", val)
|
||||||
|
if not m:
|
||||||
|
self.lims['valid'] = False
|
||||||
|
return
|
||||||
|
prop, cmp, val = m.groups()
|
||||||
|
prop = prop.lower()
|
||||||
|
# is val valid?
|
||||||
|
try:
|
||||||
|
if prop == "ease":
|
||||||
|
val = float(val)
|
||||||
|
else:
|
||||||
|
val = int(val)
|
||||||
|
except ValueError:
|
||||||
|
self.lims['valid'] = False
|
||||||
|
return
|
||||||
|
# is prop valid?
|
||||||
|
if prop not in ("due", "ivl", "reps", "lapses", "ease"):
|
||||||
|
self.lims['valid'] = False
|
||||||
|
return
|
||||||
|
# query
|
||||||
|
extra = "not" if neg else ""
|
||||||
|
if prop == "due":
|
||||||
|
val += self.col.sched.today
|
||||||
|
# only valid for review/daily learning
|
||||||
|
self.lims['preds'].append("queue in (2,3)")
|
||||||
|
elif prop == "ease":
|
||||||
|
prop = "factor"
|
||||||
|
val = int(val*1000)
|
||||||
|
sql = "%s (%s %s %s)" % ("not" if neg else "",
|
||||||
|
prop, cmp, val)
|
||||||
|
self.lims['preds'].append(sql)
|
||||||
|
|
||||||
def _findText(self, val, neg, c):
|
def _findText(self, val, neg, c):
|
||||||
val = val.replace("*", "%")
|
val = val.replace("*", "%")
|
||||||
if not self.full:
|
if not self.full:
|
||||||
|
@ -378,6 +415,9 @@ n.mid in %s and n.id %s in %s""" % (
|
||||||
elif token['value'].startswith("deck:"):
|
elif token['value'].startswith("deck:"):
|
||||||
token['value'] = token['value'][5:].lower()
|
token['value'] = token['value'][5:].lower()
|
||||||
type = SEARCH_DECK
|
type = SEARCH_DECK
|
||||||
|
elif token['value'].startswith("prop:"):
|
||||||
|
token['value'] = token['value'][5:].lower()
|
||||||
|
type = SEARCH_PROP
|
||||||
elif token['value'].startswith("nid:") and len(token['value']) > 4:
|
elif token['value'].startswith("nid:") and len(token['value']) > 4:
|
||||||
dec = token['value'][4:]
|
dec = token['value'][4:]
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -68,8 +68,8 @@ def test_findCards():
|
||||||
assert len(deck.findCards("-is:due")) == 4
|
assert len(deck.findCards("-is:due")) == 4
|
||||||
c.queue = -1
|
c.queue = -1
|
||||||
# ensure this card gets a later mod time
|
# ensure this card gets a later mod time
|
||||||
import time; time.sleep(1)
|
|
||||||
c.flush()
|
c.flush()
|
||||||
|
deck.db.execute("update cards set mod = mod + 1 where id = ?", c.id)
|
||||||
assert deck.findCards("is:suspended") == [c.id]
|
assert deck.findCards("is:suspended") == [c.id]
|
||||||
# nids
|
# nids
|
||||||
assert deck.findCards("nid:54321") == []
|
assert deck.findCards("nid:54321") == []
|
||||||
|
@ -135,6 +135,31 @@ def test_findCards():
|
||||||
assert len(deck.findCards("deck:default")) == 7
|
assert len(deck.findCards("deck:default")) == 7
|
||||||
assert len(deck.findCards("deck:default::child")) == 1
|
assert len(deck.findCards("deck:default::child")) == 1
|
||||||
assert len(deck.findCards("deck:default -deck:default::*")) == 6
|
assert len(deck.findCards("deck:default -deck:default::*")) == 6
|
||||||
|
# properties
|
||||||
|
id = deck.db.scalar("select id from cards limit 1")
|
||||||
|
deck.db.execute(
|
||||||
|
"update cards set queue=2, ivl=10, reps=20, due=30, factor=2200 "
|
||||||
|
"where id = ?", id)
|
||||||
|
assert len(deck.findCards("prop:ivl>5")) == 1
|
||||||
|
assert len(deck.findCards("prop:ivl<5")) > 1
|
||||||
|
assert len(deck.findCards("prop:ivl>=5")) == 1
|
||||||
|
assert len(deck.findCards("prop:ivl=9")) == 0
|
||||||
|
assert len(deck.findCards("prop:ivl=10")) == 1
|
||||||
|
assert len(deck.findCards("prop:due>0")) == 1
|
||||||
|
# due dates should work
|
||||||
|
deck.sched.today = 15
|
||||||
|
assert len(deck.findCards("prop:due=14")) == 0
|
||||||
|
assert len(deck.findCards("prop:due=15")) == 1
|
||||||
|
assert len(deck.findCards("prop:due=16")) == 0
|
||||||
|
# including negatives
|
||||||
|
deck.sched.today = 32
|
||||||
|
assert len(deck.findCards("prop:due=-1")) == 0
|
||||||
|
assert len(deck.findCards("prop:due=-2")) == 1
|
||||||
|
# ease factors
|
||||||
|
assert len(deck.findCards("prop:ease=2.3")) == 0
|
||||||
|
assert len(deck.findCards("prop:ease=2.2")) == 1
|
||||||
|
assert len(deck.findCards("prop:ease>2")) == 1
|
||||||
|
assert len(deck.findCards("-prop:ease>2")) > 1
|
||||||
|
|
||||||
def test_findReplace():
|
def test_findReplace():
|
||||||
deck = getEmptyDeck()
|
deck = getEmptyDeck()
|
||||||
|
|
Loading…
Reference in a new issue