@@ -223,6 +223,28 @@ public struct ServerDescription {
223223 } ?? [ ]
224224 self . tags = hello? . tags ?? [ : ]
225225 }
226+
227+ // For testing purposes
228+ internal init ( type: ServerType ) {
229+ self . type = type
230+ self . address = ServerAddress ( host: " fake " , port: 80 )
231+ self . serverId = 0
232+ self . roundTripTime = 0
233+ self . lastUpdateTime = Date ( )
234+ self . lastWriteDate = nil
235+ self . minWireVersion = 0
236+ self . maxWireVersion = 0
237+ self . me = self . address
238+ self . setName = nil
239+ self . setVersion = nil
240+ self . electionID = nil
241+ self . primary = nil
242+ self . logicalSessionTimeoutMinutes = nil
243+ self . hosts = [ ]
244+ self . passives = [ ]
245+ self . arbiters = [ ]
246+ self . tags = [ : ]
247+ }
226248}
227249
228250extension ServerDescription : Equatable {
@@ -270,7 +292,7 @@ public struct TopologyDescription: Equatable {
270292
271293 /// Internal representation of topology type. If enums could be marked non-exhaustive in Swift, this would be
272294 /// the public representation too.
273- private enum _TopologyType : String , Equatable {
295+ fileprivate enum _TopologyType : String , Equatable {
274296 case single = " Single "
275297 case replicaSetNoPrimary = " ReplicaSetNoPrimary "
276298 case replicaSetWithPrimary = " ReplicaSetWithPrimary "
@@ -279,7 +301,7 @@ public struct TopologyDescription: Equatable {
279301 case loadBalanced = " LoadBalanced "
280302 }
281303
282- private let _topologyType : _TopologyType
304+ fileprivate let _topologyType : _TopologyType
283305
284306 private init ( _ _type: _TopologyType ) {
285307 self . _topologyType = _type
@@ -353,4 +375,64 @@ public struct TopologyDescription: Equatable {
353375 self . servers = size > 0 ? Array ( buffer) . map { ServerDescription ( $0!) } : [ ]
354376 // the buffer is documented as always containing non-nil pointers (if non-empty).
355377 }
378+
379+ // For testing purposes
380+ internal init ( type: TopologyType , servers: [ ServerDescription ] ) {
381+ self . type = type
382+ self . servers = servers
383+ }
384+ }
385+
386+ extension TopologyDescription {
387+ internal func findSuitableServers( readPreference: ReadPreference ? = nil ) -> [ ServerDescription ] {
388+ switch self . type. _topologyType {
389+ case . unknown:
390+ return [ ]
391+ case . single,
392+ . loadBalanced:
393+ return self . servers
394+ case . replicaSetNoPrimary,
395+ . replicaSetWithPrimary:
396+ switch readPreference? . mode {
397+ case . secondary:
398+ let secondaries = self . servers. filter { $0. type == . rsSecondary }
399+ return self . filterReplicaSetServers ( readPreference: readPreference, servers: secondaries)
400+ case . nearest:
401+ let secondariesAndPrimary = self . servers. filter { $0. type == . rsSecondary || $0. type == . rsPrimary }
402+ return self . filterReplicaSetServers ( readPreference: readPreference, servers: secondariesAndPrimary)
403+ case . secondaryPreferred:
404+ // If mode is 'secondaryPreferred', attempt the selection algorithm with mode 'secondary' and the
405+ // user's maxStalenessSeconds and tag_sets.If no server matches, select the primary.
406+ let secondaries = self . servers. filter { $0. type == . rsSecondary }
407+ let primaries = self . servers. filter { $0. type == . rsPrimary }
408+ let matches = self . filterReplicaSetServers ( readPreference: readPreference, servers: secondaries)
409+ return matches. isEmpty ? primaries : matches
410+ case . primaryPreferred:
411+ // If mode is 'primaryPreferred' or a readPreference is not provided, select the primary if it is known,
412+ // otherwise attempt the selection algorithm with mode 'secondary' and the user's
413+ // maxStalenessSeconds and tag_sets.
414+ let primaries = self . servers. filter { $0. type == . rsPrimary }
415+ if !primaries. isEmpty {
416+ return primaries
417+ }
418+ let secondaries = self . servers. filter { $0. type == . rsSecondary }
419+ return self . filterReplicaSetServers ( readPreference: readPreference, servers: secondaries)
420+ default :
421+ // the default mode is 'primary'.
422+ return self . servers. filter { $0. type == . rsPrimary }
423+ }
424+ case . sharded:
425+ return self . servers. filter { $0. type == . mongos }
426+ }
427+ }
428+
429+ internal func filterReplicaSetServers(
430+ readPreference _: ReadPreference ? ,
431+ servers: [ ServerDescription ]
432+ ) -> [ ServerDescription ] {
433+ // TODO: Filter out servers staler than maxStalenessSeconds
434+ // TODO: Select servers matching the tag_sets
435+ // While waiting for the above to be implemented, this helper just returns the servers it was passed
436+ servers
437+ }
356438}
0 commit comments