package routebuildermdl import ( "encoding/json" "strconv" "strings" "time" "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/servicebuildermdl" "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/dalmdl/dao" "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/loggermdl" "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/errormdl" "corelab.mkcl.org/MKCLOS/coredevelopmentplatform/corepkgv2/dalmdl/mongodb" "github.com/tidwall/gjson" ) // Master - struct for master Service type Master struct { serviceName string isCach bool cacheTime time.Duration isRestricted bool isRoleBased bool isMongo bool } // MongoQuery - for mongo service type MongoQuery struct { collection string host string query string projectionQuery string args []string isAggregationQuery bool } // FDBQuery - for fdb services type FDBQuery struct { filePath string query []string } // Runable - helps to run type Runable struct { Master MongoQuery FDBQuery } // MongoService - return mongo query object func (m *Master) MongoService(collectionName, mongoQuery string) *Runable { mongo := MongoQuery{ collection: collectionName, query: mongoQuery, } m.isMongo = true runable := &Runable{ Master: *m, MongoQuery: mongo, } return runable } // MongoServiceWithHost - return mongo query object func (m *Master) MongoServiceWithHost(hostName, collectionName, mongoQuery string) *Runable { mongo := MongoQuery{ host: hostName, collection: collectionName, query: mongoQuery, } m.isMongo = true runable := &Runable{ Master: *m, MongoQuery: mongo, } return runable } // FDBService - return mongo query object func (m *Master) FDBService(filPath string, query ...string) *Runable { FDB := FDBQuery{ filePath: filPath, query: query, } runable := &Runable{ Master: *m, FDBQuery: FDB, } return runable } // IsCachable for both fdb and mongo func (m *Master) IsCachable() *Master { m.isCach = true return m } // IsCachableWithExpiration for both fdb and mongo func (m *Master) IsCachableWithExpiration(cacheExpirationTime time.Duration) *Master { m.isCach = true m.cacheTime = cacheExpirationTime return m } // SetArgs set argument for query string func (m *Runable) SetArgs(args ...string) *Runable { if m.Master.isMongo { m.MongoQuery.args = args } return m } // SetProjectionQuery set SetProjectionQuery for query string func (m *Runable) SetProjectionQuery(query string) *Runable { if m.Master.isMongo { m.MongoQuery.projectionQuery = query } return m } // IsAggregationQuery - Set flag for aggregation query func (m *Runable) IsAggregationQuery() *Runable { if m.Master.isMongo { m.MongoQuery.isAggregationQuery = true } return m } // Register - register it in cacahe func (m *Runable) Register() { service := ServiceCache{ MasterService: m, IsMasterService: true, } commonServiceRegistration(m.Master.serviceName, service, m.Master.isRestricted, m.Master.isRoleBased) } // Run - execute and return output and error func (m *Runable) Run(data []byte, principal *servicebuildermdl.Principal) (interface{}, error) { if m.Master.isMongo { return m.runMongoService(data, principal) } return m.runFDBService() } func (m *Runable) runMongoService(data []byte, principal *servicebuildermdl.Principal) (interface{}, error) { rs := gjson.ParseBytes(data) tmp := m.MongoQuery.query var principalError error tmp, principalError = parsePricipalObject(tmp, principal) if errormdl.CheckErr(principalError) != nil { loggermdl.LogError(principalError) return nil, errormdl.CheckErr(principalError) } if m.MongoQuery.isAggregationQuery { v, formatError := m.formatAggregateQuery(&rs, tmp) if errormdl.CheckErr(formatError) != nil { loggermdl.LogError(formatError) return nil, errormdl.CheckErr(formatError) } query, getError := mongodb.GetMongoDAOWithHost(m.MongoQuery.host, m.MongoQuery.collection).GetAggregateData(v) if errormdl.CheckErr(getError) != nil { loggermdl.LogError(getError) return nil, errormdl.CheckErr(getError) } return query.Value(), nil } v, p, formatError := m.formatNormalQuery(&rs, tmp) if errormdl.CheckErr(formatError) != nil { loggermdl.LogError(formatError) return nil, errormdl.CheckErr(formatError) } query, getError := mongodb.GetMongoDAOWithHost(m.MongoQuery.host, m.MongoQuery.collection).GetProjectedData(v, p) if errormdl.CheckErr(getError) != nil { loggermdl.LogError(getError) return nil, errormdl.CheckErr(getError) } return query.Value(), nil } func (m *Runable) formatAggregateQuery(rs *gjson.Result, tmp string) ([]interface{}, error) { for i, arg := range m.MongoQuery.args { result := rs.Get(arg).String() argNotation := "~" + strconv.Itoa(i+1) tmp = strings.Replace(tmp, argNotation, result, 1) } v, ok := gjson.Parse(tmp).Value().([]interface{}) if !ok { loggermdl.LogError("Invalid Mongo Query") return nil, errormdl.Wrap("Invalid Mongo Query") } return v, nil } func (m *Runable) formatNormalQuery(rs *gjson.Result, tmp string) (map[string]interface{}, map[string]interface{}, error) { for i, arg := range m.MongoQuery.args { result := rs.Get(arg).String() argNotation := "~" + strconv.Itoa(i+1) tmp = strings.Replace(tmp, argNotation, result, 1) } v, ok := gjson.Parse(tmp).Value().(map[string]interface{}) if !ok { loggermdl.LogError("Invalid Mongo Query") return nil, nil, errormdl.Wrap("Invalid Mongo Query") } if m.MongoQuery.projectionQuery == "" { m.MongoQuery.projectionQuery = "{}" } p, ok := gjson.Parse(m.MongoQuery.projectionQuery).Value().(map[string]interface{}) if !ok { loggermdl.LogError("Invalid Mongo Projection Query Query") return nil, nil, errormdl.Wrap("Invalid Mongo Projection Query Query") } return v, p, nil } func parsePricipalObject(query string, principal *servicebuildermdl.Principal) (string, error) { ba, marshalError := json.Marshal(principal) if errormdl.CheckErr(marshalError) != nil { loggermdl.LogError(marshalError) return "", errormdl.CheckErr(marshalError) } pricipalRS := gjson.ParseBytes(ba) result := pricipalRS.Get("userId").String() argNotation := "~tokenUserId" query = strings.Replace(query, argNotation, result, 1) return query, nil } func (m *Runable) runFDBService() (interface{}, error) { rs, getError := dalmdl.GetDAO(). FilePath(m.FDBQuery.filePath). Query(m.FDBQuery.query...). IsCacheableWithDuration(m.Master.cacheTime). Run() if errormdl.CheckErr(getError) != nil { loggermdl.LogError(getError) return nil, errormdl.CheckErr(getError) } return rs.Value(), nil }