diff --git a/anki/cards.py b/anki/cards.py index 21cfab8d1..9ec9a2c98 100644 --- a/anki/cards.py +++ b/anki/cards.py @@ -3,7 +3,7 @@ # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import time -from anki.utils import intTime, hexifyID +from anki.utils import intTime, hexifyID, timestampID # Cards ########################################################################## @@ -28,7 +28,7 @@ class Card(object): self.load() else: # to flush, set fid, ord, and due - self.id = intTime(1000) + self.id = timestampID(deck.db, "cards") self.gid = 1 self.crt = intTime() self.type = 0 diff --git a/anki/facts.py b/anki/facts.py index b4a1067ab..1d41004b7 100644 --- a/anki/facts.py +++ b/anki/facts.py @@ -6,7 +6,7 @@ import time from anki.errors import AnkiError from anki.utils import fieldChecksum, intTime, \ joinFields, splitFields, ids2str, parseTags, canonifyTags, hasTag, \ - stripHTML + stripHTML, timestampID class Fact(object): @@ -17,7 +17,7 @@ class Fact(object): self.id = id self.load() else: - self.id = intTime(1000) + self.id = timestampID(deck.db, "facts") self._model = model self.gid = deck.defaultGroup(model.conf['gid']) self.mid = model.id diff --git a/anki/models.py b/anki/models.py index dc2e7267f..05575abbd 100644 --- a/anki/models.py +++ b/anki/models.py @@ -3,7 +3,8 @@ # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html import simplejson -from anki.utils import intTime, hexifyID, joinFields, splitFields, ids2str +from anki.utils import intTime, hexifyID, joinFields, splitFields, ids2str, \ + timestampID from anki.lang import _ # Models @@ -63,7 +64,7 @@ class Model(object): self.id = id self.load() else: - self.id = intTime(1000) + self.id = timestampID(deck.db, "models") self.name = u"" self.conf = defaultConf.copy() self.css = "" diff --git a/anki/utils.py b/anki/utils.py index 698a8fc29..a486f6091 100644 --- a/anki/utils.py +++ b/anki/utils.py @@ -180,6 +180,15 @@ def ids2str(ids): """Given a list of integers, return a string '(int1,int2,...)'.""" return "(%s)" % ",".join(str(i) for i in ids) +def timestampID(db, table): + "Return a non-conflicting timestamp for table." + # be careful not to create multiple objects without flushing them, or they + # may share an ID. + t = intTime(1000) + while db.scalar("select id from %s where id = ?" % table, t): + t += 1 + return t + # Tags ############################################################################## diff --git a/tests/test_deck.py b/tests/test_deck.py index 3a76dc71b..5cfdbd235 100644 --- a/tests/test_deck.py +++ b/tests/test_deck.py @@ -2,6 +2,7 @@ import os, re, datetime from tests.shared import assertException, getEmptyDeck, testDir +from anki.stdmodels import BasicModel from anki import Deck @@ -189,3 +190,11 @@ def test_addDelTags(): f.load() assert f.tags[0] == "aaa" assert len(f.tags) == 2 + +def test_timestamps(): + deck = getEmptyDeck() + assert len(deck.models()) == 2 + for i in range(100): + deck.addModel(BasicModel(deck)) + assert len(deck.models()) == 102 +