Auto-indexing service and GraphQL API for AT Protocol Records
quickslice.slices.network/
atproto
gleam
graphql
1// server/src/database/sqlite/connection.gleam
2
3import database/executor.{type DbError, type Executor, ConnectionError}
4import database/sqlite/executor as sqlite_executor
5import gleam/result
6import gleam/string
7import logging
8import sqlight
9
10/// Connect to SQLite database and return an Executor
11/// Handles SQLite-specific connection setup (PRAGMAs, etc.)
12pub fn connect(url: String) -> Result(Executor, DbError) {
13 let path = parse_path(url)
14
15 use conn <- result.try(
16 sqlight.open(path)
17 |> result.map_error(fn(e) {
18 ConnectionError(
19 "Failed to open SQLite database: " <> sqlight_error_message(e),
20 )
21 }),
22 )
23
24 // Enable WAL mode for better concurrency
25 use _ <- result.try(exec_pragma(conn, "PRAGMA journal_mode = WAL"))
26
27 // Performance tuning - safe with WAL mode
28 use _ <- result.try(exec_pragma(conn, "PRAGMA synchronous = NORMAL"))
29 use _ <- result.try(exec_pragma(conn, "PRAGMA cache_size = -64000"))
30 use _ <- result.try(exec_pragma(conn, "PRAGMA mmap_size = 268435456"))
31 use _ <- result.try(exec_pragma(conn, "PRAGMA temp_store = MEMORY"))
32 use _ <- result.try(exec_pragma(conn, "PRAGMA busy_timeout = 5000"))
33
34 // Enable foreign key constraints
35 use _ <- result.try(exec_pragma(conn, "PRAGMA foreign_keys = ON"))
36
37 logging.log(logging.Info, "Connected to SQLite database: " <> path)
38
39 Ok(sqlite_executor.new(conn))
40}
41
42/// Parse the path from a SQLite URL
43/// Supports: "sqlite:./path/to/db", "file:./path/to/db", or just "./path/to/db"
44fn parse_path(url: String) -> String {
45 case string.split_once(url, ":") {
46 Ok(#(scheme, rest)) ->
47 case scheme {
48 "sqlite" | "file" ->
49 case string.starts_with(rest, "//") {
50 True -> string.drop_start(rest, 2)
51 False -> rest
52 }
53 _ -> url
54 }
55 Error(_) -> url
56 }
57}
58
59/// Execute a PRAGMA statement
60fn exec_pragma(conn: sqlight.Connection, pragma: String) -> Result(Nil, DbError) {
61 sqlight.exec(pragma, conn)
62 |> result.map_error(fn(e) {
63 ConnectionError(
64 "Failed to execute " <> pragma <> ": " <> sqlight_error_message(e),
65 )
66 })
67}
68
69/// Get error message from sqlight error
70fn sqlight_error_message(err: sqlight.Error) -> String {
71 case err {
72 sqlight.SqlightError(_, message, _) -> message
73 }
74}