Хранилище Python-объектов
Разработать API и реализующий его пакет Python для хранения и эффективной выборки экземпляров Python dataclasses во встроенной в Python СУБД sqlite
Требования к проекту
- Минимальные зависимости на внешние модули (в идеале — никаких)
Требования к API
Хранилище выглядит как словарь таблиц по типу хранимого элемента (то есть ключом словаря является класс)
storage[Record]
Поиск эелемента
Запрос к таблице возвращает список подходящих объектов ( или итератор по ним, если так удобнее)
for record in storage[Record].search():
- Запрос может включать в себя фильтр по полям класса:
for record in storage[Record].search(name = "Колесо", kind = "Квадратное"):
«Ключом» (не вполне уникальным, см. ниже замечания про версионирование) в таблице является строковое поле ID. Запрос по этому полю должен возвращать один объект или None, если такого нет. API должно выглядеть как словарь по ID:
storage[Record]["Идентификатор"]
Выборка по ключу должна работать быстро (в идеале — амортизированный худший случай = O(1), как в словарях)
Версионирование, добавление и удаление элементов
Все объекты хранилища сопровождаются версией (временно́й меткой). В хранилище могут храниться объекты с разными версиями и одинаковым ID.
- Если при поиске (по фильтру или ключу) не указано имя поля-версии, возвращается самая свежая версия объекта
Нужно придумать синтаксис: как задавать конкретную версию, первую версию, все версии
Операция добавления элемента добавляет в таблицу соответствующий элемент (версию можно не указывать, это текущий timestamp; ID — ключ — обязательное поле объекта).
storage[Record].append(newrecord)
- Удаление элементов по ключу удаляет последнюю версию и имеет синтаксис словаря:
del storage[Record]["Идентификатор"]
- Удаление элементов по результатам поиска использует тот же синтаксис, что и поиск.
storage[Record].remove(name = "Колесо", kind = "Квадратное")
См. выше относительно задания ограничений на версии
Требования и ограничения
Нужно демонстрационное приложение, в котором вызываются все методы во всех принципиально различных вариантах
- Нужен замер производительности операций по ключу и фильтру
Допустимые ограничения
Если это упростит реализацию, можно допустить, что:
ID объектов в разных таблицах могут совпадать
- Все таблицы — небольшого размера (порядка тысячи записей)
Все хранимые объекты являются экземплярами классов с одним общим dataclass-предком
Поле-версия всегда называется timestamp
- Поля объектов могут быть не вообще любого типа, а только нескольких заданных, для которых есть адаптеры хранения
- Тем не менее должны поддерживаться
- Можно создавать служебные таблицы SQLite
- Можно вообще не использовать SQLite, а хранить всё в файле
Можно использовать SQLAlchemy, если вы в него хорошо умеете
Замечания
В Python 3.13+ есть db-бэкенд для SQlite, понадобится ли он — неизвестно, но почитать надо.
Вообще поглядеть на dbm
Вариант реализации версионирования: для каждого типа создаются две таблицы — самых свежих версий, с ключом ID, и с историей версий, с ключом ID + timestamp. Тогда поиск по ID будет работать быстро. Но тогда методы с timestamp= будут прозрачно для пользователя в другую таблицу идти, и надо подумать об атомарном изменении обеих таблиц.