

# BSON

BSON is a performant (not compact) format for storing data in MongoDB. The BSON module used here is extremely performant and support Codable.

## Primitives

MongoDB has a set of supported primitives. At the root of any BSON data lies a `Document`.

- Double
- String
- Document (Array and Dictionary)
- ObjectId
- Bool
- Int32
- Int (Int64)
- Binary
- Decimal128 (not supported)
- JavascriptCode
- Null (not nil)
- Date (from Foundation)
- MinKey
- MaxKey
- RegularExpression (BSON Type)

### Document

Document is a type that comes in two representations. Array and Dictionary-like. You should see Document as `[(String, Primitive)]`.

Array-like Documents ignore the key (`String`) whilst Dictionary-like Documents require using it. For this reason, both `Document` variants are the same struct type and behave the same way.

You can subscript a dictionary-like document with an integer, and an array-like document by it's key.

# Usage

The root type of any BSON structure is a `Document`, please note that MongoDB entities must be a dictionary-like.

To create a dictionary-like BSON Document:

    // Dictionary document by default
    var document = Document()

You can also use a dictionary or array literal. This creates the respective BSON document type.

    var arrayDocument: Document = []
    var dictionaryDocument: Document = [:]

## Accessing Dictionary Documents

To access a dictionary document you must subscript with a key:

    let username = dictionaryDocument["username"] // Primitive?

The return type is a Primitive type, which is a protocol.

## Accessing Array Documents

To a

## Primitives

To access the concrete type of the primitive you must either cast the primitive to a concrete type or loosely unwrap the type.

For the purpose of demonstration we're assuming the following Document:

    var doc: Document = [
        "_id": ObjectId(),
        "username": "Joannis",
        "admin": true,
        "year": 2018
    ]

### Casting

Casting is used when you want exactly that type. A good example is a `String`.

    let username = doc["username"] as? String // String?
    print(username) // Optional("Joannis")

The following will be nil because they're not a `String`.

    let _id: = doc["_id"] as? String // String?
    print(_id) // nil

    let admin = doc["admin"] as? String // String?
    print(admin) // nil

    let year = doc["year"] as? String // String?
    print(year) // nil

### Loosely Converting

Converting is useful when you don't care about the specifics. For example, when exposing data over JSON.

    let username = String(lossy: doc["username"]) // String?
    print(username) // Optional("Joannis")

This converts types to a String when it's sensible:

    let _id: = doc["_id"] as? String // String?
    print(_id) // Optional("afafafafafafafafafafafaf")

    let admin = doc["admin"] as? String // String?
    print(admin) // Optional("true")

    let year = doc["year"] as? String // String?
    print(year) // Optional("2018")

## Codable

BSON has highly optimized support for Codable through `BSONEncoder` and `BSONDecoder`.

    struct User: Codable {
        var _id = ObjectId()
        var username: String
        var admin: Bool = false
        var year: Int

        init(named name: String, year: Int) {
            self.username = name
            self.year = year
        }
    }

    let user = User(named: "Joannis", year: 2018)

    let userDocument = try BSONEncoder().encode(user)

    let username = userDocument["username"] as? String
    print(username) // Optional("Joannis")

    let sameUser = try BSONDecoder().decode(User.self, from: userDocument)

    print(sameUser.username) // "Joannis"