Story #307: MariaDB DDL for entity_tags + direct driver deps - #359
Open
joestump wants to merge 1 commit into
Open
Story #307: MariaDB DDL for entity_tags + direct driver deps#359joestump wants to merge 1 commit into
joestump wants to merge 1 commit into
Conversation
Implements #307. - internal/database/entity_tags.go: dedicated MySQL/MariaDB dialect DDL (BIGINT AUTO_INCREMENT PRIMARY KEY, inline KEY indexes, ENGINE=InnoDB) instead of falling through to SQLite syntax that breaks on MariaDB. DDL statements now execute one at a time so the default MySQL DSN (no multiStatements=true) works. - internal/database/entity_tags_test.go: per-dialect DDL unit test plus a driver-matrix integration test — SQLite in-memory always; Postgres and MariaDB gated behind SPOTTER_TEST_POSTGRES_DSN / SPOTTER_TEST_MYSQL_DSN with graceful skips (verified locally against postgres:16 + mariadb:11). - go.mod: lib/pq and go-sql-driver/mysql promoted to direct requires via go mod tidy (per SPEC-0014 REQ "go.mod Dependencies"). Governing: SPEC-0014 REQ "Denormalized Entity Tags Table", REQ "Driver Registration", REQ "go.mod Dependencies"; ADR-0023. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
joestump-agent
added a commit
to joestump-agent/spotter
that referenced
this pull request
Jul 10, 2026
…iver matrix tests (#33) * Port entity_tags dialect DDL test coverage and driver-matrix tests Ports joestump#359, implements joestump#307. The fork already had the core of upstream PR 359: dedicated MySQL/MariaDB dialect DDL (BIGINT AUTO_INCREMENT, table-level FKs, single-statement Exec with an information_schema index guard) and lib/pq + go-sql-driver/mysql as direct go.mod requires. This ports the remaining gaps, adapted to the fork's structure: - internal/database/entity_tags_test.go: per-dialect DDL token unit test (TestEntityTagsDDLDialects) now covering Postgres and SQLite in addition to the fork's existing MySQL invariants; unknown-driver fallback test; driver-matrix integration test (TestCreateEntityTagsTable_Matrix) — SQLite in-memory always, Postgres and MariaDB gated behind SPOTTER_TEST_POSTGRES_DSN / SPOTTER_TEST_MYSQL_DSN with graceful skips (also skips when the DSN is set but the server is unreachable). The matrix proves idempotency, insert/select round-trip, the (tag_id, entity_type, entity_id) unique constraint, column types via PRAGMA/information_schema, and (fork extension) that the MySQL information_schema index guard sees both indexes after migration. - internal/database/entity_tags.go: MySQL created_at is now DATETIME instead of TIMESTAMP (avoids the 2038 range limit and MySQL's implicit TIMESTAMP auto-init/auto-update behavior) and ENGINE=InnoDB is pinned explicitly (FK + ON DELETE CASCADE require InnoDB), matching upstream's dialect parity. Existing tables are unaffected (CREATE TABLE IF NOT EXISTS). Defect fixed while porting: upstream's reject-token check for the MySQL dialect used a substring that would false-positive on "CURRENT_TIMESTAMP,"; the ported test rejects "created_at TIMESTAMP" instead. Upstream's destructive DROP TABLE cleanup in the live matrix helpers is retained but now called out with an explicit warning to use throwaway databases. Governing: SPEC-0016 REQ "Denormalized Entity Tags Table", ADR-0023. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Xyerp7w1SH5vG48z93DxN * Document that DATETIME created_at applies to fresh MySQL databases only CREATE TABLE IF NOT EXISTS never migrates, so existing MySQL deployments keep a TIMESTAMP created_at (UTC-normalized, 2038-limited) while new installs get DATETIME (session-timezone literal). Benign while created_at is never read; the note prevents surprise if a future feature reads it. Addresses PR #33 review feedback. Governing: SPEC-0016 REQ "Denormalized Entity Tags Table", ADR-0023. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Xyerp7w1SH5vG48z93DxN --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What / Why
The
entity_tagsmigration (internal/database/entity_tags.go) only had Postgres and SQLite DDL — whenSPOTTER_DATABASE_DRIVER=mysql, it fell through to SQLite syntax (INTEGER PRIMARY KEY AUTOINCREMENT), which fails on MariaDB. This was flagged[CRITICAL]by the 2026-05-10/sdd:audit.BIGINT AUTO_INCREMENT PRIMARY KEY, explicitENGINE=InnoDB(FK +ON DELETE CASCADEsemantics require it),DATETIME DEFAULT CURRENT_TIMESTAMP, and secondary indexes declared inline inCREATE TABLE— MySQL (unlike MariaDB 10.1+) has noCREATE INDEX IF NOT EXISTS, and inlineKEYclauses stay idempotent on both.Execbatch, becausego-sql-driver/mysqlrejects multi-statement queries unless the DSN opts intomultiStatements=true(the SPEC-0014 default MySQL DSN does not).lib/pqandgo-sql-driver/mysqlpromoted from// indirectto direct requires viago mod tidy(run aftermake generate, since Ent generated code drives the dependency graph). Tidy also promotedgolang-jwt/jwt/v5andgolang.org/x/time, which were mislabeled indirect — both are directly imported by application code.Test Evidence
New
internal/database/entity_tags_test.go(no prior driver-matrix pattern existed in the repo; this establishes an env-var-gated one):TestEntityTagsDDLDialects— CI-friendly unit test asserting per-dialect DDL tokens (no server needed).TestCreateEntityTagsTable_Matrix— real DDL execution: SQLite in-memory always runs; Postgres/MariaDB run whenSPOTTER_TEST_POSTGRES_DSN/SPOTTER_TEST_MYSQL_DSNare set, otherwise skip gracefully (also skips on unreachable server). Each dialect verifies: idempotent double-run, column types viainformation_schema/PRAGMA table_info, insert/select round-trip, and the(tag_id, entity_type, entity_id)unique constraint. Docker one-liners for local runs are documented in the test file header.Verified locally against throwaway
postgres:16andmariadb:11containers:make testgreen (all packages);gofmt -l .clean;go vet ./...clean.Scope Note
The issue AC "tag upsert end-to-end on a MariaDB instance" depends on
internal/tags/upsert.go, which usesINSERT ... ON CONFLICT DO NOTHING(Postgres/SQLite syntax). Making the upsert dialect-aware is explicitly #346's scope; this PR delivers the DDL layer it will build on.🤖 Posted on behalf of
@joestumpby Claude.