go
63 lines · 7 steps
A SQLite-backed order store in Go
A small repository type wraps database/sql to open a WAL-tuned SQLite connection and stream typed order rows.
Explained by
highlit
1package storage
2
3import (
4 "context"
5 "database/sql"
6 "fmt"
7 "time"
8
9 _ "github.com/mattn/go-sqlite3"
10)
11
12type Order struct {
13 ID int64
14 Customer string
15 Total float64
16 CreatedAt time.Time
17}
18
19type OrderStore struct {
20 db *sql.DB
21}
22
23func OpenOrderStore(path string) (*OrderStore, error) {
24 db, err := sql.Open("sqlite3", path+"?_journal_mode=WAL&_busy_timeout=5000")
25 if err != nil {
26 return nil, fmt.Errorf("open sqlite: %w", err)
27 }
28 db.SetMaxOpenConns(1)
29 if err := db.Ping(); err != nil {
30 db.Close()
31 return nil, fmt.Errorf("ping: %w", err)
32 }
33 return &OrderStore{db: db}, nil
34}
35
36func (s *OrderStore) RecentByCustomer(ctx context.Context, customer string, limit int) ([]Order, error) {
37 const query = `
38 SELECT id, customer, total, created_at
39 FROM orders
40 WHERE customer = ?
41 ORDER BY created_at DESC
42 LIMIT ?`
43
44 rows, err := s.db.QueryContext(ctx, query, customer, limit)
45 if err != nil {
46 return nil, fmt.Errorf("query orders: %w", err)
47 }
48 defer rows.Close()
49
50 var orders []Order
51 for rows.Next() {
52 var o Order
53 if err := rows.Scan(&o.ID, &o.Customer, &o.Total, &o.CreatedAt); err != nil {
54 return nil, fmt.Errorf("scan order: %w", err)
55 }
56 orders = append(orders, o)
57 }
58 return orders, rows.Err()
59}
60
61func (s *OrderStore) Close() error {
62 return s.db.Close()
63}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Wrapping a *sql.DB in a small struct gives callers typed methods instead of raw SQL scattered everywhere.
- 2Parameterized queries with ? placeholders keep user input out of the SQL string and prevent injection.
- 3Always defer rows.Close and check rows.Err so partial iteration failures aren't silently swallowed.
Related explainers
go
package auth import ( "errors"
Hashing and verifying passwords with bcrypt in Go
password-hashing
bcrypt
error-handling
Intermediate
7 steps
go
package fsutil import ( "io/fs"
Walking a directory tree to find large files in Go
filesystem
recursion
closures
Intermediate
7 steps
go
package middleware import ( "log"
Per-IP rate limiting middleware in Gin
rate-limiting
middleware
concurrency
Intermediate
8 steps
go
func handleUpload(w http.ResponseWriter, r *http.Request) { if err := r.ParseMultipartForm(32 << 20); err != nil { http.Error(w, "failed to parse form: "+err.Error(), http.StatusBadRequest) return
Handling multi-file uploads in Go
multipart
file-upload
http-handler
Intermediate
9 steps
go
package render import ( "net/http"
How Gin renders MsgPack responses
serialization
content-type
interface-implementation
Intermediate
5 steps
javascript
import { createContext, useContext, useState, useId } from "react"; const AccordionContext = createContext(null); const ItemContext = createContext(null);
Building a compound Accordion in React
context
compound-components
state-management
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/a-sqlite-backed-order-store-in-go-explained-go-3f42/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.