MongoClient.swift 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091
  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2020 Realm Inc.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. //
  17. ////////////////////////////////////////////////////////////////////////////
  18. import Foundation
  19. import Realm
  20. import Realm.Private
  21. /**
  22. * The `MongoClient` enables reading and writing on a MongoDB database via the Realm Cloud service.
  23. *
  24. * It provides access to instances of `MongoDatabase`, which in turn provide access to specific
  25. * `MongoCollection`s that hold your data.
  26. *
  27. * - Note:
  28. * Before you can read or write data, a user must log in.
  29. *
  30. * - SeeAlso:
  31. * `App`, `MongoDatabase`, `MongoCollection`
  32. */
  33. public typealias MongoClient = RLMMongoClient
  34. /**
  35. * The `MongoDatabase` represents a MongoDB database, which holds a group
  36. * of collections that contain your data.
  37. *
  38. * It can be retrieved from the `MongoClient`.
  39. *
  40. * Use it to get `MongoCollection`s for reading and writing data.
  41. *
  42. * - Note:
  43. * Before you can read or write data, a user must log in`.
  44. *
  45. * - SeeAlso:
  46. * `MongoClient`, `MongoCollection`
  47. */
  48. public typealias MongoDatabase = RLMMongoDatabase
  49. /// Options to use when executing a `find` command on a `MongoCollection`.
  50. public typealias FindOptions = RLMFindOptions
  51. extension FindOptions {
  52. /// Limits the fields to return for all matching documents.
  53. public var projection: Document? {
  54. get {
  55. return ObjectiveCSupport.convert(object: __projection)?.documentValue
  56. }
  57. set {
  58. __projection = newValue.map(AnyBSON.init).map(ObjectiveCSupport.convert) as? RLMBSON
  59. }
  60. }
  61. /// The order in which to return matching documents.
  62. public var sort: Document? {
  63. get {
  64. return ObjectiveCSupport.convert(object: __sort)?.documentValue
  65. }
  66. set {
  67. __sort = newValue.map(AnyBSON.init).map(ObjectiveCSupport.convert) as? RLMBSON
  68. }
  69. }
  70. /// Options to use when executing a `find` command on a `MongoCollection`.
  71. /// - Parameters:
  72. /// - limit: The maximum number of documents to return. Specifying 0 will return all documents.
  73. /// - projected: Limits the fields to return for all matching documents.
  74. /// - sort: The order in which to return matching documents.
  75. public convenience init(_ limit: Int?, _ projection: Document?, _ sort: Document?) {
  76. self.init()
  77. self.limit = limit ?? 0
  78. self.projection = projection
  79. self.sort = sort
  80. }
  81. /// Options to use when executing a `find` command on a `MongoCollection`.
  82. /// - Parameters:
  83. /// - limit: The maximum number of documents to return. Specifying 0 will return all documents.
  84. /// - projected: Limits the fields to return for all matching documents.
  85. /// - sort: The order in which to return matching documents.
  86. public convenience init(limit: Int?, projection: Document?, sort: Document?) {
  87. self.init(limit, projection, sort)
  88. }
  89. }
  90. /// Options to use when executing a `findOneAndUpdate`, `findOneAndReplace`,
  91. /// or `findOneAndDelete` command on a `MongoCollection`.
  92. public typealias FindOneAndModifyOptions = RLMFindOneAndModifyOptions
  93. extension FindOneAndModifyOptions {
  94. /// Limits the fields to return for all matching documents.
  95. public var projection: Document? {
  96. get {
  97. return ObjectiveCSupport.convert(object: __projection)?.documentValue
  98. }
  99. set {
  100. __projection = newValue.map(AnyBSON.init).map(ObjectiveCSupport.convert) as? RLMBSON
  101. }
  102. }
  103. /// The order in which to return matching documents.
  104. public var sort: Document? {
  105. get {
  106. return ObjectiveCSupport.convert(object: __sort)?.documentValue
  107. }
  108. set {
  109. __sort = newValue.map(AnyBSON.init).map(ObjectiveCSupport.convert) as? RLMBSON
  110. }
  111. }
  112. /// Options to use when executing a `findOneAndUpdate`, `findOneAndReplace`,
  113. /// or `findOneAndDelete` command on a `MongoCollection`
  114. /// - Parameters:
  115. /// - projection: Limits the fields to return for all matching documents.
  116. /// - sort: The order in which to return matching documents.
  117. /// - upsert: Whether or not to perform an upsert, default is false
  118. /// (only available for findOneAndReplace and findOneAndUpdate)
  119. /// - shouldReturnNewDocument: When true then the new document is returned,
  120. /// Otherwise the old document is returned (default)
  121. /// (only available for findOneAndReplace and findOneAndUpdate)
  122. public convenience init(_ projection: Document?,
  123. _ sort: Document?,
  124. _ upsert: Bool=false,
  125. _ shouldReturnNewDocument: Bool=false) {
  126. self.init()
  127. self.projection = projection
  128. self.sort = sort
  129. self.upsert = upsert
  130. self.shouldReturnNewDocument = shouldReturnNewDocument
  131. }
  132. /// Options to use when executing a `findOneAndUpdate`, `findOneAndReplace`,
  133. /// or `findOneAndDelete` command on a `MongoCollection`
  134. /// - Parameters:
  135. /// - projection: Limits the fields to return for all matching documents.
  136. /// - sort: The order in which to return matching documents.
  137. /// - upsert: Whether or not to perform an upsert, default is false
  138. /// (only available for findOneAndReplace and findOneAndUpdate)
  139. /// - shouldReturnNewDocument: When true then the new document is returned,
  140. /// Otherwise the old document is returned (default)
  141. /// (only available for findOneAndReplace and findOneAndUpdate)
  142. public convenience init(projection: Document?,
  143. sort: Document?,
  144. upsert: Bool=false,
  145. shouldReturnNewDocument: Bool=false) {
  146. self.init(projection, sort, upsert, shouldReturnNewDocument)
  147. }
  148. }
  149. /// The result of an `updateOne` or `updateMany` operation a `MongoCollection`.
  150. public typealias UpdateResult = RLMUpdateResult
  151. /// Block which returns Result.success(DocumentId) on a successful insert or Result.failure(error)
  152. public typealias MongoInsertBlock = (Result<AnyBSON, Error>) -> Void
  153. /// Block which returns Result.success([ObjectId]) on a successful insertMany or Result.failure(error)
  154. public typealias MongoInsertManyBlock = (Result<[AnyBSON], Error>) -> Void
  155. /// Block which returns Result.success([Document]) on a successful find operation or Result.failure(error)
  156. public typealias MongoFindBlock = (Result<[Document], Error>) -> Void
  157. /// Block which returns Result.success(Document?) on a successful findOne operation or Result.failure(error)
  158. public typealias MongoFindOneBlock = (Result<Document?, Error>) -> Void
  159. /// Block which returns Result.success(Int) on a successful count operation or Result.failure(error)
  160. public typealias MongoCountBlock = (Result<Int, Error>) -> Void
  161. /// Block which returns Result.success(UpdateResult) on a successful update operation or Result.failure(error)
  162. public typealias MongoUpdateBlock = (Result<UpdateResult, Error>) -> Void
  163. /**
  164. * The `MongoCollection` represents a MongoDB collection.
  165. *
  166. * You can get an instance from a `MongoDatabase`.
  167. *
  168. * Create, read, update, and delete methods are available.
  169. *
  170. * Operations against the Realm Cloud server are performed asynchronously.
  171. *
  172. * - Note:
  173. * Before you can read or write data, a user must log in.
  174. *
  175. * - SeeAlso:
  176. * `MongoClient`, `MongoDatabase`
  177. */
  178. public typealias MongoCollection = RLMMongoCollection
  179. /// Acts as a middleman and processes events with WatchStream
  180. public typealias ChangeStream = RLMChangeStream
  181. /// Delegate which is used for subscribing to changes on a `MongoCollection.watch()` stream.
  182. public protocol ChangeEventDelegate: AnyObject {
  183. /// The stream was opened.
  184. /// - Parameter changeStream: The `ChangeStream` subscribing to the stream changes.
  185. func changeStreamDidOpen(_ changeStream: ChangeStream )
  186. /// The stream has been closed.
  187. /// - Parameter error: If an error occured when closing the stream, an error will be passed.
  188. func changeStreamDidClose(with error: Error?)
  189. /// A error has occured while streaming.
  190. /// - Parameter error: The streaming error.
  191. func changeStreamDidReceive(error: Error)
  192. /// Invoked when a change event has been received.
  193. /// - Parameter changeEvent:The change event in BSON format.
  194. func changeStreamDidReceive(changeEvent: AnyBSON?)
  195. }
  196. extension MongoCollection {
  197. /// Opens a MongoDB change stream against the collection to watch for changes. The resulting stream will be notified
  198. /// of all events on this collection that the active user is authorized to see based on the configured MongoDB
  199. /// rules.
  200. /// - Parameters:
  201. /// - delegate: The delegate that will react to events and errors from the resulting change stream.
  202. /// - queue: Dispatches streaming events to an optional queue, if no queue is provided the main queue is used
  203. /// - Returns: A ChangeStream which will manage the streaming events.
  204. public func watch(delegate: ChangeEventDelegate, queue: DispatchQueue = .main) -> ChangeStream {
  205. return self.__watch(with: ChangeEventDelegateProxy(delegate),
  206. delegateQueue: queue)
  207. }
  208. /// Opens a MongoDB change stream against the collection to watch for changes. The provided BSON document will be
  209. /// used as a match expression filter on the change events coming from the stream.
  210. ///
  211. /// See https://docs.mongodb.com/manual/reference/operator/aggregation/match/ for documentation around how to define
  212. /// a match filter.
  213. ///
  214. /// Defining the match expression to filter ChangeEvents is similar to defining the match expression for triggers:
  215. /// https://docs.mongodb.com/realm/triggers/database-triggers/
  216. /// - Parameters:
  217. /// - matchFilter: The $match filter to apply to incoming change events
  218. /// - delegate: The delegate that will react to events and errors from the resulting change stream.
  219. /// - queue: Dispatches streaming events to an optional queue, if no queue is provided the main queue is used
  220. /// - Returns: A ChangeStream which will manage the streaming events.
  221. public func watch(matchFilter: Document, delegate: ChangeEventDelegate, queue: DispatchQueue = .main) -> ChangeStream {
  222. let filterBSON = ObjectiveCSupport.convert(object: .document(matchFilter)) as! [String: RLMBSON]
  223. return self.__watch(withMatchFilter: filterBSON,
  224. delegate: ChangeEventDelegateProxy(delegate),
  225. delegateQueue: queue)
  226. }
  227. /// Opens a MongoDB change stream against the collection to watch for changes
  228. /// made to specific documents. The documents to watch must be explicitly
  229. /// specified by their _id.
  230. /// - Parameters:
  231. /// - filterIds: The list of _ids in the collection to watch.
  232. /// - delegate: The delegate that will react to events and errors from the resulting change stream.
  233. /// - queue: Dispatches streaming events to an optional queue, if no queue is provided the main queue is used
  234. /// - Returns: A ChangeStream which will manage the streaming events.
  235. public func watch(filterIds: [ObjectId], delegate: ChangeEventDelegate, queue: DispatchQueue = .main) -> ChangeStream {
  236. let filterBSON = ObjectiveCSupport.convert(object: .array(filterIds.map {AnyBSON($0)})) as! [RLMObjectId]
  237. return self.__watch(withFilterIds: filterBSON,
  238. delegate: ChangeEventDelegateProxy(delegate),
  239. delegateQueue: queue)
  240. }
  241. }
  242. // MongoCollection methods with result type completions
  243. extension MongoCollection {
  244. /// Encodes the provided value to BSON and inserts it. If the value is missing an identifier, one will be
  245. /// generated for it.
  246. /// - Parameters:
  247. /// - document: document A `Document` value to insert.
  248. /// - completion: The result of attempting to perform the insert. An Id will be returned for the inserted object on sucess
  249. public func insertOne(_ document: Document, _ completion: @escaping MongoInsertBlock) {
  250. let bson = ObjectiveCSupport.convert(object: .document(document))
  251. self.__insertOneDocument(bson as! [String: RLMBSON]) { objectId, error in
  252. if let objectId = ObjectiveCSupport.convert(object: objectId) {
  253. completion(.success(objectId))
  254. } else {
  255. completion(.failure(error ?? Realm.Error.callFailed))
  256. }
  257. }
  258. }
  259. /// Encodes the provided values to BSON and inserts them. If any values are missing identifiers,
  260. /// they will be generated.
  261. /// - Parameters:
  262. /// - documents: The `Document` values in a bson array to insert.
  263. /// - completion: The result of the insert, returns an array inserted document ids in order.
  264. public func insertMany(_ documents: [Document], _ completion: @escaping MongoInsertManyBlock) {
  265. let bson = ObjectiveCSupport.convert(object: .array(documents.map {.document($0)}))
  266. self.__insertManyDocuments(bson as! [[String: RLMBSON]]) { objectIds, error in
  267. if let objectIds = objectIds?.compactMap(ObjectiveCSupport.convert) {
  268. completion(.success(objectIds))
  269. } else {
  270. completion(.failure(error ?? Realm.Error.callFailed))
  271. }
  272. }
  273. }
  274. /// Finds the documents in this collection which match the provided filter.
  275. /// - Parameters:
  276. /// - filter: A `Document` as bson that should match the query.
  277. /// - options: `FindOptions` to use when executing the command.
  278. /// - completion: The resulting bson array of documents or error if one occurs
  279. public func find(filter: Document,
  280. options: FindOptions,
  281. _ completion: @escaping MongoFindBlock) {
  282. let bson = ObjectiveCSupport.convert(object: .document(filter))
  283. self.__findWhere(bson as! [String: RLMBSON], options: options) { documents, error in
  284. let bson: [Document]? = documents?.map { $0.mapValues { ObjectiveCSupport.convert(object: $0) } }
  285. if let bson = bson {
  286. completion(.success(bson))
  287. } else {
  288. completion(.failure(error ?? Realm.Error.callFailed))
  289. }
  290. }
  291. }
  292. /// Finds the documents in this collection which match the provided filter.
  293. /// - Parameters:
  294. /// - filter: A `Document` as bson that should match the query.
  295. /// - completion: The resulting bson array of documents or error if one occurs
  296. public func find(filter: Document,
  297. _ completion: @escaping MongoFindBlock) {
  298. let bson = ObjectiveCSupport.convert(object: .document(filter))
  299. self.__findWhere(bson as! [String: RLMBSON]) { documents, error in
  300. let bson: [Document]? = documents?.map { $0.mapValues { ObjectiveCSupport.convert(object: $0) } }
  301. if let bson = bson {
  302. completion(.success(bson))
  303. } else {
  304. completion(.failure(error ?? Realm.Error.callFailed))
  305. }
  306. }
  307. }
  308. /// Returns one document from a collection or view which matches the
  309. /// provided filter. If multiple documents satisfy the query, this method
  310. /// returns the first document according to the query's sort order or natural
  311. /// order.
  312. /// - Parameters:
  313. /// - filter: A `Document` as bson that should match the query.
  314. /// - options: `FindOptions` to use when executing the command.
  315. /// - completion: The resulting bson or error if one occurs
  316. public func findOneDocument(filter: Document,
  317. options: FindOptions,
  318. _ completion: @escaping MongoFindOneBlock) {
  319. let bson = ObjectiveCSupport.convert(object: .document(filter))
  320. self.__findOneDocumentWhere(bson as! [String: RLMBSON], options: options) { document, error in
  321. if let error = error {
  322. completion(.failure(error))
  323. } else {
  324. let bson: Document? = document?.mapValues { ObjectiveCSupport.convert(object: $0) }
  325. completion(.success(bson))
  326. }
  327. }
  328. }
  329. /// Returns one document from a collection or view which matches the
  330. /// provided filter. If multiple documents satisfy the query, this method
  331. /// returns the first document according to the query's sort order or natural
  332. /// order.
  333. /// - Parameters:
  334. /// - filter: A `Document` as bson that should match the query.
  335. /// - completion: The resulting bson or error if one occurs
  336. public func findOneDocument(filter: Document,
  337. _ completion: @escaping MongoFindOneBlock) {
  338. let bson = ObjectiveCSupport.convert(object: .document(filter))
  339. self.__findOneDocumentWhere(bson as! [String: RLMBSON]) { document, error in
  340. if let error = error {
  341. completion(.failure(error))
  342. } else {
  343. let bson: Document? = document?.mapValues { ObjectiveCSupport.convert(object: $0) }
  344. completion(.success(bson))
  345. }
  346. }
  347. }
  348. /// Runs an aggregation framework pipeline against this collection.
  349. /// - Parameters:
  350. /// - pipeline: A bson array made up of `Documents` containing the pipeline of aggregation operations to perform.
  351. /// - completion: The resulting bson array of documents or error if one occurs
  352. public func aggregate(pipeline: [Document],
  353. _ completion: @escaping MongoFindBlock) {
  354. let bson = ObjectiveCSupport.convert(object: .array(pipeline.map {.document($0)}))
  355. self.__aggregate(withPipeline: bson as! [[String: RLMBSON]]) { documents, error in
  356. let bson: [Document]? = documents?.map { $0.mapValues { ObjectiveCSupport.convert(object: $0) } }
  357. if let bson = bson {
  358. completion(.success(bson))
  359. } else {
  360. completion(.failure(error ?? Realm.Error.callFailed))
  361. }
  362. }
  363. }
  364. /// Counts the number of documents in this collection matching the provided filter.
  365. /// - Parameters:
  366. /// - filter: A `Document` as bson that should match the query.
  367. /// - limit: The max amount of documents to count
  368. /// - completion: Returns the count of the documents that matched the filter.
  369. public func count(filter: Document,
  370. limit: Int,
  371. _ completion: @escaping MongoCountBlock) {
  372. let bson = ObjectiveCSupport.convert(object: .document(filter))
  373. self.__countWhere(bson as! [String: RLMBSON], limit: limit) { count, error in
  374. if let error = error {
  375. completion(.failure(error))
  376. } else {
  377. completion(.success(count))
  378. }
  379. }
  380. }
  381. /// Counts the number of documents in this collection matching the provided filter.
  382. /// - Parameters:
  383. /// - filter: A `Document` as bson that should match the query.
  384. /// - completion: Returns the count of the documents that matched the filter.
  385. public func count(filter: Document,
  386. _ completion: @escaping MongoCountBlock) {
  387. let bson = ObjectiveCSupport.convert(object: .document(filter))
  388. self.__countWhere(bson as! [String: RLMBSON]) { count, error in
  389. if let error = error {
  390. completion(.failure(error))
  391. } else {
  392. completion(.success(count))
  393. }
  394. }
  395. }
  396. /// Deletes a single matching document from the collection.
  397. /// - Parameters:
  398. /// - filter: A `Document` as bson that should match the query.
  399. /// - completion: The result of performing the deletion. Returns the count of deleted objects
  400. public func deleteOneDocument(filter: Document,
  401. _ completion: @escaping MongoCountBlock) {
  402. let bson = ObjectiveCSupport.convert(object: .document(filter))
  403. self.__deleteOneDocumentWhere(bson as! [String: RLMBSON]) { count, error in
  404. if let error = error {
  405. completion(.failure(error))
  406. } else {
  407. completion(.success(count))
  408. }
  409. }
  410. }
  411. /// Deletes multiple documents
  412. /// - Parameters:
  413. /// - filter: Document representing the match criteria
  414. /// - completion: The result of performing the deletion. Returns the count of the deletion
  415. public func deleteManyDocuments(filter: Document,
  416. _ completion: @escaping MongoCountBlock) {
  417. let bson = ObjectiveCSupport.convert(object: .document(filter))
  418. self.__deleteManyDocumentsWhere(bson as! [String: RLMBSON]) { count, error in
  419. if let error = error {
  420. completion(.failure(error))
  421. } else {
  422. completion(.success(count))
  423. }
  424. }
  425. }
  426. /// Updates a single document matching the provided filter in this collection.
  427. /// - Parameters:
  428. /// - filter: A bson `Document` representing the match criteria.
  429. /// - update: A bson `Document` representing the update to be applied to a matching document.
  430. /// - upsert: When true, creates a new document if no document matches the query.
  431. /// - completion: The result of the attempt to update a document.
  432. public func updateOneDocument(filter: Document,
  433. update: Document,
  434. upsert: Bool,
  435. _ completion: @escaping MongoUpdateBlock) {
  436. let filterBSON = ObjectiveCSupport.convert(object: .document(filter))
  437. let updateBSON = ObjectiveCSupport.convert(object: .document(update))
  438. self.__updateOneDocumentWhere(filterBSON as! [String: RLMBSON],
  439. updateDocument: updateBSON as! [String: RLMBSON],
  440. upsert: upsert) { updateResult, error in
  441. if let updateResult = updateResult {
  442. completion(.success(updateResult))
  443. } else {
  444. completion(.failure(error ?? Realm.Error.callFailed))
  445. }
  446. }
  447. }
  448. /// Updates a single document matching the provided filter in this collection.
  449. /// - Parameters:
  450. /// - filter: A bson `Document` representing the match criteria.
  451. /// - update: A bson `Document` representing the update to be applied to a matching document.
  452. /// - completion: The result of the attempt to update a document.
  453. public func updateOneDocument(filter: Document,
  454. update: Document,
  455. _ completion: @escaping MongoUpdateBlock) {
  456. let filterBSON = ObjectiveCSupport.convert(object: .document(filter))
  457. let updateBSON = ObjectiveCSupport.convert(object: .document(update))
  458. self.__updateOneDocumentWhere(filterBSON as! [String: RLMBSON],
  459. updateDocument: updateBSON as! [String: RLMBSON]) { updateResult, error in
  460. if let updateResult = updateResult {
  461. completion(.success(updateResult))
  462. } else {
  463. completion(.failure(error ?? Realm.Error.callFailed))
  464. }
  465. }
  466. }
  467. /// Updates multiple documents matching the provided filter in this collection.
  468. /// - Parameters:
  469. /// - filter: A bson `Document` representing the match criteria.
  470. /// - update: A bson `Document` representing the update to be applied to a matching document.
  471. /// - upsert: When true, creates a new document if no document matches the query.
  472. /// - completion: The result of the attempt to update a document.
  473. public func updateManyDocuments(filter: Document,
  474. update: Document,
  475. upsert: Bool,
  476. _ completion: @escaping MongoUpdateBlock) {
  477. let filterBSON = ObjectiveCSupport.convert(object: .document(filter))
  478. let updateBSON = ObjectiveCSupport.convert(object: .document(update))
  479. self.__updateManyDocumentsWhere(filterBSON as! [String: RLMBSON],
  480. updateDocument: updateBSON as! [String: RLMBSON],
  481. upsert: upsert) { updateResult, error in
  482. if let updateResult = updateResult {
  483. completion(.success(updateResult))
  484. } else {
  485. completion(.failure(error ?? Realm.Error.callFailed))
  486. }
  487. }
  488. }
  489. /// Updates multiple documents matching the provided filter in this collection.
  490. /// - Parameters:
  491. /// - filter: A bson `Document` representing the match criteria.
  492. /// - update: A bson `Document` representing the update to be applied to a matching document.
  493. /// - completion: The result of the attempt to update a document.
  494. public func updateManyDocuments(filter: Document,
  495. update: Document,
  496. _ completion: @escaping MongoUpdateBlock) {
  497. let filterBSON = ObjectiveCSupport.convert(object: .document(filter))
  498. let updateBSON = ObjectiveCSupport.convert(object: .document(update))
  499. self.__updateManyDocumentsWhere(filterBSON as! [String: RLMBSON],
  500. updateDocument: updateBSON as! [String: RLMBSON]) { updateResult, error in
  501. if let updateResult = updateResult {
  502. completion(.success(updateResult))
  503. } else {
  504. completion(.failure(error ?? Realm.Error.callFailed))
  505. }
  506. }
  507. }
  508. /// Updates a single document in a collection based on a query filter and
  509. /// returns the document in either its pre-update or post-update form. Unlike
  510. /// `updateOneDocument`, this action allows you to atomically find, update, and
  511. /// return a document with the same command. This avoids the risk of other
  512. /// update operations changing the document between separate find and update
  513. /// operations.
  514. /// - Parameters:
  515. /// - filter: A bson `Document` representing the match criteria.
  516. /// - update: A bson `Document` representing the update to be applied to a matching document.
  517. /// - options: `RemoteFindOneAndModifyOptions` to use when executing the command.
  518. /// - completion: The result of the attempt to update a document.
  519. public func findOneAndUpdate(filter: Document,
  520. update: Document,
  521. options: FindOneAndModifyOptions,
  522. _ completion: @escaping MongoFindOneBlock) {
  523. let filterBSON = ObjectiveCSupport.convert(object: .document(filter))
  524. let updateBSON = ObjectiveCSupport.convert(object: .document(update))
  525. self.__findOneAndUpdateWhere(filterBSON as! [String: RLMBSON],
  526. updateDocument: updateBSON as! [String: RLMBSON],
  527. options: options) { document, error in
  528. if let error = error {
  529. completion(.failure(error))
  530. } else {
  531. let bson: Document? = document?.mapValues { ObjectiveCSupport.convert(object: $0) }
  532. completion(.success(bson))
  533. }
  534. }
  535. }
  536. /// Updates a single document in a collection based on a query filter and
  537. /// returns the document in either its pre-update or post-update form. Unlike
  538. /// `updateOneDocument`, this action allows you to atomically find, update, and
  539. /// return a document with the same command. This avoids the risk of other
  540. /// update operations changing the document between separate find and update
  541. /// operations.
  542. /// - Parameters:
  543. /// - filter: A bson `Document` representing the match criteria.
  544. /// - update: A bson `Document` representing the update to be applied to a matching document.
  545. /// - completion: The result of the attempt to update a document.
  546. public func findOneAndUpdate(filter: Document,
  547. update: Document,
  548. _ completion: @escaping MongoFindOneBlock) {
  549. let filterBSON = ObjectiveCSupport.convert(object: .document(filter))
  550. let updateBSON = ObjectiveCSupport.convert(object: .document(update))
  551. self.__findOneAndUpdateWhere(filterBSON as! [String: RLMBSON],
  552. updateDocument: updateBSON as! [String: RLMBSON]) { document, error in
  553. if let error = error {
  554. completion(.failure(error))
  555. } else {
  556. let bson: Document? = document?.mapValues { ObjectiveCSupport.convert(object: $0) }
  557. completion(.success(bson))
  558. }
  559. }
  560. }
  561. /// Overwrites a single document in a collection based on a query filter and
  562. /// returns the document in either its pre-replacement or post-replacement
  563. /// form. Unlike `updateOneDocument`, this action allows you to atomically find,
  564. /// replace, and return a document with the same command. This avoids the
  565. /// risk of other update operations changing the document between separate
  566. /// find and update operations.
  567. /// - Parameters:
  568. /// - filter: A `Document` that should match the query.
  569. /// - replacement: A `Document` describing the replacement.
  570. /// - options: `FindOneAndModifyOptions` to use when executing the command.
  571. /// - completion: The result of the attempt to replace a document.
  572. public func findOneAndReplace(filter: Document,
  573. replacement: Document,
  574. options: FindOneAndModifyOptions,
  575. _ completion: @escaping MongoFindOneBlock) {
  576. let filterBSON = ObjectiveCSupport.convert(object: .document(filter))
  577. let replacementBSON = ObjectiveCSupport.convert(object: .document(replacement))
  578. self.__findOneAndReplaceWhere(filterBSON as! [String: RLMBSON],
  579. replacementDocument: replacementBSON as! [String: RLMBSON],
  580. options: options) { document, error in
  581. if let error = error {
  582. completion(.failure(error))
  583. } else {
  584. let bson: Document? = document?.mapValues { ObjectiveCSupport.convert(object: $0) }
  585. completion(.success(bson))
  586. }
  587. }
  588. }
  589. /// Overwrites a single document in a collection based on a query filter and
  590. /// returns the document in either its pre-replacement or post-replacement
  591. /// form. Unlike `updateOneDocument`, this action allows you to atomically find,
  592. /// replace, and return a document with the same command. This avoids the
  593. /// risk of other update operations changing the document between separate
  594. /// find and update operations.
  595. /// - Parameters:
  596. /// - filter: A `Document` that should match the query.
  597. /// - replacement: A `Document` describing the replacement.
  598. /// - options: `RLMFindOneAndModifyOptions` to use when executing the command.
  599. /// - completion: The result of the attempt to replace a document.
  600. public func findOneAndReplace(filter: Document,
  601. replacement: Document,
  602. _ completion: @escaping MongoFindOneBlock) {
  603. let filterBSON = ObjectiveCSupport.convert(object: .document(filter))
  604. let replacementBSON = ObjectiveCSupport.convert(object: .document(replacement))
  605. self.__findOneAndReplaceWhere(filterBSON as! [String: RLMBSON],
  606. replacementDocument: replacementBSON as! [String: RLMBSON]) { document, error in
  607. if let error = error {
  608. completion(.failure(error))
  609. } else {
  610. let bson: Document? = document?.mapValues { ObjectiveCSupport.convert(object: $0) }
  611. completion(.success(bson))
  612. }
  613. }
  614. }
  615. /// Removes a single document from a collection based on a query filter and
  616. /// returns a document with the same form as the document immediately before
  617. /// it was deleted. Unlike `deleteOneDocument`, this action allows you to atomically
  618. /// find and delete a document with the same command. This avoids the risk of
  619. /// other update operations changing the document between separate find and
  620. /// delete operations.
  621. /// - Parameters:
  622. /// - filter: A `Document` that should match the query.
  623. /// - options: `FindOneAndModifyOptions` to use when executing the command.
  624. /// - completion: The result of the attempt to delete a document.
  625. public func findOneAndDelete(filter: Document,
  626. options: FindOneAndModifyOptions,
  627. _ completion: @escaping MongoFindOneBlock) {
  628. let filterBSON = ObjectiveCSupport.convert(object: .document(filter))
  629. self.__findOneAndDeleteWhere(filterBSON as! [String: RLMBSON],
  630. options: options) { document, error in
  631. if let error = error {
  632. completion(.failure(error))
  633. } else {
  634. let bson: Document? = document?.mapValues { ObjectiveCSupport.convert(object: $0) }
  635. completion(.success(bson))
  636. }
  637. }
  638. }
  639. /// Removes a single document from a collection based on a query filter and
  640. /// returns a document with the same form as the document immediately before
  641. /// it was deleted. Unlike `deleteOneDocument`, this action allows you to atomically
  642. /// find and delete a document with the same command. This avoids the risk of
  643. /// other update operations changing the document between separate find and
  644. /// delete operations.
  645. /// - Parameters:
  646. /// - filter: A `Document` that should match the query.
  647. /// - completion: The result of the attempt to delete a document.
  648. public func findOneAndDelete(filter: Document,
  649. _ completion: @escaping MongoFindOneBlock) {
  650. let filterBSON = ObjectiveCSupport.convert(object: .document(filter))
  651. self.__findOneAndDeleteWhere(filterBSON as! [String: RLMBSON]) { document, error in
  652. if let error = error {
  653. completion(.failure(error))
  654. } else {
  655. let bson: Document? = document?.mapValues { ObjectiveCSupport.convert(object: $0) }
  656. completion(.success(bson))
  657. }
  658. }
  659. }
  660. }
  661. private class ChangeEventDelegateProxy: RLMChangeEventDelegate {
  662. private weak var proxyDelegate: ChangeEventDelegate?
  663. init(_ proxyDelegate: ChangeEventDelegate) {
  664. self.proxyDelegate = proxyDelegate
  665. }
  666. func changeStreamDidOpen(_ changeStream: RLMChangeStream) {
  667. proxyDelegate?.changeStreamDidOpen(changeStream)
  668. }
  669. func changeStreamDidCloseWithError(_ error: Error?) {
  670. proxyDelegate?.changeStreamDidClose(with: error)
  671. }
  672. func changeStreamDidReceiveError(_ error: Error) {
  673. proxyDelegate?.changeStreamDidReceive(error: error)
  674. }
  675. func changeStreamDidReceiveChangeEvent(_ changeEvent: RLMBSON) {
  676. let bson = ObjectiveCSupport.convert(object: changeEvent)
  677. proxyDelegate?.changeStreamDidReceive(changeEvent: bson)
  678. }
  679. }
  680. #if canImport(Combine)
  681. import Combine
  682. @available(OSX 10.15, watchOS 6.0, iOS 13.0, iOSApplicationExtension 13.0, OSXApplicationExtension 10.15, tvOS 13.0, *)
  683. extension Publishers {
  684. class WatchSubscription<S: Subscriber>: ChangeEventDelegate, Subscription where S.Input == AnyBSON, S.Failure == Error {
  685. private let collection: MongoCollection
  686. private var changeStream: ChangeStream?
  687. private var subscriber: S?
  688. private var onOpen: (() -> Void)?
  689. init(collection: MongoCollection,
  690. subscriber: S,
  691. queue: DispatchQueue = .main,
  692. filterIds: [ObjectId]? = nil,
  693. matchFilter: Document? = nil,
  694. onOpen: (() -> Void)? = nil) {
  695. self.collection = collection
  696. self.subscriber = subscriber
  697. self.onOpen = onOpen
  698. if let matchFilter = matchFilter {
  699. changeStream = collection.watch(matchFilter: matchFilter,
  700. delegate: self,
  701. queue: queue)
  702. } else if let filterIds = filterIds {
  703. changeStream = collection.watch(filterIds: filterIds,
  704. delegate: self,
  705. queue: queue)
  706. } else {
  707. changeStream = collection.watch(delegate: self,
  708. queue: queue)
  709. }
  710. }
  711. func request(_ demand: Subscribers.Demand) { }
  712. func cancel() {
  713. changeStream?.close()
  714. }
  715. func changeStreamDidOpen(_ changeStream: RLMChangeStream) {
  716. onOpen?()
  717. }
  718. func changeStreamDidClose(with error: Error?) {
  719. guard let error = error else {
  720. subscriber?.receive(completion: .finished)
  721. return
  722. }
  723. subscriber?.receive(completion: .failure(error))
  724. }
  725. func changeStreamDidReceive(error: Error) {
  726. subscriber?.receive(completion: .failure(error))
  727. }
  728. func changeStreamDidReceive(changeEvent: AnyBSON?) {
  729. guard let changeEvent = changeEvent else {
  730. return
  731. }
  732. _ = subscriber?.receive(changeEvent)
  733. }
  734. }
  735. /// A publisher that emits a change event each time the remote MongoDB collection changes.
  736. public struct WatchPublisher: Publisher {
  737. public typealias Output = AnyBSON
  738. public typealias Failure = Error
  739. private let collection: MongoCollection
  740. private let queue: DispatchQueue
  741. private let filterIds: [ObjectId]?
  742. private let matchFilter: Document?
  743. private let openEvent: (() -> Void)?
  744. init(collection: MongoCollection,
  745. queue: DispatchQueue,
  746. filterIds: [ObjectId]? = nil,
  747. matchFilter: Document? = nil,
  748. onOpen: (() -> Void)? = nil) {
  749. self.collection = collection
  750. self.queue = queue
  751. self.filterIds = filterIds
  752. self.matchFilter = matchFilter
  753. self.openEvent = onOpen
  754. }
  755. /// Triggers an event when the watch change stream is opened.
  756. ///
  757. /// Use this function when you require a change stream to be open before you perform any work.
  758. /// This should be called directly after invoking the publisher.
  759. ///
  760. /// - Parameter event: Callback which will be invoked once the change stream is open.
  761. /// - Returns: A publisher that emits a change event each time the remote MongoDB collection changes.
  762. public func onOpen(_ event: @escaping (() -> Void)) -> Self {
  763. Self(collection: collection,
  764. queue: queue,
  765. filterIds: filterIds,
  766. matchFilter: matchFilter,
  767. onOpen: event)
  768. }
  769. /// :nodoc:
  770. public func receive<S: Subscriber>(subscriber: S) where Failure == S.Failure, Output == S.Input {
  771. let subscription = WatchSubscription(collection: collection,
  772. subscriber: subscriber,
  773. queue: queue,
  774. filterIds: filterIds,
  775. matchFilter: matchFilter,
  776. onOpen: openEvent)
  777. subscriber.receive(subscription: subscription)
  778. }
  779. /// Specifies the scheduler on which to perform subscribe, cancel, and request operations.
  780. ///
  781. /// - parameter scheduler: The dispatch queue to perform the subscription on.
  782. /// - returns: A publisher which subscribes on the given scheduler.
  783. public func subscribe<S: Scheduler>(on scheduler: S) -> WatchPublisher {
  784. guard let queue = scheduler as? DispatchQueue else {
  785. fatalError("Cannot subscribe on scheduler \(scheduler): only dispatch queues are currently implemented.")
  786. }
  787. return Self(collection: collection,
  788. queue: queue,
  789. filterIds: filterIds,
  790. matchFilter: matchFilter,
  791. onOpen: openEvent)
  792. }
  793. }
  794. }
  795. @available(OSX 10.15, watchOS 6.0, iOS 13.0, iOSApplicationExtension 13.0, OSXApplicationExtension 10.15, tvOS 13.0, *)
  796. extension MongoCollection {
  797. /// Creates a publisher that emits a AnyBSON change event each time the MongoDB collection changes.
  798. ///
  799. /// - returns: A publisher that emits the AnyBSON change event each time the collection changes.
  800. public func watch() -> Publishers.WatchPublisher {
  801. return Publishers.WatchPublisher(collection: self, queue: .main)
  802. }
  803. /// Creates a publisher that emits a AnyBSON change event each time the MongoDB collection changes.
  804. ///
  805. /// - Parameter filterIds: The list of _ids in the collection to watch.
  806. /// - Returns: A publisher that emits the AnyBSON change event each time the collection changes.
  807. public func watch(filterIds: [ObjectId]) -> Publishers.WatchPublisher {
  808. return Publishers.WatchPublisher(collection: self, queue: .main, filterIds: filterIds)
  809. }
  810. /// Creates a publisher that emits a AnyBSON change event each time the MongoDB collection changes.
  811. ///
  812. /// - Parameter matchFilter: The $match filter to apply to incoming change events.
  813. /// - Returns: A publisher that emits the AnyBSON change event each time the collection changes.
  814. public func watch(matchFilter: Document) -> Publishers.WatchPublisher {
  815. return Publishers.WatchPublisher(collection: self, queue: .main, matchFilter: matchFilter)
  816. }
  817. }
  818. @available(OSX 10.15, watchOS 6.0, iOS 13.0, iOSApplicationExtension 13.0, OSXApplicationExtension 10.15, tvOS 13.0, macCatalyst 13.0, macCatalystApplicationExtension 13.0, *)
  819. public extension MongoCollection {
  820. /// Encodes the provided value to BSON and inserts it. If the value is missing an identifier, one will be
  821. /// generated for it.
  822. /// @param document: A `Document` value to insert.
  823. /// @returns A publisher that eventually return the object id of the inserted document or `Error`.
  824. func insertOne(_ document: Document) -> Future<AnyBSON, Error> {
  825. return Future { self.insertOne(document, $0) }
  826. }
  827. /// Encodes the provided values to BSON and inserts them. If any values are missing identifiers,
  828. /// they will be generated.
  829. /// @param documents: The `Document` values in a bson array to insert.
  830. /// @returns A publisher that eventually return the object ids of inserted documents or `Error`.
  831. func insertMany(_ documents: [Document]) -> Future<[AnyBSON], Error> {
  832. return Future { self.insertMany(documents, $0) }
  833. }
  834. /// Finds the documents in this collection which match the provided filter.
  835. /// @param filter: A `Document` as bson that should match the query.
  836. /// @param options: `FindOptions` to use when executing the command.
  837. /// @returns A publisher that eventually return `[ObjectId]` of documents or `Error`.
  838. func find(filter: Document, options: FindOptions) -> Future<[Document], Error> {
  839. return Future { self.find(filter: filter, options: options, $0) }
  840. }
  841. /// Finds the documents in this collection which match the provided filter.
  842. /// @param filter: A `Document` as bson that should match the query.
  843. /// @returns A publisher that eventually return `[ObjectId]` of documents or `Error`.
  844. func find(filter: Document) -> Future<[Document], Error> {
  845. return Future { self.find(filter: filter, $0) }
  846. }
  847. /// Returns one document from a collection or view which matches the
  848. /// provided filter. If multiple documents satisfy the query, this method
  849. /// returns the first document according to the query's sort order or natural
  850. /// order.
  851. /// @param filter: A `Document` as bson that should match the query.
  852. /// @param options: `FindOptions` to use when executing the command.
  853. /// @returns A publisher that eventually return `Document` or `Error`.
  854. func findOneDocument(filter: Document, options: FindOptions) -> Future<Document?, Error> {
  855. return Future { self.findOneDocument(filter: filter, $0) }
  856. }
  857. /// Returns one document from a collection or view which matches the
  858. /// provided filter. If multiple documents satisfy the query, this method
  859. /// returns the first document according to the query's sort order or natural
  860. /// order.
  861. /// @param filter: A `Document` as bson that should match the query.
  862. /// @returns A publisher that eventually return `Document` or `nil` if document wasn't found or `Error`.
  863. func findOneDocument(filter: Document) -> Future<Document?, Error> {
  864. return Future { self.findOneDocument(filter: filter, $0) }
  865. }
  866. /// Runs an aggregation framework pipeline against this collection.
  867. /// @param pipeline: A bson array made up of `Documents` containing the pipeline of aggregation operations to perform.
  868. /// @returns A publisher that eventually return `Document` or `Error`.
  869. func aggregate(pipeline: [Document]) -> Future<[Document], Error> {
  870. return Future { self.aggregate(pipeline: pipeline, $0) }
  871. }
  872. /// Counts the number of documents in this collection matching the provided filter.
  873. /// @param filter: A `Document` as bson that should match the query.
  874. /// @param limit: The max amount of documents to count
  875. /// @returns A publisher that eventually return `Int` count of documents or `Error`.
  876. func count(filter: Document, limit: Int) -> Future<Int, Error> {
  877. return Future { self.count(filter: filter, limit: limit, $0) }
  878. }
  879. /// Counts the number of documents in this collection matching the provided filter.
  880. /// @param filter: A `Document` as bson that should match the query.
  881. /// @returns A publisher that eventually return `Int` count of documents or `Error`.
  882. func count(filter: Document) -> Future<Int, Error> {
  883. return Future { self.count(filter: filter, $0) }
  884. }
  885. /// Deletes a single matching document from the collection.
  886. /// @param filter: A `Document` as bson that should match the query.
  887. /// @returns A publisher that eventually return `Int` count of deleted documents or `Error`.
  888. func deleteOneDocument(filter: Document) -> Future<Int, Error> {
  889. return Future { self.deleteOneDocument(filter: filter, $0) }
  890. }
  891. /// Deletes multiple documents
  892. /// @param filter: Document representing the match criteria
  893. /// @returns A publisher that eventually return `Int` count of deleted documents or `Error`.
  894. func deleteManyDocuments(filter: Document) -> Future<Int, Error> {
  895. return Future { self.deleteManyDocuments(filter: filter, $0) }
  896. }
  897. /// Updates a single document matching the provided filter in this collection.
  898. /// @param filter: A bson `Document` representing the match criteria.
  899. /// @param update: A bson `Document` representing the update to be applied to a matching document.
  900. /// @param upsert: When true, creates a new document if no document matches the query.
  901. /// @returns A publisher that eventually return `UpdateResult` or `Error`.
  902. func updateOneDocument(filter: Document, update: Document, upsert: Bool) -> Future<UpdateResult, Error> {
  903. return Future { self.updateOneDocument(filter: filter, update: update, upsert: upsert, $0) }
  904. }
  905. /// Updates a single document matching the provided filter in this collection.
  906. /// @param filter: A bson `Document` representing the match criteria.
  907. /// @param update: A bson `Document` representing the update to be applied to a matching document.
  908. /// @returns A publisher that eventually return `UpdateResult` or `Error`.
  909. func updateOneDocument(filter: Document, update: Document) -> Future<UpdateResult, Error> {
  910. return Future { self.updateOneDocument(filter: filter, update: update, $0) }
  911. }
  912. /// Updates multiple documents matching the provided filter in this collection.
  913. /// @param filter: A bson `Document` representing the match criteria.
  914. /// @param update: A bson `Document` representing the update to be applied to a matching document.
  915. /// @param upsert: When true, creates a new document if no document matches the query.
  916. /// @returns A publisher that eventually return `UpdateResult` or `Error`.
  917. func updateManyDocuments(filter: Document, update: Document, upsert: Bool) -> Future<UpdateResult, Error> {
  918. return Future { self.updateManyDocuments(filter: filter, update: update, upsert: upsert, $0) }
  919. }
  920. /// Updates multiple documents matching the provided filter in this collection.
  921. /// @param filter: A bson `Document` representing the match criteria.
  922. /// @param update: A bson `Document` representing the update to be applied to a matching document.
  923. /// @returns A publisher that eventually return `UpdateResult` or `Error`.
  924. func updateManyDocuments(filter: Document, update: Document) -> Future<UpdateResult, Error> {
  925. return Future { self.updateManyDocuments(filter: filter, update: update, $0) }
  926. }
  927. /// Updates a single document in a collection based on a query filter and
  928. /// returns the document in either its pre-update or post-update form. Unlike
  929. /// `updateOneDocument`, this action allows you to atomically find, update, and
  930. /// return a document with the same command. This avoids the risk of other
  931. /// update operations changing the document between separate find and update
  932. /// operations.
  933. /// @param filter: A bson `Document` representing the match criteria.
  934. /// @param update: A bson `Document` representing the update to be applied to a matching document.
  935. /// @param options: `RemoteFindOneAndModifyOptions` to use when executing the command.
  936. /// @returns A publisher that eventually return `Document` or `nil` if document wasn't found or `Error`.
  937. func findOneAndUpdate(filter: Document, update: Document, options: FindOneAndModifyOptions) -> Future<Document?, Error> {
  938. return Future { self.findOneAndUpdate(filter: filter, update: update, options: options, $0) }
  939. }
  940. /// Updates a single document in a collection based on a query filter and
  941. /// returns the document in either its pre-update or post-update form. Unlike
  942. /// `updateOneDocument`, this action allows you to atomically find, update, and
  943. /// return a document with the same command. This avoids the risk of other
  944. /// update operations changing the document between separate find and update
  945. /// operations.
  946. /// @param filter: A bson `Document` representing the match criteria.
  947. /// @param update: A bson `Document` representing the update to be applied to a matching document.
  948. /// @returns A publisher that eventually return `Document` or `nil` if document wasn't found or `Error`.
  949. func findOneAndUpdate(filter: Document, update: Document) -> Future<Document?, Error> {
  950. return Future { self.findOneAndUpdate(filter: filter, update: update, $0) }
  951. }
  952. /// Overwrites a single document in a collection based on a query filter and
  953. /// returns the document in either its pre-replacement or post-replacement
  954. /// form. Unlike `updateOneDocument`, this action allows you to atomically find,
  955. /// replace, and return a document with the same command. This avoids the
  956. /// risk of other update operations changing the document between separate
  957. /// find and update operations.
  958. /// @param filter: A `Document` that should match the query.
  959. /// @param replacement: A `Document` describing the replacement.
  960. /// @param options: `FindOneAndModifyOptions` to use when executing the command.
  961. /// @returns A publisher that eventually return `Document` or `nil` if document wasn't found or `Error`.
  962. func findOneAndReplace(filter: Document, replacement: Document, options: FindOneAndModifyOptions) -> Future<Document?, Error> {
  963. return Future { self.findOneAndReplace(filter: filter, replacement: replacement, options: options, $0) }
  964. }
  965. /// Overwrites a single document in a collection based on a query filter and
  966. /// returns the document in either its pre-replacement or post-replacement
  967. /// form. Unlike `updateOneDocument`, this action allows you to atomically find,
  968. /// replace, and return a document with the same command. This avoids the
  969. /// risk of other update operations changing the document between separate
  970. /// find and update operations.
  971. /// @param filter: A `Document` that should match the query.
  972. /// @param replacement: A `Document` describing the replacement.
  973. /// @returns A publisher that eventually return `Document` or `nil` if document wasn't found or `Error`.
  974. func findOneAndReplace(filter: Document, replacement: Document) -> Future<Document?, Error> {
  975. return Future { self.findOneAndReplace(filter: filter, replacement: replacement, $0) }
  976. }
  977. /// Removes a single document from a collection based on a query filter and
  978. /// returns a document with the same form as the document immediately before
  979. /// it was deleted. Unlike `deleteOneDocument`, this action allows you to atomically
  980. /// find and delete a document with the same command. This avoids the risk of
  981. /// other update operations changing the document between separate find and
  982. /// delete operations.
  983. /// @param filter: A `Document` that should match the query.
  984. /// @param options: `FindOneAndModifyOptions` to use when executing the command.
  985. /// @returns A publisher that eventually return `Document` or `nil` if document wasn't found or `Error`.
  986. func findOneAndDelete(filter: Document, options: FindOneAndModifyOptions) -> Future<Document?, Error> {
  987. return Future { self.findOneAndDelete(filter: filter, options: options, $0) }
  988. }
  989. /// Removes a single document from a collection based on a query filter and
  990. /// returns a document with the same form as the document immediately before
  991. /// it was deleted. Unlike `deleteOneDocument`, this action allows you to atomically
  992. /// find and delete a document with the same command. This avoids the risk of
  993. /// other update operations changing the document between separate find and
  994. /// delete operations.
  995. /// @param filter: A `Document` that should match the query.
  996. /// @returns A publisher that eventually return `Document` or `nil` if document wasn't found or `Error`.
  997. func findOneAndDelete(filter: Document) -> Future<Document?, Error> {
  998. return Future { self.findOneAndDelete(filter: filter, $0) }
  999. }
  1000. }
  1001. #endif // canImport(Combine)