PGWeb − небольшая SQL-библиотека для создания web-приложений

Введение

Эта библиотека не является аналогом ORM или какого-нибудь фреймворка, будь то CodeInteger или Yii. Уж очень у нее скуп функционал. Однако, несмотря на это, с помощью нее можно несколько упростить создание веб-проектов различной направленности: блоги, CMS, CRM, интернет-магазины.

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

Библиотека разделена на 3 части (схемы): генерирование случайных ключей, работа с сессиями и хранение данных.

Основное требование - наличие СУБД PostgreSQL не ниже 10 версии.

Генерирование случайных ключей Подробнее

Данный функционал позволит вам создавать уникальные случайные ключи произвольной длины, как в единичном экземпляре, так и серийно. Серийное генерирование поможет вам ускорить работу приложения в следующих случаях: например, при загрузке файлов, когда нужно сгенерировать уникальное имя, или когда нужно создать CSRF-токен и т.п. Длина ключа может быть от 15 до 255 символов длиной. Вы можете создавать имена серийных ключей. Зачем это нужно? Все просто: например, для имен файлов вы хотите ключ длиной 20 символов, а для CSRF-токенов - 50 символов. Вы можете создать 2 имени:

SELECT schema_keys.add_name( 'files' );
SELECT schema_keys.add_name( 'csrf' );

Затем назначить им длину:

SELECT schema_keys.set_length( 'files', 20 );
SELECT schema_keys.set_length( 'csrf', 50 );

И получить результат:

SELECT schema_keys.generate( 'files' );
SELECT schema_keys.generate( 'csrf' );

А так можно получить серию в 1000 ключей:

SELECT schema_keys.generate_series( 'files', 1000 );
SELECT schema_keys.generate_series( 'csrf', 1000 );

Для удаления имени выполните:

SELECT schema_keys.remove_name( 'files' );

Также вы можете генерировать ключи и без создания имени:

SELECT schema_keys.generate();
SELECT schema_keys.generate_series( 1000 );

Работа с сессиями Подробнее

Это важно: при работе с сессиями вся ответственность за уникальность ключей сессии лежит на программисте, а не на библиотеке. Наверное, это может показаться странным, но тем не менее я счел это наиболее рациональным. Вобщем работа с сессиями разделяется на 2 этапа: 1 - сгенерировать уникальный ключ, что мы рассмотрели ранее, и 2 - добавить этот ключ в таблицу сессий.

Добавление ключа возможно только с IP-адресом клиента, а также опционально с ID пользователя, если таковой имеется. Ключ сессии, IP адрес и ID - неизменяемые значения и задаются только 1 раз при добавлении сессии.

Также предусмотрено хранение данных через jsonb.

Также вы можете удалять сессию, продлевать время жизни, удалять устаревшие сессии.

Хранение данных Подробнее

Наверное, эта часть покажется многим слишком необычной для стандартного SQL. Оговорюсь заранее, что это не является полноценной заменой NoSQL базы данных, скорее неким упрощением для работы с jsonb. Для хранения документов необходимы так называемые ноды, которые могут содержать в себе другие ноды. Говоря понятнее, ноды - это папки, а документы - файлы. Структура может иметь следующий вид (просто пример):

site
site/regions
site/regions/spb
site/regions/spb/news
site/regions/msk
site/regions/msk/news

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

Далее. Каждая нода может иметь собственную схему валидации добавляемых в нее документов. Сама схема записывается в формате JSON.

Пример схемы:

{
    "type": "object", // тип
    "data": [
        {
            "type": "string",
            "name": "city", // имя параметра
            "min": 3, // минимальная длина
            "max": 6, // максимальная длина
            "regexp": "^[0-9a-zA-Z]{3,6}$"
        },
        {
            "type": "number",
            "name": "age",
            "min": 18, // минимальное значение
            "max": 99 // максимальное значение
        },
        {
            "type": "boolean",
            "name": "is_banned",
            "required": false // должен ли присутствовать в документе
        },
        {
            "type": "array",
            "name": "sessions_keys",
            "min": 0, // минимальная длина массива
            "max": 10, // максмальная длина массива
            "data": {
                "type": "string",
                "regexp": "^[0-9a-zA-Z]{15,255}$"
            }
        }
    ]
}

Документ, который пройдет валидацию:

{
    "city": "spb",
    "age": 20,
    "sessions_keys": [ "aaaaabbbbbccccc" ]
}

Документ, который не пройдет валидацию :-) :

{
    "city": "spb",
    "age": 20,
    "sessions_keys": [ "aaaaabbbbbccccc-" ]
}

Сама валидация разделяется на 2 вида: детальную и быструю. По-умолчанию срабатывает быстрая валидация, если это возможно (если пытаться как-то отвалидировать строку, например указать ее максимальную длину или регулярное выражение, то будет применена детальная валидация). В чем разница между двумя видами валидации? В первом случае, валидация будет выполняться с помощью SQL хранимой процедуры, также указанием места ошибки (например неверный параметр sessions_keys), а во втором - на помощь придет расширение jsquery, но в таком случае вы просто получите ошибку валидации.

Также по умолчанию каждая нода предусматривает партиционирование документов. По умолчанию это значение составляет 50000. В любой момент вы можете изменить это значение и таблица будет перестроена.

Еще в ноде можно указывать какие данные из схемы должны быть в индексе. Главное условие создания индекса наличие схемы. Добавленные индексы учитывают партиционирование.

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

Поиск по документам осуществляется через стандартный SELECT к таблице docs, например:

SELECT id, id_node, name, data FROM schema_docs.docs;