Skip to content

Commit

Permalink
Add docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Joannis committed Dec 17, 2022
1 parent d93cb0b commit 188419b
Show file tree
Hide file tree
Showing 13 changed files with 99 additions and 9 deletions.
2 changes: 1 addition & 1 deletion Sources/BSON/Codable/Decoding/BSONDecoder.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

/// A helper that is able to decode BSON data types into a `Decodable` type
/// A helper that is able to decode BSON data types into a `Decodable` type.
public struct BSONDecoder {
/// The configuration used for decoding
public var settings: BSONDecoderSettings
Expand Down
3 changes: 2 additions & 1 deletion Sources/BSON/Document/Document+Array.swift
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ extension Document: ExpressibleByArrayLiteral {
storage.setInteger(int, at: valueOffset, endianness: .little)
case let decimal128 as Decimal128:
reserveRoom(.decimal128, 16)
storage.setBytes(decimal128.storage, at: valueOffset)
storage.setInteger(decimal128.low, at: valueOffset)
storage.setInteger(decimal128.high, at: valueOffset + 8)
case is MaxKey: // 0x7F
reserveRoom(.maxKey, 0)
case is MinKey: // 0xFF
Expand Down
6 changes: 5 additions & 1 deletion Sources/BSON/Document/Document+Collection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ extension Document: RandomAccessCollection, MutableCollection {
}
}

/// A type that can be used as a key in a `Document`.
public struct DocumentIndex: Comparable, Hashable {
/// The offset in the Document to look for
var offset: Int
Expand All @@ -119,12 +120,15 @@ public struct DocumentPair {
public var value: Primitive
}

/// An iterator that iterates over each pair in a `Document`.
public struct DocumentPairIterator: IteratorProtocol, Sequence {
/// The Document that is being iterated over
fileprivate let document: Document

/// The next index to be returned
/// The next index to be returned. This is incremented after each call to `next()`
public private(set) var currentIndex = 0

/// The current index in the binary representation of the Document.
public private(set) var currentBinaryIndex = 4

/// If `true`, the end of this iterator has been reached
Expand Down
1 change: 1 addition & 0 deletions Sources/BSON/Document/Document+Helpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ extension Document {
}
}

/// Thrown when a value is not found in a document.
public struct BSONValueNotFound: Error, CustomStringConvertible {
public let type: Any.Type
public let path: [String]
Expand Down
7 changes: 5 additions & 2 deletions Sources/BSON/Document/Document+Mutations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -241,11 +241,14 @@ extension Document {
case .int32:
return self.storage.getInteger(at: offset, endianness: .little, as: Int32.self)
case .decimal128:
guard let slice = storage.getBytes(at: offset, length: 16) else {
guard
let low: UInt64 = storage.getInteger(at: offset),
let high: UInt64 = storage.getInteger(at: offset + 8)
else {
return nil
}

return Decimal128(slice)
return Decimal128(low: low, high: high)
}
}

Expand Down
2 changes: 2 additions & 0 deletions Sources/BSON/Document/Document+Serialization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import Foundation
import NIOCore

extension Document {
/// Returns a `Data` representation of this `Document`. This is a copy of the underlying `ByteBuffer`'s data.
public func makeData() -> Data {
return makeByteBuffer().withUnsafeReadableBytes { Data($0) }
}

/// Returns a `ByteBuffer` representation of this `Document`. This is a copy of the underlying `ByteBuffer`.
public func makeByteBuffer() -> ByteBuffer {
return storage
}
Expand Down
5 changes: 5 additions & 0 deletions Sources/BSON/Document/DocumentSlice.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,13 @@ public struct DocumentSlice: RandomAccessCollection, MutableCollection {
public typealias Element = (String, Primitive)
public typealias SubSequence = DocumentSlice

/// The Document that is being sliced
var document: Document

/// The index of the first element in the slice
public let startIndex: DocumentIndex

/// The index after the last element in the slice
public let endIndex: DocumentIndex
}

Expand Down
15 changes: 15 additions & 0 deletions Sources/BSON/Types/Binary.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import Foundation
import NIOCore

/// A BSON Binary. This is used for storing binary data in MongoDB
/// See https://docs.mongodb.com/manual/reference/bson-types/#binary
public struct Binary: Primitive, Hashable, @unchecked Sendable {
public static func == (lhs: Binary, rhs: Binary) -> Bool {
return lhs.subType.identifier == rhs.subType.identifier && lhs.storage == rhs.storage
Expand All @@ -13,13 +15,25 @@ public struct Binary: Primitive, Hashable, @unchecked Sendable {
}
}

/// The different types of binary data that can be stored in a Binary instance. The identifier is the byte that is stored in the BSON document.
/// See https://docs.mongodb.com/manual/reference/bson-types/#binary
public enum SubType: Sendable {
/// A generic binary type. The identifier is 0x00.
case generic

/// A function type. The identifier is 0x01.
case function

/// A UUID type. The identifier is 0x04.
case uuid

/// An MD5 type. The identifier is 0x05.
case md5

/// A user defined type. The identifier is any byte other than 0x00, 0x01, 0x04, or 0x05.
case userDefined(UInt8)

/// Initializes a SubType from a byte. If the byte is not a valid identifier, the SubType will be set to .userDefined.
init(_ byte: UInt8) {
switch byte {
case 0x00: self = .generic
Expand All @@ -30,6 +44,7 @@ public struct Binary: Primitive, Hashable, @unchecked Sendable {
}
}

/// The byte that represents this SubType
var identifier: UInt8 {
switch self {
case .generic: return 0x00
Expand Down
2 changes: 2 additions & 0 deletions Sources/BSON/Types/JavaScript.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/// A JavaScript code. This is used for storing JavaScript functions in MongoDB.
public struct JavaScriptCode: Primitive, ExpressibleByStringLiteral, Hashable {
public var code: String

Expand All @@ -10,6 +11,7 @@ public struct JavaScriptCode: Primitive, ExpressibleByStringLiteral, Hashable {
}
}

/// A JavaScript code with scope. This is used for storing JavaScript functions in MongoDB.
public struct JavaScriptCodeWithScope: Primitive, Hashable {
public var code: String
public var scope: Document
Expand Down
2 changes: 1 addition & 1 deletion Sources/BSON/Types/Null.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/// The BSON Null type
/// The BSON Null type.
public struct Null: Primitive {
/// Creates a new `Null`
public init() {}
Expand Down
11 changes: 8 additions & 3 deletions Sources/BSON/Types/ObjectId.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@ private struct InvalidObjectIdString: Error {
var hex: String
}

/// A BSON ObjectId. This can represent a 12-byte value consisting of a 4-byte timestamp, a 3-byte machine identifier, a 2-byte process id, and a 3-byte counter.
/// The timestamp is the number of seconds since the Unix epoch. The machine identifier, process id, and counter are random values in new ObjectId values.
/// See https://docs.mongodb.com/manual/reference/method/ObjectId/
public struct ObjectId: Sendable {
/// The internal Storage Buffer
let _timestamp: UInt32
let _random: UInt64

/// Generates a new ObjectId. This is the default initializer.
public init() {
self._timestamp = UInt32(Date().timeIntervalSince1970)
self._random = .random(in: .min ... .max)
Expand All @@ -21,6 +25,7 @@ public struct ObjectId: Sendable {
_random = random
}

/// Creates an ObjectId from a 24-character hex string. Throws an error if the string is invalid.
public static func make(from hex: String) throws -> ObjectId {
guard let me = self.init(hex) else {
throw InvalidObjectIdString(hex: hex)
Expand All @@ -29,7 +34,7 @@ public struct ObjectId: Sendable {
return me
}

/// Decodes the ObjectID from the provided (24 character) hexString
/// Decodes the ObjectID from the provided (24 character) hexString. Returns nil if the string is invalid.
public init?(_ hex: String) {
var buffer = ByteBufferAllocator().buffer(capacity: 12)

Expand Down Expand Up @@ -58,7 +63,7 @@ public struct ObjectId: Sendable {
_random = buffer.readInteger()!
}

/// The 12 bytes represented as 24-character hex-string
/// The 12 bytes represented as 24-character hex-string. This is the default string representation of an ObjectId.
public var hexString: String {
var data = Data()
data.reserveCapacity(24)
Expand Down Expand Up @@ -88,7 +93,7 @@ public struct ObjectId: Sendable {
return String(data: data, encoding: .utf8)!
}

/// The creation date of this ObjectId
/// The creation date of this ObjectId.
public var date: Date {
return Date(timeIntervalSince1970: Double(_timestamp))
}
Expand Down
1 change: 1 addition & 0 deletions Sources/BSON/Types/Timestamp.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/// Special internal type used by MongoDB replication and sharding. First 4 bytes are an increment, second 4 are a timestamp.
/// See https://docs.mongodb.com/manual/reference/bson-types/#timestamps
public struct Timestamp: Primitive, Hashable {
public var increment: Int32
public var timestamp: Int32
Expand Down
51 changes: 51 additions & 0 deletions Tests/BSONTests/BSONPublicTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,57 @@ final class BSONPublicTests: XCTestCase {
XCTAssertEqual(doc.keys, ["int32"])
}

func testDocumentToJSON() throws {
let id = ObjectId()
let org1 = ObjectId()
let org2 = ObjectId()
let now = Date()
let document: Document = [
"_id": id,
"name": "Joannis",
"createdAt": now,
"admin": true,
"organizations": [
org1, org2
],
"profile": [
"email": "[email protected]"
],
"null": Null(),
"map": [
"a": 0,
"b": 1
]
]

let json = try JSONEncoder().encode(document)
struct User: Codable, Equatable {
struct Profile: Codable, Equatable {
let email: String
}

let _id: ObjectId
let name: String
let createdAt: Date
let admin: Bool
let organizations: [ObjectId]
let profile: Profile
let null: String?
let map: [String: Int]
}

let user = try JSONDecoder().decode(User.self, from: json)
XCTAssertEqual(user._id, id)
XCTAssertEqual(user.name, "Joannis")
XCTAssertEqual(user.createdAt.timeIntervalSince1970, now.timeIntervalSince1970, accuracy: 0.01)
XCTAssertEqual(user.admin, true)
XCTAssertEqual(user.organizations, [org1, org2])
XCTAssertEqual(user.profile.email, "[email protected]")
XCTAssertEqual(user.null, nil)
XCTAssertEqual(user.map["a"], 0)
XCTAssertEqual(user.map["b"], 1)
}

func testSubdocumentBasicAccess() throws{
var doc = Document()
let subdoc = ["foo": "bar"] as Document
Expand Down

0 comments on commit 188419b

Please sign in to comment.