Update sqlitehandler.py

This commit is contained in:
Schimon Jehudah 2023-11-02 05:18:01 +00:00
parent 1f3aa9459e
commit 85d98609c5

View file

@ -42,7 +42,7 @@ def create_connection(db_file):
def create_tables(db_file): def create_tables(db_file):
""" """
Create SQLite tables. Create SQLite tables.
:param db_file: Database filename. :param db_file: Database filename.
""" """
with create_connection(db_file) as conn: with create_connection(db_file) as conn:
@ -89,7 +89,7 @@ def create_tables(db_file):
def get_cursor(db_file): def get_cursor(db_file):
""" """
Allocate a cursor to connection per database. Allocate a cursor to connection per database.
:param db_file: Database filename. :param db_file: Database filename.
:return: Cursor. :return: Cursor.
""" """
@ -105,7 +105,7 @@ def get_cursor(db_file):
async def add_feed(db_file, title, url, res): async def add_feed(db_file, title, url, res):
""" """
Add a new feed into the feeds table. Add a new feed into the feeds table.
:param db_file: Database filename. :param db_file: Database filename.
:param title: Feed title. :param title: Feed title.
:param url: URL. :param url: URL.
@ -134,14 +134,15 @@ async def add_feed(db_file, title, url, res):
cur.execute(sql, feed) cur.execute(sql, feed)
source = title if title else '<' + url + '>' source = title if title else '<' + url + '>'
msg = '> {}\nNews source "{}" has been added to subscription list'.format(url, source) msg = """> {}\nNews source \"{}\" has been added to subscription list.
""".format(url, source)
return msg return msg
async def remove_feed(db_file, ix): async def remove_feed(db_file, ix):
""" """
Delete a feed by feed id. Delete a feed by feed id.
:param db_file: Database filename. :param db_file: Database filename.
:param ix: Index of feed. :param ix: Index of feed.
:return: Message. :return: Message.
@ -151,18 +152,20 @@ async def remove_feed(db_file, ix):
cur = conn.cursor() cur = conn.cursor()
try: try:
sql = "SELECT address FROM feeds WHERE id = ?" sql = "SELECT address FROM feeds WHERE id = ?"
url = cur.execute(sql, (ix,)) # cur
for i in url: # for i in url:
url = i[0] # url = i[0]
url = cur.execute(sql, (ix,)).fetchone()[0]
sql = "SELECT name FROM feeds WHERE id = ?"
name = cur.execute(sql, (ix,)).fetchone()[0]
# NOTE Should we move DBLOCK to this line? 2022-12-23 # NOTE Should we move DBLOCK to this line? 2022-12-23
sql = "DELETE FROM entries WHERE source = ?" sql = "DELETE FROM entries WHERE source = ?"
cur.execute(sql, (url,)) cur.execute(sql, (url,))
sql = "DELETE FROM feeds WHERE id = ?" sql = "DELETE FROM feeds WHERE id = ?"
cur.execute(sql, (ix,)) cur.execute(sql, (ix,))
msg = """News source <{}> has been removed from subscription list msg = "> {}\nNews source \"{}\" has been removed from subscription list.".format(url, name)
""".format(url)
except: except:
msg = """No news source with ID {}""".format(ix) msg = "No news source with ID {}.".format(ix)
return msg return msg
@ -170,22 +173,21 @@ async def check_feed_exist(db_file, url):
""" """
Check whether a feed exists. Check whether a feed exists.
Query for feeds by given url. Query for feeds by given url.
:param db_file: Database filename. :param db_file: Database filename.
:param url: URL. :param url: URL.
:return: Index ID and Name or None. :return: Index ID and Name or None.
""" """
cur = get_cursor(db_file) cur = get_cursor(db_file)
sql = "SELECT id, name FROM feeds WHERE address = ?" sql = "SELECT id, name FROM feeds WHERE address = ?"
cur.execute(sql, (url,)) result = cur.execute(sql, (url,)).fetchone()
result = cur.fetchone()
return result return result
async def get_number_of_items(db_file, str): async def get_number_of_items(db_file, str):
""" """
Return number of entries or feeds. Return number of entries or feeds.
:param cur: Cursor object. :param cur: Cursor object.
:param str: "entries" or "feeds". :param str: "entries" or "feeds".
:return: Number of rows. :return: Number of rows.
@ -193,8 +195,22 @@ async def get_number_of_items(db_file, str):
with create_connection(db_file) as conn: with create_connection(db_file) as conn:
cur = conn.cursor() cur = conn.cursor()
sql = "SELECT count(id) FROM {}".format(str) sql = "SELECT count(id) FROM {}".format(str)
count = cur.execute(sql) count = cur.execute(sql).fetchone()[0]
count = cur.fetchone()[0] return count
async def get_number_of_feeds_active(db_file):
"""
Return number of active feeds.
:param db_file: Database filename.
:param cur: Cursor object.
:return: Number of rows.
"""
with create_connection(db_file) as conn:
cur = conn.cursor()
sql = "SELECT count(id) FROM feeds WHERE enabled = 1"
count = cur.execute(sql).fetchone()[0]
return count return count
@ -209,8 +225,7 @@ async def get_number_of_entries_unread(db_file):
with create_connection(db_file) as conn: with create_connection(db_file) as conn:
cur = conn.cursor() cur = conn.cursor()
sql = "SELECT count(id) FROM entries WHERE read = 0" sql = "SELECT count(id) FROM entries WHERE read = 0"
count = cur.execute(sql) count = cur.execute(sql).fetchone()[0]
count = cur.fetchone()[0]
return count return count
@ -223,26 +238,18 @@ async def get_entry_unread(db_file):
""" """
with create_connection(db_file) as conn: with create_connection(db_file) as conn:
cur = conn.cursor() cur = conn.cursor()
entry = []
sql = "SELECT id FROM entries WHERE read = 0" sql = "SELECT id FROM entries WHERE read = 0"
ix = cur.execute(sql).fetchone() ix = cur.execute(sql).fetchone()
if ix is None: if ix is None:
return False return False
ix = ix[0] ix = ix[0]
sql = "SELECT title FROM entries WHERE id = :id" sql = "SELECT title FROM entries WHERE id = :id"
cur.execute(sql, (ix,)) title = cur.execute(sql, (ix,)).fetchone()[0]
title = cur.fetchone()[0]
entry.append(title)
sql = "SELECT summary FROM entries WHERE id = :id" sql = "SELECT summary FROM entries WHERE id = :id"
cur.execute(sql, (ix,)) summary = cur.execute(sql, (ix,)).fetchone()[0]
summary = cur.fetchone()[0]
entry.append(summary)
sql = "SELECT link FROM entries WHERE id = :id" sql = "SELECT link FROM entries WHERE id = :id"
cur.execute(sql, (ix,)) link = cur.execute(sql, (ix,)).fetchone()[0]
link = cur.fetchone()[0] entry = "{}\n\n{}\n\n{}".format(title, summary, link)
entry.append(link)
entry = "{}\n\n{}\n\n{}".format(entry[0], entry[1], entry[2])
# print(entry)
async with DBLOCK: async with DBLOCK:
await mark_as_read(cur, ix) await mark_as_read(cur, ix)
# async with DBLOCK: # async with DBLOCK:
@ -264,17 +271,28 @@ async def mark_as_read(cur, ix):
async def statistics(db_file): async def statistics(db_file):
""" """
Return table statistics. Return table statistics.
:param db_file: Database filename. :param db_file: Database filename.
:return: News item as message. :return: News item as message.
""" """
feeds = await get_number_of_items(db_file, 'feeds') feeds = await get_number_of_items(db_file, 'feeds')
active_feeds = await get_number_of_feeds_active(db_file)
entries = await get_number_of_items(db_file, 'entries') entries = await get_number_of_items(db_file, 'entries')
unread_entries = await get_number_of_entries_unread(db_file) unread_entries = await get_number_of_entries_unread(db_file)
msg = "You have {} unread news items out of {} from {} news sources.".format(unread_entries, entries, feeds) # msg = """You have {} unread news items out of {} from {} news sources.
# """.format(unread_entries, entries, feeds)
with create_connection(db_file) as conn:
cur = conn.cursor()
sql = "SELECT value FROM settings WHERE key = \"enabled\""
status = cur.execute(sql).fetchone()[0]
sql = "SELECT value FROM settings WHERE key = \"interval\""
interval = cur.execute(sql).fetchone()[0]
msg = """News items: {} ({})\nNews sources: {} ({})\nUpdate interval: {}\nOperation status: {}
""".format(unread_entries, entries, active_feeds, feeds, interval, status)
return msg return msg
#TODO statistics
async def update_statistics(cur): async def update_statistics(cur):
""" """
Update table statistics. Update table statistics.
@ -293,8 +311,7 @@ async def update_statistics(cur):
cur.execute(sql, {"title": i, "num": stat_dict[i]}) cur.execute(sql, {"title": i, "num": stat_dict[i]})
else: else:
sql = "SELECT count(id) FROM statistics" sql = "SELECT count(id) FROM statistics"
count = cur.execute(sql) count = cur.execute(sql).fetchone()[0]
count = cur.fetchone()[0]
ix = count + 1 ix = count + 1
sql = "INSERT INTO statistics VALUES(?,?,?)" sql = "INSERT INTO statistics VALUES(?,?,?)"
cur.execute(sql, (ix, i, stat_dict[i])) cur.execute(sql, (ix, i, stat_dict[i]))
@ -312,33 +329,34 @@ async def toggle_status(db_file, ix):
async with DBLOCK: async with DBLOCK:
with create_connection(db_file) as conn: with create_connection(db_file) as conn:
cur = conn.cursor() cur = conn.cursor()
#cur = get_cursor(db_file) try:
sql = "SELECT name FROM feeds WHERE id = :id" #cur = get_cursor(db_file)
cur.execute(sql, (ix,)) sql = "SELECT name FROM feeds WHERE id = :id"
title = cur.fetchone()[0] title = cur.execute(sql, (ix,)).fetchone()[0]
sql = "SELECT enabled FROM feeds WHERE id = ?" sql = "SELECT enabled FROM feeds WHERE id = ?"
# NOTE [0][1][2] # NOTE [0][1][2]
cur.execute(sql, (ix,)) status = cur.execute(sql, (ix,)).fetchone()[0]
status = cur.fetchone()[0] # FIXME always set to 1
# FIXME always set to 1 # NOTE Maybe because is not integer
# NOTE Maybe because is not integer # TODO Reset feed table before further testing
# TODO Reset feed table before further testing if status == 1:
if status == 1: status = 0
status = 0 state = "disabled"
state = "disabled" else:
else: status = 1
status = 1 state = "enabled"
state = "enabled" sql = "UPDATE feeds SET enabled = :status WHERE id = :id"
sql = "UPDATE feeds SET enabled = :status WHERE id = :id" cur.execute(sql, {"status": status, "id": ix})
cur.execute(sql, {"status": status, "id": ix}) msg = "Updates for '{}' are now {}.".format(title, state)
msg = "Updates for '{}' are now {}".format(title, state) except:
msg = "No news source with ID {}.".format(ix)
return msg return msg
async def set_date(cur, url): async def set_date(cur, url):
""" """
Set last update date of feed. Set last update date of feed.
:param cur: Cursor object. :param cur: Cursor object.
:param url: URL. :param url: URL.
""" """
@ -384,7 +402,7 @@ async def update_source_validity(db_file, source, valid):
async def add_entry(cur, entry): async def add_entry(cur, entry):
""" """
Add a new entry into the entries table. Add a new entry into the entries table.
:param cur: Cursor object. :param cur: Cursor object.
:param entry: :param entry:
""" """
@ -414,8 +432,7 @@ async def remove_entry(db_file, source, length):
with create_connection(db_file) as conn: with create_connection(db_file) as conn:
cur = conn.cursor() cur = conn.cursor()
sql = "SELECT count(id) FROM entries WHERE source = ?" sql = "SELECT count(id) FROM entries WHERE source = ?"
count = cur.execute(sql, (source,)) count = cur.execute(sql, (source,)).fetchone()[0]
count = cur.fetchone()[0]
limit = count - length limit = count - length
if limit: if limit:
limit = limit; limit = limit;
@ -432,7 +449,7 @@ async def remove_nonexistent_entries(db_file, feed, source):
Remove entries that don't exist in a given parsed feed. Remove entries that don't exist in a given parsed feed.
Check the entries returned from feed and delete non Check the entries returned from feed and delete non
existing entries existing entries
:param db_file: Database filename. :param db_file: Database filename.
:param feed: URL of parsed feed. :param feed: URL of parsed feed.
:param source: URL of associated feed. :param source: URL of associated feed.
@ -441,8 +458,7 @@ async def remove_nonexistent_entries(db_file, feed, source):
with create_connection(db_file) as conn: with create_connection(db_file) as conn:
cur = conn.cursor() cur = conn.cursor()
sql = "SELECT id, title, link FROM entries WHERE source = ?" sql = "SELECT id, title, link FROM entries WHERE source = ?"
cur.execute(sql, (source,)) entries_db = cur.execute(sql, (source,)).fetchall()
entries_db = cur.fetchall()
for entry_db in entries_db: for entry_db in entries_db:
exist = False exist = False
for entry_feed in feed.entries: for entry_feed in feed.entries:
@ -477,15 +493,14 @@ async def get_subscriptions(db_file):
with create_connection(db_file) as conn: with create_connection(db_file) as conn:
cur = conn.cursor() cur = conn.cursor()
sql = "SELECT address FROM feeds WHERE enabled = 1" sql = "SELECT address FROM feeds WHERE enabled = 1"
cur.execute(sql) result = cur.execute(sql).fetchall()
result = cur.fetchall()
return result return result
async def list_subscriptions(db_file): async def list_subscriptions(db_file):
""" """
Query table feeds and list items. Query table feeds and list items.
:param db_file: Database filename. :param db_file: Database filename.
:return: List of feeds. :return: List of feeds.
""" """
@ -566,7 +581,7 @@ async def check_entry_exist(db_file, title, link):
""" """
Check whether an entry exists. Check whether an entry exists.
Query entries by title and link. Query entries by title and link.
:param db_file: Database filename. :param db_file: Database filename.
:param link: Entry URL. :param link: Entry URL.
:param title: Entry title. :param title: Entry title.
@ -574,8 +589,7 @@ async def check_entry_exist(db_file, title, link):
""" """
cur = get_cursor(db_file) cur = get_cursor(db_file)
sql = "SELECT id FROM entries WHERE title = :title and link = :link" sql = "SELECT id FROM entries WHERE title = :title and link = :link"
cur.execute(sql, {"title": title, "link": link}) result = cur.execute(sql, {"title": title, "link": link}).fetchone()
result = cur.fetchone()
return result return result
# TODO dictionary # TODO dictionary
@ -597,20 +611,22 @@ async def check_entry_exist(db_file, title, link):
async def set_settings_value(db_file, key_value): async def set_settings_value(db_file, key_value):
""" """
Set settings value. Set settings value.
:param db_file: Database filename. :param db_file: Database filename.
:param key_value: List of key ("enabled", "interval", "quantum") and value (Integer). :param key_value: List of key ("enabled", "interval", "quantum") and value (Integer).
:return: Message. :return: Message.
""" """
if isinstance(key_value, list): # if isinstance(key_value, list):
key = key_value[0] # key = key_value[0]
val = key_value[1] # val = key_value[1]
elif key_value == "enable": # elif key_value == "enable":
key = "enabled" # key = "enabled"
val = 1 # val = 1
else: # else:
key = "enabled" # key = "enabled"
val = 0 # val = 0
key = key_value[0]
val = key_value[1]
async with DBLOCK: async with DBLOCK:
with create_connection(db_file) as conn: with create_connection(db_file) as conn:
cur = conn.cursor() cur = conn.cursor()
@ -618,11 +634,15 @@ async def set_settings_value(db_file, key_value):
sql = "UPDATE settings SET value = :value WHERE key = :key" sql = "UPDATE settings SET value = :value WHERE key = :key"
cur.execute(sql, {"key": key, "value": val}) cur.execute(sql, {"key": key, "value": val})
if key == 'quantum': if key == 'quantum':
msg = "Every update will contain {} news items.".format(val) msg = "Each update will contain {} news items.".format(val)
elif key == 'interval': elif key == 'interval':
msg = "Updates will be sent every {} minutes.".format(val) msg = "Updates will be sent every {} minutes.".format(val)
else: else:
msg = "Updates are {}d.".format(key_value) if val:
status = "disabled"
else:
status = "enabled"
msg = "Updates are {}.".format(status)
return msg return msg
@ -648,7 +668,7 @@ async def set_settings_value_default(cur, key):
async def get_settings_value(db_file, key): async def get_settings_value(db_file, key):
""" """
Get settings value. Get settings value.
:param db_file: Database filename. :param db_file: Database filename.
:param key: "enabled", "interval", "quantum". :param key: "enabled", "interval", "quantum".
""" """
@ -667,8 +687,7 @@ async def get_settings_value(db_file, key):
try: try:
cur = conn.cursor() cur = conn.cursor()
sql = "SELECT value FROM settings WHERE key = ?" sql = "SELECT value FROM settings WHERE key = ?"
cur.execute(sql, (key,)) result = cur.execute(sql, (key,)).fetchone()[0]
result = cur.fetchone()[0]
except: except:
result = await set_settings_value_default(cur, key) result = await set_settings_value_default(cur, key)
if not result: if not result: