Packages
gleam_bson
0.26.0
0.27.0
retired
0.26.0
retired
0.25.0
retired
0.24.0
retired
0.23.0
retired
0.22.0
retired
0.21.0
retired
0.20.0
retired
0.19.0
retired
0.18.0
retired
0.17.0
retired
0.16.0
retired
0.15.0
retired
0.14.0
retired
0.13.0
retired
0.12.0
retired
0.11.0
retired
0.10.1
retired
0.10.0
retired
0.9.0
retired
0.8.0
retired
0.7.0
retired
0.6.0
retired
0.5.0
retired
0.4.0
retired
0.3.0
retired
0.2.0
retired
0.1.0
retired
bson encoder and decoder for gleam
Retired package: Renamed - Republished as bison
Current section
Files
Jump to
Current section
Files
src/bson/encoder.gleam
import gleam/int
import gleam/list
import gleam/bit_string
import bson/md5
import bson/uuid
import bson/kind
import bson/value
import bson/custom
import bson/generic
import bson/object_id
import birl/time
import birl/duration
type Entity {
Entity(kind: kind.Kind, value: BitString)
}
pub fn encode(doc: List(#(String, value.Value))) -> BitString {
case document(doc) {
Entity(kind: _, value: value) -> value
}
}
fn document(doc: List(#(String, value.Value))) -> Entity {
let doc =
doc
|> list.map(encode_kv)
|> bit_string.concat
let size = bit_string.byte_size(doc) + 5
Entity(
kind: kind.document,
value: [<<size:32-little>>, doc, <<0>>]
|> bit_string.concat,
)
}
fn encode_kv(pair: #(String, value.Value)) -> BitString {
let key = <<pair.0:utf8, 0>>
let value = case pair.1 {
value.Null -> null()
value.Min -> min()
value.Max -> max()
value.JS(value) -> js(value)
value.Str(value) -> string(value)
value.Array(value) -> array(value)
value.Double(value) -> double(value)
value.Boolean(value) -> boolean(value)
value.Integer(value) -> integer(value)
value.Document(value) -> document(value)
value.DateTime(value) -> datetime(value)
value.ObjectId(value) -> object_id(value)
value.Timestamp(value) -> timestamp(value)
value.Binary(value.MD5(value)) -> md5(value)
value.Binary(value.UUID(value)) -> uuid(value)
value.Binary(value.Custom(value)) -> custom(value)
value.Binary(value.Generic(value)) -> generic(value)
value.Regex(#(pattern, options)) -> regex(pattern, options)
}
case value {
Entity(kind: kind, value: value) ->
[kind.code, key, value]
|> bit_string.concat
}
}
fn null() -> Entity {
Entity(kind: kind.null, value: <<>>)
}
fn min() -> Entity {
Entity(kind: kind.min, value: <<>>)
}
fn max() -> Entity {
Entity(kind: kind.max, value: <<>>)
}
fn js(value: String) -> Entity {
let length = bit_string.byte_size(<<value:utf8>>) + 1
Entity(kind: kind.js, value: <<length:32-little, value:utf8, 0>>)
}
fn string(value: String) -> Entity {
let length = bit_string.byte_size(<<value:utf8>>) + 1
Entity(kind: kind.string, value: <<length:32-little, value:utf8, 0>>)
}
fn array(value: List(value.Value)) -> Entity {
case
list.index_map(value, fn(index, item) { #(int.to_string(index), item) })
|> document
{
Entity(kind: _, value: value) -> Entity(kind: kind.array, value: value)
}
}
fn double(value: Float) -> Entity {
Entity(kind: kind.double, value: <<value:little-float>>)
}
fn boolean(value: Bool) -> Entity {
case value {
True -> Entity(kind: kind.boolean, value: <<1>>)
False -> Entity(kind: kind.boolean, value: <<0>>)
}
}
fn integer(value: Int) -> Entity {
case value < kind.int32_max && value > kind.int32_min {
True -> Entity(kind: kind.int32, value: <<value:32-little>>)
False -> Entity(kind: kind.int64, value: <<value:64-little>>)
}
}
fn datetime(value: time.DateTime) -> Entity {
let duration.Duration(value) = time.difference(value, time.unix_epoch)
let value = value / 1000
Entity(kind: kind.datetime, value: <<value:64-little>>)
}
fn object_id(value: object_id.ObjectId) -> Entity {
Entity(kind: kind.object_id, value: object_id.to_bit_string(value))
}
fn timestamp(value: Int) -> Entity {
Entity(kind: kind.timestamp, value: <<value:64-little>>)
}
fn md5(value: md5.MD5) -> Entity {
let value = md5.to_bit_string(value)
let length = bit_string.byte_size(value)
Entity(
kind: kind.binary,
value: [<<length:32-little>>, kind.md5.code, value]
|> bit_string.concat,
)
}
fn uuid(value: uuid.UUID) -> Entity {
let value = uuid.to_bit_string(value)
let length = bit_string.byte_size(value)
Entity(
kind: kind.binary,
value: [<<length:32-little>>, kind.uuid.code, value]
|> bit_string.concat,
)
}
fn custom(value: custom.Custom) -> Entity {
let #(code, value) = custom.to_bit_string_with_code(value)
let length = bit_string.byte_size(value)
Entity(
kind: kind.binary,
value: [<<length:32-little>>, <<code>>, value]
|> bit_string.concat,
)
}
fn generic(value: generic.Generic) -> Entity {
let value = generic.to_bit_string(value)
let length = bit_string.byte_size(value)
Entity(
kind: kind.binary,
value: [<<length:32-little>>, kind.generic.code, value]
|> bit_string.concat,
)
}
fn regex(pattern: String, options: String) -> Entity {
Entity(
kind: kind.regex,
value: [<<pattern:utf8, 0, options:utf8, 0>>]
|> bit_string.concat,
)
}