Files
vdm/daemon/cmake/embed_migrations.cmake
samiandClaude Sonnet 5 4b279e8271 daemon: store/ — SQLite WAL schema + forward-only migrator (build step 3)
The daemon's persistent state. SQLite in WAL mode, foreign keys on,
5 s busy timeout so a writer waits rather than SQLITE_BUSY under the
RPC loop.

- store/sqlite — RAII Db/Stmt over the C API; errors returned as
  DbResult<T> (std::expected), never thrown — the RPC loop must not
  unwind. transaction() helper: BEGIN / fn / COMMIT, ROLLBACK on error.
- store/migrations/0001_initial.sql — the eight tables from the brief:
  settings, categories, queues, tasks, segments, rules, history,
  pairings. Notable choices:
    * tasks columns project onto proto TaskSummary with no computation;
      requested vs effective segments/buffer split per ADR 0010/0012;
      pause_reason column per ADR 0013.
    * segments end_byte is NOT constrained >= 0 so a whole-file
      zero-length download is one row with end_byte = -1 (ADR 0010 B3a).
    * pairings stores only token_sha256 — the plaintext token is
      returned once from session.pair and never persisted (CLAUDE.md §4).
    * indices on tasks(state), (category_id), (queue_id, queue_position),
      (created_at), (completed_at) for the "1000 tasks, download.list
      under 50 ms" DoD.
    * six built-in categories + a Main queue seeded.
- store/migrations — runs every embedded migration past PRAGMA
  user_version, each in its own transaction, forward-only. SQL files
  are embedded at build time by cmake/embed_migrations.cmake.

Test veloxd.store_migrations (ASan+UBSan and TSan clean): fresh DB ->
head, all tables present, seed rows, FK cascade (segment orphan
rejected, task delete cascades), the end_byte=-1 zero-length case,
idempotent re-run, and forward-only from every released user_version.

Also: daemon/docs/proto-requests-m1.md — P1 marked landed on lane/proto
as 1.4.0 (HandlerError/HandlerResult), to be adopted in rpc/ once that
merges to main; P2 resolved.

Not linked into the running daemon yet — the store is wired to the
dispatcher when download.add/list/get get real bodies, next.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Upd9WhG9oppieig5nRDLig
2026-09-10 15:27:20 +04:00

53 lines
1.6 KiB
CMake

# Generates migrations_embedded.hpp from daemon/src/store/migrations/*.sql.
#
# cmake -DMIG_DIR=<dir> -DOUT=<file> -P embed_migrations.cmake
#
# Each NNNN_name.sql becomes a Migration{ version = NNNN, name = "NNNN_name", sql = R"..." }.
# The delimiter for the raw string literal is chosen to not collide with the file body.
file(GLOB _sql_files "${MIG_DIR}/*.sql")
list(SORT _sql_files)
set(_entries "")
foreach(_f ${_sql_files})
get_filename_component(_stem "${_f}" NAME_WE) # 0001_initial
string(REGEX MATCH "^([0-9]+)_" _m "${_stem}")
if(NOT _m)
message(FATAL_ERROR "migration file '${_f}' does not start with NNNN_")
endif()
string(REGEX REPLACE "^0*([0-9]+)_.*$" "\\1" _ver "${_stem}")
file(READ "${_f}" _body)
# Pick a raw-string delimiter guaranteed absent from the body.
set(_delim "MIGSQL")
while(_body MATCHES "\\)${_delim}\"")
set(_delim "${_delim}X")
endwhile()
string(APPEND _entries
" Migration{ ${_ver}, \"${_stem}\", R\"${_delim}(\n${_body}\n)${_delim}\" },\n")
endforeach()
list(LENGTH _sql_files _count)
set(_out "// GENERATED by embed_migrations.cmake do not edit. Source: src/store/migrations/*.sql
#pragma once
#include <array>
#include \"store/migrations.hpp\"
namespace velox::daemon::store {
inline constexpr std::array<Migration, ${_count}> kEmbeddedMigrations = {{
${_entries}}};
} // namespace velox::daemon::store
")
if(EXISTS "${OUT}")
file(READ "${OUT}" _existing)
if(_existing STREQUAL "${_out}")
return() # unchanged — do not rewrite, keeps the build stable
endif()
endif()
file(WRITE "${OUT}" "${_out}")