Skip to content

Commit

Permalink
Removed Steamless time migration
Browse files Browse the repository at this point in the history
* Small refactoring on BE side
* Fix warnings for FE compilation
* Added verify target in make
  • Loading branch information
ma3a committed Aug 31, 2023
1 parent f612d47 commit c3d4925
Show file tree
Hide file tree
Showing 33 changed files with 497 additions and 758 deletions.
Empty file added defaults/python/__init__.py
Empty file.
Empty file added defaults/python/db/__init__.py
Empty file.
154 changes: 26 additions & 128 deletions defaults/python/play_time_dao.py → defaults/python/db/dao.py
Original file line number Diff line number Diff line change
@@ -1,73 +1,58 @@
import contextlib
from dataclasses import dataclass
import datetime
import logging
import sqlite3
from typing import List, Tuple
from typing import List

from python.db.sqlite_db import SqlLiteDb

logger = logging.getLogger()


@dataclass
class GameTimeDto:
def __init__(self, game_id: str, game_name: str, time: int):
self.game_id = game_id
self.game_name = game_name
self.time = time
game_id: str
game_name: str
time: int


@dataclass
class DailyGameTimeDto:
def __init__(self, date: str, game_id: str, game_name: str, time: int):
self.date = date
self.game_id = game_id
self.game_name = game_name
self.time = time


class PlayTimeDao:
"""
All methods with _ prefix are private and should not be used directly, and
should be used only in transaction context.
There are public methods with same name but without _ prefix, which should
be used instead.
"""
date: str
game_id: str
game_name: str
time: int

_database_path: str

def __init__(self, database_path: str):
self._database_path = database_path
self._migrate()
class Dao:
def __init__(self, db: SqlLiteDb):
self._db = db

def save_game_dict(
self,
game_id: str,
game_name: str):
with self._in_transaction() as connection:
game_name: str) -> None:
with self._db.transactional() as connection:
self._save_game_dict(connection, game_id, game_name)

def save_play_time(
self,
start: datetime.datetime,
time_s: int,
game_id: str,
source: str = None):
with self._in_transaction() as connection:
source: str = None) -> None:
with self._db.transactional() as connection:
self._save_play_time(connection, start, time_s, game_id, source)

def is_non_tracked_time_exists(
self,
game_id: str,
source: str) -> bool:
with self._in_transaction() as connection:
return self._is_non_tracked_time_exists(connection, game_id, source)

def apply_manual_time_for_game(
self,
create_at: datetime.datetime,
game_id: str,
game_name: str,
new_overall_time: int,
source: str
):
with self._in_transaction() as connection:
) -> None:
with self._db.transactional() as connection:
self._save_game_dict(connection, game_id, game_name)
current_time = connection.execute(
"SELECT sum(duration) FROM play_time WHERE game_id = ?",
Expand All @@ -85,19 +70,19 @@ def fetch_per_day_time_report(
begin: type[datetime.datetime],
end: type[datetime.datetime]
) -> List[DailyGameTimeDto]:
with self._in_transaction() as connection:
with self._db.transactional() as connection:
return self._fetch_per_day_time_report(connection, begin, end)

def is_there_is_data_before(
self, date: type[datetime.datetime]
) -> bool:
with self._in_transaction() as connection:
with self._db.transactional() as connection:
return self._is_there_is_data_before(connection, date)

def is_there_is_data_after(
self, date: type[datetime.datetime]
) -> bool:
with self._in_transaction() as connection:
with self._db.transactional() as connection:
return self._is_there_is_data_after(connection, date)

def _is_there_is_data_before(
Expand Down Expand Up @@ -142,7 +127,7 @@ def _save_game_dict(
)

def fetch_overall_playtime(self) -> List[GameTimeDto]:
with self._in_transaction() as connection:
with self._db.transactional() as connection:
return self._fetch_overall_playtime(connection)

def _save_play_time(
Expand All @@ -161,19 +146,6 @@ def _save_play_time(
)
self._append_overall_time(connection, game_id, time_s)

def _is_non_tracked_time_exists(
self,
connection: sqlite3.Connection,
game_id: str,
source: str) -> bool:
return connection.execute(
"""
SELECT count(1) FROM play_time
WHERE game_id = ? and migrated = ?
""",
(game_id, source)
).fetchone()[0] > 0

def _append_overall_time(
self,
connection: sqlite3.Connection,
Expand Down Expand Up @@ -231,77 +203,3 @@ def _fetch_per_day_time_report(
{"begin": begin.isoformat(), "end": end.isoformat()}
).fetchall()
return result

def _current_migration_version(self):
with self._connection() as con:
con.execute(
"CREATE TABLE IF NOT EXISTS migration (id INT PRIMARY KEY);"
)
return con.execute(
"SELECT coalesce(max(id), 0) as max_id FROM migration"
).fetchone()[0]

def _migrate(self):
version = self._current_migration_version()
self._migration(
version,
[
(1, [
"""
CREATE TABLE play_time(
date_time TEXT,
duration INT,
game_id TEXT
)
""",
"""
CREATE TABLE overall_time(
game_id TEXT PRIMARY KEY,
duration INT
)
""",
"""
CREATE TABLE game_dict(
game_id TEXT PRIMARY KEY,
name TEXT
)
""",
]),
(2, [
"""
CREATE INDEX play_time_date_time_epoch_idx
ON play_time(UNIXEPOCH(date_time))
""",
"""
CREATE INDEX play_time_game_id_idx
ON play_time(game_id)
""",
"""
CREATE INDEX overall_time_game_id_idx
ON overall_time(game_id)
"""
]),
(3, [
"ALTER TABLE play_time ADD COLUMN migrated TEXT"
])
]
)

def _migration(self, existing_migration_id: int,
migrations: List[Tuple[int, List[str]]]):
for migr in migrations:
if (migr[0] > existing_migration_id):
with self._in_transaction() as con:
for stm in migr[1]:
con.execute(stm)
con.execute(
"INSERT INTO migration (id) VALUES (?)", [migr[0]])

@contextlib.contextmanager
def _in_transaction(self):
with self._connection() as con:
yield con
con.commit()

def _connection(self):
return sqlite3.connect(self._database_path)
80 changes: 80 additions & 0 deletions defaults/python/db/migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
from dataclasses import dataclass
from typing import List
from python.db.sqlite_db import SqlLiteDb


@dataclass
class Migration:
version: int
statements: List[str]


_migrations = [
Migration(1, [
"""
CREATE TABLE play_time(
date_time TEXT,
duration INT,
game_id TEXT
)
""",
"""
CREATE TABLE overall_time(
game_id TEXT PRIMARY KEY,
duration INT
)
""",
"""
CREATE TABLE game_dict(
game_id TEXT PRIMARY KEY,
name TEXT
)
"""
]),
Migration(2, [
"""
CREATE INDEX play_time_date_time_epoch_idx
ON play_time(UNIXEPOCH(date_time))
""",
"""
CREATE INDEX play_time_game_id_idx
ON play_time(game_id)
""",
"""
CREATE INDEX overall_time_game_id_idx
ON overall_time(game_id)
"""
]),
Migration(3, [
"ALTER TABLE play_time ADD COLUMN migrated TEXT"
])
]


class DbMigration:
def __init__(self, db: SqlLiteDb):
self.db = db

def _current_migration_version(self):
with self.db.transactional() as con:
con.execute(
"CREATE TABLE IF NOT EXISTS migration (id INT PRIMARY KEY);"
)
return con.execute(
"SELECT coalesce(max(id), 0) as max_id FROM migration"
).fetchone()[0]

def _migration(self, migration: Migration):
version = self._current_migration_version()
if migration.version > version:
with self.db.transactional() as con:
for stm in migration.statements:
con.execute(stm)
con.execute(
"INSERT INTO migration (id) VALUES (?)",
[migration.version]
)

def migrate(self):
for migration in _migrations:
self._migration(migration)
19 changes: 19 additions & 0 deletions defaults/python/db/sqlite_db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import contextlib
import sqlite3
from typing import ContextManager


class SqlLiteDb:

def __init__(self, database_path: str):
self._database_path = database_path

@contextlib.contextmanager
def transactional(self) -> ContextManager[sqlite3.Connection]:
with sqlite3.connect(self._database_path) as connection:
try:
yield connection
connection.commit()
except Exception as exception:
connection.rollback()
raise exception
45 changes: 0 additions & 45 deletions defaults/python/external_time_tracker.py

This file was deleted.

Loading

0 comments on commit c3d4925

Please sign in to comment.