2025-02-13 14:51:35 -05:00
|
|
|
import os
|
|
|
|
import logging
|
2025-02-16 20:07:02 -05:00
|
|
|
from typing import LiteralString, Optional, Union
|
2025-02-13 14:51:35 -05:00
|
|
|
import aiosqlite as sqlite3
|
|
|
|
from constructors import LoveHateException
|
|
|
|
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
class DB:
|
|
|
|
"""LoveHate DB Utility Class"""
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
def __init__(self, bot) -> None:
|
2025-04-17 14:35:56 -04:00
|
|
|
self.db_path: str | LiteralString = os.path.join(
|
|
|
|
"/usr/local/share", "sqlite_dbs", "lovehate.db"
|
|
|
|
)
|
|
|
|
|
|
|
|
async def get_wholovehates(
|
|
|
|
self, thing: str, loves: bool = False, hates: bool = False
|
|
|
|
) -> Union[list[tuple], bool]:
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
Get a list of users who have professed their love OR hatred for <thing>
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Args:
|
|
|
|
thing (str): The <thing> to check
|
|
|
|
loves (bool): Are we looking for loves?
|
|
|
|
hates (bool): ...or are we looking for hates?
|
|
|
|
Returns:
|
2025-03-12 09:37:44 -04:00
|
|
|
Union[list[tuple], bool]
|
2025-04-17 14:35:56 -04:00
|
|
|
"""
|
2025-02-13 14:51:35 -05:00
|
|
|
|
|
|
|
query: str = "SELECT display_name FROM lovehate WHERE thing LIKE ? AND flag = ?"
|
|
|
|
params: tuple = tuple()
|
|
|
|
flag: Optional[int] = None
|
|
|
|
|
|
|
|
if hates and loves:
|
|
|
|
raise LoveHateException("Both hates and loves may not be True")
|
|
|
|
elif hates:
|
2025-02-15 13:57:47 -05:00
|
|
|
flag = -1
|
2025-02-13 14:51:35 -05:00
|
|
|
elif loves:
|
2025-02-15 13:57:47 -05:00
|
|
|
flag = 1
|
2025-02-13 14:51:35 -05:00
|
|
|
elif not hates and not loves:
|
|
|
|
raise LoveHateException("Neither loves nor hates were requested")
|
2025-04-17 14:35:56 -04:00
|
|
|
|
|
|
|
params = (
|
|
|
|
thing,
|
|
|
|
flag,
|
|
|
|
)
|
2025-02-13 14:51:35 -05:00
|
|
|
async with sqlite3.connect(self.db_path, timeout=2) as db_conn:
|
|
|
|
async with await db_conn.execute(query, params) as db_cursor:
|
|
|
|
result: list[tuple] = await db_cursor.fetchall()
|
|
|
|
logging.debug("Result: %s", result)
|
|
|
|
if not result:
|
|
|
|
return False
|
|
|
|
return result
|
2025-04-17 14:35:56 -04:00
|
|
|
|
|
|
|
async def get_lovehates(
|
|
|
|
self,
|
|
|
|
loves: bool = False,
|
|
|
|
hates: bool = False,
|
|
|
|
user: Optional[str] = None,
|
|
|
|
thing: Optional[str] = None,
|
|
|
|
) -> Union[list[tuple], bool]:
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
Get a list of either 1) what {user} loves/hates, or who loves/hates {thing}, depending on bools loves, hates
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Args:
|
|
|
|
loves (bool): Are we looking for loves?
|
|
|
|
hates (bool): ...OR are we looking for hates?
|
|
|
|
user (Optional[str]): the user to query against
|
|
|
|
thing (Optional[str]): ... OR the thing to query against
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Returns:
|
2025-02-16 20:07:02 -05:00
|
|
|
Union[list[tuple], bool]
|
2025-02-13 14:51:35 -05:00
|
|
|
"""
|
|
|
|
|
|
|
|
query: str = ""
|
|
|
|
params: tuple = tuple()
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
if not user and not thing:
|
2025-04-17 14:35:56 -04:00
|
|
|
raise LoveHateException(
|
|
|
|
"Neither a <user> or <thing> was specified to query against"
|
|
|
|
)
|
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
flag: Optional[int] = None
|
|
|
|
|
|
|
|
if hates and loves:
|
|
|
|
raise LoveHateException("Both hates and loves may not be True")
|
|
|
|
elif hates:
|
2025-02-15 13:57:47 -05:00
|
|
|
flag = -1
|
2025-02-13 14:51:35 -05:00
|
|
|
elif loves:
|
2025-02-15 13:57:47 -05:00
|
|
|
flag = 1
|
2025-02-13 14:51:35 -05:00
|
|
|
elif not hates and not loves:
|
|
|
|
raise LoveHateException("Neither loves nor hates were requested")
|
|
|
|
|
|
|
|
if user:
|
2025-02-15 13:57:47 -05:00
|
|
|
query = "SELECT thing FROM lovehate WHERE display_name LIKE ? AND flag == ?"
|
2025-04-17 14:35:56 -04:00
|
|
|
params = (
|
|
|
|
user,
|
|
|
|
flag,
|
|
|
|
)
|
2025-02-13 14:51:35 -05:00
|
|
|
elif thing:
|
2025-02-15 13:57:47 -05:00
|
|
|
query = "SELECT display_name FROM lovehate WHERE thing LIKE ? AND flag == ?"
|
2025-04-17 14:35:56 -04:00
|
|
|
params = (
|
|
|
|
thing,
|
|
|
|
flag,
|
|
|
|
)
|
2025-02-13 14:51:35 -05:00
|
|
|
|
|
|
|
async with sqlite3.connect(self.db_path, timeout=2) as db_conn:
|
|
|
|
async with await db_conn.execute(query, params) as db_cursor:
|
|
|
|
result = await db_cursor.fetchall()
|
|
|
|
if not result:
|
|
|
|
return False
|
|
|
|
return result
|
|
|
|
|
|
|
|
async def check_existence(self, user: str, thing: str) -> Optional[int]:
|
|
|
|
"""
|
|
|
|
Determine whether a user is opinionated on a <thing>
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Args:
|
|
|
|
user (str): The user to check
|
|
|
|
thing (str): The thing to check if the user has an opinion on
|
|
|
|
Returns:
|
|
|
|
Optional[int]
|
|
|
|
"""
|
2025-04-17 14:35:56 -04:00
|
|
|
|
|
|
|
params = (
|
|
|
|
user,
|
|
|
|
thing,
|
|
|
|
)
|
2025-02-13 14:51:35 -05:00
|
|
|
|
|
|
|
async with sqlite3.connect(self.db_path, timeout=2) as db_conn:
|
2025-04-17 14:35:56 -04:00
|
|
|
async with await db_conn.execute(
|
|
|
|
"SELECT id, flag FROM lovehate WHERE display_name LIKE ? AND thing LIKE ?",
|
|
|
|
params,
|
|
|
|
) as db_cursor:
|
2025-02-13 14:51:35 -05:00
|
|
|
result = await db_cursor.fetchone()
|
|
|
|
if not result:
|
|
|
|
return None
|
|
|
|
(_, flag) = result
|
|
|
|
return flag
|
|
|
|
|
|
|
|
async def update(self, user: str, thing: str, flag: int) -> str:
|
|
|
|
"""
|
|
|
|
Updates the lovehate database, and returns an appropriate response
|
2025-04-17 14:35:56 -04:00
|
|
|
|
2025-02-13 14:51:35 -05:00
|
|
|
Args:
|
|
|
|
user (str): The user to update
|
|
|
|
thing (str): The thing the user loves/hates/doesn't care about anymore
|
|
|
|
flag (int): int representation of love (1), hate (-1), and dontcare (0)
|
2025-04-17 14:35:56 -04:00
|
|
|
Returns:
|
2025-02-13 14:51:35 -05:00
|
|
|
str
|
|
|
|
"""
|
|
|
|
if not flag in range(-1, 2):
|
2025-04-17 14:35:56 -04:00
|
|
|
raise LoveHateException(
|
|
|
|
f"Invalid flag {flag} specified, is this love (1), hate (-1), or dontcare? (0)"
|
|
|
|
)
|
2025-02-13 14:51:35 -05:00
|
|
|
|
|
|
|
db_query: str = ""
|
2025-04-17 14:35:56 -04:00
|
|
|
params: tuple = (
|
|
|
|
user,
|
|
|
|
thing,
|
|
|
|
)
|
2025-02-13 14:51:35 -05:00
|
|
|
|
2025-02-15 13:57:47 -05:00
|
|
|
already_opinionated: Optional[int] = await self.check_existence(user, thing)
|
2025-04-17 14:35:56 -04:00
|
|
|
if already_opinionated:
|
2025-02-13 14:51:35 -05:00
|
|
|
if flag == 0:
|
2025-04-17 14:35:56 -04:00
|
|
|
db_query = (
|
|
|
|
"DELETE FROM lovehate WHERE display_name LIKE ? AND thing LIKE ?"
|
|
|
|
)
|
2025-02-13 14:51:35 -05:00
|
|
|
else:
|
|
|
|
loves_or_hates: str = "loves"
|
|
|
|
if already_opinionated == -1:
|
2025-02-15 13:57:47 -05:00
|
|
|
loves_or_hates = "hates"
|
2025-04-17 14:35:56 -04:00
|
|
|
raise LoveHateException(
|
|
|
|
f"But {user} already {loves_or_hates} {thing}..."
|
|
|
|
)
|
2025-02-13 14:51:35 -05:00
|
|
|
else:
|
|
|
|
match flag:
|
|
|
|
case -1:
|
2025-02-15 13:57:47 -05:00
|
|
|
db_query = "INSERT INTO lovehate(display_name, flag, thing) VALUES(?, -1, ?)"
|
2025-02-13 14:51:35 -05:00
|
|
|
case 1:
|
2025-02-15 13:57:47 -05:00
|
|
|
db_query = "INSERT INTO lovehate(display_name, flag, thing) VALUES(?, 1, ?)"
|
2025-02-13 14:51:35 -05:00
|
|
|
case _:
|
|
|
|
raise LoveHateException("Unknown error, default case matched")
|
|
|
|
|
|
|
|
async with sqlite3.connect(self.db_path, timeout=2) as db_conn:
|
|
|
|
async with await db_conn.execute(db_query, params) as db_cursor:
|
|
|
|
await db_conn.commit()
|
|
|
|
if db_cursor.rowcount != 1:
|
2025-04-17 14:35:56 -04:00
|
|
|
raise LoveHateException(
|
|
|
|
f"DB Error - RowCount: {db_cursor.rowcount} for INSERT query"
|
|
|
|
)
|
2025-02-13 14:51:35 -05:00
|
|
|
match flag:
|
|
|
|
case -1:
|
|
|
|
return f"We're done here, {user} hates {thing}."
|
2025-04-17 14:35:56 -04:00
|
|
|
case 0:
|
2025-02-13 14:51:35 -05:00
|
|
|
return f"We're done here, {user} no longer cares one way or the other about {thing}."
|
|
|
|
case 1:
|
|
|
|
return f"We're done here, {user} loves {thing}."
|
|
|
|
case _:
|
2025-04-17 14:35:56 -04:00
|
|
|
raise LoveHateException(
|
|
|
|
"Unknown error, default case matched [2]"
|
|
|
|
)
|