Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
22 changes: 15 additions & 7 deletions Sources/MongoSwift/MongoClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Foundation
import mongoc

/// Options to use when creating a `MongoClient`.
public struct ClientOptions: CodingStrategyProvider {
public struct ClientOptions: CodingStrategyProvider, Decodable {
/// Determines whether the client should retry supported write operations.
public let retryWrites: Bool?

Expand All @@ -14,24 +14,32 @@ public struct ClientOptions: CodingStrategyProvider {
/// be used.
public let readConcern: ReadConcern?

/// Specifies a ReadPreference to use for the client.
public let readPreference: ReadPreference?

/// Specifies a WriteConcern to use for the client. If one is not specified, the server's default write concern
/// will be used.
public let writeConcern: WriteConcern?

// swiftlint:disable redundant_optional_initialization

/// Specifies a ReadPreference to use for the client.
public var readPreference: ReadPreference? = nil

/// Specifies the `DateCodingStrategy` to use for BSON encoding/decoding operations performed by this client and any
/// databases or collections that derive from it.
public let dateCodingStrategy: DateCodingStrategy?
public var dateCodingStrategy: DateCodingStrategy? = nil

/// Specifies the `UUIDCodingStrategy` to use for BSON encoding/decoding operations performed by this client and any
/// databases or collections that derive from it.
public let uuidCodingStrategy: UUIDCodingStrategy?
public var uuidCodingStrategy: UUIDCodingStrategy? = nil

/// Specifies the `DataCodingStrategy` to use for BSON encoding/decoding operations performed by this client and any
/// databases or collections that derive from it.
public let dataCodingStrategy: DataCodingStrategy?
public var dataCodingStrategy: DataCodingStrategy? = nil

// swiftlint:enable redundant_optional_initialization

private enum CodingKeys: CodingKey {
case retryWrites, eventMonitoring, readConcern, writeConcern
}

/// Convenience initializer allowing any/all to be omitted or optional.
public init(eventMonitoring: Bool = false,
Expand Down
47 changes: 39 additions & 8 deletions Sources/MongoSwift/MongoCollection+BulkWrite.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ extension MongoCollection {
}

/// A model for a `deleteOne` operation within a bulk write.
public struct DeleteOneModel: WriteModel {
public struct DeleteOneModel: WriteModel, Decodable {
/// A `Document` representing the match criteria.
public let filter: Document

Expand Down Expand Up @@ -78,7 +78,7 @@ extension MongoCollection {
}

/// A model for a `deleteMany` operation within a bulk write.
public struct DeleteManyModel: WriteModel {
public struct DeleteManyModel: WriteModel, Decodable {
/// A `Document` representing the match criteria.
public let filter: Document

Expand Down Expand Up @@ -115,7 +115,7 @@ extension MongoCollection {
}

/// A model for an `insertOne` operation within a bulk write.
public struct InsertOneModel: WriteModel {
public struct InsertOneModel: WriteModel, Decodable {
/// The `CollectionType` to insert.
public let document: CollectionType

Expand Down Expand Up @@ -158,7 +158,7 @@ extension MongoCollection {
}

/// A model for a `replaceOne` operation within a bulk write.
public struct ReplaceOneModel: WriteModel {
public struct ReplaceOneModel: WriteModel, Decodable {
/// A `Document` representing the match criteria.
public let filter: Document

Expand Down Expand Up @@ -216,7 +216,7 @@ extension MongoCollection {
}

/// A model for an `updateOne` operation within a bulk write.
public struct UpdateOneModel: WriteModel {
public struct UpdateOneModel: WriteModel, Decodable {
/// A `Document` representing the match criteria.
public let filter: Document

Expand Down Expand Up @@ -278,7 +278,7 @@ extension MongoCollection {
}

/// A model for an `updateMany` operation within a bulk write.
public struct UpdateManyModel: WriteModel {
public struct UpdateManyModel: WriteModel, Decodable {
/// A `Document` representing the match criteria.
public let filter: Document

Expand Down Expand Up @@ -418,7 +418,7 @@ public class BulkWriteOperation: Operation {
}

/// Options to use when performing a bulk write operation on a `MongoCollection`.
public struct BulkWriteOptions: Encodable {
public struct BulkWriteOptions: Codable {
/// If `true`, allows the write to opt-out of document level validation.
public let bypassDocumentValidation: Bool?

Expand Down Expand Up @@ -454,7 +454,7 @@ public struct BulkWriteOptions: Encodable {
}

/// The result of a bulk write operation on a `MongoCollection`.
public struct BulkWriteResult {
public struct BulkWriteResult: Decodable {
/// Number of documents deleted.
public let deletedCount: Int

Expand All @@ -476,6 +476,37 @@ public struct BulkWriteResult {
/// Map of the index of the operation to the id of the upserted document.
public let upsertedIds: [Int: BSONValue]

private enum CodingKeys: CodingKey {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it always annoys me that the synthesized code is all or none and you can't use the synthesized coding keys if you use a custom init(from:) implementation...

case deletedCount, insertedCount, insertedIds, matchedCount, modifiedCount, upsertedCount, upsertedIds
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)

// None of the results must be present themselves, but at least one must.
guard !container.allKeys.isEmpty else {
throw DecodingError.valueNotFound(BulkWriteResult.self,
DecodingError.Context(codingPath: decoder.codingPath,
debugDescription: "No results found"))
}

self.deletedCount = try container.decodeIfPresent(Int.self, forKey: .deletedCount) ?? 0
self.matchedCount = try container.decodeIfPresent(Int.self, forKey: .matchedCount) ?? 0
self.modifiedCount = try container.decodeIfPresent(Int.self, forKey: .modifiedCount) ?? 0

let insertedIds =
(try container.decodeIfPresent([Int: AnyBSONValue].self, forKey: .insertedIds) ?? [:])
.mapValues { $0.value }
self.insertedIds = insertedIds
self.insertedCount = try container.decodeIfPresent(Int.self, forKey: .insertedCount) ?? insertedIds.count

let upsertedIds =
(try container.decodeIfPresent([Int: AnyBSONValue].self, forKey: .upsertedIds) ?? [:])
.mapValues { $0.value }
self.upsertedIds = upsertedIds
self.upsertedCount = try container.decodeIfPresent(Int.self, forKey: .upsertedCount) ?? upsertedIds.count
}

/**
* Create a `BulkWriteResult` from a reply and map of inserted IDs.
*
Expand Down
12 changes: 6 additions & 6 deletions Sources/MongoSwift/MongoCollection+FindAndModify.swift
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,11 @@ extension MongoCollection {
}

/// Indicates which document to return in a find and modify operation.
public enum ReturnDocument {
public enum ReturnDocument: String, Decodable {
/// Indicates to return the document before the update, replacement, or insert occurred.
case before
case before = "Before"
/// Indicates to return the document after the update, replacement, or insert occurred.
case after
case after = "After"
}

/// Indicates that an options type can be represented as a `FindAndModifyOptions`
Expand All @@ -138,7 +138,7 @@ private protocol FindAndModifyOptionsConvertible {
}

/// Options to use when executing a `findOneAndDelete` command on a `MongoCollection`.
public struct FindOneAndDeleteOptions: FindAndModifyOptionsConvertible {
public struct FindOneAndDeleteOptions: FindAndModifyOptionsConvertible, Decodable {
/// Specifies a collation to use.
public let collation: Document?

Expand Down Expand Up @@ -178,7 +178,7 @@ public struct FindOneAndDeleteOptions: FindAndModifyOptionsConvertible {
}

/// Options to use when executing a `findOneAndReplace` command on a `MongoCollection`.
public struct FindOneAndReplaceOptions: FindAndModifyOptionsConvertible {
public struct FindOneAndReplaceOptions: FindAndModifyOptionsConvertible, Decodable {
/// If `true`, allows the write to opt-out of document level validation.
public let bypassDocumentValidation: Bool?

Expand Down Expand Up @@ -235,7 +235,7 @@ public struct FindOneAndReplaceOptions: FindAndModifyOptionsConvertible {
}

/// Options to use when executing a `findOneAndUpdate` command on a `MongoCollection`.
public struct FindOneAndUpdateOptions: FindAndModifyOptionsConvertible {
public struct FindOneAndUpdateOptions: FindAndModifyOptionsConvertible, Decodable {
/// A set of filters specifying to which array elements an update should apply.
public let arrayFilters: [Document]?

Expand Down
31 changes: 23 additions & 8 deletions Sources/MongoSwift/MongoCollection+Read.swift
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ extension MongoCollection {
}

/// An index to "hint" or force MongoDB to use when performing a query.
public enum Hint: Encodable {
public enum Hint: Codable {
/// Specifies an index to use by its name.
case indexName(String)
/// Specifies an index to use by a specification `Document` containing the index key(s).
Expand All @@ -153,10 +153,19 @@ public enum Hint: Encodable {
try container.encode(doc)
}
}

public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let str = try? container.decode(String.self) {
self = .indexName(str)
} else {
self = .indexSpec(try container.decode(Document.self))
}
}
}

/// Options to use when executing an `aggregate` command on a `MongoCollection`.
public struct AggregateOptions: Encodable {
public struct AggregateOptions: Codable {
/// Enables writing to temporary files. When set to true, aggregation stages
/// can write data to the _tmp subdirectory in the dbPath directory.
public let allowDiskUse: Bool?
Expand Down Expand Up @@ -184,8 +193,10 @@ public struct AggregateOptions: Encodable {
/// A `ReadConcern` to use in read stages of this operation.
public let readConcern: ReadConcern?

// swiftlint:disable redundant_optional_initialization
/// A ReadPreference to use for this operation.
public let readPreference: ReadPreference?
public var readPreference: ReadPreference? = nil
// swiftlint:enable redundant_optional_initialization

/// A `WriteConcern` to use in `$out` stages of this operation.
public let writeConcern: WriteConcern?
Expand Down Expand Up @@ -265,7 +276,7 @@ public enum CursorType {
}

/// Options to use when executing a `find` command on a `MongoCollection`.
public struct FindOptions: Encodable {
public struct FindOptions: Codable {
/// Get partial results from a mongos if some shards are down (instead of throwing an error).
public let allowPartialResults: Bool?

Expand All @@ -278,9 +289,6 @@ public struct FindOptions: Encodable {
/// Attaches a comment to the query.
public let comment: String?

/// Indicates the type of cursor to use. This value includes both the tailable and awaitData options.
public let cursorType: CursorType?

/// If a `CursorType` is provided, indicates whether it is `.tailable` or .`tailableAwait`.
private let tailable: Bool?

Expand Down Expand Up @@ -332,8 +340,15 @@ public struct FindOptions: Encodable {
/// A ReadConcern to use for this operation.
public let readConcern: ReadConcern?

// swiftlint:disable redundant_optional_initialization

/// A ReadPreference to use for this operation.
public let readPreference: ReadPreference?
public var readPreference: ReadPreference? = nil

/// Indicates the type of cursor to use. This value includes both the tailable and awaitData options.
public var cursorType: CursorType? = nil

// swiftlint:enable redundant_optional_initialization

/// Convenience initializer allowing any/all parameters to be omitted or optional.
public init(allowPartialResults: Bool? = nil,
Expand Down
20 changes: 15 additions & 5 deletions Sources/MongoSwift/MongoCollection+Write.swift
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ private extension BulkWriteOptionsConvertible {
// Write command options structs

/// Options to use when executing an `insertOne` command on a `MongoCollection`.
public struct InsertOneOptions: Encodable, BulkWriteOptionsConvertible {
public struct InsertOneOptions: Codable, BulkWriteOptionsConvertible {
/// If true, allows the write to opt-out of document level validation.
public let bypassDocumentValidation: Bool?

Expand All @@ -251,7 +251,7 @@ public struct InsertOneOptions: Encodable, BulkWriteOptionsConvertible {
public typealias InsertManyOptions = BulkWriteOptions

/// Options to use when executing an `update` command on a `MongoCollection`.
public struct UpdateOptions: Encodable, BulkWriteOptionsConvertible {
public struct UpdateOptions: Codable, BulkWriteOptionsConvertible {
/// A set of filters specifying to which array elements an update should apply.
public let arrayFilters: [Document]?

Expand Down Expand Up @@ -282,7 +282,7 @@ public struct UpdateOptions: Encodable, BulkWriteOptionsConvertible {
}

/// Options to use when executing a `replace` command on a `MongoCollection`.
public struct ReplaceOptions: Encodable, BulkWriteOptionsConvertible {
public struct ReplaceOptions: Codable, BulkWriteOptionsConvertible {
/// If true, allows the write to opt-out of document level validation.
public let bypassDocumentValidation: Bool?

Expand All @@ -308,7 +308,7 @@ public struct ReplaceOptions: Encodable, BulkWriteOptionsConvertible {
}

/// Options to use when executing a `delete` command on a `MongoCollection`.
public struct DeleteOptions: Encodable, BulkWriteOptionsConvertible {
public struct DeleteOptions: Codable, BulkWriteOptionsConvertible {
/// Specifies a collation.
public let collation: Document?

Expand All @@ -328,7 +328,11 @@ public struct DeleteOptions: Encodable, BulkWriteOptionsConvertible {
// Write command results structs

/// The result of an `insertOne` command on a `MongoCollection`.
public struct InsertOneResult {
public struct InsertOneResult: Decodable {
private enum CodingKeys: String, CodingKey {
case insertedId
}

/// The identifier that was inserted. If the document doesn't have an identifier, this value
/// will be generated and added to the document before insertion.
public let insertedId: BSONValue
Expand All @@ -342,6 +346,12 @@ public struct InsertOneResult {
}
self.insertedId = id
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let abv = try container.decode(AnyBSONValue.self, forKey: .insertedId)
self.insertedId = abv.value
}
}

/// The result of a multi-document insert operation on a `MongoCollection`.
Expand Down
Loading