summaryrefslogtreecommitdiff
path: root/src/mongo/gotools/src/github.com/mongodb/mongo-tools/common/json/mongo_extjson.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/gotools/src/github.com/mongodb/mongo-tools/common/json/mongo_extjson.go')
-rw-r--r--src/mongo/gotools/src/github.com/mongodb/mongo-tools/common/json/mongo_extjson.go398
1 files changed, 398 insertions, 0 deletions
diff --git a/src/mongo/gotools/src/github.com/mongodb/mongo-tools/common/json/mongo_extjson.go b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/common/json/mongo_extjson.go
new file mode 100644
index 00000000000..0196c712b80
--- /dev/null
+++ b/src/mongo/gotools/src/github.com/mongodb/mongo-tools/common/json/mongo_extjson.go
@@ -0,0 +1,398 @@
+// Copyright (C) MongoDB, Inc. 2014-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 json
+
+import (
+ "fmt"
+ "gopkg.in/mgo.v2/bson"
+ "reflect"
+)
+
+// Represents base-64 encoded binary data
+type BinData struct {
+ Type byte
+ Base64 string
+}
+
+// Represents the number of milliseconds since the Unix epoch.
+type Date int64
+
+type ISODate string
+
+type ObjectId string
+
+// Represents a reference to another document.
+type DBRef struct {
+ Collection string
+ Id interface{}
+ Database string // optional
+}
+
+// Refers to a document in some namespace by wrapping a string containing the namespace
+// and the objectId in which the _id of the document is contained
+type DBPointer struct {
+ Namespace string
+ Id bson.ObjectId
+}
+
+// Represents the literal MinKey.
+type MinKey struct{}
+
+// Represents the literal MaxKey.
+type MaxKey struct{}
+
+// Represents a signed 32-bit integer.
+type NumberInt int32
+
+// Represents a signed 64-bit integer.
+type NumberLong int64
+
+// Represents a signed 64-bit float.
+type NumberFloat float64
+
+type Decimal128 struct {
+ bson.Decimal128
+}
+
+// Represents a regular expression.
+type RegExp struct {
+ Pattern string
+ Options string
+}
+
+// Represents a timestamp value.
+type Timestamp struct {
+ Seconds uint32
+ Increment uint32
+}
+
+type JavaScript struct {
+ Code string
+ Scope interface{}
+}
+
+type Float float64
+
+// Represents the literal undefined.
+type Undefined struct{}
+
+var (
+ // primitive types
+ byteType = reflect.TypeOf(byte(0))
+ stringType = reflect.TypeOf(string(""))
+ uint32Type = reflect.TypeOf(uint32(0))
+
+ // object types
+ binDataType = reflect.TypeOf(BinData{})
+ dateType = reflect.TypeOf(Date(0))
+ isoDateType = reflect.TypeOf(ISODate(""))
+ dbRefType = reflect.TypeOf(DBRef{})
+ dbPointerType = reflect.TypeOf(DBPointer{})
+ maxKeyType = reflect.TypeOf(MaxKey{})
+ minKeyType = reflect.TypeOf(MinKey{})
+ numberIntType = reflect.TypeOf(NumberInt(0))
+ numberLongType = reflect.TypeOf(NumberLong(0))
+ numberFloatType = reflect.TypeOf(NumberFloat(0))
+ objectIdType = reflect.TypeOf(ObjectId(""))
+ regexpType = reflect.TypeOf(RegExp{})
+ timestampType = reflect.TypeOf(Timestamp{})
+ undefinedType = reflect.TypeOf(Undefined{})
+ orderedBSONType = reflect.TypeOf(bson.D{})
+ interfaceType = reflect.TypeOf((*interface{})(nil))
+)
+
+func (d Date) isFormatable() bool {
+ return int64(d) < int64(32535215999000)
+}
+
+func stateBeginExtendedValue(s *scanner, c int) int {
+ switch c {
+ case 'u': // beginning of undefined
+ s.step = stateU
+ case 'B': // beginning of BinData or Boolean
+ s.step = stateB
+ case 'D': // beginning of Date
+ s.step = stateD
+ case 'I': // beginning of Infinity or ISODate
+ s.step = stateI
+ case 'M': // beginning of MinKey or MaxKey
+ s.step = stateM
+ case 'N': // beginning of NaN or NumberXX
+ s.step = stateUpperN
+ case 'O': // beginning of ObjectId
+ s.step = stateO
+ case 'R': // beginning of RegExp
+ s.step = stateR
+ case 'T': // beginning of Timestamp
+ s.step = stateUpperT
+ case '/': // beginning of /foo/i
+ s.step = stateInRegexpPattern
+ default:
+ return s.error(c, "looking for beginning of value")
+ }
+
+ return scanBeginLiteral
+}
+
+// stateB is the state after reading `B`.
+func stateB(s *scanner, c int) int {
+ if c == 'i' {
+ s.step = stateBi
+ return scanContinue
+ }
+ if c == 'o' {
+ s.step = stateBo
+ return scanContinue
+ }
+ return s.error(c, "in literal BinData or Boolean (expecting 'i' or 'o')")
+}
+
+// stateUpperN is the state after reading `N`.
+func stateUpperN(s *scanner, c int) int {
+ if c == 'a' {
+ s.step = stateUpperNa
+ return scanContinue
+ }
+ if c == 'u' {
+ s.step = stateUpperNu
+ return scanContinue
+ }
+ return s.error(c, "in literal NaN or Number (expecting 'a' or 'u')")
+}
+
+// stateM is the state after reading `M`.
+func stateM(s *scanner, c int) int {
+ if c == 'a' {
+ s.step = stateUpperMa
+ return scanContinue
+ }
+ if c == 'i' {
+ s.step = stateUpperMi
+ return scanContinue
+ }
+ return s.error(c, "in literal MaxKey or MinKey (expecting 'a' or 'i')")
+}
+
+// stateD is the state after reading `D`.
+func stateD(s *scanner, c int) int {
+ switch c {
+ case 'a':
+ s.step = stateDa
+ case 'B':
+ s.step = stateDB
+ case 'b':
+ s.step = stateDb
+ default:
+ return s.error(c, "in literal Date or DBRef (expecting 'a' or 'B')")
+ }
+ return scanContinue
+}
+
+// stateDB is the state after reading `DB`.
+func stateDB(s *scanner, c int) int {
+ if c == 'R' {
+ s.step = stateDBR
+ return scanContinue
+ }
+ if c == 'P' {
+ s.step = stateDBP
+ return scanContinue
+ }
+ return s.error(c, "in state DB (expecting 'R or P')")
+}
+
+// stateI is the state after reading `I`.
+func stateI(s *scanner, c int) int {
+ switch c {
+ case 'n':
+ s.step = stateIn
+ case 'S':
+ s.step = stateIS
+ default:
+ return s.error(c, "in literal Infinity or ISO (expecting 'n' or 'S')")
+ }
+ return scanContinue
+}
+
+// Decodes a literal stored in item into v.
+func (d *decodeState) storeExtendedLiteral(item []byte, v reflect.Value, fromQuoted bool) bool {
+ switch c := item[0]; c {
+ case 'n':
+ d.storeNewLiteral(v, fromQuoted)
+
+ case 'u': // undefined
+ switch kind := v.Kind(); kind {
+ case reflect.Interface:
+ v.Set(reflect.ValueOf(Undefined{}))
+ default:
+ d.error(fmt.Errorf("cannot store %v value into %v type", undefinedType, kind))
+ }
+
+ case 'B': // BinData or Boolean
+ switch item[1] {
+ case 'i': // BinData
+ d.storeBinData(v)
+ case 'o': // Boolean
+ d.storeBoolean(v)
+ }
+ case 'D': // Date, DBRef, DBPointer, Dbpointer,or Dbref
+ switch item[1] {
+ case 'a': // Date
+ d.storeDate(v)
+ case 'b': // Dbref
+ d.storeDBRef(v)
+ case 'B': // DBRef or DBPointer
+ switch item[2] {
+ case 'R': //DBRef
+ d.storeDBRef(v)
+ case 'P': //DBPointer
+ d.storeDBPointer(v)
+ }
+ }
+ case 'I':
+ switch item[1] {
+ case 'S': // ISODate
+ d.storeISODate(v)
+ }
+
+ case 'M': // MinKey or MaxKey
+ switch item[1] {
+ case 'i': // MinKey
+ switch kind := v.Kind(); kind {
+ case reflect.Interface:
+ v.Set(reflect.ValueOf(MinKey{}))
+ default:
+ d.error(fmt.Errorf("cannot store %v value into %v type", minKeyType, kind))
+ }
+ case 'a': // MaxKey
+ switch kind := v.Kind(); kind {
+ case reflect.Interface:
+ v.Set(reflect.ValueOf(MaxKey{}))
+ default:
+ d.error(fmt.Errorf("cannot store %v value into %v type", maxKeyType, kind))
+ }
+ }
+
+ case 'O': // ObjectId
+ d.storeObjectId(v)
+
+ case 'N': // NumberInt or NumberLong
+ switch item[6] {
+ case 'I': // NumberInt
+ d.storeNumberInt(v)
+ case 'L': // NumberLong
+ d.storeNumberLong(v)
+ }
+
+ case 'R': // RegExp constructor
+ d.storeRegexp(v)
+
+ case 'T': // Timestamp
+ d.storeTimestamp(v)
+
+ case '/': // regular expression literal
+ op := d.scanWhile(scanSkipSpace)
+ if op != scanRegexpPattern {
+ d.error(fmt.Errorf("expected beginning of regular expression pattern"))
+ }
+
+ pattern, options, err := d.regexp()
+ if err != nil {
+ d.error(err)
+ }
+ switch kind := v.Kind(); kind {
+ case reflect.Interface:
+ v.Set(reflect.ValueOf(RegExp{pattern, options}))
+ default:
+ d.error(fmt.Errorf("cannot store %v value into %v type", regexpType, kind))
+ }
+
+ default:
+ return false
+ }
+
+ return true
+}
+
+// Returns a literal from the underlying byte data.
+func (d *decodeState) getExtendedLiteral(item []byte) (interface{}, bool) {
+ switch c := item[0]; c {
+ case 'n':
+ return d.getNewLiteral(), true
+
+ case 'u': // undefined
+ return Undefined{}, true
+
+ case 'B': // BinData or Boolean
+ switch item[1] {
+ case 'i': // BinData
+ return d.getBinData(), true
+ case 'o': // Boolean
+ return d.getBoolean(), true
+ }
+
+ case 'D': // Date, DBRef, or Dbref
+ switch item[1] {
+ case 'a': // Date
+ return d.getDate(), true
+ case 'b': // Dbref
+ return d.getDBRef(), true
+ case 'B': // DBRef or DBPoiner
+ switch item[2] {
+ case 'R': // DBRef
+ return d.getDBRef(), true
+ case 'P': // DBPointer
+ return d.getDBPointer(), true
+ }
+ }
+
+ case 'M': // MinKey or MaxKey
+ switch item[1] {
+ case 'i': // MinKey
+ return MinKey{}, true
+ case 'a': // MaxKey
+ return MaxKey{}, true
+ }
+
+ case 'O': // ObjectId
+ return d.getObjectId(), true
+
+ case 'N': // NumberInt or NumberLong
+ switch item[6] {
+ case 'I': // NumberInt
+ return d.getNumberInt(), true
+ case 'L': // NumberLong
+ return d.getNumberLong(), true
+ }
+
+ case 'R': // RegExp constructor
+ return d.getRegexp(), true
+
+ case 'T': // Timestamp
+ return d.getTimestamp(), true
+
+ case 'I': // ISO Date
+ switch item[1] {
+ case 'S': // ISODate
+ return d.getDate(), true
+ }
+
+ case '/': // regular expression literal
+ op := d.scanWhile(scanSkipSpace)
+ if op != scanRegexpPattern {
+ d.error(fmt.Errorf("expected beginning of regular expression pattern"))
+ }
+
+ pattern, options, err := d.regexp()
+ if err != nil {
+ d.error(err)
+ }
+ return RegExp{pattern, options}, true
+ }
+
+ return nil, false
+}