diff --git a/ddd/ddd_repository/ddd_mongodb/repository.go b/ddd/ddd_repository/ddd_mongodb/repository.go index 9738b99..2b540c9 100644 --- a/ddd/ddd_repository/ddd_mongodb/repository.go +++ b/ddd/ddd_repository/ddd_mongodb/repository.go @@ -28,15 +28,19 @@ type Repository[T ddd.Entity] struct { } func NewRepository[T ddd.Entity](newFun func() T, mongodb *MongoDB, collection *mongo.Collection) *Repository[T] { - return &Repository[T]{ - newFun: newFun, - collection: collection, - mongodb: mongodb, - } + r := &Repository[T]{} + r.Init(newFun, mongodb, collection) + return r +} + +func (r *Repository[T]) Init(newFun func() T, mongodb *MongoDB, collection *mongo.Collection) { + r.newFun = newFun + r.collection = collection + r.mongodb = mongodb } func (r *Repository[T]) NewEntity() T { - return r.newFun() + return T{} } func (r *Repository[T]) NewEntityList() *[]T { diff --git a/ddd/ddd_repository/ddd_neo4j/base_element.go b/ddd/ddd_repository/ddd_neo4j/base_element.go new file mode 100644 index 0000000..7d0a9a4 --- /dev/null +++ b/ddd/ddd_repository/ddd_neo4j/base_element.go @@ -0,0 +1,61 @@ +package ddd_neo4j + +import "github.com/liuxd6825/dapr-go-ddd-sdk/ddd" + +type ElementEntity interface { + ddd.Entity + SetNid(int2 int64) + GetNid() int64 + + SetLabels([]string) + GetLabels() []string + + GetId() string + SetId(string) + + SetTenantId(string) + GetTenantId() string +} + +type BaseElement struct { + Id string `json:"id"` + TenantId string `json:"tenantId"` + Nid int64 `json:"-"` + Labels []string `json:"-"` +} + +func (b *BaseElement) SetNid(int2 int64) { + b.Nid = int2 +} + +func (b *BaseElement) GetNid() int64 { + return b.Nid +} + +func (b *BaseElement) SetLabels(strings []string) { + b.Labels = strings +} + +func (b *BaseElement) GetLabels() []string { + return b.Labels +} + +func (b *BaseElement) SetTenantId(s string) { + b.TenantId = s +} + +func (b *BaseElement) GetTenantId() string { + return b.TenantId +} + +func (b *BaseElement) SetId(s string) { + b.Id = s +} + +func (b *BaseElement) GetId() string { + return b.Id +} + +func newElementEntity() ElementEntity { + return &BaseElement{} +} diff --git a/ddd/ddd_repository/ddd_neo4j/base_graph.go b/ddd/ddd_repository/ddd_neo4j/base_graph.go new file mode 100644 index 0000000..16d1bdf --- /dev/null +++ b/ddd/ddd_repository/ddd_neo4j/base_graph.go @@ -0,0 +1 @@ +package ddd_neo4j diff --git a/ddd/ddd_repository/ddd_neo4j/base_node.go b/ddd/ddd_repository/ddd_neo4j/base_node.go new file mode 100644 index 0000000..b48ec4c --- /dev/null +++ b/ddd/ddd_repository/ddd_neo4j/base_node.go @@ -0,0 +1,9 @@ +package ddd_neo4j + +type NodeEntity interface { + ElementEntity +} + +type BaseNode struct { + BaseElement +} diff --git a/ddd/ddd_repository/ddd_neo4j/base_node_repository.go b/ddd/ddd_repository/ddd_neo4j/base_node_repository.go new file mode 100644 index 0000000..16d1bdf --- /dev/null +++ b/ddd/ddd_repository/ddd_neo4j/base_node_repository.go @@ -0,0 +1 @@ +package ddd_neo4j diff --git a/ddd/ddd_repository/ddd_neo4j/base_path.go b/ddd/ddd_repository/ddd_neo4j/base_path.go new file mode 100644 index 0000000..16d1bdf --- /dev/null +++ b/ddd/ddd_repository/ddd_neo4j/base_path.go @@ -0,0 +1 @@ +package ddd_neo4j diff --git a/ddd/ddd_repository/ddd_neo4j/base_relationship.go b/ddd/ddd_repository/ddd_neo4j/base_relationship.go new file mode 100644 index 0000000..bb93888 --- /dev/null +++ b/ddd/ddd_repository/ddd_neo4j/base_relationship.go @@ -0,0 +1,49 @@ +package ddd_neo4j + +type RelationshipEntity interface { + ElementEntity + + SetType(string) + GetType() string + + SetStartId(int64) + GetStartId() int64 + + SetEndId(int64) + GetEndId() int64 +} + +func NewRelationshipEntity() RelationshipEntity { + return &BaseRelationship{} +} + +type BaseRelationship struct { + BaseElement + Type string + StartId int64 + EndId int64 +} + +func (b *BaseRelationship) SetType(s string) { + b.Type = s +} + +func (b *BaseRelationship) GetType() string { + return b.Type +} + +func (b *BaseRelationship) SetStartId(i int64) { + b.StartId = i +} + +func (b *BaseRelationship) GetStartId() int64 { + return b.StartId +} + +func (b *BaseRelationship) SetEndId(i int64) { + b.EndId = i +} + +func (b *BaseRelationship) GetEndId() int64 { + return b.EndId +} diff --git a/ddd/ddd_repository/ddd_neo4j/base_relationship_repository.go b/ddd/ddd_repository/ddd_neo4j/base_relationship_repository.go new file mode 100644 index 0000000..16d1bdf --- /dev/null +++ b/ddd/ddd_repository/ddd_neo4j/base_relationship_repository.go @@ -0,0 +1 @@ +package ddd_neo4j diff --git a/ddd/ddd_repository/ddd_neo4j/base_repository.go b/ddd/ddd_repository/ddd_neo4j/base_repository.go new file mode 100644 index 0000000..7bd27db --- /dev/null +++ b/ddd/ddd_repository/ddd_neo4j/base_repository.go @@ -0,0 +1,239 @@ +package ddd_neo4j + +import ( + "context" + "errors" + "github.com/liuxd6825/dapr-go-ddd-sdk/assert" + "github.com/liuxd6825/dapr-go-ddd-sdk/ddd" + "github.com/liuxd6825/dapr-go-ddd-sdk/ddd/ddd_repository" + "github.com/liuxd6825/dapr-go-ddd-sdk/utils/reflectutils" + "github.com/neo4j/neo4j-go-driver/v4/neo4j" + "log" +) + +type Neo4jEntity interface { + ddd.Entity +} + +type BaseRepository[T ElementEntity] struct { + driver neo4j.Driver + cypherBuilder CypherBuilder +} + +type SessionOptions struct { + AccessMode *neo4j.AccessMode +} + +func NewBaseRepository[T ElementEntity](driver neo4j.Driver, builder CypherBuilder) *BaseRepository[T] { + base := &BaseRepository[T]{} + return base.Init(driver, builder) +} + +func (r *BaseRepository[T]) Init(driver neo4j.Driver, builder CypherBuilder) *BaseRepository[T] { + r.driver = driver + r.cypherBuilder = builder + return r +} + +func (r *BaseRepository[T]) Insert(ctx context.Context, entity T, opts ...*ddd_repository.SetOptions) *ddd_repository.SetResult[T] { + cypher, params, err := r.cypherBuilder.CreateOne(ctx, entity) + res, err := r.doSet(ctx, entity.GetTenantId(), cypher, params, opts...) + if err := res.GetOne("", entity); err != nil { + return ddd_repository.NewSetResultError[T](err) + } + return ddd_repository.NewSetResult(entity, err) +} + +func (r *BaseRepository[T]) Update(ctx context.Context, entity T, opts ...*ddd_repository.SetOptions) *ddd_repository.SetResult[T] { + cypher, params, err := r.cypherBuilder.UpdateById(ctx, entity) + res, err := r.doSet(ctx, entity.GetTenantId(), cypher, params, opts...) + if err := res.GetOne("", entity); err != nil { + return ddd_repository.NewSetResultError[T](err) + } + return ddd_repository.NewSetResult(entity, err) +} + +func (r *BaseRepository[T]) UpdateMany(ctx context.Context, list *[]T, opts ...*ddd_repository.SetOptions) *ddd_repository.SetManyResult[T] { + for _, entity := range *list { + if cypher, params, err := r.cypherBuilder.UpdateById(ctx, entity); err != nil { + return ddd_repository.NewSetManyResultError[T](err) + } else { + if res, err := r.doSet(ctx, entity.GetTenantId(), cypher, params, opts...); err != nil { + return ddd_repository.NewSetManyResultError[T](err) + } else if err := res.GetOne("n", entity); err != nil { + return ddd_repository.NewSetManyResultError[T](err) + } + } + } + return ddd_repository.NewSetManyResult(list, nil) +} + +func (r *BaseRepository[T]) DeleteById(ctx context.Context, entity T, opts ...*ddd_repository.SetOptions) *ddd_repository.SetResult[T] { + cypher, params, err := r.cypherBuilder.DeleteById(ctx, entity) + _, err = r.doSet(ctx, entity.GetTenantId(), cypher, params, opts...) + return ddd_repository.NewSetResult(entity, err) +} + +func (r *BaseRepository[T]) FindById(ctx context.Context, tenantId, id string) (T, error) { + var null T + cypher, err := r.cypherBuilder.FindById(ctx, tenantId, id) + if err != nil { + return null, err + } + result, err := r.Query(ctx, cypher) + entity := reflectutils.NewStruct[T]() + if err := result.GetOne("", entity); err != nil { + return null, err + } + return entity.(T), nil +} + +func (r *BaseRepository[T]) doSet(ctx context.Context, tenantId string, cypher string, params map[string]interface{}, opts ...*ddd_repository.SetOptions) (*Result, error) { + if err := assert.NotEmpty(tenantId, assert.NewOptions("tenantId is empty")); err != nil { + return nil, err + } + res, err := r.doSession(ctx, func(tx neo4j.Transaction) (*Result, error) { + r, err := tx.Run(cypher, params) + return NewResult(r), err + }) + return res, err +} + +func (r *BaseRepository[T]) getLabels(entity ElementEntity) string { + label := "" + for _, l := range entity.GetLabels() { + label = label + " :" + l + } + return label +} + +func (r *BaseRepository[T]) Write(ctx context.Context, cypher string) (*Result, error) { + return r.doSession(ctx, func(tx neo4j.Transaction) (*Result, error) { + result, err := tx.Run(cypher, nil) + if err != nil { + return nil, err + } + return NewResult(result), err + }) +} + +func (r *BaseRepository[T]) Query(ctx context.Context, cypher string) (*Result, error) { + var resultData *Result + _, err := r.doSession(ctx, func(tx neo4j.Transaction) (*Result, error) { + result, err := tx.Run(cypher, nil) + if err != nil { + log.Println("wirte to DB with error:", err) + return nil, err + } + resultData = NewResult(result) + return nil, err + }) + return resultData, err +} + +func (r *BaseRepository[T]) doSession(ctx context.Context, fun func(tx neo4j.Transaction) (*Result, error), opts ...*SessionOptions) (*Result, error) { + if fun == nil { + return nil, errors.New("doSession(ctx, fun) fun is nil") + } + if sc, ok := GetSessionContext(ctx); ok { + tx := sc.GetTransaction() + _, err := fun(tx) + return nil, err + } + + opt := NewSessionOptions() + opt.Merge(opts...) + opt.setDefault() + + session := r.driver.NewSession(neo4j.SessionConfig{AccessMode: *opt.AccessMode}) + defer func() { + _ = session.Close() + }() + + var res interface{} + var err error + if *opt.AccessMode == neo4j.AccessModeRead { + res, err = session.ReadTransaction(func(tx neo4j.Transaction) (interface{}, error) { + return fun(tx) + }) + } else if *opt.AccessMode == neo4j.AccessModeWrite { + res, err = session.WriteTransaction(func(tx neo4j.Transaction) (interface{}, error) { + return fun(tx) + }) + } + + if result, ok := res.(*Result); ok { + return result, err + } + + return nil, err +} + +func (r *BaseRepository[T]) FindPaging(ctx context.Context, query ddd_repository.FindPagingQuery, opts ...*ddd_repository.FindOptions) *ddd_repository.FindPagingResult[T] { + /* return r.DoFilter(query.GetTenantId(), query.GetFilter(), func(filter map[string]interface{}) (*ddd_repository.FindPagingResult[T], bool, error) { + if err := assert.NotEmpty(query.GetTenantId(), assert.NewOptions("tenantId is empty")); err != nil { + return nil, false, err + } + + data := r.NewEntityList() + + findOptions := getFindOptions(opts...) + if query.GetPageSize() > 0 { + findOptions.SetLimit(query.GetPageSize()) + findOptions.SetSkip(query.GetPageSize() * query.GetPageNum()) + } + if len(query.GetSort()) > 0 { + sort, err := r.getSort(query.GetSort()) + if err != nil { + return nil, false, err + } + findOptions.SetSort(sort) + } + + cursor, err := r.collection.Find(ctx, filter, findOptions) + if err != nil { + return nil, false, err + } + err = cursor.All(ctx, data) + totalRows, err := r.collection.CountDocuments(ctx, filter) + findData := ddd_repository.NewFindPagingResult[T](data, totalRows, query, err) + return findData, true, err + })*/ + return nil +} + +func (r *BaseRepository[T]) NewSetManyResult(result *Result, err error) *ddd_repository.SetManyResult[T] { + if err != nil { + return ddd_repository.NewSetManyResultError[T](err) + } + var data []T + if err := result.GetList("n", &data); err != nil { + ddd_repository.NewSetResultError[T](err) + } + return ddd_repository.NewSetManyResult[T](&data, err) +} + +func NewSessionOptions() *SessionOptions { + return &SessionOptions{} +} + +func (r *SessionOptions) SetAccessMode(accessMode neo4j.AccessMode) { + r.AccessMode = &accessMode +} + +func (r *SessionOptions) Merge(opts ...*SessionOptions) { + for _, o := range opts { + if o == nil { + continue + } + if o.AccessMode != nil { + r.SetAccessMode(*o.AccessMode) + } + } +} + +func (r *SessionOptions) setDefault() { + if r.AccessMode == nil { + r.SetAccessMode(neo4j.AccessModeWrite) + } +} diff --git a/ddd/ddd_repository/ddd_neo4j/base_repository_test.go b/ddd/ddd_repository/ddd_neo4j/base_repository_test.go new file mode 100644 index 0000000..0a2142c --- /dev/null +++ b/ddd/ddd_repository/ddd_neo4j/base_repository_test.go @@ -0,0 +1,127 @@ +package ddd_neo4j + +import ( + "context" + "github.com/google/uuid" + "github.com/neo4j/neo4j-go-driver/v4/neo4j" + "log" + "testing" +) + +type CompanyNode struct { + BaseNode + CaseId string `json:"caseId"` + GraphId string `json:"graphId"` + IsVisible bool `json:"isVisible"` + Key string `json:"key"` + Name string `json:"name"` +} + +type Rel struct { + BaseRelationship + Id string +} + +var ( + neo4jURL = "bolt://192.168.64.4:7687" + username = "neo4j" + password = "123456" +) + +func CreateDriver(uri, username, password string) (neo4j.Driver, error) { + return neo4j.NewDriver(uri, neo4j.BasicAuth(username, password, "")) +} + +func CloseDriver(driver neo4j.Driver) error { + return driver.Close() +} + +func TestWriteNode(t *testing.T) { + +} + +// Neo4j-测试获取结果集 +func TestGetList(t *testing.T) { + driver, err := CreateDriver(neo4jURL, username, password) + defer func(driver neo4j.Driver) { + err = CloseDriver(driver) + if err != nil { + log.Println("neo4j close error:", err) + } + }(driver) + if err != nil { + log.Println("error connecting to neo4j:", err) + } + + repos := NewBaseRepository[*CompanyNode](driver, NewReflectBuilder()) + cypher := "MATCH (n:graph_T1_N3eb0982799464cf199f2182d130e4a32_company)-[r*0..]->(m) RETURN n, r " + if result, err := repos.Query(context.Background(), cypher); err != nil { + log.Println("error connecting to neo4j:", err) + } else { + var comps []CompanyNode + var rels []Rel + if err := result.GetLists([]string{"n", "r"}, &comps, &rels); err != nil { + t.Error(err) + return + } + log.Printf("rels.length = %d ; company.length=%d", len(comps), len(rels)) + } +} + +type CompanyRepository[T interface{ *CompanyNode }] struct { + BaseRepository[*CompanyNode] +} + +func NewCompanyRepository(driver neo4j.Driver) *CompanyRepository[*CompanyNode] { + resp := &CompanyRepository[*CompanyNode]{} + build := NewReflectBuilder() + resp.Init(driver, build) + return resp +} + +func Test_Insert(t *testing.T) { + driver, err := CreateDriver(neo4jURL, username, password) + defer func(driver neo4j.Driver) { + err = CloseDriver(driver) + if err != nil { + log.Println("neo4j close error:", err) + } + }(driver) + if err != nil { + log.Println("error connecting to neo4j:", err) + } + + company := &CompanyNode{} + company.Id = uuid.New().String() + company.Labels = []string{"TestCompanyNode"} + company.Name = "company" + company.TenantId = "001" + company.CaseId = "caseId001" + company.GraphId = "graphId001" + + repos := NewCompanyRepository(driver) + err = repos.Insert(context.Background(), company).GetError() + if err != nil { + t.Error(err) + } + + company.Key = "keys" + err = repos.Update(context.Background(), company).GetError() + if err != nil { + t.Error(err) + return + } + + if company, err = repos.FindById(context.Background(), company.TenantId, company.Id); err != nil { + t.Error(err) + return + } else { + t.Logf("company.id = %v", company.Id) + } + + err = repos.DeleteById(context.Background(), company).GetError() + if err != nil { + t.Error(err) + } + +} diff --git a/ddd/ddd_repository/ddd_neo4j/context.go b/ddd/ddd_repository/ddd_neo4j/context.go new file mode 100644 index 0000000..4e8b2c4 --- /dev/null +++ b/ddd/ddd_repository/ddd_neo4j/context.go @@ -0,0 +1,46 @@ +package ddd_neo4j + +import ( + "context" + "github.com/neo4j/neo4j-go-driver/v4/neo4j" +) + +type sessionKey struct { +} + +type SessionContext interface { + context.Context + GetSession() neo4j.Session + GetTransaction() neo4j.Transaction +} + +func NewSessionContext(ctx context.Context, tr neo4j.Transaction, session neo4j.Session) SessionContext { + return &sessionContext{ + Context: context.WithValue(ctx, sessionKey{}, session), + tr: tr, + session: session, + } +} + +func GetSessionContext(ctx context.Context) (SessionContext, bool) { + s := ctx.Value(sessionKey{}) + if s == nil { + return nil, false + } + sess, ok := s.(SessionContext) + return sess, ok +} + +type sessionContext struct { + context.Context + tr neo4j.Transaction + session neo4j.Session +} + +func (s *sessionContext) GetSession() neo4j.Session { + return s.session +} + +func (s *sessionContext) GetTransaction() neo4j.Transaction { + return s.tr +} diff --git a/ddd/ddd_repository/ddd_neo4j/cypher_builder.go b/ddd/ddd_repository/ddd_neo4j/cypher_builder.go new file mode 100644 index 0000000..4401e45 --- /dev/null +++ b/ddd/ddd_repository/ddd_neo4j/cypher_builder.go @@ -0,0 +1,152 @@ +package ddd_neo4j + +import ( + "context" + "encoding/json" + "fmt" + "strings" +) + +type CypherBuilder interface { + CreateOne(ctx context.Context, data ElementEntity) (string, map[string]any, error) + UpdateById(ctx context.Context, data ElementEntity, setFields ...string) (string, map[string]any, error) + DeleteById(ctx context.Context, data ElementEntity) (string, map[string]any, error) + CreateMany(ctx context.Context, data ElementEntity) (string, error) + UpdateByIds(ctx context.Context, data ElementEntity) (string, error) + DeleteByIds(ctx context.Context, data ElementEntity) (string, error) + FindById(ctx context.Context, tenantId, id string) (string, error) + FindGraphById(ctx context.Context, data ElementEntity) (string, error) +} + +type ReflectBuilder struct { +} + +func (r *ReflectBuilder) CreateOne(ctx context.Context, data ElementEntity) (string, map[string]any, error) { + prosNames, mapData, err := r.getCreateProperties(ctx, data) + if err != nil { + return "", nil, err + } + labels, _ := r.getLabels(data) + cypher := fmt.Sprintf("CREATE (n%s{%s}) RETURN n ", labels, prosNames) + return cypher, mapData, nil +} + +func (r *ReflectBuilder) UpdateById(ctx context.Context, data ElementEntity, setFields ...string) (string, map[string]any, error) { + prosNames, mapData, err := r.getUpdateProperties(ctx, data, setFields...) + if err != nil { + return "", nil, err + } + cypher := fmt.Sprintf("MATCH (n{id:$id}) SET %s RETURN n ", prosNames) + return cypher, mapData, nil +} + +func (r *ReflectBuilder) DeleteById(ctx context.Context, data ElementEntity) (string, map[string]any, error) { + mapData, err := r.getMap(data) + if err != nil { + return "", nil, err + } + + cypher := fmt.Sprintf("MATCH (n{id:$id}) DETACH DELETE n") + return cypher, mapData, err +} + +func (r *ReflectBuilder) CreateMany(ctx context.Context, data ElementEntity) (string, error) { + //TODO implement me + panic("implement me") +} + +func (r *ReflectBuilder) UpdateByIds(ctx context.Context, data ElementEntity) (string, error) { + //TODO implement me + panic("implement me") +} + +func (r *ReflectBuilder) DeleteByIds(ctx context.Context, data ElementEntity) (string, error) { + //TODO implement me + panic("implement me") +} + +func (r *ReflectBuilder) FindById(ctx context.Context, tenantId, id string) (string, error) { + return fmt.Sprintf("MATCH (n{tenantId:'%v',id:'%v'}) RETURN n", tenantId, id), nil +} + +func (r *ReflectBuilder) FindGraphById(ctx context.Context, data ElementEntity) (string, error) { + //TODO implement me + panic("implement me") +} + +func (r *ReflectBuilder) getCreateProperties(ctx context.Context, data any) (string, map[string]any, error) { + mapData, err := r.getMap(data) + if err != nil { + return "", nil, err + } + var properties string + for k, _ := range mapData { + properties = fmt.Sprintf(`%s%s:$%s,`, properties, k, k) + } + if len(properties) > 0 { + properties = properties[:len(properties)-1] + } + return properties, mapData, nil +} + +func (r *ReflectBuilder) getUpdateProperties(ctx context.Context, data any, setFields ...string) (string, map[string]any, error) { + mapData, err := r.getMap(data) + if err != nil { + return "", nil, err + } + return r.getUpdatePropertiesByMap(ctx, mapData, setFields...) +} + +func (r *ReflectBuilder) getUpdatePropertiesByMap(ctx context.Context, mapData map[string]any, setFields ...string) (string, map[string]any, error) { + var properties string + isSetFields := len(setFields) > 0 + var keyFields map[string]string + if isSetFields { + keyFields = make(map[string]string) + for _, k := range setFields { + keyFields[strings.ToLower(k)] = k + } + } + + for k, _ := range mapData { + if isSetFields { + if _, ok := keyFields[strings.ToLower(k)]; ok { + properties = fmt.Sprintf(`%sn.%s=$%s,`, properties, k, k) + } + } else { + properties = fmt.Sprintf(`%sn.%s=$%s,`, properties, k, k) + } + } + + if len(properties) > 0 { + properties = properties[:len(properties)-1] + } + + return properties, mapData, nil +} + +func (r *ReflectBuilder) getLabels(data any) (string, error) { + var labels string + if element, ok := data.(ElementEntity); ok { + for _, l := range element.GetLabels() { + labels = fmt.Sprintf(":%s ", l) + } + } + return labels, nil +} + +func (r *ReflectBuilder) getMap(data any) (map[string]interface{}, error) { + mapData := make(map[string]any) + bytes, err := json.Marshal(data) + if err != nil { + return nil, err + } + if err := json.Unmarshal(bytes, &mapData); err != nil { + return nil, err + } + return mapData, nil +} + +func NewReflectBuilder() CypherBuilder { + return &ReflectBuilder{} +} diff --git a/ddd/ddd_repository/ddd_neo4j/result.go b/ddd/ddd_repository/ddd_neo4j/result.go new file mode 100644 index 0000000..a258c3a --- /dev/null +++ b/ddd/ddd_repository/ddd_neo4j/result.go @@ -0,0 +1,177 @@ +package ddd_neo4j + +import ( + "fmt" + "github.com/liuxd6825/dapr-go-ddd-sdk/utils/reflectutils" + "github.com/mitchellh/mapstructure" + "github.com/neo4j/neo4j-go-driver/v4/neo4j" + "reflect" +) + +type Result struct { + data map[string][]interface{} +} + +type KeyResult[T interface{}] struct { + result *Result + key string + newEntity func() T + list []T + isInitList bool +} + +func NewResult(result neo4j.Result, keys ...*KeyResult[interface{}]) *Result { + mapList := make(map[string][]interface{}) + init := false + for result.Next() { + record := result.Record() + if !init { + init = true + for _, key := range record.Keys { + mapList[key] = make([]interface{}, 0) + } + } + for _, key := range record.Keys { + list := mapList[key] + if value, ok := record.Get(key); ok { + if items, ok := value.([]interface{}); ok { + for _, item := range items { + list = append(list, item) + } + mapList[key] = list + } else { + mapList[key] = append(list, value) + } + + } + } + } + return &Result{ + data: mapList, + } +} + +func (r *Result) GetLists(keys []string, list ...interface{}) error { + if len(keys) != len(list) { + return fmt.Errorf("GetLists(keys, list...) keys.length != list.length") + } + for i, key := range keys { + l := list[i] + if err := r.GetList(key, l); err != nil { + return fmt.Errorf("error: GetList(key) by key \"%s\"", err.Error()) + } + } + return nil +} + +func (r *Result) GetList(key string, list interface{}) error { + dataList, ok := r.data[key] + if !ok { + return fmt.Errorf("GetList(key, list) key \"%s\" not exist ", key) + } + err := reflectutils.MappingSlice(dataList, list, func(i int, source reflect.Value, target reflect.Value) error { + return r.setEntity(source, target) + }) + if err != nil { + return err + } + + return nil +} + +func (r *Result) GetOne(key string, entity interface{}) error { + var list []any + if len(key) == 0 { + for _, v := range r.data { + list = v + break + } + } else { + neo4jList, ok := r.data[key] + if !ok { + return fmt.Errorf("GetList(key, list) key \"%s\" not exist ", key) + } + list = neo4jList + } + + if len(list) != 1 { + return fmt.Errorf("GetList(key, list) key \"%s\" entity length != 1 not exist ", key) + } + err := reflectutils.MappingStruct(list[0], entity, func(source reflect.Value, target reflect.Value) error { + return r.setEntity(source, target) + }) + if err != nil { + return err + } + + return nil +} + +func (r *Result) AddEntity(key string, value interface{}) []interface{} { + var list []interface{} + if v, ok := r.data[key]; ok { + list = v + } else { + list = make([]interface{}, 0) + r.data[key] = list + } + list = append(list, value) + return list +} + +func (r *Result) setEntity(sourceValue reflect.Value, targetValue reflect.Value) error { + source := sourceValue.Interface() + target := targetValue.Interface() + switch source.(type) { + case neo4j.Node: + node := source.(neo4j.Node) + if err := setNode(target, node); err != nil { + return err + } + break + case neo4j.Relationship: + rel := source.(neo4j.Relationship) + if err := setRelationship(target, rel); err != nil { + return err + } + break + } + return nil +} + +func setNode(data interface{}, node neo4j.Node) error { + if err := mapstructure.Decode(node.Props, data); err != nil { + return err + } + id, isId := node.Props["id"] + tenantId, isTenantId := node.Props["tenantId"] + switch data.(type) { + case ElementEntity: + n := data.(ElementEntity) + n.SetNid(node.Id) + n.SetLabels(node.Labels) + n.SetNid(node.Id) + if isId { + n.SetId(id.(string)) + } + if isTenantId { + n.SetTenantId(tenantId.(string)) + } + } + return nil +} + +func setRelationship(data interface{}, rel neo4j.Relationship) error { + if err := mapstructure.Decode(rel.Props, data); err != nil { + return err + } + if r, ok := data.(RelationshipEntity); ok { + r.SetNid(rel.Id) + r.SetType(rel.Type) + r.SetEndId(rel.EndId) + r.SetStartId(rel.StartId) + } else if e, ok := data.(ElementEntity); ok { + e.SetNid(rel.Id) + } + return nil +} diff --git a/ddd/ddd_repository/ddd_neo4j/rsql_process.go b/ddd/ddd_repository/ddd_neo4j/rsql_process.go new file mode 100644 index 0000000..16d1bdf --- /dev/null +++ b/ddd/ddd_repository/ddd_neo4j/rsql_process.go @@ -0,0 +1 @@ +package ddd_neo4j diff --git a/ddd/ddd_repository/ddd_neo4j/session.go b/ddd/ddd_repository/ddd_neo4j/session.go new file mode 100644 index 0000000..3518fef --- /dev/null +++ b/ddd/ddd_repository/ddd_neo4j/session.go @@ -0,0 +1,53 @@ +package ddd_neo4j + +import ( + "context" + "github.com/liuxd6825/dapr-go-ddd-sdk/ddd/ddd_repository" + "github.com/neo4j/neo4j-go-driver/v4/neo4j" +) + +type Neo4jSession struct { + driver neo4j.Driver + sessionConfig neo4j.SessionConfig +} + +func NewWriteSession(driver neo4j.Driver) *Neo4jSession { + return &Neo4jSession{ + driver: driver, + sessionConfig: neo4j.SessionConfig{AccessMode: neo4j.AccessModeWrite}, + } +} + +func NewReadSession(driver neo4j.Driver) *Neo4jSession { + return &Neo4jSession{ + driver: driver, + sessionConfig: neo4j.SessionConfig{AccessMode: neo4j.AccessModeRead}, + } +} + +func (r *Neo4jSession) UseTransaction(ctx context.Context, dbFunc ddd_repository.SessionFunc) error { + session := r.driver.NewSession(r.sessionConfig) + defer func() { + _ = session.Close() + }() + + _, err := session.WriteTransaction(func(tx neo4j.Transaction) (res interface{}, resErr error) { + defer func() { + if e := recover(); e != nil { + if err, ok := e.(error); ok { + resErr = err + } + } + }() + sessCtx := NewSessionContext(ctx, tx, session) + if dbFunc == nil { + return nil, nil + } + err := dbFunc(sessCtx) + if err != nil { + return nil, tx.Rollback() + } + return nil, tx.Commit() + }) + return err +} diff --git a/go.mod b/go.mod index 19516ee..b24e5f1 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,8 @@ require ( github.com/liuxd6825/dapr v1.7.1-1.0-alpha2 github.com/liuxd6825/go-sdk v1.7.1-1.0-alpha2 github.com/mitchellh/mapstructure v1.4.1 + github.com/neo4j/neo4j-go-driver/v4 v4.4.3 + github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.8.1 github.com/stretchr/testify v1.7.0 go.mongodb.org/mongo-driver v1.9.1 @@ -70,7 +72,6 @@ require ( github.com/nats-io/nats.go v1.15.0 // indirect github.com/nats-io/nkeys v0.3.0 // indirect github.com/nats-io/nuid v1.0.1 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/schollz/closestmatch v2.1.0+incompatible // indirect @@ -106,5 +107,7 @@ require ( //replace github.com/liuxd6825/components-contrib => gitee.com/liuxd6825/components-contrib v1.7.1-1.0-alpha replace github.com/liuxd6825/dapr => ../dapr + replace github.com/liuxd6825/go-sdk => ../go-sdk + replace github.com/liuxd6825/components-contrib => ../components-contrib diff --git a/go.sum b/go.sum index 8bf946d..3a1d220 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,5 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -gitee.com/liuxd6825/dapr v1.7.1-1.0-alpha2 h1:i89NDV4NBgoX37TCTyjJByHCwvz8FH/KsMtEBmzkSjo= -gitee.com/liuxd6825/dapr v1.7.1-1.0-alpha2/go.mod h1:ruZ65U/wrX53WAZS4ioXTvc0NYPZM7xzLi2uVCh8QYo= -gitee.com/liuxd6825/go-sdk v1.7.1-1.0-alpha2 h1:gpguKRJDtDZmpovPPGQI7LDP1JHAlrghKENJRJof1K0= -gitee.com/liuxd6825/go-sdk v1.7.1-1.0-alpha2/go.mod h1:/oX313iUSjgpCFf2cuEw7W8eLuQOA12N600wIEhxj+g= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU= @@ -74,6 +70,7 @@ github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0Hw= github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -114,6 +111,7 @@ github.com/go-playground/validator/v10 v10.11.0 h1:0W+xRM511GY47Yy3bZUbJVitCNg2B github.com/go-playground/validator/v10 v10.11.0/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= @@ -168,6 +166,7 @@ github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= @@ -269,7 +268,18 @@ github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8= github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/neo4j/neo4j-go-driver/v4 v4.4.3 h1:uIP106GZwdWjbJY6jxRavHVPeUWKMTcR+cq255EAjXk= +github.com/neo4j/neo4j-go-driver/v4 v4.4.3/go.mod h1:NexOfrm4c317FVjekrhVV8pHBXgtMG5P6GeweJWCyo4= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -357,6 +367,7 @@ github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.mongodb.org/mongo-driver v1.9.1 h1:m078y9v7sBItkt1aaoe2YlvWEXcD263e1a4E1fBrJ1c= go.mongodb.org/mongo-driver v1.9.1/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= @@ -380,10 +391,12 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -397,10 +410,13 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= @@ -412,9 +428,11 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -423,10 +441,15 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -434,6 +457,7 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -460,6 +484,7 @@ golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8= golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= @@ -504,15 +529,19 @@ gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/utils/reflectutils/reflectutils.go b/utils/reflectutils/reflectutils.go index 5fbf94c..3c6954c 100644 --- a/utils/reflectutils/reflectutils.go +++ b/utils/reflectutils/reflectutils.go @@ -151,7 +151,20 @@ func New(t reflect.Type) reflect.Value { if t.Kind() == reflect.Ptr { elem := reflect.New(t.Elem()) r := reflect.New(t) - r.Elem().Set(elem) + r.Set(elem) + return r } return reflect.New(t) } + +func NewStruct[T interface{}]() interface{} { + var t T + v := New(reflect.TypeOf(t)) + return v.Elem().Interface() +} + +func NewSlice[T interface{}]() interface{} { + var t T + v := New(reflect.TypeOf(t)) + return v.Elem().Interface() +}