obrimbasecli/essential/visible/service/helper/retriever/retriever.go

492 lines
11 KiB
Go

/*
|--------------------------------------------------------------------------
| Metadata
|--------------------------------------------------------------------------
|
| Name:
| - Retriever
|
| Purpose:
| - Retrieve data from supported resource providers through a unified
| retrieval interface while abstracting provider-specific
| implementation details from consumers.
|
| Guideline:
|
| ObrimRetriever()
| - Use for unified resource retrieval operations.
| - Select a supported retrieval type before execution.
| - Provide configuration according to the selected retrieval type.
| - Use resource retrieval for complete resource payloads.
| - Use path retrieval for individual nested values.
| - Use field retrieval for multiple selected values.
| - Do not provide both path and fields in the same request.
|
| ObrimRetrieverJsonRegister()
| - Register JSON providers before retrieval operations.
| - Use unique resource identifiers for provider registration.
| - Register one provider per resource identifier.
|
| ObrimRetrieverDbRegister()
| - Register database providers using unique resource identifiers.
| - Reserve registration for future database retrieval support.
| - Maintain resource-to-provider mappings through registration.
|
| Example:
|
| ObrimRetriever()
| - ObrimRetriever("json", map[string]any{
| "resource": "metadata",
| })
|
| - ObrimRetriever("json", map[string]any{
| "resource": "metadata",
| "path": "software.name",
| })
|
| - ObrimRetriever("json", map[string]any{
| "resource": "metadata",
| "fields": []string{
| "software.name",
| "software.version",
| },
| })
|
| ObrimRetrieverJsonRegister()
| - ObrimRetrieverJsonRegister(
| "metadata",
| metadataProvider,
| )
|
| ObrimRetrieverDbRegister()
| - ObrimRetrieverDbRegister(
| "database",
| databaseProvider,
| )
|
|--------------------------------------------------------------------------
*/
/*
|--------------------------------------------------------------------------
| Credit
|--------------------------------------------------------------------------
|
| Contributor:
| - Rajon Ahmed
| - Blockonite
|
|--------------------------------------------------------------------------
*/
package retriever
import (
"strings"
)
const (
obrimRetrieverTypeJson = "json"
obrimRetrieverTypeDb = "db"
obrimRetrieverCodeSuccessResource = "SUCCESS_RESOURCE_RETRIEVED"
obrimRetrieverCodeSuccessPath = "SUCCESS_PATH_RETRIEVED"
obrimRetrieverCodeSuccessFields = "SUCCESS_FIELDS_RETRIEVED"
obrimRetrieverCodeFailedUnsupportedType = "FAILED_UNSUPPORTED_TYPE"
obrimRetrieverCodeFailedMissingConfig = "FAILED_MISSING_CONFIGURATION"
obrimRetrieverCodeFailedInvalidConfig = "FAILED_INVALID_CONFIGURATION"
obrimRetrieverCodeFailedResourceNotFound = "FAILED_RESOURCE_NOT_FOUND"
obrimRetrieverCodeFailedPathNotFound = "FAILED_PATH_NOT_FOUND"
obrimRetrieverCodeFailedFieldNotFound = "FAILED_FIELD_NOT_FOUND"
obrimRetrieverCodeFailedNotImplemented = "FAILED_NOT_IMPLEMENTED"
)
// ObrimRetrieverJsonProviderRegistry stores registered JSON providers.
var ObrimRetrieverJsonProviderRegistry = map[string]any{}
// ObrimRetrieverDbProviderRegistry stores registered database providers.
var ObrimRetrieverDbProviderRegistry = map[string]any{}
// ObrimRetrieverResponse defines the standardized utility response structure.
type ObrimRetrieverResponse struct {
Status bool `json:"status"`
Code string `json:"code"`
Payload map[string]any `json:"payload"`
}
// ObrimRetriever retrieves data using a unified retrieval interface.
func ObrimRetriever(retrievalType string, config map[string]any) map[string]any {
if !obrimRetrieverValidateType(retrievalType) {
return obrimRetrieverBuildResponse(
false,
obrimRetrieverCodeFailedUnsupportedType,
nil,
)
}
validationCode := obrimRetrieverValidateConfig(retrievalType, config)
if validationCode != "" {
return obrimRetrieverBuildResponse(
false,
validationCode,
nil,
)
}
switch retrievalType {
case obrimRetrieverTypeJson:
return obrimRetrieverJson(config)
case obrimRetrieverTypeDb:
return obrimRetrieverDb(config)
default:
return obrimRetrieverBuildResponse(
false,
obrimRetrieverCodeFailedUnsupportedType,
nil,
)
}
}
// ObrimRetrieverJsonRegister registers a JSON provider.
func ObrimRetrieverJsonRegister(resource string, provider any) {
if strings.TrimSpace(resource) == "" {
return
}
ObrimRetrieverJsonProviderRegistry[resource] = provider
}
// ObrimRetrieverDbRegister registers a database provider.
func ObrimRetrieverDbRegister(resource string, provider any) {
if strings.TrimSpace(resource) == "" {
return
}
ObrimRetrieverDbProviderRegistry[resource] = provider
}
// obrimRetrieverValidateType validates a retrieval type.
func obrimRetrieverValidateType(retrievalType string) bool {
switch retrievalType {
case obrimRetrieverTypeJson:
return true
case obrimRetrieverTypeDb:
return true
default:
return false
}
}
// obrimRetrieverValidateConfig validates retrieval configuration.
func obrimRetrieverValidateConfig(
retrievalType string,
config map[string]any,
) string {
if config == nil {
return obrimRetrieverCodeFailedMissingConfig
}
switch retrievalType {
case obrimRetrieverTypeJson:
return obrimRetrieverJsonValidate(config)
case obrimRetrieverTypeDb:
return obrimRetrieverDbValidate(config)
default:
return obrimRetrieverCodeFailedUnsupportedType
}
}
// obrimRetrieverResolveProvider resolves a provider by resource identifier.
func obrimRetrieverResolveProvider(
retrievalType string,
resource string,
) (any, bool) {
switch retrievalType {
case obrimRetrieverTypeJson:
provider, exists := ObrimRetrieverJsonProviderRegistry[resource]
return provider, exists
case obrimRetrieverTypeDb:
provider, exists := ObrimRetrieverDbProviderRegistry[resource]
return provider, exists
default:
return nil, false
}
}
// obrimRetrieverBuildResponse builds a standardized utility response.
func obrimRetrieverBuildResponse(
status bool,
code string,
payload map[string]any,
) map[string]any {
return map[string]any{
"status": status,
"code": code,
"payload": payload,
}
}
// obrimRetrieverJson processes JSON retrieval requests.
func obrimRetrieverJson(config map[string]any) map[string]any {
resource := config["resource"].(string)
provider, exists := obrimRetrieverResolveProvider(
obrimRetrieverTypeJson,
resource,
)
if !exists {
return obrimRetrieverBuildResponse(
false,
obrimRetrieverCodeFailedResourceNotFound,
nil,
)
}
if fields, exists := config["fields"]; exists {
return obrimRetrieverJsonFields(provider, fields)
}
if path, exists := config["path"]; exists {
return obrimRetrieverJsonPath(provider, path.(string))
}
return obrimRetrieverJsonResource(provider)
}
// obrimRetrieverJsonResource retrieves an entire resource.
func obrimRetrieverJsonResource(provider any) map[string]any {
data, success := obrimRetrieverJsonRetrieve(provider)
if !success {
return obrimRetrieverBuildResponse(
false,
obrimRetrieverCodeFailedResourceNotFound,
nil,
)
}
return obrimRetrieverBuildResponse(
true,
obrimRetrieverCodeSuccessResource,
map[string]any{
"data": data,
},
)
}
// obrimRetrieverJsonPath retrieves a value using a dot-notation path.
func obrimRetrieverJsonPath(provider any, path string) map[string]any {
data, success := obrimRetrieverJsonRetrieve(provider)
if !success {
return obrimRetrieverBuildResponse(
false,
obrimRetrieverCodeFailedResourceNotFound,
nil,
)
}
value, found := obrimRetrieverJsonResolvePath(data, path)
if !found {
return obrimRetrieverBuildResponse(
false,
obrimRetrieverCodeFailedPathNotFound,
nil,
)
}
return obrimRetrieverBuildResponse(
true,
obrimRetrieverCodeSuccessPath,
map[string]any{
"data": value,
},
)
}
// obrimRetrieverJsonFields retrieves multiple values using field selection.
func obrimRetrieverJsonFields(provider any, fieldsValue any) map[string]any {
data, success := obrimRetrieverJsonRetrieve(provider)
if !success {
return obrimRetrieverBuildResponse(
false,
obrimRetrieverCodeFailedResourceNotFound,
nil,
)
}
fields, valid := obrimRetrieverJsonNormalizeFields(fieldsValue)
if !valid {
return obrimRetrieverBuildResponse(
false,
obrimRetrieverCodeFailedInvalidConfig,
nil,
)
}
result := map[string]any{}
for _, field := range fields {
value, found := obrimRetrieverJsonResolvePath(data, field)
if !found {
return obrimRetrieverBuildResponse(
false,
obrimRetrieverCodeFailedFieldNotFound,
nil,
)
}
result[field] = value
}
return obrimRetrieverBuildResponse(
true,
obrimRetrieverCodeSuccessFields,
map[string]any{
"data": result,
},
)
}
// obrimRetrieverJsonValidate validates JSON retrieval configuration.
func obrimRetrieverJsonValidate(config map[string]any) string {
resourceValue, exists := config["resource"]
if !exists {
return obrimRetrieverCodeFailedMissingConfig
}
resource, valid := resourceValue.(string)
if !valid {
return obrimRetrieverCodeFailedInvalidConfig
}
if strings.TrimSpace(resource) == "" {
return obrimRetrieverCodeFailedInvalidConfig
}
_, pathExists := config["path"]
_, fieldsExists := config["fields"]
if pathExists && fieldsExists {
return obrimRetrieverCodeFailedInvalidConfig
}
if pathExists {
path, valid := config["path"].(string)
if !valid || strings.TrimSpace(path) == "" {
return obrimRetrieverCodeFailedInvalidConfig
}
}
if fieldsExists {
fields, valid := obrimRetrieverJsonNormalizeFields(config["fields"])
if !valid || len(fields) == 0 {
return obrimRetrieverCodeFailedInvalidConfig
}
}
return ""
}
// obrimRetrieverDb processes database retrieval requests.
func obrimRetrieverDb(config map[string]any) map[string]any {
return obrimRetrieverBuildResponse(
false,
obrimRetrieverCodeFailedNotImplemented,
nil,
)
}
// obrimRetrieverDbValidate validates database retrieval configuration.
func obrimRetrieverDbValidate(config map[string]any) string {
return ""
}
// obrimRetrieverJsonRetrieve retrieves resource data from a provider.
func obrimRetrieverJsonRetrieve(provider any) (any, bool) {
switch retrievalProvider := provider.(type) {
case func() any:
return retrievalProvider(), true
case func() map[string]any:
return retrievalProvider(), true
case func() (any, bool):
return retrievalProvider()
case map[string]any:
return retrievalProvider, true
default:
return nil, false
}
}
// obrimRetrieverJsonResolvePath resolves a dot-notation path.
func obrimRetrieverJsonResolvePath(data any, path string) (any, bool) {
current := data
for _, segment := range strings.Split(path, ".") {
object, valid := current.(map[string]any)
if !valid {
return nil, false
}
value, exists := object[segment]
if !exists {
return nil, false
}
current = value
}
return current, true
}
// obrimRetrieverJsonNormalizeFields normalizes field selections.
func obrimRetrieverJsonNormalizeFields(fieldsValue any) ([]string, bool) {
switch fields := fieldsValue.(type) {
case []string:
return fields, true
case []any:
result := make([]string, 0, len(fields))
for _, field := range fields {
fieldString, valid := field.(string)
if !valid {
return nil, false
}
result = append(result, fieldString)
}
return result, true
default:
return nil, false
}
}