_sqlite.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import logging
  2. from datetime import datetime
  3. from pathlib import Path
  4. from room_cal.store._backend import EventRecord, register_backend
  5. _log = logging.getLogger(__name__)
  6. _CREATE_TABLE = '''
  7. CREATE TABLE IF NOT EXISTS events (
  8. uid TEXT NOT NULL,
  9. calendar_name TEXT NOT NULL,
  10. start TEXT NOT NULL,
  11. end TEXT NOT NULL,
  12. all_day INTEGER NOT NULL,
  13. title TEXT NOT NULL,
  14. description TEXT NOT NULL DEFAULT '',
  15. x_data TEXT,
  16. PRIMARY KEY (uid, calendar_name)
  17. )
  18. '''
  19. _COLS = 'uid, calendar_name, start, end, all_day, title, description, x_data'
  20. @register_backend('sqlite')
  21. class SQLiteBackend:
  22. def __init__(self, db_path: Path, calendar_name: str):
  23. self._db_path = db_path
  24. self._calendar_name = calendar_name
  25. @classmethod
  26. def from_store_config(cls, store_cfg, calendar_name: str) -> 'SQLiteBackend':
  27. from room_cal._utils import data_home
  28. db_path_str = store_cfg.sqlite.db_path
  29. db_path = Path(db_path_str) if db_path_str else data_home() / 'store.db'
  30. return cls(db_path, calendar_name)
  31. def _to_record(self, row) -> EventRecord:
  32. uid, _, start, end, all_day, title, description, x_data = row
  33. return EventRecord(
  34. uid=uid,
  35. start=datetime.fromisoformat(start),
  36. end=datetime.fromisoformat(end),
  37. all_day=bool(all_day),
  38. title=title,
  39. description=description,
  40. x_data=x_data,
  41. )
  42. async def fetch_range(self, start: datetime, end: datetime) -> list[EventRecord]:
  43. import aiosqlite
  44. async with aiosqlite.connect(self._db_path) as db:
  45. await db.execute(_CREATE_TABLE)
  46. cursor = await db.execute(
  47. f'SELECT {_COLS} FROM events WHERE calendar_name = ? AND start < ? AND end > ? ORDER BY start',
  48. (self._calendar_name, end.isoformat(), start.isoformat()),
  49. )
  50. rows = await cursor.fetchall()
  51. return [self._to_record(r) for r in rows]
  52. async def create(self, record: EventRecord) -> EventRecord:
  53. import aiosqlite
  54. async with aiosqlite.connect(self._db_path) as db:
  55. await db.execute(_CREATE_TABLE)
  56. await db.execute(
  57. f'INSERT INTO events ({_COLS}) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
  58. (record.uid, self._calendar_name, record.start.isoformat(), record.end.isoformat(),
  59. int(record.all_day), record.title, record.description, record.x_data),
  60. )
  61. await db.commit()
  62. _log.info('create date=%s title=%r', record.start.date(), record.title)
  63. return record
  64. async def update(self, uid: str, *, title: str | None = None,
  65. description: str | None = None, x_data: str | None = None) -> EventRecord:
  66. import aiosqlite
  67. async with aiosqlite.connect(self._db_path) as db:
  68. await db.execute(_CREATE_TABLE)
  69. if title is not None:
  70. await db.execute(
  71. 'UPDATE events SET title = ? WHERE uid = ? AND calendar_name = ?',
  72. (title, uid, self._calendar_name),
  73. )
  74. if description is not None:
  75. await db.execute(
  76. 'UPDATE events SET description = ? WHERE uid = ? AND calendar_name = ?',
  77. (description, uid, self._calendar_name),
  78. )
  79. if x_data is not None:
  80. await db.execute(
  81. 'UPDATE events SET x_data = ? WHERE uid = ? AND calendar_name = ?',
  82. (x_data, uid, self._calendar_name),
  83. )
  84. await db.commit()
  85. cursor = await db.execute(
  86. f'SELECT {_COLS} FROM events WHERE uid = ? AND calendar_name = ?',
  87. (uid, self._calendar_name),
  88. )
  89. row = await cursor.fetchone()
  90. _log.info('update uid=%s', uid)
  91. return self._to_record(row)
  92. async def delete(self, uid: str) -> None:
  93. import aiosqlite
  94. async with aiosqlite.connect(self._db_path) as db:
  95. await db.execute(_CREATE_TABLE)
  96. await db.execute(
  97. 'DELETE FROM events WHERE uid = ? AND calendar_name = ?',
  98. (uid, self._calendar_name),
  99. )
  100. await db.commit()
  101. _log.info('delete uid=%s', uid)