Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 55 additions & 31 deletions simyan/sqlite_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
__all__ = ["SQLiteCache"]
import json
import sqlite3
from collections.abc import Generator
from contextlib import contextmanager
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import Any, Optional
Expand All @@ -23,13 +25,37 @@ class SQLiteCache:
"""

def __init__(self, path: Optional[Path] = None, expiry: Optional[int] = 14):
self.expiry = expiry
self.connection = sqlite3.connect(path or get_cache_root() / "cache.sqlite")
self.connection.row_factory = sqlite3.Row

self.connection.execute("CREATE TABLE IF NOT EXISTS queries (query, response, query_date);")
self._db_path = path or (get_cache_root() / "cache.sqlite")
self._expiry = expiry
self.initialize()
self.cleanup()

@contextmanager
def _connect(self) -> Generator[sqlite3.Connection]:
conn = None
try:
conn = sqlite3.connect(self._db_path)
conn.row_factory = sqlite3.Row
conn.execute("PRAGMA foreign_keys = ON")
yield conn
finally:
if conn:
conn.close()

def initialize(self) -> None:
"""Create the cache table if it doesn't exist."""
with self._connect() as conn:
conn.execute(
"""
CREATE TABLE IF NOT EXISTS cache (
query TEXT NOT NULL PRIMARY KEY,
response TEXT,
timestamp TIMESTAMP
);
"""
)
conn.commit()

def select(self, query: str) -> dict[str, Any]:
"""Retrieve data from the cache database.

Expand All @@ -39,17 +65,16 @@ def select(self, query: str) -> dict[str, Any]:
Returns:
Empty dict or select results.
"""
if self.expiry:
expiry = datetime.now(tz=timezone.utc).astimezone().date() - timedelta(days=self.expiry)
cursor = self.connection.execute(
"SELECT * FROM queries WHERE query = ? and query_date > ?;",
(query, expiry.isoformat()),
)
else:
cursor = self.connection.execute("SELECT * FROM queries WHERE query = ?;", (query,))
if results := cursor.fetchone():
return json.loads(results["response"])
return {}
with self._connect() as conn:
if self._expiry:
expiry = datetime.now(tz=timezone.utc) - timedelta(days=self._expiry)
row = conn.execute(
"SELECT * FROM cache WHERE query = ? and timestamp > ?;",
(query, expiry.isoformat()),
).fetchone()
else:
row = conn.execute("SELECT * FROM cache WHERE query = ?;", (query,)).fetchone()
return json.loads(row["response"]) if row else {}

def insert(self, query: str, response: dict[str, Any]) -> None:
"""Insert data into the cache database.
Expand All @@ -58,29 +83,28 @@ def insert(self, query: str, response: dict[str, Any]) -> None:
query: Url string used as key.
response: Response dict from url.
"""
self.connection.execute(
"INSERT INTO queries (query, response, query_date) VALUES (?, ?, ?);",
(
query,
json.dumps(response),
datetime.now(tz=timezone.utc).astimezone().date().isoformat(),
),
)
self.connection.commit()
with self._connect() as conn:
conn.execute(
"INSERT INTO cache (query, response, timestamp) VALUES (?, ?, ?);",
(query, json.dumps(response), datetime.now(tz=timezone.utc).isoformat()),
)
conn.commit()

def delete(self, query: str) -> None:
"""Remove entry from the cache with the provided url.

Args:
query: Url string used as key.
"""
self.connection.execute("DELETE FROM queries WHERE query = ?;", (query,))
self.connection.commit()
with self._connect() as conn:
conn.execute("DELETE FROM cache WHERE query = ?;", (query,))
conn.commit()

def cleanup(self) -> None:
"""Remove all expired entries from the cache database."""
if not self.expiry:
if not self._expiry:
return
expiry = datetime.now(tz=timezone.utc).astimezone().date() - timedelta(days=self.expiry)
self.connection.execute("DELETE FROM queries WHERE query_date < ?;", (expiry.isoformat(),))
self.connection.commit()
expiry = datetime.now(tz=timezone.utc) - timedelta(days=self._expiry)
with self._connect() as conn:
conn.execute("DELETE FROM cache WHERE timestamp < ?;", (expiry.isoformat(),))
conn.commit()
Binary file modified tests/cache.sqlite
Binary file not shown.
6 changes: 3 additions & 3 deletions tests/characters_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ def test_get_character(session: Comicvine) -> None:
assert len(result.enemies) == 150
assert len(result.enemy_teams) == 25
assert len(result.friendly_teams) == 17
assert len(result.friends) == 233
assert len(result.issues) == 1714
assert len(result.friends) == 232
assert len(result.issues) == 1732
assert len(result.powers) == 28
assert len(result.story_arcs) == 0
assert len(result.teams) == 21
Expand All @@ -49,7 +49,7 @@ def test_list_characters(session: Comicvine) -> None:
assert result.date_of_birth is None
assert result.first_issue.id == 38445
assert result.gender == 1
assert result.issue_count == 1714
assert result.issue_count == 1732
assert result.name == "Kyle Rayner"
assert result.origin.id == 4
assert result.publisher.id == 10
Expand Down
4 changes: 2 additions & 2 deletions tests/concepts_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def test_get_concept(session: Comicvine) -> None:
assert result is not None
assert result.id == 41148

assert len(result.issues) == 2589
assert len(result.issues) == 2653
assert len(result.volumes) == 1


Expand All @@ -38,7 +38,7 @@ def test_list_concepts(session: Comicvine) -> None:
assert str(result.api_url) == "https://comicvine.gamespot.com/api/concept/4015-41148/"
assert result.date_added == datetime(2008, 6, 6, 11, 27, 52)
assert result.first_issue.id == 144069
assert result.issue_count == 2589
assert result.issue_count == 2653
assert result.name == "Green Lantern"
assert str(result.site_url) == "https://comicvine.gamespot.com/green-lantern/4015-41148/"
assert result.start_year == 1940
Expand Down
8 changes: 4 additions & 4 deletions tests/creators_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ def test_get_creator(session: Comicvine) -> None:
assert result is not None
assert result.id == 40439

assert len(result.characters) == 309
assert len(result.issues) == 1608
assert len(result.story_arcs) == 23
assert len(result.volumes) == 595
assert len(result.characters) == 320
assert len(result.issues) == 1640
assert len(result.story_arcs) == 27
assert len(result.volumes) == 604


def test_get_creator_fail(session: Comicvine) -> None:
Expand Down
8 changes: 4 additions & 4 deletions tests/items_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ def test_get_item(session: Comicvine) -> None:
assert result is not None
assert result.id == 41361

assert len(result.issues) == 3308
assert len(result.story_arcs) == 454
assert len(result.volumes) == 993
assert len(result.issues) == 3336
assert len(result.story_arcs) == 457
assert len(result.volumes) == 1007


def test_get_item_fail(session: Comicvine) -> None:
Expand All @@ -39,7 +39,7 @@ def test_list_items(session: Comicvine) -> None:
assert str(result.api_url) == "https://comicvine.gamespot.com/api/object/4055-41361/"
assert result.date_added == datetime(2008, 6, 6, 11, 27, 50)
assert result.first_issue.id == 123898
assert result.issue_count == 3308
assert result.issue_count == 3336
assert result.name == "Green Power Ring"
assert str(result.site_url) == "https://comicvine.gamespot.com/green-power-ring/4055-41361/"
assert result.start_year == 1940
Expand Down
2 changes: 1 addition & 1 deletion tests/origins_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def test_get_origin(session: Comicvine) -> None:
assert result.id == 1

assert result.character_set is None
assert len(result.characters) == 4399
assert len(result.characters) == 4480
assert len(result.profiles) == 0


Expand Down
2 changes: 1 addition & 1 deletion tests/powers_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def test_get_power(session: Comicvine) -> None:
assert result is not None
assert result.id == 1

assert len(result.characters) == 8310
assert len(result.characters) == 8367


def test_get_power_fail(session: Comicvine) -> None:
Expand Down
12 changes: 6 additions & 6 deletions tests/publishers_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@

def test_get_publisher(session: Comicvine) -> None:
"""Test the get_publisher function with a valid id."""
result = session.get_publisher(publisher_id=10)
result = session.get_publisher(publisher_id=364)
assert result is not None
assert result.id == 10
assert result.id == 364

assert len(result.characters) == 24149
assert len(result.story_arcs) == 895
assert len(result.teams) == 1869
assert len(result.volumes) == 9416
assert len(result.characters) == 775
assert len(result.story_arcs) == 38
assert len(result.teams) == 42
assert len(result.volumes) == 4692


def test_get_publisher_fail(session: Comicvine) -> None:
Expand Down
4 changes: 2 additions & 2 deletions tests/teams_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def test_get_team(session: Comicvine) -> None:
assert len(result.friends) == 10
assert len(result.issues) == 120
assert len(result.issues_disbanded_in) == 1
assert len(result.members) == 18
assert len(result.members) == 19
assert len(result.story_arcs) == 0
assert len(result.volumes) == 65

Expand All @@ -42,7 +42,7 @@ def test_list_teams(session: Comicvine) -> None:

assert str(result.api_url) == "https://comicvine.gamespot.com/api/team/4060-50163/"
assert result.issue_count == 0
assert result.member_count == 18
assert result.member_count == 19
assert result.date_added == datetime(2008, 6, 6, 11, 27, 45)
assert result.first_issue.id == 119950
assert result.name == "Blue Lantern Corps"
Expand Down
2 changes: 1 addition & 1 deletion tests/volumes_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def test_get_volume(session: Comicvine) -> None:
assert result.id == 18216

assert len(result.characters) == 368
assert len(result.concepts) == 19
assert len(result.concepts) == 10
assert len(result.creators) == 95
assert len(result.issues) == 67
assert len(result.locations) == 48
Expand Down
Loading