1
0
mirror of https://github.com/mainflux/mainflux.git synced 2025-05-06 19:29:15 +08:00
Aleksandar Novaković 58cdf2cddc MF-312 - Implement basic MongoDB reader (#344)
* Add mongodb reader service

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Add tests for mongodb reader service

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Add documentation for mongodb reader service

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Fix test function name

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>

* Update comment in docker-compose for mongodb-reader service

Signed-off-by: Aleksandar Novakovic <aleksandar.novakovic@mainflux.com>
2018-08-08 13:38:34 +02:00

124 lines
3.1 KiB
Go

// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package mongo
import (
"context"
"errors"
"fmt"
"io"
"net"
"reflect"
"strings"
"github.com/mongodb/mongo-go-driver/bson"
"github.com/mongodb/mongo-go-driver/bson/objectid"
)
// Dialer is used to make network connections.
type Dialer interface {
DialContext(ctx context.Context, network, address string) (net.Conn, error)
}
// TransformDocument handles transforming a document of an allowable type into
// a *bson.Document. This method is called directly after most methods that
// have one or more parameters that are documents.
//
// The supported types for document are:
//
// bson.Marshaler
// bson.DocumentMarshaler
// bson.Reader
// []byte (must be a valid BSON document)
// io.Reader (only 1 BSON document will be read)
// A custom struct type
//
func TransformDocument(document interface{}) (*bson.Document, error) {
switch d := document.(type) {
case nil:
return bson.NewDocument(), nil
case *bson.Document:
return d, nil
case bson.Marshaler, bson.Reader, []byte, io.Reader:
return bson.NewDocumentEncoder().EncodeDocument(document)
case bson.DocumentMarshaler:
return d.MarshalBSONDocument()
default:
var kind reflect.Kind
if t := reflect.TypeOf(document); t.Kind() == reflect.Ptr {
kind = t.Elem().Kind()
}
if reflect.ValueOf(document).Kind() == reflect.Struct || kind == reflect.Struct {
return bson.NewDocumentEncoder().EncodeDocument(document)
}
if reflect.ValueOf(document).Kind() == reflect.Map &&
reflect.TypeOf(document).Key().Kind() == reflect.String {
return bson.NewDocumentEncoder().EncodeDocument(document)
}
return nil, fmt.Errorf("cannot transform type %s to a *bson.Document", reflect.TypeOf(document))
}
}
func ensureID(d *bson.Document) (interface{}, error) {
var id interface{}
elem, err := d.LookupElementErr("_id")
switch {
case err == bson.ErrElementNotFound:
oid := objectid.New()
d.Append(bson.EC.ObjectID("_id", oid))
id = oid
case err != nil:
return nil, err
default:
id = elem
}
return id, nil
}
func ensureDollarKey(doc *bson.Document) error {
if elem, ok := doc.ElementAtOK(0); !ok || !strings.HasPrefix(elem.Key(), "$") {
return errors.New("update document must contain key beginning with '$'")
}
return nil
}
func transformAggregatePipeline(pipeline interface{}) (*bson.Array, error) {
var pipelineArr *bson.Array
switch t := pipeline.(type) {
case *bson.Array:
pipelineArr = t
case []*bson.Document:
pipelineArr = bson.NewArray()
for _, doc := range t {
pipelineArr.Append(bson.VC.Document(doc))
}
case []interface{}:
pipelineArr = bson.NewArray()
for _, val := range t {
doc, err := TransformDocument(val)
if err != nil {
return nil, err
}
pipelineArr.Append(bson.VC.Document(doc))
}
default:
p, err := TransformDocument(pipeline)
if err != nil {
return nil, err
}
pipelineArr = bson.ArrayFromDocument(p)
}
return pipelineArr, nil
}