Add a CompletionHistory instead of HistoryVisits table

This commit is contained in:
Florian Bruhin 2017-06-07 16:02:10 +02:00 committed by Ryan Roden-Corrent
parent c64b7d00e6
commit 57d96a4512
5 changed files with 33 additions and 43 deletions

View File

@ -72,13 +72,13 @@ class Entry:
return self.url.toString(QUrl.FullyEncoded | QUrl.RemovePassword)
class HistoryVisits(sql.SqlTable):
class CompletionHistory(sql.SqlTable):
"""Secondary table with visited URLs and timestamps."""
"""History which only has the newest entry for each URL."""
def __init__(self, parent=None):
super().__init__("Visits", ['url', 'atime'],
fkeys={'url': 'History(url)'})
super().__init__("CompletionHistory", ['url', 'title', 'last_atime'],
constraints={'url': 'PRIMARY KEY'}, parent=parent)
class WebHistory(sql.SqlTable):
@ -86,14 +86,11 @@ class WebHistory(sql.SqlTable):
"""The global history of visited pages."""
def __init__(self, parent=None):
super().__init__("History",
['url', 'title', 'last_atime', 'redirect'],
constraints={'url': 'PRIMARY KEY'},
super().__init__("History", ['url', 'title', 'atime', 'redirect'],
parent=parent)
self.visits = HistoryVisits(parent=self)
self.completion = CompletionHistory(parent=self)
self.create_index('HistoryIndex', 'url')
self._contains_query = self.contains_query('url')
# FIXME
self._between_query = sql.Query('SELECT * FROM History '
'where not redirect '
'and not url like "qute://%" '
@ -117,8 +114,10 @@ class WebHistory(sql.SqlTable):
def _add_entry(self, entry):
"""Add an entry to the in-memory database."""
self.insert([entry.url_str(), entry.title, int(entry.atime),
entry.redirect], replace=True)
self.visits.insert([entry.url_str(), int(entry.atime)])
entry.redirect])
if not entry.redirect:
self.completion.insert([entry.url_str(), entry.title,
int(entry.atime)], replace=True)
def get_recent(self):
"""Get the most recent history entries."""
@ -229,9 +228,10 @@ class WebHistory(sql.SqlTable):
raise ValueError("Invalid flags {!r}".format(flags))
redirect = 'r' in flags
row = (url, title, float(atime), redirect)
completion_row = None if redirect else (url, title, float(atime))
return ((url, float(atime)),
(url, title, float(atime), bool(redirect)))
return (row, completion_row)
def import_txt(self):
"""Import a history text file into sqlite if it exists.
@ -258,20 +258,21 @@ class WebHistory(sql.SqlTable):
"""Import a text file into the sql database."""
with open(path, 'r', encoding='utf-8') as f:
rows = []
visit_rows = []
completion_rows = []
for (i, line) in enumerate(f):
line = line.strip()
if not line:
continue
try:
visit_row, row = self._parse_entry(line.strip())
row, completion_row = self._parse_entry(line.strip())
rows.append(row)
visit_rows.append(visit_row)
if completion_row is not None:
completion_rows.append(completion_row)
except ValueError:
raise Exception('Failed to parse line #{} of {}: "{}"'
.format(i, path, line))
self.insert_batch(rows, replace=True)
self.visits.insert_batch(visit_rows)
self.insert_batch(rows)
self.completion.insert_batch(completion_rows, replace=True)
@cmdutils.register(instance='web-history', debug=True)
def debug_dump_history(self, dest):
@ -280,7 +281,6 @@ class WebHistory(sql.SqlTable):
Args:
dest: Where to write the file to.
"""
# FIXME
dest = os.path.expanduser(dest)
lines = ('{}{} {} {}'

View File

@ -30,7 +30,7 @@ class SqlCategory(QSqlQueryModel):
"""Wraps a SqlQuery for use as a completion category."""
def __init__(self, name, *, filter_fields, sort_by=None, sort_order=None,
select='*', where=None, group_by=None, suffix=None, parent=None):
select='*', where=None, group_by=None, parent=None):
"""Create a new completion category backed by a sql table.
Args:

View File

@ -77,8 +77,8 @@ def url():
timefmt = config.get('completion', 'timestamp-format')
select_time = "strftime('{}', last_atime, 'unixepoch')".format(timefmt)
hist_cat = sqlcategory.SqlCategory(
'History', sort_order='desc', sort_by='last_atime',
'CompletionHistory', sort_order='desc', sort_by='last_atime',
filter_fields=['url', 'title'],
select='url, title, {}'.format(select_time), where='not redirect')
select='url, title, {}'.format(select_time))
model.add_category(hist_cat)
return model

View File

@ -106,8 +106,7 @@ class SqlTable(QObject):
changed = pyqtSignal()
def __init__(self, name, fields, constraints=None, fkeys=None,
parent=None):
def __init__(self, name, fields, constraints=None, parent=None):
"""Create a new table in the sql database.
Raises SqlException if the table already exists.
@ -116,22 +115,16 @@ class SqlTable(QObject):
name: Name of the table.
fields: A list of field names.
constraints: A dict mapping field names to constraint strings.
fkeys: A dict mapping field names to foreign keys.
"""
super().__init__(parent)
self._name = name
constraints = constraints or {}
fkeys = fkeys or {}
column_defs = ['{} {}'.format(field, constraints.get(field, ''))
for field in fields]
for field, fkey in sorted(fkeys.items()):
column_defs.append('FOREIGN KEY({}) REFERENCES {}'.format(
field, fkey))
q = Query("CREATE TABLE IF NOT EXISTS {} ({})"
.format(name, ','.join(column_defs)))
q.run()
# pylint: disable=invalid-name
self.Entry = collections.namedtuple(name + '_Entry', fields)

View File

@ -155,24 +155,22 @@ def bookmarks(bookmark_manager_stub):
@pytest.fixture
def web_history_stub(stubs, init_sql):
return sql.SqlTable("History", ['url', 'title', 'atime', 'redirect'])
return sql.SqlTable("CompletionHistory", ['url', 'title', 'last_atime'])
@pytest.fixture
def web_history(web_history_stub, init_sql):
"""Pre-populate the web-history database."""
web_history_stub.insert(['http://some-redirect.example.com', 'redirect',
datetime(2016, 9, 5).timestamp(), True])
web_history_stub.insert(['http://qutebrowser.org', 'qutebrowser',
datetime(2015, 9, 5).timestamp(), False])
datetime(2015, 9, 5).timestamp()])
web_history_stub.insert(['https://python.org', 'Welcome to Python.org',
datetime(2016, 2, 8).timestamp(), False])
datetime(2016, 2, 8).timestamp()])
web_history_stub.insert(['https://python.org', 'Welcome to Python.org',
datetime(2016, 3, 8).timestamp(), False])
datetime(2016, 3, 8).timestamp()])
web_history_stub.insert(['https://python.org', 'Welcome to Python.org',
datetime(2014, 3, 8).timestamp(), False])
datetime(2014, 3, 8).timestamp()])
web_history_stub.insert(['https://github.com', 'https://github.com',
datetime(2016, 5, 1).timestamp(), False])
datetime(2016, 5, 1).timestamp()])
return web_history_stub
@ -336,7 +334,7 @@ def test_url_completion_pattern(config_stub, web_history_stub,
url, title, pattern, rowcount):
"""Test that url completion filters by url and title."""
config_stub.data['completion'] = {'timestamp-format': '%Y-%m-%d'}
web_history_stub.insert([url, title, 0, False])
web_history_stub.insert([url, title, 0])
model = urlmodel.url()
model.set_pattern(pattern)
# 2, 0 is History
@ -582,10 +580,9 @@ def test_url_completion_benchmark(benchmark, config_stub,
'web-history-max-items': 1000}
entries = [web_history_stub.Entry(
atime=i,
last_atime=i,
url='http://example.com/{}'.format(i),
title='title{}'.format(i),
redirect=False)
title='title{}'.format(i))
for i in range(100000)]
web_history_stub.insert_batch(entries)