Ddb Поверх Rdb В Python

Несколько месяцев назад мне понадобилась база данных документов для запланированного проекта Python. Не знаю, как так получилось, но погуглив, я умудрился не заметить ни одного существующего решения и пришёл к выводу, что единственный выход — написать своё.

Поскольку мне хотелось как можно быстрее получить работающее решение, я решил опираться на существующие реляционные базы данных, чтобы не беспокоиться о реализации хранения, поиска, транзакций и тому подобного.

В итоге мое творение приобрело достойный вид, и я решил написать о нем заметку здесь — может быть, кому-нибудь она окажется полезной.



Где взять

Для самых нетерпеливых: База данных выполнена в виде модуля и для использования требует Python 3 (а для запуска модульных тестов — Python 3.1, там добавлены очень хорошие методы).

Сразу прошу прощения у всех ортодоксальных людей, которые до сих пор не могут решиться на переход даже на 2.6 - я, конечно, мог бы портировать свой модуль на 2.*, но поленился.

Как я уже говорил, в качестве нижнего слоя модуль использует обычную реляционную базу данных.

В настоящее время поддерживаются SQLite (тот, который поставляется с Python) и Postgre 8 (если установлен py-postgresql).



… и что с этим делать

Я предполагаю, что многие люди уже знакомы с базами данных документов, поэтому я буду краток.

Итак, наше основное понятие — объект. Объект имеет уникальный идентификатор и ряд различных типов данных.

В моей базе данных данные представляют собой комбинацию простых типов — int, float, str, bytes и None — и сложных типов — dict и list. Уровень вложенности ограничен только реляционным движком, о причинах я расскажу позже.

Сам идентификатор объекта также может храниться в другом (или в том же) объекте.

Объекты можно создавать, удалять, а их содержимое можно изменять любым способом; и, конечно же, поиск необходимых объектов по заданным критериям.

Итак, предположим, что вы уже скачали и установили модуль.

Или даже просто подарили – не важно.

Для иллюстрации работы с модулем я просто скопирую сюда несколько примеров из документации (для тех, кому было лень пройти по ссылке выше).

Итак, подключим модуль и создадим соединение.

Для простоты будет использоваться реляционный механизм по умолчанию (SQLite) и база данных в памяти.



>>> import brain >>> conn = brain.connect(None, None)

Теперь давайте создадим пару объектов.

Обратите внимание на вложенный список во втором объекте.



>>> id1 = conn.create({'a': 1, 'b': 1.345}) >>> id2 = conn.create({'id1': id1, 'list': [1, 2, 'some_value']})

Объекты можно читать целиком или выделить определенную область.

Во втором случае используется путь к нужным данным — просто список, где строка означает ключ в дикте, а число означает индекс в списке.



>>> print(conn.read(id1)) {'a': 1, 'b': 1.345} >>> print(conn.read(id2, ['list'])) [1, 2, 'some_value']

Содержимое объекта можно изменить.



>>> conn.modify(id1, ['a'], 2) >>> print(conn.read(id1)) {'a': 2, 'b': 1.345}

И наконец, нужный объект может быть найден.



>>> import brain.op as op >>> objs = conn.search(['list', 0], op.EQ, 1) >>> print(objs == [id2]) True

Используемое условие расшифровывается как «0-й элемент списка, находящегося в ключе 'dict' корневого словаря, равен 1».



И все это?

Не совсем.

Для списков существует специальная команда вставки (которая работает почти так же, как ее эквивалент в Python).

Объекты и их части можно удалять (в том числе с помощью масок).

Условия поиска можно комбинировать с помощью логических операторов.

Ах да, транзакции тоже поддерживаются, есть простой RPC-сервер и кеширующее соединение (довольно глупое).

Обо всем этом вы можете прочитать в документации.



Что внутри?

Внутри все довольно просто.

Для каждого уникального пути создается таблица с соответствующим именем (причем пути, отличающиеся только индексами в списках, используют одну и ту же таблицу).

Например, для таких данных, как {'key': [{'key2': 'val'}]}, значение 'val' будет храниться в таблице с именем "field.TEXT.key.key2" (пустое пространство между двумя точками говорит, что список находится по ключу 'key').

Кроме того, имеется одна большая таблица, в которой для каждого объекта записаны имеющиеся у него поля и их типы.

Таким образом, если вдруг что-то пойдет не так, данные можно будет восстановить, используя доступные инструменты работы с реляционными базами данных.

Это приводит к ограничению уровня вложенности хранимых структур данных — все зависит от максимальной длины имени таблицы, которую поддерживает реляционная база данных.



И что дальше?

Как я уже сказал, существующей версии базы данных вполне достаточно для моих целей.

Но если вдруг кто-то подумает, что это творение может быть полезно кому-то еще, то я буду рад добавить необходимые функции.

И, конечно же, приветствуется любая конструктивная критика по коду/архитектуре/документации.

Теги: #python #sql #ddb #Chulan

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.