From bc94f2b188e6e45f2bfa8d9cc7deb4d69cc12dcf Mon Sep 17 00:00:00 2001 From: mr Date: Mon, 26 Jan 2026 10:36:15 +0100 Subject: [PATCH] Adjust Mongo --- dbs/dbs.go | 119 +++++++++++------------- dbs/mongo/mongo.go | 25 +---- models/resources/interfaces.go | 5 + models/resources/native_tools.go | 4 + models/resources/resource.go | 68 ++++++++++++-- models/resources/tests/resource_test.go | 4 + models/resources/workflow.go | 4 + 7 files changed, 133 insertions(+), 96 deletions(-) diff --git a/dbs/dbs.go b/dbs/dbs.go index ce4fdef..36bcc83 100644 --- a/dbs/dbs.go +++ b/dbs/dbs.go @@ -2,6 +2,7 @@ package dbs import ( "fmt" + "runtime/debug" "strings" "go.mongodb.org/mongo-driver/bson" @@ -19,6 +20,7 @@ const ( GT EQUAL NOT + ELEMMATCH ) var str = [...]string{ @@ -31,87 +33,37 @@ var str = [...]string{ "gt", "equal", "not", + "elemMatch", } func (m Operator) String() string { return str[m] } -func (m Operator) ToMongoEOperator(k string, value interface{}) bson.E { - defer func() { - if r := recover(); r != nil { - fmt.Println("Recovered. Error:\n", r) - } - }() - defaultValue := bson.E{Key: k, Value: bson.M{"$regex": ToValueOperator(StringToOperator(m.String()), value)}} - switch m { - case LIKE: - return bson.E{Key: k, Value: bson.M{"$regex": ToValueOperator(StringToOperator(m.String()), value)}} - case EXISTS: - return bson.E{Key: k, Value: bson.M{"$exists": ToValueOperator(StringToOperator(m.String()), value)}} - case IN: - return bson.E{Key: k, Value: bson.M{"$in": ToValueOperator(StringToOperator(m.String()), value)}} - case GTE: - return bson.E{Key: k, Value: bson.M{"$gte": ToValueOperator(StringToOperator(m.String()), value)}} - case GT: - return bson.E{Key: k, Value: bson.M{"$gt": ToValueOperator(StringToOperator(m.String()), value)}} - case LTE: - return bson.E{Key: k, Value: bson.M{"$lte": ToValueOperator(StringToOperator(m.String()), value)}} - case LT: - return bson.E{Key: k, Value: bson.M{"$lt": ToValueOperator(StringToOperator(m.String()), value)}} - case EQUAL: - return bson.E{Key: k, Value: value} - case NOT: - v := value.(Filters) - orList := bson.A{} - andList := bson.A{} - f := bson.D{} - for k, filter := range v.Or { - for _, ff := range filter { - orList = append(orList, StringToOperator(ff.Operator).ToMongoOperator(k, ff.Value)) - } - } - for k, filter := range v.And { - for _, ff := range filter { - andList = append(andList, StringToOperator(ff.Operator).ToMongoOperator(k, ff.Value)) - } - } - if len(orList) > 0 && len(andList) == 0 { - f = bson.D{{"$or", orList}} - } else { - if len(orList) > 0 { - andList = append(andList, bson.M{"$or": orList}) - } - f = bson.D{{"$and", andList}} - } - return bson.E{Key: "$not", Value: f} - default: - return defaultValue - } -} - func (m Operator) ToMongoOperator(k string, value interface{}) bson.M { defer func() { if r := recover(); r != nil { - fmt.Println("Recovered. Error:\n", r) + fmt.Println("Recovered. Error:\n", r, debug.Stack()) } }() - defaultValue := bson.M{k: bson.M{"$regex": ToValueOperator(StringToOperator(m.String()), value)}} + defaultValue := bson.M{k: bson.M{"$regex": m.ToValueOperator(StringToOperator(m.String()), value)}} switch m { case LIKE: - return bson.M{k: bson.M{"$regex": ToValueOperator(StringToOperator(m.String()), value)}} + return bson.M{k: bson.M{"$regex": m.ToValueOperator(StringToOperator(m.String()), value)}} case EXISTS: - return bson.M{k: bson.M{"$exists": ToValueOperator(StringToOperator(m.String()), value)}} + return bson.M{k: bson.M{"$exists": m.ToValueOperator(StringToOperator(m.String()), value)}} case IN: - return bson.M{k: bson.M{"$in": ToValueOperator(StringToOperator(m.String()), value)}} + return bson.M{k: bson.M{"$in": m.ToValueOperator(StringToOperator(m.String()), value)}} case GTE: - return bson.M{k: bson.M{"$gte": ToValueOperator(StringToOperator(m.String()), value)}} + return bson.M{k: bson.M{"$gte": m.ToValueOperator(StringToOperator(m.String()), value)}} case GT: - return bson.M{k: bson.M{"$gt": ToValueOperator(StringToOperator(m.String()), value)}} + return bson.M{k: bson.M{"$gt": m.ToValueOperator(StringToOperator(m.String()), value)}} case LTE: - return bson.M{k: bson.M{"$lte": ToValueOperator(StringToOperator(m.String()), value)}} + return bson.M{k: bson.M{"$lte": m.ToValueOperator(StringToOperator(m.String()), value)}} case LT: - return bson.M{k: bson.M{"$lt": ToValueOperator(StringToOperator(m.String()), value)}} + return bson.M{k: bson.M{"$lt": m.ToValueOperator(StringToOperator(m.String()), value)}} + case ELEMMATCH: + return bson.M{k: bson.M{"$elemMatch": m.ToValueOperator(StringToOperator(m.String()), value)}} case EQUAL: return bson.M{k: value} case NOT: @@ -152,13 +104,46 @@ func StringToOperator(s string) Operator { return LIKE } -func ToValueOperator(operator Operator, value interface{}) interface{} { - if strings.TrimSpace(fmt.Sprintf("%v", value)) == "*" { - value = "" +func GetBson(filters *Filters) bson.D { + f := bson.D{} + orList := bson.A{} + andList := bson.A{} + if filters != nil { + for k, filter := range filters.Or { + for _, ff := range filter { + orList = append(orList, StringToOperator(ff.Operator).ToMongoOperator(k, ff.Value)) + } + } + for k, filter := range filters.And { + for _, ff := range filter { + andList = append(andList, StringToOperator(ff.Operator).ToMongoOperator(k, ff.Value)) + } + } + if len(orList) > 0 && len(andList) == 0 { + f = bson.D{{"$or", orList}} + } else { + if len(orList) > 0 { + andList = append(andList, bson.M{"$or": orList}) + } + f = bson.D{{"$and", andList}} + } } - if operator == LIKE { - return "(?i).*" + strings.TrimSpace(fmt.Sprintf("%v", value)) + ".*" + return f +} + +func (m Operator) ToValueOperator(operator Operator, value interface{}) interface{} { + switch value.(type) { + case *Filters: + return GetBson(value.(*Filters)) + default: + if strings.TrimSpace(fmt.Sprintf("%v", value)) == "*" { + value = "" + } + if operator == LIKE { + return "(?i).*" + strings.TrimSpace(fmt.Sprintf("%v", value)) + ".*" + } } + return value } diff --git a/dbs/mongo/mongo.go b/dbs/mongo/mongo.go index 76f0877..9234006 100644 --- a/dbs/mongo/mongo.go +++ b/dbs/mongo/mongo.go @@ -289,29 +289,8 @@ func (m *MongoDB) Search(filters *dbs.Filters, collection_name string) (*mongo.C opts := options.Find() opts.SetLimit(1000) targetDBCollection := CollectionMap[collection_name] - orList := bson.A{} - andList := bson.A{} - f := bson.D{} - if filters != nil { - for k, filter := range filters.Or { - for _, ff := range filter { - orList = append(orList, dbs.StringToOperator(ff.Operator).ToMongoOperator(k, ff.Value)) - } - } - for k, filter := range filters.And { - for _, ff := range filter { - andList = append(andList, dbs.StringToOperator(ff.Operator).ToMongoOperator(k, ff.Value)) - } - } - if len(orList) > 0 && len(andList) == 0 { - f = bson.D{{"$or", orList}} - } else { - if len(orList) > 0 { - andList = append(andList, bson.M{"$or": orList}) - } - f = bson.D{{"$and", andList}} - } - } + + f := dbs.GetBson(filters) MngoCtx, cancel = context.WithTimeout(context.Background(), 5*time.Second) // defer cancel() diff --git a/models/resources/interfaces.go b/models/resources/interfaces.go index 48b9b61..dcb4d10 100755 --- a/models/resources/interfaces.go +++ b/models/resources/interfaces.go @@ -1,6 +1,7 @@ package resources import ( + "cloud.o-forge.io/core/oc-lib/dbs" "cloud.o-forge.io/core/oc-lib/models/booking" "cloud.o-forge.io/core/oc-lib/models/common/pricing" "cloud.o-forge.io/core/oc-lib/models/utils" @@ -10,6 +11,7 @@ import ( type ResourceInterface interface { utils.DBObject Trim() + FilterPeer(peerID string) *dbs.Filters GetBookingModes() map[booking.BookingMode]*pricing.PricingVariation ConvertToPricedResource(t tools.DataType, a *int, selectedPartnership *int, selectedBuyingStrategy *int, selectedStrategy *int, b *int, request *tools.APIRequest) (pricing.PricedItemITF, error) GetType() string @@ -17,6 +19,7 @@ type ResourceInterface interface { ClearEnv() utils.DBObject SetAllowedInstances(request *tools.APIRequest) AddInstances(instance ResourceInstanceITF) + RefineResourceByPartnership(peerID string) ResourceInterface } type ResourceInstanceITF interface { @@ -29,9 +32,11 @@ type ResourceInstanceITF interface { GetPricingsProfiles(peerID string, groups []string) []pricing.PricingProfileITF GetPeerGroups() ([]ResourcePartnerITF, []map[string][]string) ClearPeerGroups() + RefineResourceByPartnership(peerID string) (ResourceInstanceITF, bool) } type ResourcePartnerITF interface { + RefineResourceByPartnership(peerID string) (ResourcePartnerITF, bool) GetPricingsProfiles(peerID string, groups []string) []pricing.PricingProfileITF GetPeerGroups() map[string][]string ClearPeerGroups() diff --git a/models/resources/native_tools.go b/models/resources/native_tools.go index 98bfd49..37c6d77 100644 --- a/models/resources/native_tools.go +++ b/models/resources/native_tools.go @@ -55,6 +55,10 @@ func (w *NativeTool) ConvertToPricedResource(t tools.DataType, selectedInstance }, nil } +func (abs *NativeTool) RefineResourceByPartnership(peerID string) ResourceInterface { + return abs +} + func InitNative() { for _, kind := range []native_tools.NativeToolsEnum{native_tools.WORKFLOW_EVENT} { newNative := &NativeTool{} diff --git a/models/resources/resource.go b/models/resources/resource.go index 1916fdd..0cdc4a1 100755 --- a/models/resources/resource.go +++ b/models/resources/resource.go @@ -5,6 +5,7 @@ import ( "slices" "cloud.o-forge.io/core/oc-lib/config" + "cloud.o-forge.io/core/oc-lib/dbs" "cloud.o-forge.io/core/oc-lib/models/booking" "cloud.o-forge.io/core/oc-lib/models/common/models" "cloud.o-forge.io/core/oc-lib/models/common/pricing" @@ -27,6 +28,10 @@ type AbstractResource struct { AllowedBookingModes map[booking.BookingMode]*pricing.PricingVariation `bson:"allowed_booking_modes" json:"allowed_booking_modes"` } +func (abs *AbstractResource) FilterPeer(peerID string) *dbs.Filters { + return nil +} + func (r *AbstractResource) GetBookingModes() map[booking.BookingMode]*pricing.PricingVariation { if len(r.AllowedBookingModes) == 0 { return map[booking.BookingMode]*pricing.PricingVariation{ @@ -68,6 +73,35 @@ type AbstractInstanciatedResource[T ResourceInstanceITF] struct { Instances []T `json:"instances,omitempty" bson:"instances,omitempty"` // Bill is the bill of the resource // Bill is the bill of the resource } +// PEERID found +func (abs *AbstractInstanciatedResource[T]) RefineResourceByPartnership(peerID string) ResourceInterface { + instances := []T{} + for _, i := range instances { + i, ok := i.RefineResourceByPartnership(peerID) + if ok { + instances = append(instances, i.(T)) + } + } + abs.Instances = instances + return abs +} + +func (abs *AbstractInstanciatedResource[T]) FilterPeer(peerID string) *dbs.Filters { + return &dbs.Filters{ + And: map[string][]dbs.Filter{ + "instances": {{Operator: dbs.ELEMMATCH.String(), Value: &dbs.Filters{ + And: map[string][]dbs.Filter{ + "partnerships": {{Operator: dbs.ELEMMATCH.String(), Value: &dbs.Filters{ + And: map[string][]dbs.Filter{ + "peer_groups." + peerID: {{Operator: dbs.EXISTS.String(), Value: true}}, + }, + }}}, + }, + }}}, + }, + } +} + func (abs *AbstractInstanciatedResource[T]) AddInstances(instance ResourceInstanceITF) { abs.Instances = append(abs.Instances, instance.(T)) } @@ -132,7 +166,7 @@ func (abs *AbstractInstanciatedResource[T]) SetAllowedInstances(request *tools.A if request != nil && request.PeerID == abs.CreatorID && request.PeerID != "" { return } - abs.Instances = VerifyAuthAction[T](abs.Instances, request) + abs.Instances = VerifyAuthAction(abs.Instances, request) } func (d *AbstractInstanciatedResource[T]) Trim() { @@ -145,7 +179,7 @@ func (d *AbstractInstanciatedResource[T]) Trim() { } func (abs *AbstractInstanciatedResource[T]) VerifyAuth(callName string, request *tools.APIRequest) bool { - return len(VerifyAuthAction[T](abs.Instances, request)) > 0 || abs.AbstractObject.VerifyAuth(callName, request) + return len(VerifyAuthAction(abs.Instances, request)) > 0 || abs.AbstractObject.VerifyAuth(callName, request) } func VerifyAuthAction[T ResourceInstanceITF](baseInstance []T, request *tools.APIRequest) []T { @@ -186,10 +220,6 @@ type ResourceInstance[T ResourcePartnerITF] struct { Inputs []models.Param `json:"inputs,omitempty" bson:"inputs,omitempty"` Outputs []models.Param `json:"outputs,omitempty" bson:"outputs,omitempty"` - // SelectedPartnershipIndex int `json:"selected_partnership_index,omitempty" bson:"selected_partnership_index,omitempty"` - // SelectedBuyingStrategy int `json:"selected_buying_strategy,omitempty" bson:"selected_buying_strategy,omitempty"` - // SelectedStrategy int `json:"selected_strategy,omitempty" bson:"selected_strategy,omitempty"` - Partnerships []T `json:"partnerships,omitempty" bson:"partnerships,omitempty"` } @@ -205,6 +235,19 @@ func NewInstance[T ResourcePartnerITF](name string) *ResourceInstance[T] { } } +func (abs *ResourceInstance[T]) RefineResourceByPartnership(peerID string) (ResourceInstanceITF, bool) { + okk := false + partners := []T{} + for _, p := range abs.Partnerships { + partner, ok := p.RefineResourceByPartnership(peerID) + if ok { + partners = append(partners, partner.(T)) + okk = true + } + } + return abs, okk +} + func (ri *ResourceInstance[T]) ClearEnv() { ri.Env = []models.Param{} ri.Inputs = []models.Param{} @@ -267,6 +310,19 @@ type ResourcePartnerShip[T pricing.PricingProfileITF] struct { // to upgrade pricing profiles. to be a map BuyingStrategy, map of Strategy } +func (ri *ResourcePartnerShip[T]) RefineResourceByPartnership(peerID string) (ResourcePartnerITF, bool) { + ok := false + peerGrp := map[string][]string{} + for k, v := range ri.PeerGroups { + if k == peerID { + peerGrp[k] = v + ok = true + } + } + ri.PeerGroups = peerGrp + return ri, ok +} + func (ri *ResourcePartnerShip[T]) GetProfile(buying *int, strategy *int) pricing.PricingProfileITF { if buying != nil && strategy != nil { if strat, ok := ri.PricingProfiles[*buying]; ok { diff --git a/models/resources/tests/resource_test.go b/models/resources/tests/resource_test.go index 414eaec..8ab2b9b 100644 --- a/models/resources/tests/resource_test.go +++ b/models/resources/tests/resource_test.go @@ -36,6 +36,10 @@ type MockPartner struct { groups map[string][]string } +func (abs *MockPartner) RefineResourceByPartnership(peerID string) (resources.ResourceInstanceITF, bool) { + return nil, false +} + func (m *MockPartner) GetProfile(buying *int, strategy *int) pricing.PricingProfileITF { return nil } diff --git a/models/resources/workflow.go b/models/resources/workflow.go index 6f84813..a78e814 100755 --- a/models/resources/workflow.go +++ b/models/resources/workflow.go @@ -19,6 +19,10 @@ func (d *WorkflowResource) GetAccessor(request *tools.APIRequest) utils.Accessor return NewAccessor[*WorkflowResource](tools.WORKFLOW_RESOURCE, request, func() utils.DBObject { return &WorkflowResource{} }) } +func (abs *WorkflowResource) RefineResourceByPartnership(peerID string) ResourceInterface { + return abs +} + func (r *WorkflowResource) AddInstances(instance ResourceInstanceITF) { }