Blasta/blasta/database/sqlite.py

2042 lines
62 KiB
Python
Raw Permalink Normal View History

#!/usr/bin/python
# -*- coding: utf-8 -*-
from asyncio import Lock
from sqlite3 import connect, Error, IntegrityError
import sys
import time
DBLOCK = Lock()
class DatabaseSQLite:
#from slixfeed.log import Logger
#from slixfeed.utilities import DateAndTime, Url
# DBLOCK = Lock()
#logger = Logger(__name__)
def create_connection(db_file):
"""
Create a database connection to the SQLite database
specified by db_file.
Parameters
----------
db_file : str
Path to database file.
Returns
-------
conn : object
Connection object or None.
"""
time_begin = time.time()
function_name = sys._getframe().f_code.co_name
# message_log = '{}'
# logger.debug(message_log.format(function_name))
conn = None
try:
conn = connect(db_file)
conn.execute("PRAGMA foreign_keys = ON")
# return conn
except Error as e:
print(e)
# logger.warning('Error creating a connection to database {}.'.format(db_file))
# logger.error(e)
time_end = time.time()
difference = time_end - time_begin
if difference > 1: logger.warning('{} (time: {})'.format(function_name,
difference))
return conn
def create_tables(sql_filename, db_file):
"""
Create SQLite tables.
Parameters
----------
db_file : str
Path to database file.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {}'
# .format(function_name, db_file))
with DatabaseSQLite.create_connection(db_file) as conn:
# Read the SQL script from the file
with open(sql_filename, 'r') as sql_file:
sql_script = sql_file.read()
cur = conn.cursor()
# Execute the SQL script
try:
cur.executescript(sql_script)
print("Table created successfully.")
except sqlite3.Error as e:
print(f"An error occurred: {e}")
async def associate_entries_tags_jids(db_file, entry):
async with DBLOCK:
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
jid = entry['jid']
url_hash = entry['url_hash']
entry_id = DatabaseSQLite.get_entry_id_by_url_hash(db_file, url_hash)
jid_id = DatabaseSQLite.get_jid_id_by_jid(db_file, jid)
if entry_id:
for tag in entry['tags']:
tag_id = DatabaseSQLite.get_tag_id_by_tag(db_file, tag)
cet_id = DatabaseSQLite.get_combination_id_by_entry_id_tag_id_jid_id(db_file, entry_id, tag_id, jid_id)
if not cet_id:
sql = (
"""
INSERT
INTO combination_entries_tags_jids (
entry_id, tag_id, jid_id)
VALUES (
?, ?, ?);
"""
)
par = (entry_id, tag_id, jid_id)
try:
cur.execute(sql, par)
except IntegrityError as e:
print('associate_entries_tags_jids')
print(e)
async def add_tags(db_file, entries):
"""
Batch insertion of tags.
Parameters
----------
db_file : str
Path to database file.
entries : list
Set of entries.
Returns
-------
None.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {}'
# .format(function_name, db_file))
async with DBLOCK:
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
for entry in entries:
tags = entry['tags']
for tag in tags:
# sql = (
# """
# INSERT OR IGNORE INTO main_tags(tag) VALUES (?);
# """
# )
if not DatabaseSQLite.get_tag_id_by_tag(db_file, tag):
sql = (
"""
INSERT INTO main_tags(tag) VALUES(?);
"""
)
par = (tag,)
try:
cur.execute(sql, par)
except IntegrityError as e:
print(e)
async def add_new_entries(db_file, entries):
"""
Batch insert of new entries into table entries.
Parameters
----------
db_file : str
Path to database file.
entries : list
Set of entries.
Returns
-------
None.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {}'
# .format(function_name, db_file))
async with DBLOCK:
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
for entry in entries:
url_hash = entry['url_hash']
url = entry['link']
title = entry['title']
summary = entry['summary']
jid = entry['jid']
date_first = entry['published']
date_last = entry['published']
# instances = entry['instances']
# Import entries
jid_id = DatabaseSQLite.get_jid_id_by_jid(db_file, jid)
sql = (
"""
INSERT
INTO main_entries(
url_hash, url, title, summary, jid_id, date_first, date_last)
VALUES(
?, ?, ?, ?, ?, ?, ?);
"""
)
par = (url_hash, url, title, summary, jid_id, date_first, date_last)
try:
cur.execute(sql, par)
except IntegrityError as e:
print(e)
print(jid_id)
print(entry)
# logger.warning("Skipping: " + str(url))
# logger.error(e)
# TODO An additional function to ssociate jid_id (jid) with entry_id (hash_url)
async def set_jid(db_file, jid):
"""
Add a JID to database.
Parameters
----------
db_file : str
Path to database file.
jid : str
A Jabber ID.
Returns
-------
None.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} jid: {}'
# .format(function_name, db_file, jid))
sql = (
"""
INSERT
INTO main_jids(
jid)
VALUES(
?);
"""
)
par = (jid, )
async with DBLOCK:
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
try:
cur.execute(sql, par)
except IntegrityError as e:
print(e)
# logger.warning("Skipping: " + str(url))
# logger.error(e)
def get_entries_count(db_file):
"""
Get entries count.
Parameters
----------
db_file : str
Path to database file.
Returns
-------
result : tuple
Number.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {}'
# .format(function_name, db_file))
sql = (
"""
SELECT count
FROM main_statistics
WHERE type = "entries";
"""
)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql).fetchone()
return result[0] if result and len(result) == 1 else result
def get_combination_id_by_entry_id_tag_id_jid_id(db_file, entry_id, tag_id, jid_id):
"""
Get ID by a given Entry ID and a given Tag ID and a given Jabber ID.
Parameters
----------
db_file : str
Path to database file.
entry_id : str
Entry ID.
tag_id : str
Tag ID.
jid_id : str
Jabber ID.
Returns
-------
result : tuple
ID.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} entry_id: {} tag_id: {} jid_id: {}'
# .format(function_name, db_file, entry_id, tag_id, jid_id))
sql = (
"""
SELECT id
FROM combination_entries_tags_jids
WHERE entry_id = :entry_id AND tag_id = :tag_id AND jid_id = :jid_id;
"""
)
par = {
"entry_id": entry_id,
"tag_id": tag_id,
"jid_id": jid_id
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchone()
return result[0] if result and len(result) == 1 else result
async def delete_combination_row_by_url_hash_and_tag_and_jid(db_file, url_hash, tags, jid):
"""
Delete a row by a given entry ID and a given Jabber ID and given tags.
Parameters
----------
db_file : str
Path to database file.
url_hash : str
URL hash.
tags : list
Tags.
jid : str
Jabber ID.
Returns
-------
None.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} url_hash: {} tag_id: {} jid_id: {}'
# .format(function_name, db_file, url_hash, tag_id, jid_id))
sql = (
"""
DELETE
FROM combination_entries_tags_jids
WHERE
entry_id = (SELECT id FROM main_entries WHERE url_hash = :url_hash) AND
tag_id = (SELECT id FROM main_tags WHERE tag = :tag) AND
jid_id = (SELECT id FROM main_jids WHERE jid = :jid);
"""
)
async with DBLOCK:
with DatabaseSQLite.create_connection(db_file) as conn:
for tag in tags:
par = {
"url_hash": url_hash,
"tag": tag,
"jid": jid
}
cur = conn.cursor()
cur.execute(sql, par)
def get_tag_id_and_instances_by_tag(db_file, tag):
"""
Get a tag ID and instances by a given tag.
Parameters
----------
db_file : str
Path to database file.
tag : str
Tag.
Returns
-------
result : tuple
Tag ID.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} tag: {}'
# .format(function_name, db_file, tag))
sql = (
"""
SELECT id, instances
FROM main_tags
WHERE tag = ?;
"""
)
par = (tag,)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchone()
# return result[0] if result else None, None
if not result: result = None, None
return result
def get_tags_and_instances_by_url_hash(db_file, url_hash):
"""
Get tags and instances by a given URL hash.
Parameters
----------
db_file : str
Path to database file.
url_hash : str
A hash of a URL.
Returns
-------
result : tuple
Tags and instances.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
sql = (
"""
SELECT mt.tag, mt.instances
FROM main_tags AS mt
INNER JOIN combination_entries_tags_jids AS co ON mt.id = co.tag_id
INNER JOIN main_entries AS me ON me.id = co.entry_id
WHERE me.url_hash = ?
ORDER BY mt.instances DESC;
"""
)
par = (url_hash,)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_tags_and_instances_by_entry_id(db_file, entry_id):
"""
Get tags and instances by a given ID entry.
Parameters
----------
db_file : str
Path to database file.
entry_id : str
An ID of an entry.
Returns
-------
result : tuple
Tags and instances.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
sql = (
"""
SELECT main_tags.tag, main_tags.instances
FROM main_tags
INNER JOIN combination_entries_tags_jids ON main_tags.id = combination_entries_tags_jids.tag_id
WHERE combination_entries_tags_jids.entry_id = ?
ORDER BY main_tags.instances DESC;
"""
)
par = (entry_id,)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_jids_and_tags_by_entry_id(db_file, entry_id):
"""
Get JIDs and tags by a given ID entry.
Parameters
----------
db_file : str
Path to database file.
entry_id : str
An ID of an entry.
Returns
-------
result : tuple
JIDs and tags.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
sql = (
"""
SELECT main_jids.jid, main_tags.tag
FROM main_tags
INNER JOIN combination_entries_tags_jids ON main_tags.id = combination_entries_tags_jids.tag_id
INNER JOIN main_jids ON main_jids.id = combination_entries_tags_jids.jid_id
WHERE combination_entries_tags_jids.entry_id = ?
ORDER BY main_tags.instances DESC;
"""
)
par = (entry_id,)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_jids_and_tags_by_url_hash(db_file, url_hash):
"""
Get JIDs and tags by a given URI hash.
Parameters
----------
db_file : str
Path to database file.
url_hash : str
A URL hash of an entry.
Returns
-------
result : tuple
JIDs and tags.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
sql = (
"""
SELECT main_jids.jid, main_tags.tag
FROM main_tags
INNER JOIN combination_entries_tags_jids ON main_tags.id = combination_entries_tags_jids.tag_id
INNER JOIN main_jids ON main_jids.id = combination_entries_tags_jids.jid_id
INNER JOIN main_entries ON main_entries.id = combination_entries_tags_jids.entry_id
WHERE main_entries.url_hash = ?
ORDER BY main_tags.instances DESC;
"""
)
par = (url_hash,)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_tag_id_by_tag(db_file, tag):
"""
Get a tag ID by a given tag.
Parameters
----------
db_file : str
Path to database file.
tag : str
Tag.
Returns
-------
result : tuple
Tag ID.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} tag: {}'
# .format(function_name, db_file, tag))
sql = (
"""
SELECT id
FROM main_tags
WHERE tag = ?;
"""
)
par = (tag,)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchone()
return result[0] if result and len(result) == 1 else result
def get_entry_id_by_url_hash(db_file, url_hash):
"""
Get an entry ID by a given URL hash.
Parameters
----------
db_file : str
Path to database file.
url_hash : str
MD5 hash of URL.
Returns
-------
result : tuple
Entry ID.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} url_hash: {}'
# .format(function_name, db_file, url_hash))
sql = (
"""
SELECT id
FROM main_entries
WHERE url_hash = ?;
"""
)
par = (url_hash,)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchone()
return result[0] if result and len(result) == 1 else result
def get_entry_instances_by_url_hash(db_file, url_hash):
"""
Get value of entry instances by a given URL hash.
Parameters
----------
db_file : str
Path to database file.
url_hash : str
MD5 hash of URL.
Returns
-------
result : tuple
Value of entry instances.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} url_hash: {}'
# .format(function_name, db_file, url_hash))
sql = (
"""
SELECT instances
FROM main_entries
WHERE url_hash = ?;
"""
)
par = (url_hash,)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchone()
return result[0] if result and len(result) == 1 else result
def get_entry_by_url_hash(db_file, url_hash):
"""
Get entry of a given URL hash.
Parameters
----------
db_file : str
Path to database file.
url_hash : str
MD5 hash of URL.
Returns
-------
result : tuple
Entry properties.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} url_hash: {}'
# .format(function_name, db_file, url_hash))
sql = (
"""
SELECT *
FROM main_entries
WHERE url_hash = ?;
"""
)
par = (url_hash,)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchone()
return result[0] if result and len(result) == 1 else result
def get_entries_new(db_file, index_first):
"""
Get new entries.
Parameters
----------
db_file : str
Path to database file.
index_first : str
.
Returns
-------
result : tuple
Entries properties.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
# NOTE Consider date_first
sql = (
"""
SELECT *
FROM main_entries
ORDER BY date_first DESC
LIMIT 10
OFFSET ?;
"""
)
par = (index_first,)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_entries_popular(db_file, index_first):
"""
Get popular entries.
Parameters
----------
db_file : str
Path to database file.
index_first : str
.
Returns
-------
result : tuple
Entries properties.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
# NOTE Consider date_first
sql = (
"""
SELECT *
FROM main_entries
ORDER BY instances DESC
LIMIT 10
OFFSET ?;
"""
)
par = (index_first,)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_entries_recent(db_file, index_first):
"""
Get recent entries.
Parameters
----------
db_file : str
Path to database file.
index_first : str
.
Returns
-------
result : tuple
Entries properties.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
# NOTE Consider date_first
sql = (
"""
SELECT *
FROM main_entries
ORDER BY date_last DESC
LIMIT 10
OFFSET ?;
"""
)
par = (index_first,)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_entries_by_query(db_file, query, index_first):
"""
Get entries by a query.
Parameters
----------
db_file : str
Path to database file.
query : str
Search query.
index_first : str
.
Returns
-------
result : tuple
Entries properties.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
# NOTE Consider date_first
sql = (
"""
SELECT *
FROM main_entries
WHERE title LIKE :query OR url LIKE :query OR summary LIKE :query
ORDER BY instances DESC
LIMIT 10
OFFSET :index_first;
"""
)
par = {
"query": f'%{query}%',
"index_first": index_first
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_entries_count_by_query(db_file, query):
"""
Get entries count by a query.
Parameters
----------
db_file : str
Path to database file.
query : str
Search query.
Returns
-------
result : tuple
Entries properties.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {}'
# .format(function_name, db_file))
# NOTE Consider date_first
sql = (
"""
SELECT COUNT(id)
FROM main_entries
WHERE title LIKE :query OR url LIKE :query OR summary LIKE :query
ORDER BY instances DESC;
"""
)
par = {
"query": f'%{query}%',
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchone()
return result[0] if result and len(result) == 1 else result
def get_entries_by_jid_and_tag(db_file, jid, tag, index_first):
"""
Get entries by a tag and a Jabber ID.
Parameters
----------
db_file : str
Path to database file.
tag : str
Tag.
jid : str
Jabber ID.
index_first : str
.
Returns
-------
result : tuple
Entries properties.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} tag: {} jid: {} index_first: {}'
# .format(function_name, db_file, tag, jid, index_first))
# NOTE Consider date_first
sql = (
"""
SELECT DISTINCT me.*
FROM main_entries AS me
INNER JOIN combination_entries_tags_jids AS co ON co.entry_id = me.id
INNER JOIN main_jids AS mj ON mj.id = co.jid_id
INNER JOIN main_tags AS mt ON mt.id = co.tag_id
WHERE mj.jid = :jid AND mt.tag = :tag
ORDER BY instances DESC
LIMIT 10
OFFSET :index_first;
"""
)
par = {
"jid": jid,
"tag": tag,
"index_first": index_first
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_entries_count_by_jid_and_tag(db_file, jid, tag):
"""
Get entries count by a tag and a Jabber ID.
Parameters
----------
db_file : str
Path to database file.
tag : str
Tag.
jid : str
Jabber ID.
Returns
-------
result : tuple
Entries properties.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} tag: {} jid: {}'
# .format(function_name, db_file, tag, jid))
# NOTE Consider date_first
sql = (
"""
SELECT COUNT(DISTINCT me.id)
FROM main_entries AS me
INNER JOIN combination_entries_tags_jids AS co ON co.entry_id = me.id
INNER JOIN main_jids AS mj ON mj.id = co.jid_id
INNER JOIN main_tags AS mt ON mt.id = co.tag_id
WHERE mj.jid = :jid AND mt.tag = :tag;
"""
)
par = {
"jid": jid,
"tag": tag
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchone()
return result[0] if result and len(result) == 1 else result
def get_entries_by_jid_and_query(db_file, jid, query, index_first):
"""
Get entries by a query and a Jabber ID.
Parameters
----------
db_file : str
Path to database file.
query : str
Search query.
jid : str
Jabber ID.
index_first : str
.
Returns
-------
result : tuple
Entries properties.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} query: {} jid: {} index_first: {}'
# .format(function_name, db_file, query, jid, index_first))
# NOTE Consider date_first
sql = (
"""
SELECT DISTINCT me.*
FROM main_entries AS me
INNER JOIN combination_entries_tags_jids AS co ON co.entry_id = me.id
INNER JOIN main_jids AS mj ON mj.id = co.jid_id
WHERE mj.jid = :jid AND (title LIKE :query OR url LIKE :query OR summary LIKE :query)
ORDER BY instances DESC
LIMIT 10
OFFSET :index_first;
"""
)
par = {
"jid": jid,
"query": f'%{query}%',
"index_first": index_first
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_entries_count_by_jid_and_query(db_file, jid, query):
"""
Get entries count by a query and a Jabber ID.
Parameters
----------
db_file : str
Path to database file.
query : str
Search query.
jid : str
Jabber ID.
Returns
-------
result : tuple
Entries properties.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} query: {} jid: {}'
# .format(function_name, db_file, query, jid))
# NOTE Consider date_first
sql = (
"""
SELECT COUNT(DISTINCT me.id)
FROM main_entries AS me
INNER JOIN combination_entries_tags_jids AS co ON co.entry_id = me.id
INNER JOIN main_jids AS mj ON mj.id = co.jid_id
WHERE mj.jid = :jid AND (title LIKE :query OR url LIKE :query OR summary LIKE :query);
"""
)
par = {
"jid": jid,
"query": f'%{query}%'
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchone()
return result[0] if result and len(result) == 1 else result
def get_entries_by_jid(db_file, jid, index_first):
"""
Get entries by a Jabber ID.
Parameters
----------
db_file : str
Path to database file.
jid : str
Jabber ID.
index_first : str
.
Returns
-------
result : tuple
Entries properties.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} jid: {} index_first: {}'
# .format(function_name, db_file, jid, index_first))
# NOTE Consider date_first
sql = (
"""
SELECT DISTINCT me.*
FROM main_entries AS me
INNER JOIN combination_entries_tags_jids AS co ON co.entry_id = me.id
INNER JOIN main_jids AS mj ON mj.id = co.jid_id
WHERE mj.jid = :jid
ORDER BY instances DESC
LIMIT 10
OFFSET :index_first;
"""
)
par = {
"jid": jid,
"index_first": index_first
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_entries_count_by_jid(db_file, jid):
"""
Get entries count by a Jabber ID.
Parameters
----------
db_file : str
Path to database file.
jid : str
Jabber ID.
Returns
-------
result : tuple
Entries properties.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} jid: {}'
# .format(function_name, db_file, jid))
# NOTE Consider date_first
sql = (
"""
SELECT COUNT(DISTINCT me.id)
FROM main_entries AS me
INNER JOIN combination_entries_tags_jids AS co ON co.entry_id = me.id
INNER JOIN main_jids AS mj ON mj.id = co.jid_id
WHERE mj.jid = :jid;
"""
)
par = {
"jid": jid
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchone()
return result[0] if result and len(result) == 1 else result
def get_entries_count_by_tag(db_file, tag):
"""
Get entries count by a given tag.
Parameters
----------
db_file : str
Path to database file.
tag : str
A tag.
Returns
-------
result : tuple
Entries.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} tag: {}'
# .format(function_name, db_file, tag))
sql = (
"""
SELECT COUNT(DISTINCT entries.id)
FROM main_entries AS entries
INNER JOIN combination_entries_tags_jids AS co ON entries.id = co.entry_id
INNER JOIN main_tags AS tags ON tags.id = co.tag_id
WHERE tags.tag = :tag;
"""
)
par = (tag,)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchone()
return result[0] if result and len(result) == 1 else result
def get_entries_popular_by_tag(db_file, tag, index_first):
"""
Get popular entries by a given tag.
Parameters
----------
db_file : str
Path to database file.
tag : str
A tag.
index_first : str
.
Returns
-------
result : tuple
Entries.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} tag: {}'
# .format(function_name, db_file, tag))
sql = (
"""
SELECT DISTINCT entries.*
FROM main_entries AS entries
INNER JOIN combination_entries_tags_jids AS co ON entries.id = co.entry_id
INNER JOIN main_tags AS tags ON tags.id = co.tag_id
WHERE tags.tag = :tag
ORDER BY entries.instances DESC
LIMIT 10
OFFSET :index_first;
"""
)
par = {
"tag": tag,
"index_first": index_first
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_entries_recent_by_tag(db_file, tag, index_first):
"""
Get recent entries by a given tag.
Parameters
----------
db_file : str
Path to database file.
tag : str
A tag.
index_first : str
.
Returns
-------
result : tuple
Entries.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} tag: {}'
# .format(function_name, db_file, tag))
sql = (
"""
SELECT DISTINCT entries.*
FROM main_entries AS entries
INNER JOIN combination_entries_tags_jids AS co ON entries.id = co.entry_id
INNER JOIN main_tags AS tags ON tags.id = co.tag_id
WHERE tags.tag = :tag
ORDER BY date_last DESC
LIMIT 10
OFFSET :index_first;
"""
)
par = {
"tag": tag,
"index_first": index_first
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_entries_new_by_tag(db_file, tag, index_first):
"""
Get new entries by a given tag.
Parameters
----------
db_file : str
Path to database file.
tag : str
A tag.
index_first : str
.
Returns
-------
result : tuple
Entries.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} tag: {}'
# .format(function_name, db_file, tag))
sql = (
"""
SELECT DISTINCT entries.*
FROM main_entries AS entries
INNER JOIN combination_entries_tags_jids AS co ON entries.id = co.entry_id
INNER JOIN main_tags AS tags ON tags.id = co.tag_id
WHERE tags.tag = :tag
ORDER BY date_first DESC
LIMIT 10
OFFSET :index_first;
"""
)
par = {
"tag": tag,
"index_first": index_first
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_tags_30(db_file):
"""
Get 30 tags.
Parameters
----------
db_file : str
Path to database file.
Returns
-------
result : tuple
Tags and number of instances.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
sql = (
"""
SELECT tag, instances
FROM main_tags
ORDER BY instances DESC
LIMIT 30;
"""
)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql).fetchall()
return result
def get_30_tags_by_entries_popular(db_file, index_first):
"""
Get 30 tags by currently viewed popular entries.
Parameters
----------
db_file : str
Path to database file.
index_first : str
.
Returns
-------
result : tuple
Tags and number of instances.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
sql = (
"""
SELECT DISTINCT mt.tag, mt.instances
FROM combination_entries_tags_jids AS co
INNER JOIN main_tags AS mt ON mt.id = co.tag_id
WHERE co.entry_id IN (
SELECT id
FROM main_entries
ORDER BY instances DESC
LIMIT 10
OFFSET ?
)
ORDER BY mt.instances DESC
LIMIT 30;
"""
)
par = (index_first,)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_30_tags_by_entries_new_by_tag(db_file, tag, index_first):
"""
Get 30 tags by currently viewed new entries by a given tag.
Parameters
----------
db_file : str
Path to database file.
index_first : str
.
Returns
-------
result : tuple
Tags and number of instances.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
sql = (
"""
SELECT DISTINCT mt.tag, mt.instances
FROM combination_entries_tags_jids AS co
INNER JOIN main_tags AS mt ON mt.id = co.tag_id
WHERE co.entry_id IN (
SELECT DISTINCT entries.id
FROM main_entries AS entries
INNER JOIN combination_entries_tags_jids AS co ON entries.id = co.entry_id
INNER JOIN main_tags AS tags ON tags.id = co.tag_id
WHERE tags.tag = :tag
ORDER BY date_first DESC
LIMIT 10
OFFSET :index_first
)
ORDER BY mt.instances DESC
LIMIT 30;
"""
)
par = {
"tag": tag,
"index_first": index_first
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_30_tags_by_entries_popular_by_tag(db_file, tag, index_first):
"""
Get 30 tags by currently viewed popular entries by a given tag.
Parameters
----------
db_file : str
Path to database file.
index_first : str
.
Returns
-------
result : tuple
Tags and number of instances.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
sql = (
"""
SELECT DISTINCT mt.tag, mt.instances
FROM combination_entries_tags_jids AS co
INNER JOIN main_tags AS mt ON mt.id = co.tag_id
WHERE co.entry_id IN (
SELECT DISTINCT entries.id
FROM main_entries AS entries
INNER JOIN combination_entries_tags_jids AS co ON entries.id = co.entry_id
INNER JOIN main_tags AS tags ON tags.id = co.tag_id
WHERE tags.tag = :tag
ORDER BY entries.instances DESC
LIMIT 10
OFFSET :index_first
)
ORDER BY mt.instances DESC
LIMIT 30;
"""
)
par = {
"tag": tag,
"index_first": index_first
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_30_tags_by_entries_recent_by_tag(db_file, tag, index_first):
"""
Get 30 tags by currently viewed recent entries by a given tag.
Parameters
----------
db_file : str
Path to database file.
index_first : str
.
Returns
-------
result : tuple
Tags and number of instances.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
sql = (
"""
SELECT DISTINCT mt.tag, mt.instances
FROM combination_entries_tags_jids AS co
INNER JOIN main_tags AS mt ON mt.id = co.tag_id
WHERE co.entry_id IN (
SELECT DISTINCT entries.id
FROM main_entries AS entries
INNER JOIN combination_entries_tags_jids AS co ON entries.id = co.entry_id
INNER JOIN main_tags AS tags ON tags.id = co.tag_id
WHERE tags.tag = :tag
ORDER BY date_last DESC
LIMIT 10
OFFSET :index_first
)
ORDER BY mt.instances DESC
LIMIT 30;
"""
)
par = {
"tag": tag,
"index_first": index_first
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_30_tags_by_entries_new(db_file, index_first):
"""
Get 30 tags by currently viewed new entries.
Parameters
----------
db_file : str
Path to database file.
index_first : str
.
Returns
-------
result : tuple
Tags and number of instances.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
sql = (
"""
SELECT DISTINCT mt.tag, mt.instances
FROM combination_entries_tags_jids AS co
INNER JOIN main_tags AS mt ON mt.id = co.tag_id
WHERE co.entry_id IN (
SELECT id
FROM main_entries
ORDER BY date_first DESC
LIMIT 10
OFFSET ?
)
ORDER BY mt.instances DESC
LIMIT 30;
"""
)
par = (index_first,)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_30_tags_by_entries_recent(db_file, index_first):
"""
Get 30 tags by currently viewed recent entries.
Parameters
----------
db_file : str
Path to database file.
index_first : str
.
Returns
-------
result : tuple
Tags and number of instances.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
sql = (
"""
SELECT DISTINCT mt.tag, mt.instances
FROM combination_entries_tags_jids AS co
INNER JOIN main_tags AS mt ON mt.id = co.tag_id
WHERE co.entry_id IN (
SELECT id
FROM main_entries
ORDER BY date_last DESC
LIMIT 10
OFFSET ?
)
ORDER BY mt.instances DESC
LIMIT 30;
"""
)
par = (index_first,)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_30_tags_by_entries_by_query_recent(db_file, query, index_first):
"""
Get 30 tags by currently viewed entries by query.
Parameters
----------
db_file : str
Path to database file.
query : str
A search query.
index_first : str
.
Returns
-------
result : tuple
Tags and number of instances.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
sql = (
"""
SELECT DISTINCT mt.tag, mt.instances
FROM combination_entries_tags_jids AS co
INNER JOIN main_tags AS mt ON mt.id = co.tag_id
WHERE co.entry_id IN (
SELECT id
FROM main_entries
WHERE title LIKE :query OR url LIKE :query OR summary LIKE :query
ORDER BY instances DESC
LIMIT 10
OFFSET :index_first
)
ORDER BY mt.instances DESC
LIMIT 30;
"""
)
par = {
"query": f'%{query}%',
"index_first": index_first
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_30_tags_by_jid_and_tag(db_file, jid, tag, index_first):
"""
Get 30 tags by Jabber ID and tags.
Parameters
----------
db_file : str
Path to database file.
jid : str
Jabber ID.
tag : str
A tag.
index_first : str
.
Returns
-------
result : tuple
Tags and number of instances.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
sql = (
"""
SELECT DISTINCT mt.tag, mt.instances
FROM combination_entries_tags_jids AS co
INNER JOIN main_tags AS mt ON mt.id = co.tag_id
WHERE co.entry_id IN (
SELECT co.entry_id
FROM main_entries AS me
INNER JOIN combination_entries_tags_jids AS co ON co.entry_id = me.id
INNER JOIN main_jids AS mj ON mj.id = co.jid_id
INNER JOIN main_tags AS mt ON mt.id = co.tag_id
WHERE mj.jid = :jid AND mt.tag = :tag
LIMIT 10
OFFSET :index_first
)
ORDER BY mt.instances DESC
LIMIT 30;
"""
)
par = {
"jid": jid,
"tag": tag,
"index_first": index_first
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_30_tags_by_jid_and_query(db_file, jid, query, index_first):
"""
Get 30 tags by Jabber ID and query.
Parameters
----------
db_file : str
Path to database file.
jid : str
Jabber ID.
query : str
A search query.
index_first : str
.
Returns
-------
result : tuple
Tags and number of instances.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
sql = (
"""
SELECT DISTINCT mt.tag, mt.instances
FROM combination_entries_tags_jids AS co
INNER JOIN main_tags AS mt ON mt.id = co.tag_id
WHERE co.entry_id IN (
SELECT co.entry_id
FROM main_entries AS me
INNER JOIN combination_entries_tags_jids AS co ON co.entry_id = me.id
INNER JOIN main_jids AS mj ON mj.id = co.jid_id
INNER JOIN main_tags AS mt ON mt.id = co.tag_id
WHERE mj.jid = :jid AND (title LIKE :query OR url LIKE :query OR summary LIKE :query)
LIMIT 10
OFFSET :index_first
)
ORDER BY mt.instances DESC
LIMIT 30;
"""
)
par = {
"jid": jid,
"query": f'%{query}%',
"index_first": index_first
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_30_tags_by_jid(db_file, jid, index_first):
"""
Get 30 tags by Jabber ID.
Parameters
----------
db_file : str
Path to database file.
jid : str
Jabber ID.
Returns
-------
result : tuple
Tags and number of instances.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
sql = (
"""
SELECT DISTINCT mt.tag, mt.instances
FROM combination_entries_tags_jids AS co
INNER JOIN main_tags AS mt ON mt.id = co.tag_id
WHERE co.entry_id IN (
SELECT DISTINCT me.id
FROM main_entries AS me
INNER JOIN combination_entries_tags_jids AS co ON co.entry_id = me.id
INNER JOIN main_jids AS mj ON mj.id = co.jid_id
WHERE mj.jid = :jid
ORDER BY instances DESC
LIMIT 10
OFFSET :index_first
)
ORDER BY mt.instances DESC
LIMIT 30;
"""
)
par = {
"jid": jid,
"index_first": index_first
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_tags_500(db_file):
"""
Get 500 tags.
Parameters
----------
db_file : str
Path to database file.
Returns
-------
result : tuple
Tags and number of instances.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {}'
# .format(function_name, db_file))
sql = (
"""
WITH Common500Tags AS (
SELECT tag, instances
FROM main_tags
ORDER BY instances DESC
LIMIT 500
)
SELECT tag, instances
FROM Common500Tags
ORDER BY tag ASC;
"""
)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql).fetchall()
return result
def get_500_tags_by_jid_sorted_by_name(db_file, jid):
"""
Get 500 tags by Jabber ID, sorted by name.
Parameters
----------
db_file : str
Path to database file.
jid : str
Jabber ID.
Returns
-------
result : tuple
Tags and number of instances.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
sql = (
"""
SELECT mt.tag, COUNT(*) AS instances
FROM main_tags mt
JOIN combination_entries_tags_jids combination ON mt.id = combination.tag_id
JOIN main_jids mj ON combination.jid_id = mj.id
WHERE mj.jid = :jid
GROUP BY mt.tag
LIMIT 500;
"""
)
par = {
"jid": jid
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_500_tags_by_jid_sorted_by_instance(db_file, jid):
"""
Get 500 tags by Jabber ID, sorted by instance.
Parameters
----------
db_file : str
Path to database file.
jid : str
Jabber ID.
Returns
-------
result : tuple
Tags and number of instances.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
sql = (
"""
SELECT mt.tag, COUNT(*) AS instances
FROM main_tags mt
JOIN combination_entries_tags_jids combination ON mt.id = combination.tag_id
JOIN main_jids mj ON combination.jid_id = mj.id
WHERE mj.jid = :jid
GROUP BY mt.tag
ORDER BY instances DESC
LIMIT 500;
"""
)
par = {
"jid": jid
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
# FIXME It appear that the wrong table is fetched
# The table to be fetched is combination_entries_tags_jids
def is_jid_associated_with_url_hash(db_file, jid, url_hash):
"""
Check whether a given Jabber ID is associated with a given URL hash.
Parameters
----------
db_file : str
Path to database file.
jid : str
A Jabber ID.
url_hash : str
An MD5 checksuum of a URL.
Returns
-------
result : tuple
Tags.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} jid: {} url_hash: {}'
# .format(function_name, db_file, jid, url_hash))
sql = (
"""
SELECT mj.jid, me.url_hash
FROM main_jids AS mj
INNER JOIN combination_entries_tags_jids AS co ON mj.id = co.jid_id
INNER JOIN main_entries AS me ON me.id = co.entry_id
WHERE mj.jid = :jid AND me.url_hash = :url_hash;
"""
)
par = {
"jid": jid,
"url_hash": url_hash
}
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchone()
return result[0] if result and len(result) == 1 else result
#deassociate_entry_from_jid
async def delete_combination_row_by_jid_and_url_hash(db_file, url_hash, jid):
"""
Remove association of a given Jabber ID and a given URL hash.
Parameters
----------
db_file : str
Path to database file.
jid : str
A Jabber ID.
url_hash : str
An MD5 checksuum of a URL.
Returns
-------
None.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} jid: {} url_hash: {}'
# .format(function_name, db_file, jid, url_hash))
sql = (
"""
DELETE FROM combination_entries_tags_jids
WHERE id IN (
SELECT co.id
FROM combination_entries_tags_jids co
JOIN main_entries me ON co.entry_id = me.id
JOIN main_jids mj ON co.jid_id = mj.id
WHERE me.url_hash = :url_hash AND mj.jid = :jid
);
"""
)
par = {
"jid": jid,
"url_hash": url_hash
}
async with DBLOCK:
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
cur.execute(sql, par)
# NOTE The result was ordered by number of instances
# ORDER BY main_tags.instances DESC
# And has been changed to order of alphabet
# ORDER BY main_tags.tag ASC
def get_tags_by_entry_id(db_file, entry_id):
"""
Get tags by an ID entry.
Parameters
----------
db_file : str
Path to database file.
entry_id : str
An ID of an entry.
Returns
-------
result : tuple
Tags.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} index_first: {}'
# .format(function_name, db_file, index_first))
sql = (
"""
SELECT DISTINCT main_tags.tag
FROM main_tags
INNER JOIN combination_entries_tags_jids ON main_tags.id = combination_entries_tags_jids.tag_id
WHERE combination_entries_tags_jids.entry_id = ?
ORDER BY main_tags.tag ASC
LIMIT 5;
"""
)
par = (entry_id,)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchall()
return result
def get_jid_id_by_jid(db_file, jid):
"""
Get id of a given jid.
Parameters
----------
db_file : str
Path to database file.
jid : str
Jabber ID.
Returns
-------
result : tuple
ID.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} jid: {}'
# .format(function_name, db_file, jid))
sql = (
"""
SELECT id
FROM main_jids
WHERE jid = ?;
"""
)
par = (jid,)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchone()
return result[0] if result and len(result) == 1 else result
def get_jid_by_jid_id(db_file, jid_id):
"""
Get jid of a given jid_id.
Parameters
----------
db_file : str
Path to database file.
jid_id : str
ID of Jabber ID.
Returns
-------
result : tuple
ID.
"""
function_name = sys._getframe().f_code.co_name
# logger.debug('{}: db_file: {} jid_id: {}'
# .format(function_name, db_file, jid_id))
sql = (
"""
SELECT jid
FROM main_jids
WHERE id = ?;
"""
)
par = (jid_id,)
with DatabaseSQLite.create_connection(db_file) as conn:
cur = conn.cursor()
result = cur.execute(sql, par).fetchone()
return result[0] if result and len(result) == 1 else result