Die schnellere Pagination ohne Offset habe ich inzwischen wirklich für ursprung umgesetzt. Das war letzten Endes einige Arbeit.
Statt einem Link wie archive/older=datum
sollte es dann doch wieder ein Link mit Seitenzahl sein, also archive/2
für Seite 2. Also brauchte das System eine Liste, um Seitenzahlen auf eine Datumsangaben zu mappen. Außerdem muss das System sich merken, welcher Eintrag bereits in der Pagination berücksichtigt ist. Denn immer dann, wenn die neu erstellt wird (bei jedem Löschen eines Eintrags) muss dies gezählt werden, statt einfach nur die Anzahl insgesamt vorhandener Einträge zu zählen.
Die Kernfunktion ist das Hinzufügen eine Seite zur Pagination und deren Anpassung:
# Add the page to the precomputed mapping of page to entry date, to enable the no offset pagination
# This also has to take care of shrinking the buffer (the second archive page, n -1), so that all other archive pages remain stable
def addToPagination(entry:)
limit = 5
# the tag can't just be nil, because in sqlite3 INSERT OR REPLACE on shared primary keys detects ('abc', NULL) and ('abc', NULL) not as a conflict
tags = entry.tags.empty? ? [self.NOTAG] : (entry.tags << self.NOTAG)
tags.each do |tag|
totalPages, totalEntries = self.getTotalPages(limit, tag)
totalEntries += 1 # the current entry is not already counted by that function
page = (totalEntries > 1 && totalEntries % limit == 1) ? totalPages + 1 : totalPages
# start date of n is now entry.date
@@db.execute("INSERT OR REPLACE INTO pagination(page, tag, startDate) VALUES(?, ?, ?)", page, tag, entry.date)
if totalEntries > limit
# now the start second archive page, the shrinking and growing buffer, has to be set as well
tagSQL = tag == self.NOTAG ? "" : "AND id IN (SELECT entryId FROM tags WHERE tag = '#{SQLite3::Database.quote(tag)}')"
bufferStart = @@db.execute("SELECT date FROM entries WHERE date < (SELECT startDate FROM pagination WHERE page = ? AND tag = ?) #{tagSQL} ORDER BY date DESC LIMIT ?", page, tag, limit).last['date']
@@db.execute("INSERT OR REPLACE INTO pagination(page, tag, startDate) VALUES(?, ?, ?)", page - 1, tag, bufferStart)
if (totalEntries > (limit * 2)) && (totalEntries % limit == 1)
# if we have more than two pages and the buffer just overgrew, we can set it back to 1 and move the full amount of entries to a stable page
bufferEnd = @@db.execute("SELECT date FROM entries WHERE date < (SELECT startDate FROM pagination WHERE page = ? AND tag = ?) #{tagSQL} ORDER BY date DESC LIMIT ?", page - 1, tag, 1).last['date']
# this will never be changed again
@@db.execute("INSERT OR REPLACE INTO pagination(page, tag, startDate) VALUES(?, ?, ?)", page - 2, tag, bufferEnd)
end
end
end
@@db.execute("UPDATE entries SET paginated = 1 WHERE id = ?", entry.id)
end
Schließlich hat es aber durchaus funktioniert. Das Aufrufen einer Archivseite in einem vollen Blog ist schneller geworden, ohne dass sich für den Nutzer etwas geändert hätte. Es fehlt nur noch ein schlaueres Vorgehen beim Löschen eines Eintrags, dass die Pagination angepasst wird statt sie zu löschen und neu zu erstellen.
Wobei ich das Gefühl nicht loswerde, dass meine Implementation unnötig kompliziert ist.