bson

The bson library provides predicates for parsing and generating the BSON 1.1 binary interchange format:

The library requires a backend Prolog compiler with unbounded integer arithmetic support.

API documentation

Open the ../../apis/library_index.html#bson link in a web browser.

Loading

To load all entities in this library, load the loader.lgt file:

| ?- logtalk_load(bson(loader)).

Testing

To test this library predicates, load the tester.lgt file:

| ?- logtalk_load(bson(tester)).

The test set uses the official MongoDB BSON corpus files in the test_files directory. Canonical BSON vectors are parsed successfully and used for semantic generator round-trip tests, and BSON decode-error vectors are checked for rejection. See test_files/NOTES.md for provenance.

Representation

  • Documents are represented by ordered curly-bracketed terms, {Pairs}, where each pair is represented by Key-Value. The empty document is {}. Pair order and duplicate keys are preserved.

  • Arrays are represented by lists. BSON array keys are generated and validated as the canonical sequence "0", "1", and so on.

  • Strings and document keys can be represented by atoms, chars(List), or codes(List). Use the bson/1 parameterized object with the parameter bound to atom, chars, or codes to select the decoded representation. BSON strings and keys are validated using strict UTF-8 conversion.

  • The BSON Boolean, null, undefined, minimum-key, and maximum-key values are represented by @false, @true, @null, @undefined, @min_key, and @max_key, respectively.

  • BSON 32-bit and 64-bit integers are represented by int32(Integer) and int64(Integer). Decoding preserves the encoded width. Generation also accepts plain integers, using int32 when possible and int64 otherwise.

  • BSON doubles are represented by floats. IEEE 754 infinities and NaNs use @infinity, @negative_infinity, @not_a_number, and not_a_number(Bytes), following the ieee_754 library conventions. Standard Prolog does not provide a portable distinct representation for IEEE 754 negative zero. Depending on the backend, parsing negative zero may produce 0.0, in which case generation cannot recover the original sign bit.

  • Binary values use binary(Subtype, bytes(Bytes)). Subtypes 0 through 9 and user-defined subtypes 128 through 255 are supported. The deprecated subtype 2 inner length is parsed and generated transparently. Payloads for encrypted, compressed-column, sensitive, and vector subtypes are kept opaque.

  • Object identifiers use object_id(bytes(Bytes)), where Bytes contains exactly 12 bytes.

  • UTC datetimes use date_time(Milliseconds), where Milliseconds is the signed 64-bit count since the Unix epoch.

  • Regular expressions use regular_expression(Pattern, Options). Options must be unique, alphabetically sorted, and selected from i, m, s, u, and x.

  • DBPointer, JavaScript, symbol, and JavaScript-with-scope values use db_pointer(Namespace, ObjectId), javascript(Code), symbol(Symbol), and javascript(Code, Scope), respectively. These deprecated BSON values remain fully readable and writable.

  • Timestamps use timestamp(Increment, Seconds), with both fields represented as unsigned 32-bit integers.

  • Decimal128 values use the lossless wire representation decimal128(bytes(Bytes)), where Bytes contains exactly 16 bytes. Decimal arithmetic and conversion are outside this library’s scope.

Encoding and decoding

The public API consists of generate/2 and parse/2 predicates operating on complete BSON documents represented as byte lists:

| ?- bson::generate({name-alice, active - @true}, Bytes).
Bytes = [30,0,0,0,2,110,97,109,101,0,6,0,0,0,97,108,105,99,101,0,8,97,99,116,105,118,101,0,1,0]
yes

| ?- bson::parse([12,0,0,0,16,110,0,42,0,0,0,0], Document).
Document = {n-int32(42)}
yes

Parsing rejects malformed lengths, terminators, UTF-8, array keys, Boolean bytes, type codes, subtypes, regular-expression options, fixed-width payloads, and JavaScript-with-scope lengths. The MongoDB 16 MiB server document limit is not a BSON format limit and is therefore not imposed by this library.

For untrusted input, prefer bson(codes) or bson(chars) to avoid interning arbitrary decoded strings as atoms.