InfluxDB client functions in Gleam - extremely basic, not recommended for use, but worth a look!
influx.gleam
1import gleam/float
2import gleam/http
3import gleam/http/request.{type Request}
4import gleam/http/response.{Response}
5import gleam/httpc
6import gleam/int
7import gleam/list
8import gleam/option.{type Option}
9import gleam/result
10import gleam/string
11import gleam/time/timestamp
12
13pub type Client {
14 Client(url: String, token: String, bucket: String, org: String)
15}
16
17pub fn new(base_url url: String) -> Client {
18 Client(url:, token: "", bucket: "", org: "")
19}
20
21pub fn set_url(client: Client, url: String) -> Client {
22 Client(..client, url:)
23}
24
25pub fn set_token(client: Client, token: String) -> Client {
26 Client(..client, token:)
27}
28
29pub fn set_bucket(client: Client, bucket: String) -> Client {
30 Client(..client, bucket:)
31}
32
33pub fn set_org(client: Client, org: String) -> Client {
34 Client(..client, org:)
35}
36
37pub type LineField {
38 LineFloat(number: Float)
39 LineInt(number: Int)
40 LineUInt(number: Int)
41 LineString(text: String)
42 LineBool(boolean: Bool)
43}
44
45fn encode_line_field(field: LineField) -> String {
46 case field {
47 LineBool(b) ->
48 case b {
49 True -> "true"
50 False -> "false"
51 }
52 LineFloat(number) -> number |> float.to_string
53 LineInt(number) -> number |> int.to_string <> "i"
54 LineString(s) -> "\"" <> s <> "\""
55 LineUInt(number) -> number |> int.to_string <> "u"
56 }
57}
58
59pub type Point {
60 Point(
61 measurement: String,
62 tags: List(#(String, String)),
63 fields: List(#(String, LineField)),
64 time: Option(timestamp.Timestamp),
65 )
66}
67
68fn encode_points(points: List(Point)) -> String {
69 list.fold(points, "", fn(points_body, point) {
70 [
71 points_body,
72 point.measurement,
73 ",",
74 point.tags
75 |> list.map(fn(tag) { tag.0 <> "=" <> tag.1 })
76 |> string.join(","),
77 " ",
78 point.fields
79 |> list.map(fn(field) { field.0 <> "=" <> encode_line_field(field.1) })
80 |> string.join(","),
81 " ",
82 option.unwrap(point.time, timestamp.system_time())
83 |> timestamp.to_unix_seconds
84 |> float.multiply(1_000_000_000.0)
85 |> float.round
86 |> int.to_string,
87 "\n",
88 ]
89 |> string.join("")
90 })
91}
92
93pub fn set_measurements(client: Client, points: List(Point)) -> Request(String) {
94 let assert Ok(req) = request.to(client.url <> "/api/v2")
95
96 req
97 |> request.set_body(encode_points(points))
98 |> request.set_query([#("org", client.org), #("bucket", client.bucket)])
99 |> request.set_header("Authorization", "Token " <> client.token)
100 |> request.set_path(req.path <> "/write")
101 |> request.set_method(http.Post)
102}
103
104pub fn append_measurements(
105 req: Request(String),
106 points: List(Point),
107) -> Request(String) {
108 req
109 |> request.set_body(req.body <> encode_points(points))
110}
111
112pub fn send_request(req: Request(String)) -> response.Response(String) {
113 req
114 |> httpc.send
115 |> result.unwrap(Response(
116 status: 500,
117 headers: [],
118 body: "failed to produce a response",
119 ))
120}