Skip to content

Typed predicates + SQLite spellfix1 handle to retire raw SQL fragments#2

Merged
arthurpro merged 2 commits into
mainfrom
feat/zero-raw-sql
Jun 19, 2026
Merged

Typed predicates + SQLite spellfix1 handle to retire raw SQL fragments#2
arthurpro merged 2 commits into
mainfrom
feat/zero-raw-sql

Conversation

@arthurpro

Copy link
Copy Markdown
Member

Adds typed query-builder surface for the cases that previously forced raw Where/Set/Field fragments in otherwise-typed code, plus a typed handle for SQLite's spellfix1 fuzzy-match vocabulary. Two commits: the portable predicates, then the spellfix1 handle.

Typed predicates & helpers (portable across all four dialects):

  • OnConflict(...).DoNothing() — ignore a conflicting row on upsert: ON CONFLICT DO NOTHING (SQLite/Postgres), a no-op ON DUPLICATE KEY UPDATE (MySQL), a MERGE with no matched arm (SQL Server).
  • Column.HasPrefix/HasSuffix/Contains — LIKE with the needle's %/_ escaped so user input matches literally (LIKE ? ESCAPE '~').
  • Column.EqCol/Of + ExistsField — column-to-column equality, and a correlated EXISTS projected as a portable CASE WHEN EXISTS(...) THEN 1 ELSE 0 END boolean column.
  • UpdateBuilder.Inc/Dec — atomic col = col ± n.
  • PluckExpr/PluckExprFirst — project a raw scalar expression (MAX(x), COALESCE(...), rowid) into []V / V.

SQLite:

  • query.Match + dialect.FeatMatch — the MATCH operator as a feature-gated predicate, rejected at build time on non-SQLite dialects.
  • dialect/sqlite/search.Spellfix — a typed fuzzy-correction vocabulary (NewSpellfix/OpenSpellfix/Add/Correct/Size/Drop), the third extension handle alongside Vector and FullText. It delegates to gosqlite's spellfix1.Vocab, so create/populate/query are all typed — no hand-written virtual-table SQL.

Add typed query-builder surface for cases that previously forced raw
Where/Set/Field fragments:

- OnConflict(...).DoNothing(): ignore a conflicting row on upsert — ON CONFLICT
  DO NOTHING on SQLite/Postgres, a no-op ON DUPLICATE KEY UPDATE on MySQL, and a
  MERGE with no matched arm on SQL Server.
- Column.HasPrefix/HasSuffix/Contains: LIKE with the needle's % and _ escaped so
  user input matches literally (LIKE ? ESCAPE '~').
- Column.EqCol/Of and ExistsField: column-to-column equality, and a correlated
  EXISTS projected as a portable CASE WHEN EXISTS(...) boolean column.
- UpdateBuilder.Inc/Dec: atomic col = col +/- n.
- PluckExpr/PluckExprFirst: project a raw scalar expression into []V / V.
- query.Match + dialect.FeatMatch: the SQLite MATCH operator as a feature-gated
  predicate, rejected at build time on other dialects.

Covered by render tests across all four dialects, real-SQLite behavior tests, and
ormsuite conformance (DoNothing, HasPrefix escaping, Inc, PluckExpr, ExistsField).
Query guide, recipes, pitfalls, and orm/orm-models skills updated to the typed forms.
Add a typed handle for gosqlite's spellfix1 fuzzy-match vocabulary — the third
SQLite search extension alongside Vector and FullText. NewSpellfix/OpenSpellfix
create or attach a vocabulary, Add populates it (one transaction, deduped),
Correct returns the nearest words by edit distance, and Size/Drop/Name round it
out. It delegates to gosqlite's spellfix1.Vocab over the session's *sql.DB, so
create, populate, and query are all typed — no hand-written virtual-table SQL.
Importing the package registers the spellfix1 module.

Also documents the SQLite MATCH predicate and the spellfix1 handle in the
sqlite-search guide and skill, and exercises MATCH against a spellfix1 vtab.
@arthurpro arthurpro requested a review from ditalini June 19, 2026 04:45
@arthurpro arthurpro merged commit 7a03134 into main Jun 19, 2026
10 checks passed
@arthurpro arthurpro deleted the feat/zero-raw-sql branch June 19, 2026 04:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants