Skip to content

Commit ffe28d2

Browse files
committed
Add SQLite as default storage backend
Enable single-binary deployment with zero external dependencies by adding SQLite support via modernc.org/sqlite (pure Go, no CGO). - Extract Repository interface from concrete Neo4j implementation - Add SQLiteRepository with FTS5 full-text search and recursive CTEs - Add backend selection via MEMEX_BACKEND env var (default: "sqlite") - Rename Neo4j struct to Neo4jRepository for clarity Neo4j remains available for enterprise scale via MEMEX_BACKEND=neo4j.
1 parent ed1924c commit ffe28d2

8 files changed

Lines changed: 1871 additions & 55 deletions

File tree

cmd/memex-server/main.go

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,42 @@ import (
1818

1919
func main() {
2020
// Load configuration from environment
21-
neo4jURI := getEnv("NEO4J_URI", "bolt://localhost:7687")
22-
neo4jUser := getEnv("NEO4J_USER", "neo4j")
23-
neo4jPassword := getEnv("NEO4J_PASSWORD", "password")
21+
backend := getEnv("MEMEX_BACKEND", "sqlite")
2422
port := getEnv("PORT", "8080")
2523

26-
// Initialize Neo4j repository
2724
ctx := context.Background()
28-
repo, err := graph.New(ctx, graph.Config{
29-
URI: neo4jURI,
30-
Username: neo4jUser,
31-
Password: neo4jPassword,
32-
Database: "neo4j",
33-
})
34-
if err != nil {
35-
log.Fatalf("Failed to connect to Neo4j: %v", err)
25+
var repo graph.Repository
26+
var err error
27+
28+
switch backend {
29+
case "sqlite":
30+
sqlitePath := getEnv("SQLITE_PATH", "./memex.db")
31+
log.Printf("Using SQLite backend: %s", sqlitePath)
32+
repo, err = graph.NewSQLite(ctx, sqlitePath)
33+
if err != nil {
34+
log.Fatalf("Failed to open SQLite database: %v", err)
35+
}
36+
case "neo4j":
37+
neo4jURI := getEnv("NEO4J_URI", "bolt://localhost:7687")
38+
neo4jUser := getEnv("NEO4J_USER", "neo4j")
39+
neo4jPassword := getEnv("NEO4J_PASSWORD", "password")
40+
41+
log.Printf("Using Neo4j backend: %s", neo4jURI)
42+
repo, err = graph.NewNeo4j(ctx, graph.Config{
43+
URI: neo4jURI,
44+
Username: neo4jUser,
45+
Password: neo4jPassword,
46+
Database: "neo4j",
47+
})
48+
if err != nil {
49+
log.Fatalf("Failed to connect to Neo4j: %v", err)
50+
}
51+
default:
52+
log.Fatalf("Unknown backend: %s (use 'sqlite' or 'neo4j')", backend)
3653
}
3754
defer repo.Close(ctx)
3855

39-
log.Println("Connected to Neo4j successfully")
56+
log.Println("Connected to database successfully")
4057

4158
// Create indexes for performance
4259
if err := repo.EnsureIndexes(ctx); err != nil {

go.mod

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ require (
2121
github.com/charmbracelet/x/exp/slice v0.0.0-20250327172914-2fdc97757edf // indirect
2222
github.com/charmbracelet/x/term v0.2.1 // indirect
2323
github.com/dlclark/regexp2 v1.11.0 // indirect
24+
github.com/dustin/go-humanize v1.0.1 // indirect
2425
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
2526
github.com/gen2brain/shm v0.1.0 // indirect
2627
github.com/godbus/dbus/v5 v5.1.0 // indirect
@@ -38,14 +39,21 @@ require (
3839
github.com/muesli/cancelreader v0.2.2 // indirect
3940
github.com/muesli/reflow v0.3.0 // indirect
4041
github.com/muesli/termenv v0.16.0 // indirect
42+
github.com/ncruces/go-strftime v1.0.0 // indirect
43+
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
4144
github.com/rivo/uniseg v0.4.7 // indirect
4245
github.com/spf13/cobra v1.10.2 // indirect
4346
github.com/spf13/pflag v1.0.9 // indirect
4447
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
4548
github.com/yuin/goldmark v1.7.8 // indirect
4649
github.com/yuin/goldmark-emoji v1.0.5 // indirect
50+
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect
4751
golang.org/x/net v0.33.0 // indirect
48-
golang.org/x/sys v0.36.0 // indirect
52+
golang.org/x/sys v0.37.0 // indirect
4953
golang.org/x/term v0.31.0 // indirect
5054
golang.org/x/text v0.24.0 // indirect
55+
modernc.org/libc v1.67.6 // indirect
56+
modernc.org/mathutil v1.7.1 // indirect
57+
modernc.org/memory v1.11.0 // indirect
58+
modernc.org/sqlite v1.44.3 // indirect
5159
)

go.sum

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNE
2727
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
2828
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
2929
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
30+
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
31+
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
3032
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
3133
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
3234
github.com/gen2brain/shm v0.1.0 h1:MwPeg+zJQXN0RM9o+HqaSFypNoNEcNpeoGp0BTSx2YY=
@@ -66,8 +68,12 @@ github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
6668
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
6769
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
6870
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
71+
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
72+
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
6973
github.com/neo4j/neo4j-go-driver/v5 v5.28.4 h1:7toxehVcYkZbyxV4W3Ib9VcnyRBQPucF+VwNNmtSXi4=
7074
github.com/neo4j/neo4j-go-driver/v5 v5.28.4/go.mod h1:Vff8OwT7QpLm7L2yYr85XNWe9Rbqlbeb9asNXJTHO4k=
75+
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
76+
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
7177
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
7278
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
7379
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
@@ -85,6 +91,8 @@ github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRla
8591
github.com/yuin/goldmark-emoji v1.0.5 h1:EMVWyCGPlXJfUXBXpuMu+ii3TIaxbVBnEX9uaDC4cIk=
8692
github.com/yuin/goldmark-emoji v1.0.5/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U=
8793
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
94+
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY=
95+
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=
8896
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
8997
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
9098
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -94,10 +102,20 @@ golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
94102
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
95103
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
96104
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
105+
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
106+
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
97107
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
98108
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
99109
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
100110
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
101111
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
102112
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
103113
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
114+
modernc.org/libc v1.67.6 h1:eVOQvpModVLKOdT+LvBPjdQqfrZq+pC39BygcT+E7OI=
115+
modernc.org/libc v1.67.6/go.mod h1:JAhxUVlolfYDErnwiqaLvUqc8nfb2r6S6slAgZOnaiE=
116+
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
117+
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
118+
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
119+
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
120+
modernc.org/sqlite v1.44.3 h1:+39JvV/HWMcYslAwRxHb8067w+2zowvFOUrOWIy9PjY=
121+
modernc.org/sqlite v1.44.3/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA=

internal/server/api/handlers.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ import (
1818

1919
// Server holds the HTTP server dependencies
2020
type Server struct {
21-
repo *graph.Repository
21+
repo graph.Repository
2222
subMgr *subscriptions.Manager
2323
}
2424

2525
// New creates a new API server
26-
func New(repo *graph.Repository, subMgr *subscriptions.Manager) *Server {
26+
func New(repo graph.Repository, subMgr *subscriptions.Manager) *Server {
2727
return &Server{repo: repo, subMgr: subMgr}
2828
}
2929

0 commit comments

Comments
 (0)