Skip to content

Commit 3393a2c

Browse files
committed
Complete rewrite once again
1 parent 051ded2 commit 3393a2c

File tree

1 file changed

+115
-51
lines changed

1 file changed

+115
-51
lines changed

lib/db/__init__.py

+115-51
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,141 @@
1-
from os.path import isfile
2-
from sqlite3 import Connection, Cursor, connect
1+
import re
2+
import sys
3+
from sqlite3 import Connection, Cursor, connect, Error
34

45

56
class DB:
67
DB_PATH = "./data/database.db"
78
cxn: Connection
89
cur: Cursor
910

10-
tables: dict[str, dict[str, str]] = {
11-
'bans': {
12-
'guild_id': 'TEXT',
13-
'user_id': 'TEXT',
14-
'mod_id': 'TEXT',
15-
'reason': 'TEXT',
16-
'ts': 'INTEGER'
11+
table_info: list[dict[str, dict[str, dict[str, str | list[str]]]]] = [
12+
{
13+
'table': {
14+
'guilds': {
15+
'id': 'TEXT',
16+
'level_id': 'TEXT',
17+
'announce_id': 'TEXT'
18+
}
19+
},
20+
'constraints': {'not_null': ['id'], 'primary_key': 'id'}
1721
},
18-
'guilds': {
19-
'id': 'TEXT PRIMARY KEY NOT NULL',
20-
'level_id': 'TEXT',
21-
'announce_id': 'TEXT'
22+
{
23+
'table': {
24+
'bans': {
25+
'guild_id': 'TEXT',
26+
'user_id': 'TEXT',
27+
'mod_id': 'TEXT',
28+
'reason': 'TEXT',
29+
'ts': 'INTEGER'
30+
}
31+
},
32+
'constraints': {'foreign_key': {
33+
'guild_id': ['guilds', 'id']
34+
}}
2235
},
23-
'reports': {
24-
'guild_id': 'TEXT',
25-
'user_id': 'TEXT',
26-
'target_id': 'TEXT',
27-
'report': 'TEXT'
36+
{
37+
'table': {
38+
'reports': {
39+
'guild_id': 'TEXT',
40+
'user_id': 'TEXT',
41+
'target_id': 'TEXT',
42+
'report': 'TEXT'
43+
}
44+
},
45+
'constraints': {}
2846
},
29-
'commands': {
30-
'command_name': 'TEXT',
31-
'guild_id': 'TEXT',
32-
'user_id': 'TEXT',
33-
'params': 'JSON',
34-
'ts': 'INTEGER'
47+
{
48+
'table': {
49+
'commands': {
50+
'command_name': 'TEXT',
51+
'guild_id': 'TEXT',
52+
'user_id': 'TEXT',
53+
'params': 'JSON',
54+
'ts': 'INTEGER'
55+
}
56+
},
57+
'constraints': {}
3558
},
36-
'levels': {
37-
'guild_id': 'TEXT',
38-
'user_id': 'TEXT',
39-
'xp': 'INTEGER'
59+
{
60+
'table': {
61+
'levels': {
62+
'guild_id': 'TEXT',
63+
'user_id': 'TEXT',
64+
'xp': 'INTEGER'
65+
}
66+
},
67+
'constraints': {}
4068
},
41-
'youtube': {
42-
'handle': 'TEXT',
43-
'guild_id': 'TEXT',
44-
'message': 'TEXT',
45-
'latest_url': 'TEXT'
69+
{
70+
'table': {
71+
'youtube': {
72+
'handle': 'TEXT',
73+
'guild_id': 'TEXT',
74+
'message': 'TEXT',
75+
'latest_url': 'TEXT'
76+
}
77+
},
78+
'constraints': {}
4679
}
47-
}
80+
]
4881

4982
def __init__(self):
5083
self.cxn = connect(self.DB_PATH, check_same_thread=False)
5184
self.cur = self.cxn.cursor()
5285

53-
def update_table(self, table: str, columns_str_list: list[str], columns_list: dict[str, str]):
54-
self.cur.execute(f"CREATE TABLE {table}_new ({' '.join(columns_str_list)});")
86+
def update_table(self, table: str, data: str):
87+
try:
88+
self.cur.execute(f"SELECT * FROM {table}_new")
89+
self.cur.execute(f"INSERT INTO {table} SELECT * FROM {table}_new")
90+
self.cur.execute(f"DROP TABLE {table}_new")
91+
except Error:
92+
pass
93+
self.cur.execute(f"CREATE TABLE {table}_new {data};")
5594
self.cur.execute(f"INSERT INTO {table}_new SELECT * FROM {table};")
5695
self.cur.execute(f"DROP TABLE {table};")
5796
self.cur.execute(f"ALTER TABLE {table}_new RENAME TO {table};")
5897

5998
def build(self) -> None:
60-
for table, columns in self.tables.items():
61-
# Create tables
62-
columns_str_list = []
63-
for index, (name, data_type) in enumerate(columns.items()):
64-
columns_str_list.append(f"{name} {data_type}," if index < len(columns) - 1 else f"{name} {data_type}")
65-
66-
self.cur.execute(f"CREATE TABLE IF NOT EXISTS {table} ({' '.join(columns_str_list)});")
67-
68-
# Update tables in case the types need to be updated
69-
self.update_table(table, columns_str_list, columns)
99+
print('Building Database...')
100+
for table in self.table_info:
101+
table_data = table['table']
102+
for table_name, columns in table_data.items():
103+
print(f' - {table_name}')
104+
create_table_query = f"CREATE TABLE IF NOT EXISTS {table_name}("
105+
constraints = table.get('constraints')
106+
for column_name, data_type in columns.items():
107+
print(f' - {column_name}')
108+
if constraints:
109+
not_null = constraints.get('not_null')
110+
if not_null:
111+
if column_name in not_null:
112+
data_type += f" NOT NULL"
113+
create_table_query += f"{column_name} {data_type}, "
114+
if constraints:
115+
primary_key = constraints.get('primary_key')
116+
default = constraints.get('default')
117+
if default:
118+
for column, value in default:
119+
create_table_query += f"{column} DEFAULT {value}, "
120+
if primary_key:
121+
create_table_query += f"PRIMARY KEY({primary_key}), "
122+
unique = constraints.get('unique')
123+
if unique:
124+
for column in unique:
125+
create_table_query += f"UNIQUE({column}), "
126+
foreign_key = constraints.get('foreign_key')
127+
if foreign_key:
128+
for column, [ref_table, ref_column] in foreign_key.items():
129+
create_table_query += f"FOREIGN KEY({column}) REFERENCES {ref_table}({ref_column}), "
130+
check = constraints.get('check')
131+
if check:
132+
for column, condition in check:
133+
create_table_query += f"CHECK({column} {condition}), "
134+
create_table_query = create_table_query.rstrip(', ')
135+
create_table_query += ")"
136+
self.cur.execute(create_table_query)
137+
data = re.search(r"\((?<=\()(?:.)+", create_table_query).group()
138+
self.update_table(table_name, data)
70139
self.commit()
71140

72141
def commit(self) -> None:
@@ -91,11 +160,6 @@ def records(self, command, *values) -> list:
91160

92161
return self.cur.fetchall()
93162

94-
def column(self, command, *values) -> list:
95-
self.cur.execute(command, tuple(values))
96-
97-
return [item[0] for item in self.cur.fetchall()]
98-
99163
def execute(self, command, *values) -> None:
100164
self.cur.execute(command, tuple(values))
101165

0 commit comments

Comments
 (0)