Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support ChangeStream #125

Merged
merged 7 commits into from
Mar 27, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
support ChangeStream
  • Loading branch information
tayloraswift committed Mar 26, 2024
commit 2e1332189e712d5ebcc96e3805d4725fa2f4f86c
10 changes: 8 additions & 2 deletions Sources/BSONABI/BSON.AnyType.swift
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ extension BSON

case javascriptScope = 0x0F
case int32 = 0x10
case uint64 = 0x11
case timestamp = 0x11
case int64 = 0x12
case decimal128 = 0x13

@@ -30,6 +30,12 @@ extension BSON
}
}
extension BSON.AnyType
{
@available(*, deprecated, renamed: "timestamp")
@inlinable public static
var uint64:BSON.AnyType { .timestamp }
}
extension BSON.AnyType
{
/// Calls ``init(rawValue:)``, but throws a ``TypeError`` instead of returning
/// nil.
@@ -70,7 +76,7 @@ extension BSON.AnyType
case 0x0E: self = .string
case 0x0F: self = .javascriptScope
case 0x10: self = .int32
case 0x11: self = .uint64
case 0x11: self = .timestamp
case 0x12: self = .int64
case 0x13: self = .decimal128
case 0xFF: self = .min
23 changes: 16 additions & 7 deletions Sources/BSONABI/BSON.AnyValue.swift
Original file line number Diff line number Diff line change
@@ -57,7 +57,16 @@ extension BSON
/// behavior is not part of the BSON specification, and does not
/// affect roundtrippability of BSON documents that are not stored
/// in a Mongo database.
case uint64(UInt64)
case timestamp(BSON.Timestamp)
}
}
extension BSON.AnyValue
{
@available(*, deprecated, renamed: "timestamp(_:)")
@inlinable public static
func uint64(_ value:UInt64) -> Self
{
.timestamp(.init(value))
}
}
extension BSON.AnyValue:Equatable
@@ -89,7 +98,7 @@ extension BSON.AnyValue
case .pointer: .pointer
case .regex: .regex
case .string: .string
case .uint64: .uint64
case .timestamp: .timestamp
}
}
/// The size of this variant value when encoded.
@@ -134,7 +143,7 @@ extension BSON.AnyValue
regex.size
case .string(let string):
string.size
case .uint64:
case .timestamp:
8
}
}
@@ -182,7 +191,7 @@ extension BSON.AnyValue
/// - Returns:
/// An integer derived from the payload of this variant
/// if it matches one of ``int32(_:)``, ``int64(_:)``, or
/// ``uint64(_:)``, and it can be represented exactly by `T`;
/// ``timestamp(_:)``, and it can be represented exactly by `T`;
/// nil otherwise.
///
/// The ``decimal128(_:)``, ``double(_:)``, and ``millisecond(_:)``
@@ -215,14 +224,14 @@ extension BSON.AnyValue
{
throw BSON.IntegerOverflowError<Integer>.int64(int64)
}
case .uint64(let uint64):
if let integer:Integer = .init(exactly: uint64)
case .timestamp(let timestamp):
if let integer:Integer = .init(exactly: timestamp.value)
{
return integer
}
else
{
throw BSON.IntegerOverflowError<Integer>.uint64(uint64)
throw BSON.IntegerOverflowError<Integer>.uint64(timestamp.value)
}
default:
return nil
4 changes: 2 additions & 2 deletions Sources/BSONABI/Fields/BSON.FieldEncoder.swift
Original file line number Diff line number Diff line change
@@ -59,9 +59,9 @@ extension BSON.FieldEncoder
self[.int32].serialize(integer: int32)
}
@inlinable public mutating
func encode(uint64:UInt64)
func encode(timestamp:BSON.Timestamp)
{
self[.uint64].serialize(integer: uint64)
self[.timestamp].serialize(integer: timestamp.value)
}
@inlinable public mutating
func encode(int64:Int64)
4 changes: 2 additions & 2 deletions Sources/BSONABI/IO/BSON.Input.swift
Original file line number Diff line number Diff line change
@@ -266,8 +266,8 @@ extension BSON.Input
case .int32:
return .int32(try self.parse(as: Int32.self))

case .uint64:
return .uint64(try self.parse(as: UInt64.self))
case .timestamp:
return .timestamp(.init(try self.parse(as: UInt64.self)))

case .int64:
return .int64(try self.parse(as: Int64.self))
4 changes: 2 additions & 2 deletions Sources/BSONABI/IO/BSON.Output.swift
Original file line number Diff line number Diff line change
@@ -115,8 +115,8 @@ extension BSON.Output
case .int32(let int32):
self.serialize(integer: int32)

case .uint64(let uint64):
self.serialize(integer: uint64)
case .timestamp(let timestamp):
self.serialize(integer: timestamp.value)

case .int64(let int64):
self.serialize(integer: int64)
41 changes: 41 additions & 0 deletions Sources/BSONABI/Primitives/BSON.Timestamp.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
extension BSON
{
@frozen public
struct Timestamp:Equatable, Hashable, Sendable
{
public
var value:UInt64

@inlinable public
init(_ value:UInt64)
{
self.value = value
}
}
}
extension BSON.Timestamp
{
@inlinable public static
var max:Self { .init(.max) }

@inlinable public static
var min:Self { .init(.min) }
}
extension BSON.Timestamp:Comparable
{
@inlinable public static
func < (a:Self, b:Self) -> Bool { a.value < b.value }
}
extension BSON.Timestamp:ExpressibleByIntegerLiteral
{
@inlinable public
init(integerLiteral:UInt64) { self.init(integerLiteral) }
}
extension BSON.Timestamp:CustomStringConvertible
{
public
var description:String
{
"\(self.value >> 32)+\(self.value & 0x0000_0000_ffff_ffff)"
}
}
21 changes: 21 additions & 0 deletions Sources/BSONDecoding/Extensions/BSON.Timestamp (ext).swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
extension BSON.Timestamp:BSONDecodable
{
/// Attempts to cast a BSON variant backed by some storage type to a
/// MongoDB timestamp. The conversion is not a integer case, and will
/// succeed if and only if the variant has type ``BSON.AnyType/uint64``.
@inlinable public
init(bson:BSON.AnyValue) throws
{
self = try bson.cast
{
if case .timestamp(let value) = $0
{
value
}
else
{
nil
}
}
}
}
2 changes: 1 addition & 1 deletion Sources/BSONDecodingTests/Main.DecodeNumeric.swift
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ extension Main.DecodeNumeric:TestBattery
[
"int32": .int32(0x7fff_ffff),
"int64": .int64(0x7fff_ffff_ffff_ffff),
"uint64": .uint64(0x7fff_ffff_ffff_ffff),
"uint64": .timestamp(0x7fff_ffff_ffff_ffff),
]

Self.run(tests / "int32-to-uint8", bson: bson,
4 changes: 2 additions & 2 deletions Sources/BSONEncoding/Encodability/BSONEncodable.swift
Original file line number Diff line number Diff line change
@@ -111,7 +111,7 @@ extension UInt64:BSONEncodable
@inlinable public
func encode(to field:inout BSON.FieldEncoder)
{
field.encode(uint64: self)
field.encode(timestamp: .init(self))
}
}
@available(*, deprecated,
@@ -122,6 +122,6 @@ extension UInt:BSONEncodable
@inlinable public
func encode(to field:inout BSON.FieldEncoder)
{
field.encode(uint64: .init(self))
field.encode(timestamp: .init(UInt64.init(self)))
}
}
9 changes: 9 additions & 0 deletions Sources/BSONEncoding/Extensions/BSON.Timestamp (ext).swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
extension BSON.Timestamp:BSONEncodable
{
/// Encodes this timestamp as a ``BSON.AnyValue/uint64(_:)``.
@inlinable public
func encode(to field:inout BSON.FieldEncoder)
{
field.encode(timestamp: self)
}
}
8 changes: 4 additions & 4 deletions Sources/BSONReflection/BSON.AnyValue (ext).swift
Original file line number Diff line number Diff line change
@@ -42,8 +42,8 @@ extension BSON.AnyValue
"\(regex)"
case .string(let utf8):
"\"\(utf8)\""
case .uint64(let uint64):
"\(uint64) as UInt64"
case .timestamp(let timestamp):
"\(timestamp)"
}
}
}
@@ -117,7 +117,7 @@ extension BSON.AnyValue
lhs == rhs
case (.string (let lhs), .string (let rhs)):
lhs == rhs
case (.uint64 (let lhs), .uint64 (let rhs)):
case (.timestamp (let lhs), .timestamp (let rhs)):
lhs == rhs

default:
@@ -156,7 +156,7 @@ extension BSON.AnyValue
.pointer,
.regex,
.string,
.uint64:
.timestamp:
self
}
}
6 changes: 3 additions & 3 deletions Sources/BSONTests/Main.ValidBSON.swift
Original file line number Diff line number Diff line change
@@ -113,15 +113,15 @@ extension Main.ValidBSON:TestBattery
{
Self.run(tests / "(123456789, 42)",
canonical: "100000001161002A00000015CD5B0700",
expected: ["a": .uint64(123456789 << 32 | 42)])
expected: ["a": .timestamp(.init(123456789 << 32 | 42))])

Self.run(tests / "ones",
canonical: "10000000116100FFFFFFFFFFFFFFFF00",
expected: ["a": .uint64(.max)])
expected: ["a": .timestamp(.max)])

Self.run(tests / "(4000000000, 4000000000)",
canonical: "1000000011610000286BEE00286BEE00",
expected: ["a": .uint64(4000000000 << 32 | 4000000000)])
expected: ["a": .timestamp(.init(4000000000 << 32 | 4000000000))])
}

// https://github.com/mongodb/specifications/blob/master/source/bson-corpus/tests/top.json
Empty file.
17 changes: 17 additions & 0 deletions Sources/MongoBuiltins/Pipelines/Mongo.ChangeEventIdentifier.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import BSON

extension Mongo
{
@frozen public
struct ChangeEventIdentifier:RawRepresentable, BSONDecodable, BSONEncodable, Sendable
{
public
var rawValue:BSON.Document

@inlinable public
init(rawValue:BSON.Document)
{
self.rawValue = rawValue
}
}
}
Loading
Loading