sqlite

package
v4.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 5, 2026 License: MIT Imports: 17 Imported by: 0

README

db/sqlite

Client-side SQLite for GWC — a database/sql-flavored, context-first API that runs inside the browser wasm app with no cgo.

  • wasm: backed by ncruces/go-sqlite3 (SQLite compiled to wasm, executed via wazero). ~2.5 MB gzip added to the bundle.
  • native: backed by modernc.org/sqlite, so the same calling code runs in the gwc native test lane.

Public API

db, err := sqlite.Open(ctx, sqlite.Options{
    Name:        "myapp",
    Persistence: sqlite.IndexedDB, // Memory | IndexedDB | OPFS
})
defer db.Close()

db.Exec(ctx, `CREATE TABLE kv(k TEXT PRIMARY KEY, v TEXT)`)
db.Exec(ctx, `INSERT INTO kv VALUES(?, ?)`, "greeting", "hi")

var v string
db.QueryRow(ctx, `SELECT v FROM kv WHERE k = ?`, "greeting").Scan(&v)

rows, _ := db.Query(ctx, `SELECT k, v FROM kv`)
db.Tx(ctx, func(tx *sql.Tx) error { /* ... */ return nil })

db.Flush(ctx) // force-persist to the durable backend now

The package exposes the standard library's *sql.Rows, sql.Result, *sql.Row and *sql.Tx directly — the surface is identical across builds.

Persistence

Mode Behavior
Memory In-wasm only; lost on reload.
IndexedDB DB image snapshotted to IndexedDB on Flush/Close, rehydrated on Open. Main-thread, no worker. (v1 default durable backend)
OPFS Reserved for incremental, Web-Worker-backed durability. Falls back to IndexedDB in v1.

Durability happens at Flush/Close points. Consumers that need write-through (e.g. the state binding) drive their own debounced Flush.

How IndexedDB durability works

Memory/IndexedDB use gwcmem, a snapshot-able in-memory vfs.VFS (adapted from ncruces' memdb) that owns its byte buffer and exposes snapshot/restore. On Open the image is read from IndexedDB (via interop.PersistentStore, base64) and restored before the connection opens; on Flush the image is snapshotted back out and written. Whole-file granularity — ideal for small KV state.

Files

  • sqlite.go — shared types (DB, Options, Persistence), pragmas, helpers.
  • open_wasm.go / open_native.go — build-specific Open.
  • gwcmem_wasm.go — the snapshot-able in-memory VFS.
  • persist_wasm.go — the IndexedDB durability backend.

Tests

  • Native: go test ./db/sqlite/
  • Wasm: GOOS=js GOARCH=wasm go test -exec=<node wasm runner> ./db/sqlite/

Documentation

Overview

Package sqlite is GWC's client-side SQLite battery: a database/sql-flavored, context-first API that runs inside the browser wasm app with no cgo.

On js/wasm it is backed by github.com/ncruces/go-sqlite3 (SQLite compiled to wasm, executed via wazero). On native builds it is backed by modernc.org/sqlite so the same calling code runs in the gwc native test lane.

Durability options (see Persistence):

  • Memory: in-wasm only, lost on reload.
  • IndexedDB: the DB image is snapshotted to IndexedDB (via interop) on Flush/Close and rehydrated on Open. Whole-file granularity, main-thread, no Web Worker required. This is the v1 durable backend.
  • OPFS: reserved for incremental, worker-backed durability. In v1 it transparently falls back to IndexedDB.

The package deliberately exposes the standard library's *sql.Rows, sql.Result, *sql.Row and *sql.Tx rather than re-wrapping them, so the API is identical across the wasm and native builds.

Index

Constants

This section is empty.

Variables

View Source
var ErrDecrypt = errors.New("sqlite: decryption failed (wrong passphrase or corrupted/tampered data)")

ErrDecrypt is returned when an image cannot be opened — wrong passphrase, or corrupted/tampered ciphertext (the GCM auth tag did not verify).

Functions

This section is empty.

Types

type DB

type DB struct {
	// contains filtered or unexported fields
}

DB is a single client-side SQLite database. It is safe for sequential use; the underlying connection pool is capped to one connection.

func Open

func Open(parseCtx context.Context, parseOptions Options) (*DB, error)

Open opens (and, for durable backends, rehydrates) a database.

func (*DB) Close

func (parseDB *DB) Close() error

Close flushes (for durable backends) and closes the database.

func (*DB) Exec

func (parseDB *DB) Exec(parseCtx context.Context, parseSQL string, parseArgs ...any) (sql.Result, error)

Exec runs a statement that returns no rows.

func (*DB) Flush

func (parseDB *DB) Flush(parseCtx context.Context) error

Flush forces the current database image to its durable backend. It is a no-op for Memory and for native file-backed databases.

func (*DB) Query

func (parseDB *DB) Query(parseCtx context.Context, parseSQL string, parseArgs ...any) (*sql.Rows, error)

Query runs a query that returns rows. Close the returned *sql.Rows.

func (*DB) QueryRow

func (parseDB *DB) QueryRow(parseCtx context.Context, parseSQL string, parseArgs ...any) *sql.Row

QueryRow runs a query expected to return at most one row.

func (*DB) Tx

func (parseDB *DB) Tx(parseCtx context.Context, parseFn func(*sql.Tx) error) (parseErr error)

Tx runs fn inside a transaction, committing on success and rolling back on error (including a panic, which is re-raised after rollback).

type Encryptor

type Encryptor interface {
	Seal(parsePlaintext []byte) ([]byte, error)
	Open(parseBlob []byte) ([]byte, error)
}

Encryptor seals and opens the persisted database image. Implement it to plug a different scheme (e.g. a stored non-extractable WebCrypto key); the default is NewPassphraseEncryptor.

func NewPassphraseEncryptor

func NewPassphraseEncryptor(parsePassphrase string, parseIterations int) Encryptor

NewPassphraseEncryptor returns an Encryptor that derives an AES-256-GCM key from passphrase via PBKDF2-HMAC-SHA256. iterations defaults to 600000 when <= 0. A random salt is minted once per instance and travels (with a fresh per-seal nonce) in the ciphertext header; the key itself is never persisted.

type Options

type Options struct {
	// Name is the logical database name; it keys the IndexedDB/OPFS entry.
	// Defaults to "gwc". Keep it to letters, digits, '-' and '_'.
	Name string
	// Persistence selects the durability backend. Defaults to Memory.
	Persistence Persistence
	// Pragmas are applied via "PRAGMA k=v" after the connection opens. When nil,
	// sensible defaults are used (foreign_keys=ON, busy_timeout=5000).
	Pragmas map[string]string
	// FlushDebounce is advisory metadata for consumers (e.g. the state binding)
	// that drive their own debounced Flush; the driver itself does not debounce.
	FlushDebounce time.Duration
	// Encryptor, when non-nil, seals the database image before it is written to
	// the persistent store and opens it on restore — encryption at rest. Use
	// NewPassphraseEncryptor for the passphrase-derived AES-256-GCM scheme. nil
	// stores the image unencrypted (base64 only). See encryption.go for the
	// threat model. Ignored for Persistence == Memory (nothing is persisted).
	Encryptor Encryptor
}

Options configure a DB opened with Open.

type Persistence

type Persistence int

Persistence selects how a DB survives (or does not survive) a page reload.

const (
	// Memory keeps the database in wasm memory only; it is lost on reload.
	Memory Persistence = iota
	// IndexedDB snapshots the database image to IndexedDB on Flush/Close and
	// rehydrates it on Open. Main-thread, no worker. The v1 durable backend.
	IndexedDB
	// OPFS is reserved for incremental, Web-Worker-backed durability. In v1 it
	// falls back to IndexedDB behavior.
	OPFS
)

func (Persistence) String

func (parseP Persistence) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL