blob: f19711386dd200016232adea1e414d55487bf420 [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 wiremessage
8
9import (
10 "errors"
11 "fmt"
12 "github.com/mongodb/mongo-go-driver/x/bsonx"
13 "strings"
14)
15
16// GetMore represents the OP_GET_MORE message of the MongoDB wire protocol.
17type GetMore struct {
18 MsgHeader Header
19 Zero int32
20 FullCollectionName string
21 NumberToReturn int32
22 CursorID int64
23}
24
25// MarshalWireMessage implements the Marshaler and WireMessage interfaces.
26func (gm GetMore) MarshalWireMessage() ([]byte, error) {
27 b := make([]byte, 0, gm.Len())
28 return gm.AppendWireMessage(b)
29}
30
31// ValidateWireMessage implements the Validator and WireMessage interfaces.
32func (gm GetMore) ValidateWireMessage() error {
33 if int(gm.MsgHeader.MessageLength) != gm.Len() {
34 return errors.New("incorrect header: message length is not correct")
35 }
36 if gm.MsgHeader.OpCode != OpGetMore {
37 return errors.New("incorrect header: op code is not OpGetMore")
38 }
39 if strings.Index(gm.FullCollectionName, ".") == -1 {
40 return errors.New("incorrect header: collection name does not contain a dot")
41 }
42
43 return nil
44}
45
46// AppendWireMessage implements the Appender and WireMessage interfaces.
47//
48// AppendWireMessage will set the MessageLength property of the MsgHeader
49// if it is zero. It will also set the OpCode to OpGetMore if the OpCode is
50// zero. If either of these properties are non-zero and not correct, this
51// method will return both the []byte with the wire message appended to it
52// and an invalid header error.
53func (gm GetMore) AppendWireMessage(b []byte) ([]byte, error) {
54 var err error
55 err = gm.MsgHeader.SetDefaults(gm.Len(), OpGetMore)
56
57 b = gm.MsgHeader.AppendHeader(b)
58 b = appendInt32(b, gm.Zero)
59 b = appendCString(b, gm.FullCollectionName)
60 b = appendInt32(b, gm.NumberToReturn)
61 b = appendInt64(b, gm.CursorID)
62 return b, err
63}
64
65// String implements the fmt.Stringer interface.
66func (gm GetMore) String() string {
67 return fmt.Sprintf(
68 `OP_GET_MORE{MsgHeader: %s, Zero: %d, FullCollectionName: %s, NumberToReturn: %d, CursorID: %d}`,
69 gm.MsgHeader, gm.Zero, gm.FullCollectionName, gm.NumberToReturn, gm.CursorID,
70 )
71}
72
73// Len implements the WireMessage interface.
74func (gm GetMore) Len() int {
75 // Header + Zero + CollectionName + Null Terminator + Return + CursorID
76 return 16 + 4 + len(gm.FullCollectionName) + 1 + 4 + 8
77}
78
79// UnmarshalWireMessage implements the Unmarshaler interface.
80func (gm *GetMore) UnmarshalWireMessage([]byte) error {
81 panic("not implemented")
82}
83
84// CommandDocument creates a BSON document representing this command.
85func (gm GetMore) CommandDocument() bsonx.Doc {
86 parts := strings.Split(gm.FullCollectionName, ".")
87 collName := parts[len(parts)-1]
88
89 doc := bsonx.Doc{
90 {"getMore", bsonx.Int64(gm.CursorID)},
91 {"collection", bsonx.String(collName)},
92 }
93 if gm.NumberToReturn != 0 {
94 doc = doc.Append("batchSize", bsonx.Int32(gm.NumberToReturn))
95 }
96
97 return doc
98}
99
100// DatabaseName returns the name of the database for this command.
101func (gm GetMore) DatabaseName() string {
102 return strings.Split(gm.FullCollectionName, ".")[0]
103}