blob: ba793e15e85f05e308b9ecd40858c39416e08ffa [file] [log] [blame]
Don Newton379ae252019-04-01 12:17:06 -04001// 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 command
8
9import (
10 "context"
11
12 "github.com/mongodb/mongo-go-driver/bson"
13 "github.com/mongodb/mongo-go-driver/mongo/readconcern"
14 "github.com/mongodb/mongo-go-driver/mongo/readpref"
15 "github.com/mongodb/mongo-go-driver/x/bsonx"
16 "github.com/mongodb/mongo-go-driver/x/mongo/driver/session"
17 "github.com/mongodb/mongo-go-driver/x/network/description"
18 "github.com/mongodb/mongo-go-driver/x/network/result"
19 "github.com/mongodb/mongo-go-driver/x/network/wiremessage"
20)
21
22// Distinct represents the disctinct command.
23//
24// The distinct command returns the distinct values for a specified field
25// across a single collection.
26type Distinct struct {
27 NS Namespace
28 Field string
29 Query bsonx.Doc
30 Opts []bsonx.Elem
31 ReadPref *readpref.ReadPref
32 ReadConcern *readconcern.ReadConcern
33 Clock *session.ClusterClock
34 Session *session.Client
35
36 result result.Distinct
37 err error
38}
39
40// Encode will encode this command into a wire message for the given server description.
41func (d *Distinct) Encode(desc description.SelectedServer) (wiremessage.WireMessage, error) {
42 cmd, err := d.encode(desc)
43 if err != nil {
44 return nil, err
45 }
46
47 return cmd.Encode(desc)
48}
49
50// Encode will encode this command into a wire message for the given server description.
51func (d *Distinct) encode(desc description.SelectedServer) (*Read, error) {
52 if err := d.NS.Validate(); err != nil {
53 return nil, err
54 }
55
56 command := bsonx.Doc{{"distinct", bsonx.String(d.NS.Collection)}, {"key", bsonx.String(d.Field)}}
57
58 if d.Query != nil {
59 command = append(command, bsonx.Elem{"query", bsonx.Document(d.Query)})
60 }
61
62 command = append(command, d.Opts...)
63
64 return &Read{
65 Clock: d.Clock,
66 DB: d.NS.DB,
67 ReadPref: d.ReadPref,
68 Command: command,
69 ReadConcern: d.ReadConcern,
70 Session: d.Session,
71 }, nil
72}
73
74// Decode will decode the wire message using the provided server description. Errors during decoding
75// are deferred until either the Result or Err methods are called.
76func (d *Distinct) Decode(desc description.SelectedServer, wm wiremessage.WireMessage) *Distinct {
77 rdr, err := (&Read{}).Decode(desc, wm).Result()
78 if err != nil {
79 d.err = err
80 return d
81 }
82
83 return d.decode(desc, rdr)
84}
85
86func (d *Distinct) decode(desc description.SelectedServer, rdr bson.Raw) *Distinct {
87 d.err = bson.Unmarshal(rdr, &d.result)
88 return d
89}
90
91// Result returns the result of a decoded wire message and server description.
92func (d *Distinct) Result() (result.Distinct, error) {
93 if d.err != nil {
94 return result.Distinct{}, d.err
95 }
96 return d.result, nil
97}
98
99// Err returns the error set on this command.
100func (d *Distinct) Err() error { return d.err }
101
102// RoundTrip handles the execution of this command using the provided wiremessage.ReadWriter.
103func (d *Distinct) RoundTrip(ctx context.Context, desc description.SelectedServer, rw wiremessage.ReadWriter) (result.Distinct, error) {
104 cmd, err := d.encode(desc)
105 if err != nil {
106 return result.Distinct{}, err
107 }
108
109 rdr, err := cmd.RoundTrip(ctx, desc, rw)
110 if err != nil {
111 return result.Distinct{}, err
112 }
113
114 return d.decode(desc, rdr).Result()
115}