# DuckDB: SQL для CSV, JSON и Parquet

Девять реальных SQL-сценариев на согласованных демонстрационных данных CRM.
Авторские исходники MIT. Вымышленные имена и суммы.

## Версии и механизм

- Node.js 22 или новее, npm; tested Node 24.
- Официальный @duckdb/node-api 2.0.0-r.1 (native DuckDB v2.0.0).
- Официальный @duckdb/duckdb-wasm 1.32.0 (ядро v1.4.3, wasm_mvp).
- Bootstrap 5.3.8, esbuild 0.28.2. Точные зависимости в package-lock.json.
- Браузерный пакет и нативный runtime имеют разные версии. SQL-сценарии используют совместимые конструкции; обновлять и проверять обе ветки нужно отдельно.

В браузере работает настоящий SQL-движок в отдельном Worker. JSON и Parquet — подписанные официальные расширения для v1.4.3 / wasm_mvp, сохранённые локально. BUILD проверяет их SHA256. Происхождение — assets/provenance.json. Ядро около 39.4 МБ + расширения около 3.6 МБ до HTTP-сжатия. Загрузка только после нажатия кнопки, до 120 секунд на первый старт; SQL — до 10 секунд. COOP/COEP для выбранного однопоточного MVP bundle не требуются. Память DuckDB ограничена 256MB; этот параметр не гарантирует такой же предел для всей вкладки.

## Windows / PowerShell

Распакуйте весь архив в отдельный каталог и перейдите в него. Установите Node.js с официального сайта, откройте новый терминал и проверьте node --version.

```powershell
npm.cmd ci --ignore-scripts
npm.cmd run build
npm.cmd test
node bin/report.mjs summary
node bin/report.mjs export report.json
node bin/report.mjs export report.csv
npm.cmd run serve
```

Откройте http://127.0.0.1:8187/. Ctrl+C останавливает только этот сервер. index.html через file:// не запускайте: Worker и WASM должны загружаться по HTTP. report.json и report.csv создаются с flag wx: существующий отчёт не перезаписывается.

## Linux / VPS

Нужен поддерживаемый Node.js LTS 22+ для архитектуры сервера. Используйте официальный вариант установки из https://nodejs.org/en/download. Пакет ОС может быть старее. На Linux arm64/x64 npm выберет соответствующий optional native binding из lock; не переносите Windows node_modules на Linux.

```bash
node --version
npm --version
npm ci --ignore-scripts
npm run build
npm test
node bin/report.mjs join
node bin/report.mjs export report.json
npm run serve
```

Сервер слушает только loopback. Для проверки на VPS:

```bash
ssh -L 8187:127.0.0.1:8187 user@your-vps
```

Открывайте локальный адрес 8187 через туннель. Для постоянной публикации раздавайте public существующим HTTPS-сервером. Например отдельный Caddy site, без замены конфигурации работающего сайта:

```caddyfile
data.example.org {
    root * /srv/duckdb/public
    encode zstd gzip
    file_server
}
```

Для Nginx добавьте в существующий подходящий server блок location, проверьте наличие `application/wasm wasm;` и `application/javascript js;` в mime.types. Публикуются `.js`, не `.mjs`.

```nginx
location /duckdb/ {
    alias /srv/duckdb/public/;
    index index.html;
    add_header X-Content-Type-Options nosniff;
}
```

Проверьте caddy validate или sudo nginx -t перед reload. URL расширений должен отдавать бинарный WASM, а не страницу 404/входа. CSP в HTML разрешает same-origin Worker/WASM, внешних CDN нет. Архив проектного сайта располагается на уровень выше public как duckdb-project.zip; при отдельном развёртывании можно изменить эту ссылку в src/index.html.

## Серверный отчёт с собственными данными

Исходный CSV — UTF-8 с заголовком `order_id,order_date,client_id,city,manager,amount_minor,status`. Суммы — целые копейки, даты ISO YYYY-MM-DD. Сохраните оригинал выгрузки неизменным. Перед изменением fixtures сделайте свою копию проекта; `npm run fixtures` генерирует учебные данные и перезаписывает их. Это не команда импорта рабочих данных.

tools/native.mjs читает фиксированные файлы из fixtures, создаёт orders_raw, типизированную orders_clean, clients, events и parquet_orders. Для настоящего отчёта адаптируйте эти разрешённые пути и проверки схемы в собственной копии. Не принимайте путь и SQL произвольного посетителя сайта. Контекст SQL на сервере имеет права файловой системы процесса. Нативный CLI-пример — локальное доверенное задание, а не HTTP SQL API.

Результат повторяем: bin/report.mjs принимает один из id сценариев и необязательный путь нового JSON/CSV. Сохраните параметры и дату выгрузки рядом. Для планировщика используйте отдельного пользователя с чтением каталога входа и записью каталога отчётов, без привилегий root. Пример cron, если Node установлен системно именно по /usr/bin/node (путь предварительно проверить `command -v node`):

```cron
15 3 * * * cd /srv/duckdb-job && /usr/bin/node bin/report.mjs export /srv/reports/orders-$(date +\%F).json >> /srv/reports/job.log 2>&1
```

Задание завершится с ошибкой, если файл на эту дату уже существует. Для production обеспечьте контроль свободного места, ротацию логов, наблюдение exit code, полноту выгрузки и атомарную публикацию результата через временный файл + rename.

## Данные и сценарии

24 строки orders.csv → 20 валидных уникальных orders_clean. У O004 повтор; O021 содержит невозможную дату; O022 неверную сумму; одна строка без ID. Из 20 заказов 16 оплачены. Клиент 999 отсутствует в clients, LEFT JOIN сохраняет заказ O020. Суммы в копейках. JSON содержит 6 событий с вложенным context.

1. schema — схема сырого CSV и очищенной таблицы.
2. quality — пустые ключи, дата, сумма, повторные ID.
3. summary — выручка, число заказов, средний чек по городу.
4. join — LEFT JOIN со справочником клиентов.
5. window — рейтинг менеджеров и накопленная выручка.
6. json — вложенный JSON, структура context, сводка каналов.
7. parquet — реальное чтение Parquet и контрольная сверка с CSV.
8. params — prepared statement, начало включительно / конец исключительно / минимум копеек.
9. export — отчёт по дням, JSON/CSV/SQL.

Все сценарии в src/scenarios.js. fixtures/expected.json — зафиксированные ожидания. `node tools/fixtures.mjs --accept` намеренно переписывает эталоны после осознанной проверки; обычные тесты ничего не перегенерируют.

## Ограничения мастерской

CSV/JSON: 1 байт–2 МиБ, UTF-8. CSV импортируется строками; для преобразования используйте TRY_CAST. JSON auto-detect; для сложных производственных схем задайте columns явно. Пользовательский файл — таблица uploaded, импортируется при новом запуске. Он не отправляется на сервер и не сохраняется после закрытия страницы. Код намеренно не сохраняет SQL и файлы в localStorage.

После контролируемого импорта включены enable_external_access=false и lock_configuration=true. Редактор оборачивает один SELECT/WITH в подзапрос с LIMIT 501, не выполняет DDL. Более 500 строк и вывод больше 1 МиБ отклоняются целиком: урезанный отчёт нельзя случайно принять за полный. Ошибка SQL не отключает последующие запросы. Отмена завершает настоящий Worker; следующий запуск создаёт базу заново. Это не серверная песочница: правила относятся к данному браузерному экземпляру.

SQL-параметры передаются отдельным prepared statement, не интерполируются. JSON экспортирует BIGINT как строку для точности. Arrow DECIMAL преобразуется в строку по масштабу поля, без промежуточного Number; NaN и Infinity также становятся строками, поскольку стандарт JSON не содержит таких чисел. CSV экранирует кавычки, разделители/переносы, добавляет BOM; текстовые значения с префиксом формулы получают апостроф (числовые типы не изменяются). Для машинного обмена выбирайте JSON с согласованной схемой; NULL и пустая строка в CSV неразличимы. График — первые 12 неотрицательных безопасных целых, подписи в исходных единицах.

DuckDB — аналитический embedded движок, не замена PostgreSQL/MySQL для многопользовательских транзакционных сервисов. Нативный движок может выгружать промежуточные данные на диск при настройке temp_directory; WASM-демо ограничено памятью браузера. Размер мини-фикстур не является бенчмарком эффективности CSV/Parquet.

## Проверка и исходники

`npm test` запускает девять сценариев настоящим Node API, сравнивает эталоны, проверяет суммы/плохие данные/параметры/BIGINT/DECIMAL/SQL-ошибки, экспорт и заблокированный внешний доступ. Тесты UI-обработчиков с управляемым Worker-транспортом воспроизводят отмену загрузки и файла, новый запуск, полный возврат параметров и сброс экспорта после редактирования. Они не заменяют реальное WASM-выполнение. Браузер отдельно проверяется на текущем сервере: девять сценариев, изменение параметров, собственный файл, ошибка и восстановление, остановка Worker, скачивания, мобильная ширина и отсутствие внешних запросов.

Исходники находятся в src/, tools/, bin/, tests/. public содержит готовую статическую мастерскую и копии исходников `.txt`; это не замена исходному каталогу проекта. Полные лицензии и происхождение бинарных расширений — licenses/ и assets/provenance.json. npm audit относится к npm-зависимостям; он не проверяет все свойства native/WASM ядра.

Официальные материалы: https://duckdb.org/docs/stable/ ; https://duckdb.org/docs/stable/clients/node_neo/overview ; https://duckdb.org/docs/stable/clients/wasm/overview ; https://github.com/duckdb/duckdb-wasm ; https://duckdb.org/docs/stable/data/parquet/overview
