github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/go.mongodb.org/mongo-driver/x/mongo/driver/operation/count.go (about)

     1  // Copyright (C) MongoDB, Inc. 2019-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  
     7  package operation
     8  
     9  import (
    10  	"context"
    11  	"errors"
    12  	"fmt"
    13  	"time"
    14  
    15  	"go.mongodb.org/mongo-driver/bson/bsontype"
    16  	"go.mongodb.org/mongo-driver/event"
    17  	"go.mongodb.org/mongo-driver/mongo/description"
    18  	"go.mongodb.org/mongo-driver/mongo/readconcern"
    19  	"go.mongodb.org/mongo-driver/mongo/readpref"
    20  	"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
    21  	"go.mongodb.org/mongo-driver/x/mongo/driver"
    22  	"go.mongodb.org/mongo-driver/x/mongo/driver/session"
    23  )
    24  
    25  // Count represents a count operation.
    26  type Count struct {
    27  	maxTime        *time.Duration
    28  	query          bsoncore.Document
    29  	session        *session.Client
    30  	clock          *session.ClusterClock
    31  	collection     string
    32  	comment        bsoncore.Value
    33  	monitor        *event.CommandMonitor
    34  	crypt          driver.Crypt
    35  	database       string
    36  	deployment     driver.Deployment
    37  	readConcern    *readconcern.ReadConcern
    38  	readPreference *readpref.ReadPref
    39  	selector       description.ServerSelector
    40  	retry          *driver.RetryMode
    41  	result         CountResult
    42  	serverAPI      *driver.ServerAPIOptions
    43  	timeout        *time.Duration
    44  }
    45  
    46  // CountResult represents a count result returned by the server.
    47  type CountResult struct {
    48  	// The number of documents found
    49  	N int64
    50  }
    51  
    52  func buildCountResult(response bsoncore.Document) (CountResult, error) {
    53  	elements, err := response.Elements()
    54  	if err != nil {
    55  		return CountResult{}, err
    56  	}
    57  	cr := CountResult{}
    58  	for _, element := range elements {
    59  		switch element.Key() {
    60  		case "n": // for count using original command
    61  			var ok bool
    62  			cr.N, ok = element.Value().AsInt64OK()
    63  			if !ok {
    64  				return cr, fmt.Errorf("response field 'n' is type int64, but received BSON type %s",
    65  					element.Value().Type)
    66  			}
    67  		case "cursor": // for count using aggregate with $collStats
    68  			firstBatch, err := element.Value().Document().LookupErr("firstBatch")
    69  			if err != nil {
    70  				return cr, err
    71  			}
    72  
    73  			// get count value from first batch
    74  			val := firstBatch.Array().Index(0)
    75  			count, err := val.Document().LookupErr("n")
    76  			if err != nil {
    77  				return cr, err
    78  			}
    79  
    80  			// use count as Int64 for result
    81  			var ok bool
    82  			cr.N, ok = count.AsInt64OK()
    83  			if !ok {
    84  				return cr, fmt.Errorf("response field 'n' is type int64, but received BSON type %s",
    85  					element.Value().Type)
    86  			}
    87  		}
    88  	}
    89  	return cr, nil
    90  }
    91  
    92  // NewCount constructs and returns a new Count.
    93  func NewCount() *Count {
    94  	return &Count{}
    95  }
    96  
    97  // Result returns the result of executing this operation.
    98  func (c *Count) Result() CountResult { return c.result }
    99  
   100  func (c *Count) processResponse(info driver.ResponseInfo) error {
   101  	var err error
   102  	c.result, err = buildCountResult(info.ServerResponse)
   103  	return err
   104  }
   105  
   106  // Execute runs this operations and returns an error if the operation did not execute successfully.
   107  func (c *Count) Execute(ctx context.Context) error {
   108  	if c.deployment == nil {
   109  		return errors.New("the Count operation must have a Deployment set before Execute can be called")
   110  	}
   111  
   112  	err := driver.Operation{
   113  		CommandFn:         c.command,
   114  		ProcessResponseFn: c.processResponse,
   115  		RetryMode:         c.retry,
   116  		Type:              driver.Read,
   117  		Client:            c.session,
   118  		Clock:             c.clock,
   119  		CommandMonitor:    c.monitor,
   120  		Crypt:             c.crypt,
   121  		Database:          c.database,
   122  		Deployment:        c.deployment,
   123  		MaxTime:           c.maxTime,
   124  		ReadConcern:       c.readConcern,
   125  		ReadPreference:    c.readPreference,
   126  		Selector:          c.selector,
   127  		ServerAPI:         c.serverAPI,
   128  		Timeout:           c.timeout,
   129  	}.Execute(ctx)
   130  
   131  	// Swallow error if NamespaceNotFound(26) is returned from aggregate on non-existent namespace
   132  	if err != nil {
   133  		dErr, ok := err.(driver.Error)
   134  		if ok && dErr.Code == 26 {
   135  			err = nil
   136  		}
   137  	}
   138  	return err
   139  }
   140  
   141  func (c *Count) command(dst []byte, _ description.SelectedServer) ([]byte, error) {
   142  	dst = bsoncore.AppendStringElement(dst, "count", c.collection)
   143  	if c.query != nil {
   144  		dst = bsoncore.AppendDocumentElement(dst, "query", c.query)
   145  	}
   146  	if c.comment.Type != bsontype.Type(0) {
   147  		dst = bsoncore.AppendValueElement(dst, "comment", c.comment)
   148  	}
   149  	return dst, nil
   150  }
   151  
   152  // MaxTime specifies the maximum amount of time to allow the query to run on the server.
   153  func (c *Count) MaxTime(maxTime *time.Duration) *Count {
   154  	if c == nil {
   155  		c = new(Count)
   156  	}
   157  
   158  	c.maxTime = maxTime
   159  	return c
   160  }
   161  
   162  // Query determines what results are returned from find.
   163  func (c *Count) Query(query bsoncore.Document) *Count {
   164  	if c == nil {
   165  		c = new(Count)
   166  	}
   167  
   168  	c.query = query
   169  	return c
   170  }
   171  
   172  // Session sets the session for this operation.
   173  func (c *Count) Session(session *session.Client) *Count {
   174  	if c == nil {
   175  		c = new(Count)
   176  	}
   177  
   178  	c.session = session
   179  	return c
   180  }
   181  
   182  // ClusterClock sets the cluster clock for this operation.
   183  func (c *Count) ClusterClock(clock *session.ClusterClock) *Count {
   184  	if c == nil {
   185  		c = new(Count)
   186  	}
   187  
   188  	c.clock = clock
   189  	return c
   190  }
   191  
   192  // Collection sets the collection that this command will run against.
   193  func (c *Count) Collection(collection string) *Count {
   194  	if c == nil {
   195  		c = new(Count)
   196  	}
   197  
   198  	c.collection = collection
   199  	return c
   200  }
   201  
   202  // Comment sets a value to help trace an operation.
   203  func (c *Count) Comment(comment bsoncore.Value) *Count {
   204  	if c == nil {
   205  		c = new(Count)
   206  	}
   207  
   208  	c.comment = comment
   209  	return c
   210  }
   211  
   212  // CommandMonitor sets the monitor to use for APM events.
   213  func (c *Count) CommandMonitor(monitor *event.CommandMonitor) *Count {
   214  	if c == nil {
   215  		c = new(Count)
   216  	}
   217  
   218  	c.monitor = monitor
   219  	return c
   220  }
   221  
   222  // Crypt sets the Crypt object to use for automatic encryption and decryption.
   223  func (c *Count) Crypt(crypt driver.Crypt) *Count {
   224  	if c == nil {
   225  		c = new(Count)
   226  	}
   227  
   228  	c.crypt = crypt
   229  	return c
   230  }
   231  
   232  // Database sets the database to run this operation against.
   233  func (c *Count) Database(database string) *Count {
   234  	if c == nil {
   235  		c = new(Count)
   236  	}
   237  
   238  	c.database = database
   239  	return c
   240  }
   241  
   242  // Deployment sets the deployment to use for this operation.
   243  func (c *Count) Deployment(deployment driver.Deployment) *Count {
   244  	if c == nil {
   245  		c = new(Count)
   246  	}
   247  
   248  	c.deployment = deployment
   249  	return c
   250  }
   251  
   252  // ReadConcern specifies the read concern for this operation.
   253  func (c *Count) ReadConcern(readConcern *readconcern.ReadConcern) *Count {
   254  	if c == nil {
   255  		c = new(Count)
   256  	}
   257  
   258  	c.readConcern = readConcern
   259  	return c
   260  }
   261  
   262  // ReadPreference set the read preference used with this operation.
   263  func (c *Count) ReadPreference(readPreference *readpref.ReadPref) *Count {
   264  	if c == nil {
   265  		c = new(Count)
   266  	}
   267  
   268  	c.readPreference = readPreference
   269  	return c
   270  }
   271  
   272  // ServerSelector sets the selector used to retrieve a server.
   273  func (c *Count) ServerSelector(selector description.ServerSelector) *Count {
   274  	if c == nil {
   275  		c = new(Count)
   276  	}
   277  
   278  	c.selector = selector
   279  	return c
   280  }
   281  
   282  // Retry enables retryable mode for this operation. Retries are handled automatically in driver.Operation.Execute based
   283  // on how the operation is set.
   284  func (c *Count) Retry(retry driver.RetryMode) *Count {
   285  	if c == nil {
   286  		c = new(Count)
   287  	}
   288  
   289  	c.retry = &retry
   290  	return c
   291  }
   292  
   293  // ServerAPI sets the server API version for this operation.
   294  func (c *Count) ServerAPI(serverAPI *driver.ServerAPIOptions) *Count {
   295  	if c == nil {
   296  		c = new(Count)
   297  	}
   298  
   299  	c.serverAPI = serverAPI
   300  	return c
   301  }
   302  
   303  // Timeout sets the timeout for this operation.
   304  func (c *Count) Timeout(timeout *time.Duration) *Count {
   305  	if c == nil {
   306  		c = new(Count)
   307  	}
   308  
   309  	c.timeout = timeout
   310  	return c
   311  }