habitmove/src/habitmove/repetitions.py

114 lines
4.2 KiB
Python
Raw Normal View History

from __future__ import annotations
2021-08-28 21:03:12 +00:00
import sqlite3
from typing import Optional
2021-12-03 15:22:54 +00:00
from datetime import datetime
from habitmove.loopdata import Habit, Repetition
from habitmove.nomiedata import Event
2021-08-28 21:03:12 +00:00
def migrate(db: sqlite3.Connection, habits: list[Habit], events: list[Event]) -> None:
"""Move Loop Activities contained in all Events matching Habits passed in into database.
:param db: Database to populate.
:param habits: List of Habits to find matching repetitions for.
:param events: List of events to find repetitions in.
"""
2021-08-28 21:03:12 +00:00
c = db.cursor()
habits_with_sql_id = habit_list_add_ids(c, habits)
repetitions = get_all_repetitions(habits_with_sql_id, events)
2021-08-30 08:39:07 +00:00
for rep in repetitions:
add_to_database(c, habits_with_sql_id, rep)
2021-08-30 21:00:28 +00:00
LOOP_RANGE_VALUE_MULTIPLIER = 1000
2021-08-30 08:39:07 +00:00
def get_all_repetitions(
habits: dict[int, Habit], events: list[Event]
) -> list[Repetition]:
"""Return list of all repetitions found in events passed in.
:param habits: Dict of habits with sql_ids that repetitions can be for.
:param events: List of events to search through for repetitions.
:return repetitions: List of Loop repetitions.
2021-08-30 08:39:07 +00:00
"""
repetitions = []
2021-08-28 21:03:12 +00:00
for event in events:
2021-12-03 15:22:54 +00:00
for activity in event.activities:
for habit in habits.values():
# TODO Fix reaching a layer too far into activity -> tracker
if habit.uuid == activity.tracker.id:
rep = Repetition(
habit_uuid=habit.uuid, timestamp=event.end, value=2
)
if habit.type == 1 and activity.value:
rep.value = activity.value * LOOP_RANGE_VALUE_MULTIPLIER
repetitions.append(rep)
2021-08-30 21:38:49 +00:00
2021-08-30 08:39:07 +00:00
return repetitions
2021-08-29 09:11:58 +00:00
2021-08-30 21:00:28 +00:00
# TODO possibly just get rid of this entirely
def habit_list_add_ids(c: sqlite3.Cursor, habitlist: list[Habit]) -> dict[int, Habit]:
"""Return the collection of habits with their sqlite id added.
:param c: SQL cursor of database to query.
:param habitlist: Habits to get sql IDs for.
:return habit_id_dict: The habit collection as a dict with the keys
2021-12-02 22:08:58 +00:00
consisting of the habit's sqlite database ID.
2021-08-30 08:39:07 +00:00
"""
with_id: dict[int, Habit] = {}
2021-12-02 22:08:58 +00:00
for h in habitlist:
sql_id = fetch_habit_id(c, h.uuid or "")
if sql_id is not None:
with_id[sql_id] = h
2021-12-02 22:08:58 +00:00
return with_id
2021-08-29 08:13:28 +00:00
def fetch_habit_id(cursor: sqlite3.Cursor, uuid: str) -> Optional[int]:
2021-08-30 08:39:07 +00:00
"""Return sqlite internal id for habit with uuid.
2021-12-03 15:22:54 +00:00
:param c: SQL cursor of database to query.
:param uuid: Unique id of habit to query for.
:return id: SQLite internal id for habit queried for.
2021-08-30 08:39:07 +00:00
"""
2021-12-03 15:22:54 +00:00
cursor.execute("select id from Habits where uuid = ?", ([uuid]))
id = cursor.fetchone()
2021-08-29 09:11:58 +00:00
if id is not None:
return id[0]
2021-08-28 21:03:12 +00:00
return None
2021-08-28 21:03:12 +00:00
2021-12-03 15:22:54 +00:00
def add_to_database(
cursor: sqlite3.Cursor, habits: dict[int, Habit], repetition: Repetition
) -> None:
2021-12-03 15:22:54 +00:00
"""Insert the repetition into a sqlite3 table suitable for Loop.
:param c: SQL cursor of database to query.
:sql_id: Internal sqlite database id of the habit the repetition belongs to.
"""
for sql_id, habit in habits.items():
if repetition.habit_uuid == habit.uuid:
try:
cursor.execute(
"""
INSERT INTO
Repetitions(id, habit, timestamp, value)
VALUES (NULL, ?, ?, ?)
""",
(sql_id, repetition.timestamp, repetition.value),
)
except sqlite3.IntegrityError:
# FIXME better error handling
# TODO think about adapting this to allow importing into existing databases
2021-12-03 15:22:54 +00:00
print(
f"{sql_id}, {habit.name}: timestamp {datetime.fromtimestamp(repetition.timestamp/1000)} not unique, moving timestamp slightly."
)
add_to_database(
cursor,
habits,
Repetition(
repetition.habit_uuid,
repetition.timestamp + 1,
repetition.value,
),
)