Skip to content

Commit 12f5e0e

Browse files
committed
Switch to MariaDB
MariaDB methods added with necessary syntax tweaks.
1 parent 0734603 commit 12f5e0e

File tree

5 files changed

+76
-56
lines changed

5 files changed

+76
-56
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,7 @@ dmypy.json
137137
*.db
138138
*.zip
139139
*.bk
140+
*.db-wal
141+
*.db-shm
142+
*.csv
143+
*.htm

api.env

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# API Environment
22

3-
export DATABASE_PATH=
43
export KUPO_URL=
54
export KUPO_PORT=
5+
export DB_USER=
6+
export DB_PASS=
7+
export DB_DATABASE=

requirements/requirements.txt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# requirements for the production project.
22

3-
apsw==3.46.1.0
4-
fastapi==0.115.3
5-
humanize==4.11.0
3+
fastapi==0.115.12
4+
humanize==4.12.2
5+
mariadb==1.1.12
66
simple-sign==0.1.0-rc.6
7-
uvicorn==0.32.0
8-
folium==0.19.3
7+
uvicorn==0.34.0
8+
folium==0.19.5

src/itn_api/api.py

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,9 @@
1717
import os
1818
import time
1919
from contextlib import asynccontextmanager
20-
from pathlib import Path
2120
from typing import Final
2221

23-
import apsw
24-
import apsw.bestpractice
22+
import mariadb
2523
import uvicorn
2624
from fastapi import FastAPI
2725
from fastapi.middleware.cors import CORSMiddleware
@@ -80,21 +78,23 @@
8078
]
8179

8280

83-
def _enable_best_practice(connection: apsw.Connection):
84-
"""Enable aspw best practice."""
85-
apsw.bestpractice.connection_wal(connection)
86-
apsw.bestpractice.library_logging()
81+
def _get_database_connection() -> mariadb.Connection:
82+
"""Get a MriaDB database connection."""
83+
connection = mariadb.connect(
84+
user=os.environ["DB_USER"],
85+
password=os.environ["DB_PASS"],
86+
host="127.0.0.1",
87+
port=3306,
88+
database=os.environ["DB_DATABASE"],
89+
autocommit=True,
90+
)
91+
return connection
8792

8893

8994
@asynccontextmanager
9095
async def lifespan(app: FastAPI):
9196
"""Load the database connection for the life of the app.s"""
92-
db_path = Path(os.environ["DATABASE_PATH"])
93-
logger.info("validator database: %s", db_path)
94-
app.state.connection = apsw.Connection(
95-
str(db_path), flags=apsw.SQLITE_OPEN_READONLY
96-
)
97-
_enable_best_practice(app.state.connection)
97+
app.state.connection = _get_database_connection()
9898
app.state.kupo_url = os.environ["KUPO_URL"]
9999
app.state.kupo_port = os.environ["KUPO_PORT"]
100100
yield
@@ -141,34 +141,36 @@ def redirect_root_to_docs():
141141
@app.get("/get_active_participants", tags=[TAG_STATISTICS])
142142
async def get_active_participants():
143143
"""Return participants in the ITN database."""
144+
cursor = app.state.connection.cursor()
144145
try:
145-
participants = app.state.connection.execute(
146-
"select distinct address from data_points;"
147-
)
148-
except apsw.SQLError as err:
146+
cursor.execute("select distinct address from data_points;")
147+
except mariadb.Error as err:
149148
return {"error": f"{err}"}
150-
data = [participant[0] for participant in participants]
149+
data = [participant[0] for participant in cursor]
150+
cursor.close()
151151
return data
152152

153153

154154
@app.get("/get_participants_counts_total", tags=[TAG_STATISTICS])
155155
async def get_participants_counts_total():
156156
"""Return participants total counts."""
157+
cursor = app.state.connection.cursor()
157158
try:
158-
participants_count_total = app.state.connection.execute(
159+
cursor.execute(
159160
"select count(*) as count, address from data_points group by address order by count desc;"
160161
)
161-
except apsw.SQLError as err:
162+
except mariadb.Error as err:
162163
return {"error": f"{err}"}
163-
return participants_count_total
164+
res = list(cursor)
165+
cursor.close()
166+
return res
164167

165168

166169
@app.get("/get_participants_counts_day", tags=[TAG_STATISTICS])
167170
async def get_participants_counts_day(
168171
date_start: str = "1970-01-01", date_end: str = "1970-01-03"
169172
):
170173
"""Return participants in ITN."""
171-
172174
report = reports.get_participants_counts_date_range(app, date_start, date_end)
173175
return report
174176

@@ -231,28 +233,33 @@ async def get_itn_participants() -> str:
231233
@app.get("/online_collectors", tags=[TAG_HTMX], response_class=HTMLResponse)
232234
async def get_online_collectors() -> str:
233235
"""Return ITN aliases and collector counts."""
236+
cursor = app.state.connection.cursor()
234237
try:
235-
participants_count = app.state.connection.execute(
238+
cursor.execute(
236239
"""SELECT address, COUNT(*) AS total_count,
237-
SUM(CASE WHEN datetime(date_time) >= datetime('now', '-24 hours')
240+
SUM(CASE WHEN date_time >= (SELECT DATE_SUB(NOW(), INTERVAL 1 DAY))
238241
THEN 1 ELSE 0 END) AS count_24hr
239242
FROM data_points
240243
GROUP BY address ORDER BY total_count DESC;
241244
"""
242245
)
243-
except apsw.SQLError:
246+
except mariadb.Error:
244247
return "zero collectors online"
245248

249+
participants_count = list(cursor)
250+
246251
try:
247-
feed_count = app.state.connection.execute(
252+
cursor.execute(
248253
"""SELECT distinct feed_id
249254
from data_points
250-
where datetime(date_time) >= datetime('now', '-48 hours');
255+
where date_time >= (SELECT DATE_SUB(NOW(), INTERVAL 1 DAY));
251256
"""
252257
)
253-
except apsw.SQLError:
258+
except mariadb.Error:
254259
return "zero collectors online"
255260

261+
feed_count = list(cursor)
262+
256263
no_feeds = len(list(feed_count))
257264

258265
# FIXME: These can all be combined better, e.g. into a dataclass or
@@ -308,13 +315,13 @@ async def get_locations_map_hx():
308315
@app.get("/count_active_participants", tags=[TAG_HTMX], response_class=HTMLResponse)
309316
async def count_active_participants():
310317
"""Count active participants."""
318+
cursor = app.state.connection.cursor()
311319
try:
312-
participants = app.state.connection.execute(
313-
"select count(distinct address) as count from data_points;"
314-
)
315-
except apsw.SQLError as err:
320+
cursor.execute("select count(distinct address) as count from data_points;")
321+
except mariadb.Error as err:
316322
return {"error": f"{err}"}
317-
data = list(participants)
323+
data = list(cursor)
324+
cursor.close()
318325
return f"{data[0][0]}"
319326

320327

src/itn_api/reports.py

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
from dataclasses import dataclass
99
from typing import List, Tuple
1010

11-
import apsw
1211
import humanize
12+
import mariadb
1313
from fastapi import FastAPI
1414

1515
try:
@@ -85,7 +85,7 @@ def get_all_license_holders_csv(app: FastAPI, min_stake: int, sort: str) -> str:
8585
)
8686
csv = "idx,staking,license,value\n"
8787
for idx, data in enumerate(alias_addr_data, 1):
88-
stake = humanize.intcomma(data.staked).replace(",", ".")
88+
stake = humanize.intcomma(data.staked).replace(",", "")
8989
csv = f"{csv}{idx:0>4}, {data.staking}, {' '.join(data.licenses)}, {stake}\n"
9090
return csv
9191

@@ -158,7 +158,7 @@ def _get_addr_minute_feed_dicts(data: list, addresses: list):
158158
for item in data:
159159
if item[0] != addr:
160160
continue
161-
minutes = item[1].rsplit(":", 1)[0].strip()
161+
minutes = str(item[1]).rsplit(":", 1)[0].strip()
162162
feed = item[2].strip()
163163
addr_minute_values = helpers.update_dict(
164164
addr_minute_values, addr, f"{feed}|{minutes}"
@@ -243,7 +243,8 @@ def _get_participant_data_by_date_range(
243243
app: FastAPI, date_start: str, date_end: str
244244
) -> list:
245245
"""Query the database and get the results."""
246-
participants = app.state.connection.execute(
246+
cursor = app.state.connection.cursor()
247+
cursor.execute(
247248
f"""
248249
select address, date_time, feed_id
249250
from data_points
@@ -252,7 +253,9 @@ def _get_participant_data_by_date_range(
252253
order by address;
253254
"""
254255
)
255-
return list(participants)
256+
res = list(cursor)
257+
cursor.close()
258+
return res
256259

257260

258261
def generate_participant_count_csv(report: dict) -> str:
@@ -269,7 +272,7 @@ def generate_participant_count_csv(report: dict) -> str:
269272
for stake_addr, value in data.items():
270273
participant = stake_addr
271274
license_no = value.get("license", "").replace("Validator License", "").strip()
272-
stake = humanize.intcomma(int(value.get("stake", 0))).replace(",", ".")
275+
stake = humanize.intcomma(int(value.get("stake", 0))).replace(",", "")
273276
total_data_points = value.get("total_data_points", 0)
274277
average_per_feed = value.get("average_mins_collecting_per_feed", 0)
275278
total_collected = value.get("number_of_feeds_collected", 0)
@@ -297,10 +300,10 @@ def generate_participant_count_csv(report: dict) -> str:
297300

298301
async def get_date_ranges(app: FastAPI):
299302
"""Return min and max dates from the database."""
300-
min_max_dates = app.state.connection.execute(
301-
"select min(date_time), max(date_time) from data_points;"
302-
)
303-
dates = list(min_max_dates)[0]
303+
cursor = app.state.connection.cursor()
304+
cursor.execute("select min(date_time), max(date_time) from data_points;")
305+
dates = list(cursor)[0]
306+
cursor.close()
304307
return {
305308
"earliest_date": dates[0],
306309
"latest_date": dates[1],
@@ -315,14 +318,16 @@ async def get_locations(app: FastAPI) -> list:
315318
* https://stackoverflow.com/a/571487
316319
317320
"""
321+
cursor = app.state.connection.cursor()
318322
try:
319-
unique_raw_data = app.state.connection.execute(
323+
cursor.execute(
320324
"select min(node_id), raw_data from data_points group by node_id;"
321325
)
322-
except apsw.SQLError:
326+
except mariadb.Error:
323327
return "zero collectors online"
324328

325-
res = list(unique_raw_data)
329+
res = list(cursor)
330+
cursor.close()
326331
countries = []
327332
for item in res:
328333
node = item[0]
@@ -356,18 +361,20 @@ async def get_locations_stake_key(app: FastAPI) -> list:
356361
* https://stackoverflow.com/a/571487
357362
358363
"""
364+
cursor = app.state.connection.cursor()
359365
try:
360-
unique_raw_data = app.state.connection.execute(
366+
cursor.execute(
361367
"""select node_id, raw_data, min(address), date_time
362368
from data_points
363-
where datetime(date_time) >= datetime('now', '-24 hours')
369+
where date_time >= (SELECT DATE_SUB(NOW(), INTERVAL 1 DAY))
364370
group by address;
365371
"""
366372
)
367-
except apsw.SQLError:
373+
except mariadb.Error:
368374
return "zero collectors online"
369375

370-
res = list(unique_raw_data)
376+
res = list(cursor)
377+
cursor.close()
371378
key_loc = {}
372379
for item in res:
373380
node = item[0]

0 commit comments

Comments
 (0)