RedBase 3.2.0 — SQLite-провайдер: один файл, офлайн, Blazor WASM и мобилки

redb

С тех пор как мы выложили RedBase в опенсорс, чаще всего спрашивали одно и то же: «а под SQLite будет?» — и почти всегда по двум причинам. Первая — Blazor WebAssembly: типизированное объектное хранилище прямо в браузере, без похода на бэкенд. Вторая — мобилки и десктоп (MAUI, offline-first, один файл .db, который едет вместе с приложением). Postgres и MSSql — прекрасные серверы, но их не встроишь в iOS-приложение и не положишь в WASM-бандл.

В RedBase 3.2.0 вышел SQLite-провайдер. Тот же LINQ, та же модель из 13 таблиц, та же регистрация AddRedb(...), что и для Postgres/MSSql — только теперь Data Source=app.db.

Если про REDB впервые — короткий контекст из предыдущих статей серии:


Самое короткое объяснение

services.AddRedb(options => options
    .UseSqlite("Data Source=app.db"));

Всё. Дальше redb.Query<Employee>().Where(e => e.Salary > 80_000).OrderBy(e => e.HireDate).ToListAsync(), деревья, группировки, оконные функции, словари, List<ListItem>, soft-delete — тот же самый код, что на Postgres или MSSql. Провайдер меняется одной строкой в DI; приложение не знает, на какой базе оно работает. Ровно ради этого и существует DB-агностичное ядро — и SQLite теперь в нём полноценный гражданин.


Два тира, и тот, что важен для Blazor и мобилок

У RedBase всегда были тиры Free и Pro. Для SQLite граница ложится туда, куда и должна:

SQLite Pro — чистый C#, ни строчки нативного кода. SQL запроса генерится в C# (ProSqlBuilder), материализация props — тоже в C#. Он не вызывает ни одной серверной функции БД. А значит — работает везде, где работает Microsoft.Data.Sqlite: в том числе в Blazor WebAssembly и на мобилках (MAUI / iOS / Android), где нативное расширение SQLite загрузить нельзя в принципе. Это и есть тот тир, который у нас просили: типизированное LINQ-хранилище в одном файле прямо внутри браузера или приложения.

Pro — бесплатный. Нужно только зарегистрироваться на redb.ru и получить лицензионный ключ — инструкция по подключению там же, сразу после регистрации. Тир для WASM/мобилок не стоит денег; регистрация — просто способ выдать ключ.

SQLite Free — нативное загружаемое расширение. Прямой аналог того, как Free устроен на Postgres/MSSql: вся тяжёлая машинерия (материализатор get_object_json, компилятор запросов) живёт внутри БД как in-DB SQL-функции. На SQLite это нативное C-расширение (redb.dll / .so / .dylib), грузится на каждое соединение. Работает везде, где грузится нативный код — десктоп, сервер, CI — и это же то, что дёрнет не-.NET хост (Python, sqlite3 CLI), чтобы говорить с базой RedBase напрямую.

Итого: WASM и мобилки → Pro; десктоп/сервер/Python → любой. Разница между Free и Pro — в материализации и change-tracking, а не в том, какой запрос вы получаете: форма запроса у обоих тиров одна и та же.


Чего стоило собрать Free-расширение

Самое интересное. На Postgres и MSSql «Free» — это ворох серверных SQL-функций (PL/pgSQL, T-SQL): движок запросов v2-pvt, get_object_json, save_object_json, soft-delete, view прав. У SQLite процедурного языка нет вообще. Поэтому под Free мы портировали весь этот движок в нативное C-расширение поверх sqlite3ext.h:

  • get_object_json — рекурсивный материализатор: base-поля, скаляры, массивы и словари (реляционно через _array_index / _array_parent_id), вложенные Class-поля, ссылки на объекты, ListItem (включая ListItem, который сам несёт Object). Читает _values и собирает JSON, который десериализует C#-слой.
  • Компилятор pvt_* — ~9 тысяч строк логики PL/pgSQL, заново выраженных на C как генерация SQL-строк: pvt_build_query_sql, pvt_build_aggregate_sql, pvt_build_groupby_sql, pvt_build_window_sql, pvt_build_projection_sql, pvt_build_array_groupby_sql. Postgres-измы переезжают в SQLite: array_agg … FILTERjson_group_array … FILTER, = ANY(arr)IN (SELECT value FROM json_each(...)), EXTRACT(… FROM x)CAST(strftime(...) AS INTEGER), ILIKELIKE и так далее.
  • Идентификаторы — последовательностей в SQLite нет, поэтому генератор ключей использует нативную AUTOINCREMENT-таблицу и резервирует блоки id из sqlite_sequence; C-расширение и C#-генератор двигают один и тот же счётчик, так что id остаются глобально уникальными — хоть из .NET, хоть из Python-хоста.
  • Soft-delete и праваmark_for_deletion / purge_trash как нативный мульти-стейтмент SQL, и view v_user_permissions (рекурсивное наследование прав по дереву + глобальный fallback) для эффективных прав.

Оба тира проходят полный набор примеров (145/145) — тот же, что гейтит Postgres и MSSql.

Минимальная версия SQLite — 3.44.0+ (ноябрь 2023): мы опираемся на FILTER (WHERE …), современные оконные функции, RETURNING, JSON1 и рекурсивные CTE, чтобы SQLite-SQL оставался близок к Postgres-SQL, а не превращался в переписывание с нуля.


С чего начать

Free (десктоп/сервер — нативное расширение):

services.AddRedb(options => options
    .UseSqlite("Data Source=app.db"));
// путь к нативному расширению — через env REDB_SQLITE_EXTENSION,
// либо резолвится redb.{dll,so,dylib} из runtimes-папки пакета

Pro (Blazor WASM / мобилки / где угодно — чистый C#):

services.AddRedbPro(options => options
    .WithLicense(licenseKey)
    .UseSqlite("Data Source=app.db"));

Одна деталь — общая для обоих: UseSqlite тир-агностичен. AddRedb даёт Free, AddRedbPro — Pro, и тир переключается без правки using-ов. Дальше — тот LINQ, который вы и так пишете.


Что честно ещё не доделано

В серии принято говорить и про то, что не готово:

  • Кросс-платформенные нативные бинарники Free. C-расширение сейчас собрано под Windows x64. Linux (.so) и macOS (.dylib, включая arm64) собираются из того же CMake-проекта — CI-матрица и per-RID упаковка в NuGet (runtimes/<rid>/native/) следующие в списке. У Pro нативной зависимости нет — он уже сегодня работает везде, и это ровно то, что нужно WASM/мобилкам.
  • In-memory базы работают, но :memory: в SQLite — per-connection: нужен Mode=Memory;Cache=Shared плюс один удерживаемый коннект, чтобы пул видел одну и ту же базу. Это особенность жизненного цикла SQLite, не RedBase.
  • Точность decimal. NUMERIC по умолчанию маппится в REAL (быстро, но лоссово за пределами double); точный вариант через TEXT — запланированная настройка. Известное слабое место SQLite.
  • Скорость Free-запросов — это модель серверных функций: для embedded/локальных нагрузок ок, но на больших выборках по сырой пропускной способности C#-материализация Pro быстрее (by design — это и есть разница тиров).

Почему это тот релиз, который хотелось выпустить

RedBase начинался как «альтернатива EF Core для сложных графов объектов на Postgres/MSSql». В 3.2.0 тот же движок — тот же LINQ, та же модель без миграций, те же деревья и проекции — крутится во вкладке браузера и на телефоне, из одного файла, офлайн. Это не порт; это DB-агностичное ядро, наконец доехавшее туда, куда его чаще всего и просили.

Репозиторий, доки и пакеты — redbase.app. Вопросы, «а делает ли оно X на SQLite» и баг-репорты — несите, провайдер совсем новый, обратная связь открыта.

Также опубликовано:Habr ↗