--- name: shaderlab_db kind: function lang: cpp domain: gfx version: "1.0.0" purity: impure signature: "bool shaderlab_db_save_generator(GeneratorRecord& gen, std::string* err); std::vector shaderlab_db_list_generators(); bool shaderlab_db_get_generator(const std::string& id, GeneratorRecord& out); bool shaderlab_db_delete_generator(const std::string& id);" description: "CRUD persistente para generators custom de shaders_lab via sqlite3. Guarda el GLSL original, el body traducido para el DAG, los DagControl y los param_defaults en una BD local (shaders_lab.db). Soporta open(:memory:) para tests." tags: [sqlite, shaders, glsl, dag, gfx, persistence, crud, shaders_lab] uses_functions: [] uses_types: - dag_types_cpp_gfx returns: [] returns_optional: false error_type: "error_go_core" imports: [sqlite3, string, vector, chrono, ctime, iomanip, sstream] tested: true tests: - "open in-memory + list empty" - "save + get roundtrip preserva controls/params/defaults" - "list ordenado por label" - "update preserva created_at y bumps updated_at" - "delete devuelve true solo si existia" test_file_path: "cpp/functions/gfx/shaderlab_db.cpp" file_path: "cpp/functions/gfx/shaderlab_db.cpp" params: - name: gen desc: "Registro del generator. Debe llevar id (snake_case), label, source_glsl original, body_glsl traducido, param_count y los param_defaults/controls coherentes." - name: id desc: "ID snake_case del generator (clave primaria de la tabla)." - name: out desc: "Registro de salida en get; queda relleno solo si la funcion devuelve true." - name: err desc: "Mensaje de error opcional si save falla (constraint, schema, IO)." output: "Persistencia en la tabla generators de shaders_lab.db. Las listas vienen ordenadas por label." --- ## Schema ```sql CREATE TABLE generators ( id TEXT PRIMARY KEY, label TEXT NOT NULL, description TEXT NOT NULL DEFAULT '', source_glsl TEXT NOT NULL, body_glsl TEXT NOT NULL, param_count INTEGER NOT NULL, param_defaults TEXT NOT NULL, -- CSV de floats param_names TEXT NOT NULL, -- LF-separated strings controls TEXT NOT NULL, -- LF-separated, fields '|': kind|label|p0|p1|p2|min|max|step tags TEXT NOT NULL DEFAULT '', created_at TEXT NOT NULL, updated_at TEXT NOT NULL ); ``` ## Notas - Formato de serializacion custom (no JSON): CSV para floats, LF para strings, `|` para fields de control. Sin escape de separadores; los labels no deben contener `\n` ni `|`. - `shaderlab_db_open` es idempotente: re-abrir con el mismo path es no-op. - `:memory:` como path crea una BD temporal en memoria (usado en tests). - `save_generator` hace upsert (`ON CONFLICT DO UPDATE`). Setea `created_at` solo si esta vacio. - Tests inline activables con `-DSHADERLAB_DB_TEST` y linkando sqlite3 (amalgamation o `-lsqlite3`).