diff --git a/Examples/Docs/Package.swift b/Examples/Docs/Package.swift index 16f53de38..d628ac726 100644 --- a/Examples/Docs/Package.swift +++ b/Examples/Docs/Package.swift @@ -1,12 +1,14 @@ -// swift-tools-version:4.2 +// swift-tools-version:5.0 import PackageDescription let package = Package( name: "DocsExamples", dependencies: [ - .package(url: "https://github.com/mongodb/mongo-swift-driver", .upToNextMajor(from: "0.1.0")) + .package(url: "https://github.com/mongodb/mongo-swift-driver", .upToNextMajor(from: "1.0.0")), + .package(url: "https://github.com/apple/swift-nio", .upToNextMajor(from: "2.0.0")) ], targets: [ - .target(name: "DocsExamples", dependencies: ["MongoSwift"]) + .target(name: "SyncExamples", dependencies: ["MongoSwiftSync"]), + .target(name: "AsyncExamples", dependencies: ["MongoSwift", "NIO"]) ] ) diff --git a/Examples/Docs/Sources/AsyncExamples/main.swift b/Examples/Docs/Sources/AsyncExamples/main.swift new file mode 100644 index 000000000..edf07eb7a --- /dev/null +++ b/Examples/Docs/Sources/AsyncExamples/main.swift @@ -0,0 +1,149 @@ +import Foundation +import MongoSwift +import NIO + +// swiftlint:disable force_unwrapping + +/// Examples used for the MongoDB documentation on Causal Consistency. +/// - SeeAlso: https://docs.mongodb.com/manual/core/read-isolation-consistency-recency/#examples +private func causalConsistency() throws { + let elg = MultiThreadedEventLoopGroup(numberOfThreads: 1) + let client1 = try MongoClient(using: elg) + defer { + client1.syncShutdown() + try? elg.syncShutdownGracefully() + } + + // Start Causal Consistency Example 1 + let s1 = client1.startSession(options: ClientSessionOptions(causalConsistency: true)) + let currentDate = Date() + var dbOptions = DatabaseOptions( + readConcern: ReadConcern(.majority), + writeConcern: try WriteConcern(w: .majority, wtimeoutMS: 1000) + ) + let items = client1.db("test", options: dbOptions).collection("items") + let result1 = items.updateOne( + filter: ["sku": "111", "end": .null], + update: ["$set": ["end": .datetime(currentDate)]], + session: s1 + ).flatMap { _ in + items.insertOne(["sku": "nuts-111", "name": "Pecans", "start": .datetime(currentDate)], session: s1) + } + // End Causal Consistency Example 1 + + let client2 = try MongoClient(using: elg) + + // Start Causal Consistency Example 2 + let options = ClientSessionOptions(causalConsistency: true) + let result2: EventLoopFuture = client2.withSession(options: options) { s2 in + // The cluster and operation times are guaranteed to be non-nil since we already used s1 for operations above. + s2.advanceClusterTime(to: s1.clusterTime!) + s2.advanceOperationTime(to: s1.operationTime!) + + dbOptions.readPreference = ReadPreference(.secondary) + let items2 = client2.db("test", options: dbOptions).collection("items") + + return items2.find(["end": .null], session: s2).flatMap { cursor in + cursor.forEach { item in + print(item) + } + } + } + // End Causal Consistency Example 2 +} + +/// Examples used for the MongoDB documentation on Change Streams. +/// - SeeAlso: https://docs.mongodb.com/manual/changeStreams/ +private func changeStreams() throws { + let elg = MultiThreadedEventLoopGroup(numberOfThreads: 1) + let client = try MongoClient(using: elg) + let db = client.db("example") + + // The following examples assume that you have connected to a MongoDB replica set and have + // accessed a database that contains an inventory collection. + + do { + // Start Changestream Example 1 + let inventory = db.collection("inventory") + + // Option 1: retrieve next document via next() + let next = inventory.watch().flatMap { cursor in + cursor.next() + } + + // Option 2: register a callback to execute for each document + let result = inventory.watch().flatMap { cursor in + cursor.forEach { event in + // process event + print(event) + } + } + // End Changestream Example 1 + } + + do { + // Start Changestream Example 2 + let inventory = db.collection("inventory") + + // Option 1: use next() to iterate + let next = inventory.watch(options: ChangeStreamOptions(fullDocument: .updateLookup)) + .flatMap { changeStream in + changeStream.next() + } + + // Option 2: register a callback to execute for each document + let result = inventory.watch(options: ChangeStreamOptions(fullDocument: .updateLookup)) + .flatMap { changeStream in + changeStream.forEach { event in + // process event + print(event) + } + } + // End Changestream Example 2 + } + + do { + // Start Changestream Example 3 + let inventory = db.collection("inventory") + + inventory.watch(options: ChangeStreamOptions(fullDocument: .updateLookup)) + .flatMap { changeStream in + changeStream.next().map { _ in + changeStream.resumeToken + }.always { _ in + _ = changeStream.kill() + } + }.flatMap { resumeToken in + inventory.watch(options: ChangeStreamOptions(resumeAfter: resumeToken)).flatMap { newStream in + newStream.forEach { event in + // process event + print(event) + } + } + } + // End Changestream Example 3 + } + + do { + // Start Changestream Example 4 + let pipeline: [Document] = [ + ["$match": ["fullDocument.username": "alice"]], + ["$addFields": ["newField": "this is an added field!"]] + ] + let inventory = db.collection("inventory") + + // Option 1: use next() to iterate + let next = inventory.watch(pipeline, withEventType: Document.self).flatMap { changeStream in + changeStream.next() + } + + // Option 2: register a callback to execute for each document + let result = inventory.watch(pipeline, withEventType: Document.self).flatMap { changeStream in + changeStream.forEach { event in + // process event + print(event) + } + } + // End Changestream Example 4 + } +} diff --git a/Examples/Docs/Sources/DocsExamples/main.swift b/Examples/Docs/Sources/SyncExamples/main.swift similarity index 76% rename from Examples/Docs/Sources/DocsExamples/main.swift rename to Examples/Docs/Sources/SyncExamples/main.swift index 0b430f455..09bf4c467 100644 --- a/Examples/Docs/Sources/DocsExamples/main.swift +++ b/Examples/Docs/Sources/SyncExamples/main.swift @@ -1,5 +1,5 @@ import Foundation -import MongoSwift +import MongoSwiftSync // swiftlint:disable force_unwrapping @@ -9,7 +9,7 @@ private func causalConsistency() throws { let client1 = try MongoClient() // Start Causal Consistency Example 1 - let s1 = try client1.startSession(options: ClientSessionOptions(causalConsistency: true)) + let s1 = client1.startSession(options: ClientSessionOptions(causalConsistency: true)) let currentDate = Date() var dbOptions = DatabaseOptions( readConcern: ReadConcern(.majority), @@ -53,28 +53,28 @@ private func changeStreams() throws { do { // Start Changestream Example 1 let inventory = db.collection("inventory") - let cursor = try inventory.watch() - let next = try cursor.nextOrError() + let changeStream = try inventory.watch() + let next = changeStream.next() // End Changestream Example 1 } do { // Start Changestream Example 2 let inventory = db.collection("inventory") - let cursor = try inventory.watch(options: ChangeStreamOptions(fullDocument: .updateLookup)) - let next = try cursor.nextOrError() + let changeStream = try inventory.watch(options: ChangeStreamOptions(fullDocument: .updateLookup)) + let next = changeStream.next() // End Changestream Example 2 } do { // Start Changestream Example 3 let inventory = db.collection("inventory") - let cursor = try inventory.watch(options: ChangeStreamOptions(fullDocument: .updateLookup)) - let next = try cursor.nextOrError() + let changeStream = try inventory.watch(options: ChangeStreamOptions(fullDocument: .updateLookup)) + let next = changeStream.next() - let resumeToken = cursor.resumeToken - let resumedCursor = try inventory.watch(options: ChangeStreamOptions(resumeAfter: resumeToken)) - let nextAfterResume = try resumedCursor.nextOrError() + let resumeToken = changeStream.resumeToken + let resumedChangeStream = try inventory.watch(options: ChangeStreamOptions(resumeAfter: resumeToken)) + let nextAfterResume = resumedChangeStream.next() // End Changestream Example 3 } @@ -85,8 +85,8 @@ private func changeStreams() throws { ["$addFields": ["newField": "this is an added field!"]] ] let inventory = db.collection("inventory") - let cursor = try inventory.watch(pipeline, withEventType: Document.self) - let next = try cursor.nextOrError() + let changeStream = try inventory.watch(pipeline, withEventType: Document.self) + let next = changeStream.next() // End Changestream Example 4 } }