1// Copyright (C) MongoDB, Inc. 2017-present. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); you may 4// not use this file except in compliance with the License. You may obtain 5// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 7package driver 8 9import ( 10 "context" 11 "time" 12 13 "go.mongodb.org/mongo-driver/bson/bsoncodec" 14 "go.mongodb.org/mongo-driver/x/bsonx" 15 16 "go.mongodb.org/mongo-driver/mongo/options" 17 "go.mongodb.org/mongo-driver/x/mongo/driver/session" 18 "go.mongodb.org/mongo-driver/x/mongo/driver/topology" 19 "go.mongodb.org/mongo-driver/x/mongo/driver/uuid" 20 "go.mongodb.org/mongo-driver/x/network/command" 21 "go.mongodb.org/mongo-driver/x/network/description" 22) 23 24// Count handles the full cycle dispatch and execution of a count command against the provided 25// topology. 26func Count( 27 ctx context.Context, 28 cmd command.Count, 29 topo *topology.Topology, 30 selector description.ServerSelector, 31 clientID uuid.UUID, 32 pool *session.Pool, 33 registry *bsoncodec.Registry, 34 opts ...*options.CountOptions, 35) (int64, error) { 36 37 ss, err := topo.SelectServer(ctx, selector) 38 if err != nil { 39 return 0, err 40 } 41 42 desc := ss.Description() 43 conn, err := ss.Connection(ctx) 44 if err != nil { 45 return 0, err 46 } 47 defer conn.Close() 48 49 rp, err := getReadPrefBasedOnTransaction(cmd.ReadPref, cmd.Session) 50 if err != nil { 51 return 0, err 52 } 53 cmd.ReadPref = rp 54 55 // If no explicit session and deployment supports sessions, start implicit session. 56 if cmd.Session == nil && topo.SupportsSessions() { 57 cmd.Session, err = session.NewClientSession(pool, clientID, session.Implicit) 58 if err != nil { 59 return 0, err 60 } 61 defer cmd.Session.EndSession() 62 } 63 64 countOpts := options.MergeCountOptions(opts...) 65 66 if countOpts.Limit != nil { 67 cmd.Opts = append(cmd.Opts, bsonx.Elem{"limit", bsonx.Int64(*countOpts.Limit)}) 68 } 69 if countOpts.MaxTime != nil { 70 cmd.Opts = append(cmd.Opts, bsonx.Elem{ 71 "maxTimeMS", bsonx.Int64(int64(*countOpts.MaxTime / time.Millisecond)), 72 }) 73 } 74 if countOpts.Skip != nil { 75 cmd.Opts = append(cmd.Opts, bsonx.Elem{"skip", bsonx.Int64(*countOpts.Skip)}) 76 } 77 if countOpts.Collation != nil { 78 if desc.WireVersion.Max < 5 { 79 return 0, ErrCollation 80 } 81 collDoc, err := bsonx.ReadDoc(countOpts.Collation.ToDocument()) 82 if err != nil { 83 return 0, err 84 } 85 cmd.Opts = append(cmd.Opts, bsonx.Elem{"collation", bsonx.Document(collDoc)}) 86 } 87 if countOpts.Hint != nil { 88 hintElem, err := interfaceToElement("hint", countOpts.Hint, registry) 89 if err != nil { 90 return 0, err 91 } 92 93 cmd.Opts = append(cmd.Opts, hintElem) 94 } 95 96 return cmd.RoundTrip(ctx, desc, conn) 97} 98