SCB-1500 decouple primitive.ObjectID
diff --git a/client/client_test.go b/client/client_test.go
index d92ca14..0d1af45 100644
--- a/client/client_test.go
+++ b/client/client_test.go
@@ -131,7 +131,7 @@
Endpoint: "http://127.0.0.1:30110",
})
It("should be 204", func() {
- err := client3.Delete(context.TODO(), kv.ID.Hex(), "", WithProject("test"))
+ err := client3.Delete(context.TODO(), kv.ID.String(), "", WithProject("test"))
Ω(err).ShouldNot(HaveOccurred())
})
})
diff --git a/go.mod b/go.mod
index b4cffa8..3ad8c09 100644
--- a/go.mod
+++ b/go.mod
@@ -16,6 +16,6 @@
github.com/urfave/cli v1.20.0
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect
github.com/xdg/stringprep v1.0.0 // indirect
- go.mongodb.org/mongo-driver v1.0.0
+ go.mongodb.org/mongo-driver v1.0.3
gopkg.in/yaml.v2 v2.2.1
)
diff --git a/pkg/model/mongodb_doc.go b/pkg/model/mongodb_doc.go
index 5e89975..2879154 100644
--- a/pkg/model/mongodb_doc.go
+++ b/pkg/model/mongodb_doc.go
@@ -17,25 +17,27 @@
package model
-import "go.mongodb.org/mongo-driver/bson/primitive"
+import (
+ "github.com/apache/servicecomb-kie/server/id"
+)
//LabelDoc is database struct to store labels
type LabelDoc struct {
- ID primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
- Labels map[string]string `json:"labels,omitempty"`
- Revision int `json:"revision,omitempty"`
- Domain string `json:"domain,omitempty"` //tenant info
- Project string `json:"project,omitempty"`
+ ID id.ID `json:"_id,omitempty" bson:"_id,omitempty"`
+ Labels map[string]string `json:"labels,omitempty"`
+ Revision int `json:"revision,omitempty"`
+ Domain string `json:"domain,omitempty"` //tenant info
+ Project string `json:"project,omitempty"`
}
//KVDoc is database struct to store kv
type KVDoc struct {
- ID primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
- LabelID string `json:"label_id,omitempty" bson:"label_id,omitempty"`
- Key string `json:"key"`
- Value string `json:"value,omitempty"`
- ValueType string `json:"value_type,omitempty" bson:"value_type,omitempty"` //ini,json,text,yaml,properties
- Checker string `json:"check,omitempty"` //python script
+ ID id.ID `json:"_id,omitempty" bson:"_id,omitempty"`
+ LabelID string `json:"label_id,omitempty" bson:"label_id,omitempty"`
+ Key string `json:"key"`
+ Value string `json:"value,omitempty"`
+ ValueType string `json:"value_type,omitempty" bson:"value_type,omitempty"` //ini,json,text,yaml,properties
+ Checker string `json:"check,omitempty"` //python script
Labels map[string]string `json:"labels,omitempty"` //redundant
Domain string `json:"domain,omitempty"` //redundant
@@ -45,10 +47,10 @@
//LabelRevisionDoc is database struct to store label history stats
type LabelRevisionDoc struct {
- ID primitive.ObjectID `json:"_id,omitempty" bson:"_id,omitempty"`
- LabelID string `json:"label_id,omitempty" bson:"label_id,omitempty"`
- Labels map[string]string `json:"labels,omitempty"`
- Domain string `json:"-"`
- KVs []*KVDoc `json:"data,omitempty"`
- Revision int `json:"revision"`
+ ID id.ID `json:"_id,omitempty" bson:"_id,omitempty"`
+ LabelID string `json:"label_id,omitempty" bson:"label_id,omitempty"`
+ Labels map[string]string `json:"labels,omitempty"`
+ Domain string `json:"-"`
+ KVs []*KVDoc `json:"data,omitempty"`
+ Revision int `json:"revision"`
}
diff --git a/server/id/id.go b/server/id/id.go
new file mode 100644
index 0000000..b48556b
--- /dev/null
+++ b/server/id/id.go
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package id
+
+import (
+ "fmt"
+ "go.mongodb.org/mongo-driver/bson/bsontype"
+ "go.mongodb.org/mongo-driver/bson/primitive"
+ "go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
+)
+
+//ID decouple mongodb
+type ID string
+
+//UnmarshalBSONValue is implement
+func (id *ID) UnmarshalBSONValue(t bsontype.Type, raw []byte) error {
+ if t == bsontype.ObjectID && len(raw) == 12 {
+ var objID primitive.ObjectID
+ copy(objID[:], raw)
+ *id = ID(objID.Hex())
+ return nil
+ } else if t == bsontype.String {
+ if str, _, ok := bsoncore.ReadString(raw); ok {
+ *id = ID(str)
+ return nil
+ }
+ }
+
+ return fmt.Errorf("unable to unmarshal bson id — type: %v, length: %v", len(raw), t)
+}
+
+//String return string
+func (id ID) String() string {
+ return string(id)
+}
diff --git a/server/id/id_test.go b/server/id/id_test.go
new file mode 100644
index 0000000..aa517f8
--- /dev/null
+++ b/server/id/id_test.go
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package id_test
+
+import (
+ "github.com/apache/servicecomb-kie/server/id"
+ "github.com/stretchr/testify/assert"
+ "go.mongodb.org/mongo-driver/bson"
+ "go.mongodb.org/mongo-driver/bson/primitive"
+ "testing"
+)
+
+func TestID_MarshalBSONValue(t *testing.T) {
+ type Obj struct {
+ ID id.ID `bson:"label_id,omitempty"`
+ }
+
+ o := new(Obj)
+ o.ID = id.ID(primitive.NewObjectID().Hex())
+
+ b, err := bson.Marshal(o)
+ assert.NoError(t, err)
+ t.Log(b)
+
+ o2 := new(Obj)
+ err = bson.Unmarshal(b, o2)
+ assert.NoError(t, err)
+ t.Log(o2)
+}
diff --git a/server/service/mongo/history/dao.go b/server/service/mongo/history/dao.go
index f445be0..bd5db63 100644
--- a/server/service/mongo/history/dao.go
+++ b/server/service/mongo/history/dao.go
@@ -33,18 +33,14 @@
//AddHistory increment labels revision and save current label stats to history, then update current revision to db
func AddHistory(ctx context.Context,
labelRevision *model.LabelRevisionDoc, labelID string, kvs []*model.KVDoc) (int, error) {
- c, err := session.GetClient()
- if err != nil {
- return 0, err
- }
labelRevision.Revision = labelRevision.Revision + 1
//save current kv states
labelRevision.KVs = kvs
//clear prev id
- labelRevision.ID = primitive.NilObjectID
- collection := c.Database(session.Name).Collection(session.CollectionLabelRevision)
- _, err = collection.InsertOne(ctx, labelRevision)
+ labelRevision.ID = ""
+ collection := session.GetDB().Collection(session.CollectionLabelRevision)
+ _, err := collection.InsertOne(ctx, labelRevision)
if err != nil {
openlogging.Error(err.Error())
return 0, err
@@ -54,7 +50,7 @@
openlogging.Error(fmt.Sprintf("convert %s,err:%s", labelID, err))
return 0, err
}
- labelCollection := c.Database(session.Name).Collection(session.CollectionLabel)
+ labelCollection := session.GetDB().Collection(session.CollectionLabel)
_, err = labelCollection.UpdateOne(ctx, bson.M{"_id": hex}, bson.D{
{"$set", bson.D{
{"revision", labelRevision.Revision},
@@ -68,11 +64,7 @@
}
func getHistoryByLabelID(ctx context.Context, filter bson.M) ([]*model.LabelRevisionDoc, error) {
- c, err := session.GetClient()
- if err != nil {
- return nil, err
- }
- collection := c.Database(session.Name).Collection(session.CollectionLabelRevision)
+ collection := session.GetDB().Collection(session.CollectionLabelRevision)
cur, err := collection.Find(ctx, filter, options.Find().SetSort(map[string]interface{}{
"revisions": -1,
}))
diff --git a/server/service/mongo/kv/kv_dao.go b/server/service/mongo/kv/kv_dao.go
index f9aef91..c5f534c 100644
--- a/server/service/mongo/kv/kv_dao.go
+++ b/server/service/mongo/kv/kv_dao.go
@@ -20,6 +20,7 @@
import (
"context"
"fmt"
+ "github.com/apache/servicecomb-kie/server/id"
"github.com/apache/servicecomb-kie/server/service"
"github.com/apache/servicecomb-kie/server/service/mongo/label"
"github.com/apache/servicecomb-kie/server/service/mongo/session"
@@ -36,10 +37,6 @@
//and increase revision of label
//and insert key
func createKey(ctx context.Context, kv *model.KVDoc) (*model.KVDoc, error) {
- c, err := session.GetClient()
- if err != nil {
- return nil, err
- }
r, err := label.GetLatestLabel(ctx, kv.LabelID)
if err != nil {
if err != service.ErrRevisionNotExist {
@@ -54,13 +51,13 @@
if r != nil {
r.Revision = r.Revision + 1
}
- collection := c.Database(session.Name).Collection(session.CollectionKV)
+ collection := session.GetDB().Collection(session.CollectionKV)
res, err := collection.InsertOne(ctx, kv)
if err != nil {
return nil, err
}
objectID, _ := res.InsertedID.(primitive.ObjectID)
- kv.ID = objectID
+ kv.ID = id.ID(objectID.Hex())
kvs, err := findKeys(ctx, bson.M{"label_id": kv.LabelID}, true)
//Key may be empty When delete
if err != nil && err != service.ErrKeyNotExists {
@@ -82,11 +79,7 @@
//and increase revision of label
//and updateKeyValue and them add new revision
func updateKeyValue(ctx context.Context, kv *model.KVDoc) (int, error) {
- c, err := session.GetClient()
- if err != nil {
- return 0, err
- }
- collection := c.Database(session.Name).Collection(session.CollectionKV)
+ collection := session.GetDB().Collection(session.CollectionKV)
ur, err := collection.UpdateOne(ctx, bson.M{"key": kv.Key, "label_id": kv.LabelID}, bson.D{
{"$set", bson.D{
{"value", kv.Value},
@@ -118,11 +111,7 @@
}
func findKV(ctx context.Context, domain string, project string, opts service.FindOptions) (*mongo.Cursor, error) {
- c, err := session.GetClient()
- if err != nil {
- return nil, err
- }
- collection := c.Database(session.Name).Collection(session.CollectionKV)
+ collection := session.GetDB().Collection(session.CollectionKV)
ctx, _ = context.WithTimeout(ctx, opts.Timeout)
filter := bson.M{"domain": domain, "project": project}
if opts.Key != "" {
@@ -145,17 +134,13 @@
return cur, err
}
func findOneKey(ctx context.Context, filter bson.M) ([]*model.KVDoc, error) {
- c, err := session.GetClient()
- if err != nil {
- return nil, err
- }
- collection := c.Database(session.Name).Collection(session.CollectionKV)
+ collection := session.GetDB().Collection(session.CollectionKV)
sr := collection.FindOne(ctx, filter)
if sr.Err() != nil {
return nil, sr.Err()
}
curKV := &model.KVDoc{}
- err = sr.Decode(curKV)
+ err := sr.Decode(curKV)
if err != nil {
if err == mongo.ErrNoDocuments {
return nil, service.ErrKeyNotExists
@@ -168,11 +153,7 @@
//deleteKV by kvID
func deleteKV(ctx context.Context, hexID primitive.ObjectID, project string) error {
- c, err := session.GetClient()
- if err != nil {
- return err
- }
- collection := c.Database(session.Name).Collection(session.CollectionKV)
+ collection := session.GetDB().Collection(session.CollectionKV)
dr, err := collection.DeleteOne(ctx, bson.M{"_id": hexID, "project": project})
//check error and delete number
if err != nil {
@@ -187,11 +168,7 @@
return err
}
func findKeys(ctx context.Context, filter bson.M, withoutLabel bool) ([]*model.KVDoc, error) {
- c, err := session.GetClient()
- if err != nil {
- return nil, err
- }
- collection := c.Database(session.Name).Collection(session.CollectionKV)
+ collection := session.GetDB().Collection(session.CollectionKV)
cur, err := collection.Find(ctx, filter)
if err != nil {
if err.Error() == context.DeadlineExceeded.Error() {
diff --git a/server/service/mongo/kv/kv_service.go b/server/service/mongo/kv/kv_service.go
index f9af41c..30477c3 100644
--- a/server/service/mongo/kv/kv_service.go
+++ b/server/service/mongo/kv/kv_service.go
@@ -20,14 +20,15 @@
import (
"context"
"fmt"
- "github.com/apache/servicecomb-kie/server/service"
- "github.com/apache/servicecomb-kie/server/service/mongo/label"
- "github.com/apache/servicecomb-kie/server/service/mongo/session"
+ "github.com/apache/servicecomb-kie/server/id"
"reflect"
"time"
"github.com/apache/servicecomb-kie/pkg/model"
+ "github.com/apache/servicecomb-kie/server/service"
"github.com/apache/servicecomb-kie/server/service/mongo/history"
+ "github.com/apache/servicecomb-kie/server/service/mongo/label"
+ "github.com/apache/servicecomb-kie/server/service/mongo/session"
"github.com/go-mesh/openlogging"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
@@ -74,7 +75,7 @@
}
}
- kv.LabelID = labelID.Hex()
+ kv.LabelID = string(labelID)
if kv.ValueType == "" {
kv.ValueType = session.DefaultValueType
}
@@ -104,7 +105,7 @@
}
//Exist supports you query by label map or labels id
-func (s *Service) Exist(ctx context.Context, domain, key string, project string, options ...service.FindOption) (primitive.ObjectID, error) {
+func (s *Service) Exist(ctx context.Context, domain, key string, project string, options ...service.FindOption) (id.ID, error) {
ctx, _ = context.WithTimeout(context.Background(), session.Timeout)
opts := service.FindOptions{}
for _, o := range options {
@@ -113,16 +114,16 @@
if opts.LabelID != "" {
kvs, err := findKVByLabelID(ctx, domain, opts.LabelID, key, project)
if err != nil {
- return primitive.NilObjectID, err
+ return "", err
}
return kvs[0].ID, nil
}
kvs, err := s.FindKV(ctx, domain, project, service.WithExactLabels(), service.WithLabels(opts.Labels), service.WithKey(key))
if err != nil {
- return primitive.NilObjectID, err
+ return "", err
}
if len(kvs) != 1 {
- return primitive.NilObjectID, session.ErrTooMany
+ return "", session.ErrTooMany
}
return kvs[0].Data[0].ID, nil
diff --git a/server/service/mongo/kv/kv_test.go b/server/service/mongo/kv/kv_test.go
index 70a3bd9..b816aa4 100644
--- a/server/service/mongo/kv/kv_test.go
+++ b/server/service/mongo/kv/kv_test.go
@@ -55,7 +55,7 @@
Expect(err).Should(BeNil())
})
It("should has ID", func() {
- Expect(kv.ID.Hex()).ShouldNot(BeEmpty())
+ Expect(kv.ID.String()).ShouldNot(BeEmpty())
})
})
@@ -80,7 +80,7 @@
Expect(err).Should(BeNil())
})
It("should has ID", func() {
- Expect(kv.ID.Hex()).ShouldNot(BeEmpty())
+ Expect(kv.ID.String()).ShouldNot(BeEmpty())
})
It("should exist", func() {
Expect(oid).ShouldNot(BeEmpty())
@@ -115,13 +115,13 @@
Project: "test",
})
It("should has same id", func() {
- Expect(afterKV.ID.Hex()).Should(Equal(beforeKV.ID.Hex()))
+ Expect(afterKV.ID.String()).Should(Equal(beforeKV.ID.String()))
})
oid, err := kvsvc.Exist(context.Background(), "default", "timeout", "test", service.WithLabels(map[string]string{
"app": "mall",
}))
It("should exists", func() {
- Expect(oid.Hex()).Should(Equal(beforeKV.ID.Hex()))
+ Expect(oid.String()).Should(Equal(beforeKV.ID.String()))
})
kvs, err := kvsvc.FindKV(context.Background(), "default", "test", service.WithKey("timeout"), service.WithLabels(map[string]string{
"app": "mall",
@@ -223,7 +223,7 @@
Expect(err).Should(BeNil())
})
- err = kvsvc.Delete(kv1.ID.Hex(), "", "default", "test")
+ err = kvsvc.Delete(kv1.ID.String(), "", "default", "test")
It("should not return err", func() {
Expect(err).Should(BeNil())
})
@@ -246,7 +246,7 @@
Expect(err).Should(BeNil())
})
- err = kvsvc.Delete(kv1.ID.Hex(), kv1.LabelID, "default", "test")
+ err = kvsvc.Delete(kv1.ID.String(), kv1.LabelID, "default", "test")
It("should not return err", func() {
Expect(err).Should(BeNil())
})
diff --git a/server/service/mongo/label/label_dao.go b/server/service/mongo/label/label_dao.go
index 7e5355c..87149fc 100644
--- a/server/service/mongo/label/label_dao.go
+++ b/server/service/mongo/label/label_dao.go
@@ -21,6 +21,7 @@
"context"
"fmt"
"github.com/apache/servicecomb-kie/pkg/model"
+ "github.com/apache/servicecomb-kie/server/id"
"github.com/apache/servicecomb-kie/server/service"
"github.com/apache/servicecomb-kie/server/service/mongo/session"
"github.com/go-mesh/openlogging"
@@ -36,11 +37,7 @@
//FindLabels find label doc by labels and project, check if the project has certain labels
//if map is empty. will return default labels doc which has no labels
func FindLabels(ctx context.Context, domain, project string, labels map[string]string) (*model.LabelDoc, error) {
- c, err := session.GetClient()
- if err != nil {
- return nil, err
- }
- collection := c.Database(session.Name).Collection(session.CollectionLabel)
+ collection := session.GetDB().Collection(session.CollectionLabel)
filter := bson.M{"domain": domain, "project": project}
for k, v := range labels {
@@ -80,11 +77,7 @@
//GetLatestLabel query revision table and find maximum revision number
func GetLatestLabel(ctx context.Context, labelID string) (*model.LabelRevisionDoc, error) {
- c, err := session.GetClient()
- if err != nil {
- return nil, err
- }
- collection := c.Database(session.Name).Collection(session.CollectionLabelRevision)
+ collection := session.GetDB().Collection(session.CollectionLabelRevision)
filter := bson.M{"label_id": labelID}
@@ -112,16 +105,16 @@
}
//Exist check whether the project has certain label or not and return label ID
-func Exist(ctx context.Context, domain string, project string, labels map[string]string) (primitive.ObjectID, error) {
+func Exist(ctx context.Context, domain string, project string, labels map[string]string) (id.ID, error) {
l, err := FindLabels(ctx, domain, project, labels)
if err != nil {
if err.Error() == context.DeadlineExceeded.Error() {
openlogging.Error("find label failed, dead line exceeded", openlogging.WithTags(openlogging.Tags{
"timeout": session.Timeout,
}))
- return primitive.NilObjectID, fmt.Errorf("operation timout %s", session.Timeout)
+ return "", fmt.Errorf("operation timout %s", session.Timeout)
}
- return primitive.NilObjectID, err
+ return "", err
}
return l.ID, nil
@@ -130,21 +123,17 @@
//CreateLabel create a new label
func CreateLabel(ctx context.Context, domain string, labels map[string]string, project string) (*model.LabelDoc, error) {
- c, err := session.GetClient()
- if err != nil {
- return nil, err
- }
l := &model.LabelDoc{
Domain: domain,
Labels: labels,
Project: project,
}
- collection := c.Database(session.Name).Collection(session.CollectionLabel)
+ collection := session.GetDB().Collection(session.CollectionLabel)
res, err := collection.InsertOne(ctx, l)
if err != nil {
return nil, err
}
objectID, _ := res.InsertedID.(primitive.ObjectID)
- l.ID = objectID
+ l.ID = id.ID(objectID.Hex())
return l, nil
}
diff --git a/server/service/mongo/session/session.go b/server/service/mongo/session/session.go
index f1596bc..1eb43e2 100644
--- a/server/service/mongo/session/session.go
+++ b/server/service/mongo/session/session.go
@@ -24,19 +24,23 @@
"crypto/x509"
"errors"
"fmt"
+ "github.com/apache/servicecomb-kie/pkg/model"
+ "github.com/go-mesh/openlogging"
+ "go.mongodb.org/mongo-driver/bson"
+ "go.mongodb.org/mongo-driver/bson/bsoncodec"
+ "go.mongodb.org/mongo-driver/mongo/options"
"io/ioutil"
+ "reflect"
"sync"
"time"
"github.com/apache/servicecomb-kie/server/config"
- "github.com/go-mesh/openlogging"
"go.mongodb.org/mongo-driver/mongo"
- "go.mongodb.org/mongo-driver/mongo/options"
)
//const for db name and collection name
const (
- Name = "kie"
+ DBName = "kie"
CollectionLabel = "label"
CollectionKV = "kv"
CollectionLabelRevision = "label_revision"
@@ -60,6 +64,7 @@
var client *mongo.Client
var once sync.Once
+var db *mongo.Database
//Timeout db operation time out
var Timeout time.Duration
@@ -76,14 +81,13 @@
if Timeout == 0 {
Timeout = DefaultTimeout
}
- return nil
-}
-
-//GetClient create a new mongo db client
-//if client is created, just return.
-func GetClient() (*mongo.Client, error) {
- var err error
once.Do(func() {
+ sc, _ := bsoncodec.NewStructCodec(bsoncodec.DefaultStructTagParser)
+ reg := bson.NewRegistryBuilder().
+ RegisterEncoder(reflect.TypeOf(model.LabelDoc{}), sc).
+ RegisterEncoder(reflect.TypeOf(model.KVDoc{}), sc).
+ RegisterEncoder(reflect.TypeOf(model.LabelRevisionDoc{}), sc).
+ Build()
clientOps := []*options.ClientOptions{options.Client().ApplyURI(config.GetDB().URI)}
if config.GetDB().SSLEnabled {
if config.GetDB().RootCA == "" {
@@ -115,7 +119,14 @@
return
}
openlogging.Info("DB connected")
+ db = client.Database(DBName, &options.DatabaseOptions{
+ Registry: reg,
+ })
})
+ return nil
+}
- return client, err
+//GetDB get mongo db client
+func GetDB() *mongo.Database {
+ return db
}