# -*- coding: utf-8 -*- # Copyright: Damien Elmes # License: GNU GPL, version 3 or later; http://www.gnu.org/copyleft/gpl.html import time from anki.errors import AnkiError from anki.utils import stripHTMLMedia, fieldChecksum, intTime, \ addTags, deleteTags, parseTags class Fact(object): def __init__(self, deck, model=None, id=None): assert not (model and id) self.deck = deck if id: self.id = id self.load() else: self.id = None self.model = model self.mid = model.id self.crt = intTime() self.mod = self.crt self.tags = "" self.cache = "" self._fields = [""] * len(self.model.fields) self.data = "" self._fmap = self.model.fieldMap() def load(self): (self.mid, self.crt, self.mod, self.tags, self._fields, self.data) = self.deck.db.first(""" select mid, crt, mod, tags, flds, data from facts where id = ?""", self.id) self._fields = self._field.split("\x1f") self.model = self.deck.getModel(self.mid) def flush(self, cache=True): self.mod = intTime() # facts table sfld = self._fields[self.model.sortField()] res = self.deck.db.execute(""" insert or replace into facts values (?, ?, ?, ?, ?, ?, ?, ?)""", self.id, self.mid, self.crt, self.mod, self.tags, self.joinedFields(), sfld, self.data) self.id = res.lastrowid def joinedFields(self): return "\x1f".join(self._fields) # # fdata table # self.deck.db.execute("delete from fdata where fid = ?", self.id) # d = [] # for (fmid, ord, conf) in self._fmap.values(): # val = self._fields[ord] # d.append(dict(fid=self.id, fmid=fmid, ord=ord, # val=val)) # d.append(dict(fid=self.id, fmid=0, ord=-1, val=self.tags)) # self.deck.db.executemany(""" # insert into fdata values (:fid, :fmid, :ord, :val, '')""", d) # # media and caches # self.deck.updateCache([self.id], "fact") def cards(self): return [self.deck.getCard(id) for id in self.deck.db.list( "select id from cards where fid = ? order by ord", self.id)] # Dict interface ################################################## def keys(self): return self._fmap.keys() def values(self): return self._fields def items(self): return [(k, self._fields[v[0]]) for (k, v) in self._fmap.items()] def _fieldOrd(self, key): try: return self._fmap[key][0] except: raise KeyError(key) def __getitem__(self, key): return self._fields[self._fieldOrd(key)] def __setitem__(self, key, value): self._fields[self._fieldOrd(key)] = value # Tags ################################################## def addTags(self, tags): self.tags = addTags(tags, self.tags) def deleteTags(self, tags): self.tags = deleteTags(tags, self.tags) # Unique/duplicate checks ################################################## def fieldUnique(self, name): (ord, conf) = self._fmap[name] if not conf['uniq']: return True val = self[name] csum = fieldChecksum(val) if self.id: lim = "and fid != :fid" else: lim = "" return not self.deck.db.scalar( "select 1 from fdata where csum = :c %s and val = :v" % lim, c=csum, v=val, fid=self.id) def fieldComplete(self, name, text=None): (ord, conf) = self._fmap[name] if not conf['req']: return True return self[name] def problems(self): d = [] for (k, (ord, conf)) in self._fmap.items(): if not self.fieldUnique(k): d.append((ord, "unique")) elif not self.fieldComplete(k): d.append((ord, "required")) else: d.append((ord, None)) return [x[1] for x in sorted(d)]