Довольно часто на этапе прототипирования (и всегда — в пет-проектах) я не запариваюсь с бэкэндом и поднимаю апи на express с sqlite3. Это легко и довольно удобно для несложной логики, а для сложной есть бэкэндеры с их отдельным миром. Единственный геморрой, который долгое время меня преследовал на этапе написания апи — невозможность быстро заглянуть в базу и отследить изменения. Можно дебажить по памяти, конечно, но это как-то странно, когда можно просто вытащить содержимое по запросу и отобразить его на какой-нибудь страничке. Вот только каждый раз заново парсить json и распихивать его в таблицы по лучшим практикам очередного фреймворка мне не хотелось, поэтому я после недолгих поисков нашёл sqljs и набросал на нём простейший визуализатор.
Про sqljs
Это библиотека, позволяющая создавать sqlite базы, читать, писать и вообще строить любой апи на них. Он построен на wasm, поэтому работает медленнее чем тот же sqlite3, и использует emscripten для сборки. По умолчанию создаётся in-memory база, но можно читать из файла и экспортировать файл из памяти. Демо. В конце концов, sqljs не завязан на node или любое другое окружение и спокойно работает в браузере, но мне было проще запустить его из ноды, всё равно ж использую.
Ссылки
Вот сайт, документация и примеры. Есть легаси-версия с asm.js и web worker версия, все дистрибутивы доступны через CDN и на GitHub.
Использование
0. Подключаем библиотеку
CDN:
<script src="https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.4.0/dist/sql-wasm.js" integrity="sha512-8oJoeo0ykAzuJzQFJDnwz9t4Rr+1xue7LFX+kr0NJMpOHH9QJPC563If+sakheUe3QbLwTTgXIGPC6YZTwp7Iw==" crossorigin="anonymous"></script>
npm:
npm install sqljs
1. Инициализация библиотеки
// Используя модуль:
const initSqlJs = require('sql.js');
// При использовании в браузере:
var initSqlJs = window.initSqlJs;
2. Загружаем инстанс
const SQL = await initSqlJs({
// Асинхронная загрузка бинарника wasm. Разумеется, его можно хранить и у себя
// В node не требуется
locateFile: file => `https://sql.js.org/dist/${file}`
});
3. Создаём базу, выполняем INSERT/SELECT
var db = new SQL.Database();
// Также можно использовать new SQL.Database(data), где
// data это Uint8Array с файлом sqlite
sqlstr = "CREATE TABLE hello (a int, b char);";
sqlstr += "INSERT INTO hello VALUES (0, 'hello');"
sqlstr += "INSERT INTO hello VALUES (1, 'world');"
db.run(sqlstr);
var res = db.exec("SELECT * FROM hello");
/*
[
{columns:['a','b'], values:[[0,'hello'],[1,'world']]}
]
*/
4. Формируем смешанный запрос и привязываем переменные к значениям ответа
var stmt = db.prepare("SELECT * FROM hello WHERE a=:aval AND b=:bval");
var result = stmt.getAsObject({':aval' : 1, ':bval' : 'world'});
console.log(result); // {a:1, b:'world'}
// Освобождаем память выражения
stmt.free();
// После освобождения использовать выражение нельзя,
// но бесконтрольное использование приведёт к утечкам памяти
Демо: https://jsfiddle.net/5f3ahx8o/
Визуализация
Из-за разницы в производительности и не особенно нужного in-memory, возможно и стоило изначально брать проверенный sqlite3, но надо было бы притянуть немного бойлерплейта, да и логично было бы пустить отображение через апи, а мне хотелось иметь отдельно работающий молчаливый сервис. Чтобы не плодить сущности я взял express-handlebars для отображения и прокинул в основную вьюху {{{renderedTables}}}.
Базу забирал из той же директории, но можно прописать любой путь.
var filebuffer = fs.readFileSync('sqlitedb');
/* ... */
initSqlJs().then(function(SQL){
var db = new SQL.Database(filebuffer);
Данные из всех таблиц получаются в две строчки:
var schema = db.exec('SELECT name, sql FROM sqlite_master WHERE type="table";')[0].values;
schema.forEach(t => all[t[0]] = db.exec('SELECT * FROM ' + t[0]));
Дальше идёт скучный рендер таблицы и, наконец, отправка её на страницу. Полный код есть в репо.
Заключение
Меня на протяжении всего этого процесса не покидало ощущение, что я изобретаю какой-то тупейший велосипед и всё уже точно написано до меня, обмазано тестами и схемами, но топорного варианта для себя, «запустил и забыл», так и не обнаружил. Ну, тем забавнее будет, если эта штука кому-то окажется полезна. Можно ещё прикрутить хот-релоад и эти долбаные схемы, но зачем их заводить для mock database на пару таблиц, мне неочевидно.
На правах рекламы
Мощные виртуальные серверы с процессорами AMD EPYC для разработчиков. Частота ядра CPU до 3.4 GHz. Максимальная конфигурация позволит оторваться на полную — 128 ядер CPU, 512 ГБ RAM, 4000 ГБ NVMe.