Skip to content

Instantly share code, notes, and snippets.

@mtlynch
Created September 6, 2024 13:04
Show Gist options
  • Save mtlynch/638e10675377515f15d9b086b929bb71 to your computer and use it in GitHub Desktop.
Save mtlynch/638e10675377515f15d9b086b929bb71 to your computer and use it in GitHub Desktop.
package main
import (
"database/sql"
"fmt"
"io"
"log"
"os"
"strings"
"time"
"github.com/ncruces/go-sqlite3"
"github.com/ncruces/go-sqlite3/driver"
_ "github.com/ncruces/go-sqlite3/embed"
"github.com/ncruces/go-sqlite3/ext/blobio"
)
type DB struct {
db *sql.DB
}
func New(dbName string) (*DB, error) {
db, err := driver.Open(dbName, blobio.Register)
if err != nil {
return nil, err
}
_, err = db.Exec(`CREATE TABLE IF NOT EXISTS entries (id TEXT PRIMARY KEY, contents)`)
if err != nil {
db.Close()
return nil, err
}
return &DB{db: db}, nil
}
func (d *DB) Close() error {
return d.db.Close()
}
func (d *DB) WriteEntry(message string) (string, error) {
reader := strings.NewReader(message)
id := fmt.Sprintf("id:%s", time.Now().Format(time.RFC3339))
_, err := d.db.Exec(`INSERT INTO entries VALUES (:id, :data)`,
sql.Named("id", id),
sql.Named("data", sqlite3.ZeroBlob(len(message))))
if err != nil {
return "", err
}
_, err = d.db.Exec(`SELECT writeblob('main', 'entries', 'contents', last_insert_rowid(), :offset, :data)`,
sql.Named("offset", 0),
sql.Named("data", sqlite3.Pointer(reader)))
if err != nil {
return "", err
}
return id, nil
}
func (d *DB) ReadEntry(id string) error {
_, err := d.db.Exec(`
SELECT openblob('main', 'entries', 'contents', (SELECT rowid FROM entries WHERE id = :id), :writeMode, :callback)
`,
sql.Named("id", id),
sql.Named("writeMode", false),
sql.Named("callback",
sqlite3.Pointer[blobio.OpenCallback](func(b *sqlite3.Blob, _ ...sqlite3.Value) error {
log.Printf("start callback")
if _, err := io.Copy(os.Stdout, b); err != nil {
panic(err)
}
fmt.Fprint(os.Stdout, "\n")
log.Printf("end callback")
return nil
})))
if err != nil {
return fmt.Errorf("error opening blob for id %s: %w", id, err)
}
return nil
}
func main() {
db, err := New("test.db")
if err != nil {
panic(err)
}
defer db.Close()
message := strings.Repeat("A", 50)
id, err := db.WriteEntry(message)
if err != nil {
panic(err)
}
err = db.ReadEntry(id)
if err != nil {
panic(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment