Auto-indexing service and GraphQL API for AT Protocol Records
quickslice.slices.network/
atproto
gleam
graphql
1// server/src/database/sqlite/executor.gleam
2
3import database/executor.{
4 type DbError, type Executor, type Value, Blob, Bool, ConstraintError, Float,
5 Int, Null, QueryError, SQLite, Text, Timestamptz,
6}
7import gleam/dynamic/decode
8import gleam/list
9import gleam/result
10import gleam/string
11import sqlight
12
13/// Create an Executor for SQLite from an open connection
14pub fn new(conn: sqlight.Connection) -> Executor {
15 executor.new(
16 SQLite,
17 fn(sql, params) {
18 sqlight.query(
19 sql,
20 on: conn,
21 with: to_sqlight_values(params),
22 expecting: decode.dynamic,
23 )
24 |> result.map_error(sqlight_error_to_db_error)
25 },
26 fn(sql, params) {
27 sqlight.query(
28 sql,
29 on: conn,
30 with: to_sqlight_values(params),
31 expecting: decode.dynamic,
32 )
33 |> result.map(fn(_) { Nil })
34 |> result.map_error(sqlight_error_to_db_error)
35 },
36 fn(_index) { "?" },
37 fn(column, field) { "json_extract(" <> column <> ", '$." <> field <> "')" },
38 fn(column, path) {
39 let path_str = string.join(path, ".")
40 "json_extract(" <> column <> ", '$." <> path_str <> "')"
41 },
42 fn() { "datetime('now')" },
43 )
44}
45
46/// Convert our Value type to sqlight.Value
47fn to_sqlight_values(values: List(Value)) -> List(sqlight.Value) {
48 list.map(values, fn(v) {
49 case v {
50 Text(s) -> sqlight.text(s)
51 Int(i) -> sqlight.int(i)
52 Float(f) -> sqlight.float(f)
53 Bool(b) ->
54 case b {
55 True -> sqlight.int(1)
56 False -> sqlight.int(0)
57 }
58 Null -> sqlight.null()
59 Blob(b) -> sqlight.blob(b)
60 // SQLite stores timestamps as TEXT
61 Timestamptz(s) -> sqlight.text(s)
62 }
63 })
64}
65
66/// Convert sqlight.Error to our DbError type
67fn sqlight_error_to_db_error(err: sqlight.Error) -> DbError {
68 case err {
69 sqlight.SqlightError(code, message, _) ->
70 case code {
71 sqlight.ConstraintCheck
72 | sqlight.ConstraintCommithook
73 | sqlight.ConstraintDatatype
74 | sqlight.ConstraintForeignkey
75 | sqlight.ConstraintFunction
76 | sqlight.ConstraintNotnull
77 | sqlight.ConstraintPinned
78 | sqlight.ConstraintPrimarykey
79 | sqlight.ConstraintRowid
80 | sqlight.ConstraintTrigger
81 | sqlight.ConstraintUnique
82 | sqlight.ConstraintVtab -> ConstraintError(message)
83 _ -> QueryError(message)
84 }
85 }
86}