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 mongo
8
9import (
10	"fmt"
11
12	"go.mongodb.org/mongo-driver/bson"
13	"go.mongodb.org/mongo-driver/x/mongo/driver/operation"
14)
15
16// BulkWriteResult is the result type returned by a BulkWrite operation.
17type BulkWriteResult struct {
18	// The number of documents inserted.
19	InsertedCount int64
20
21	// The number of documents matched by filters in update and replace operations.
22	MatchedCount int64
23
24	// The number of documents modified by update and replace operations.
25	ModifiedCount int64
26
27	// The number of documents deleted.
28	DeletedCount int64
29
30	// The number of documents upserted by update and replace operations.
31	UpsertedCount int64
32
33	// A map of operation index to the _id of each upserted document.
34	UpsertedIDs map[int64]interface{}
35}
36
37// InsertOneResult is the result type returned by an InsertOne operation.
38type InsertOneResult struct {
39	// The _id of the inserted document. A value generated by the driver will be of type primitive.ObjectID.
40	InsertedID interface{}
41}
42
43// InsertManyResult is a result type returned by an InsertMany operation.
44type InsertManyResult struct {
45	// The _id values of the inserted documents. Values generated by the driver will be of type primitive.ObjectID.
46	InsertedIDs []interface{}
47}
48
49// DeleteResult is the result type returned by DeleteOne and DeleteMany operations.
50type DeleteResult struct {
51	DeletedCount int64 `bson:"n"` // The number of documents deleted.
52}
53
54// ListDatabasesResult is a result of a ListDatabases operation.
55type ListDatabasesResult struct {
56	// A slice containing one DatabaseSpecification for each database matched by the operation's filter.
57	Databases []DatabaseSpecification
58
59	// The total size of the database files of the returned databases in bytes.
60	// This will be the sum of the SizeOnDisk field for each specification in Databases.
61	TotalSize int64
62}
63
64func newListDatabasesResultFromOperation(res operation.ListDatabasesResult) ListDatabasesResult {
65	var ldr ListDatabasesResult
66	ldr.Databases = make([]DatabaseSpecification, 0, len(res.Databases))
67	for _, spec := range res.Databases {
68		ldr.Databases = append(
69			ldr.Databases,
70			DatabaseSpecification{Name: spec.Name, SizeOnDisk: spec.SizeOnDisk, Empty: spec.Empty},
71		)
72	}
73	ldr.TotalSize = res.TotalSize
74	return ldr
75}
76
77// DatabaseSpecification contains information for a database. This type is returned as part of ListDatabasesResult.
78type DatabaseSpecification struct {
79	Name       string // The name of the database.
80	SizeOnDisk int64  // The total size of the database files on disk in bytes.
81	Empty      bool   // Specfies whether or not the database is empty.
82}
83
84// UpdateResult is the result type returned from UpdateOne, UpdateMany, and ReplaceOne operations.
85type UpdateResult struct {
86	MatchedCount  int64       // The number of documents matched by the filter.
87	ModifiedCount int64       // The number of documents modified by the operation.
88	UpsertedCount int64       // The number of documents upserted by the operation.
89	UpsertedID    interface{} // The _id field of the upserted document, or nil if no upsert was done.
90}
91
92// UnmarshalBSON implements the bson.Unmarshaler interface.
93func (result *UpdateResult) UnmarshalBSON(b []byte) error {
94	elems, err := bson.Raw(b).Elements()
95	if err != nil {
96		return err
97	}
98
99	for _, elem := range elems {
100		switch elem.Key() {
101		case "n":
102			switch elem.Value().Type {
103			case bson.TypeInt32:
104				result.MatchedCount = int64(elem.Value().Int32())
105			case bson.TypeInt64:
106				result.MatchedCount = elem.Value().Int64()
107			default:
108				return fmt.Errorf("Received invalid type for n, should be Int32 or Int64, received %s", elem.Value().Type)
109			}
110		case "nModified":
111			switch elem.Value().Type {
112			case bson.TypeInt32:
113				result.ModifiedCount = int64(elem.Value().Int32())
114			case bson.TypeInt64:
115				result.ModifiedCount = elem.Value().Int64()
116			default:
117				return fmt.Errorf("Received invalid type for nModified, should be Int32 or Int64, received %s", elem.Value().Type)
118			}
119		case "upserted":
120			switch elem.Value().Type {
121			case bson.TypeArray:
122				e, err := elem.Value().Array().IndexErr(0)
123				if err != nil {
124					break
125				}
126				if e.Value().Type != bson.TypeEmbeddedDocument {
127					break
128				}
129				var d struct {
130					ID interface{} `bson:"_id"`
131				}
132				err = bson.Unmarshal(e.Value().Document(), &d)
133				if err != nil {
134					return err
135				}
136				result.UpsertedID = d.ID
137			default:
138				return fmt.Errorf("Received invalid type for upserted, should be Array, received %s", elem.Value().Type)
139			}
140		}
141	}
142
143	return nil
144}
145