...

Source file src/go.mongodb.org/mongo-driver/x/mongo/driver/operation/distinct.go

Documentation: go.mongodb.org/mongo-driver/x/mongo/driver/operation

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

View as plain text