492 lines
11 KiB
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
|
|
}
|
|
}
|