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

397 lines
8.8 KiB
Go

package retriever
import (
"fmt"
"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"
ObrimRetrieverCodeFailedProviderUnavailable = "FAILED_PROVIDER_UNAVAILABLE"
)
// ObrimRetrieverJsonProvider defines a JSON retrieval provider.
type ObrimRetrieverJsonProvider interface {
Retrieve() (any, error)
}
// ObrimRetrieverResponse defines the standardized utility response.
type ObrimRetrieverResponse struct {
Status bool `json:"status"`
Code string `json:"code"`
Payload map[string]any `json:"payload"`
}
// obrimRetrieverJsonRegistry stores registered JSON providers.
var obrimRetrieverJsonRegistry = map[string]ObrimRetrieverJsonProvider{}
// obrimRetrieverDbRegistry stores registered DB providers.
var obrimRetrieverDbRegistry = map[string]any{}
// ObrimRetriever retrieves data using the configured retrieval type.
func ObrimRetriever(retrievalType string, config map[string]any) map[string]any {
if !obrimRetrieverValidateType(retrievalType) {
return obrimRetrieverBuildResponse(
false,
ObrimRetrieverCodeFailedUnsupportedType,
nil,
)
}
if errCode := obrimRetrieverValidateConfig(retrievalType, config); errCode != "" {
return obrimRetrieverBuildResponse(false, errCode, 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) {
jsonProvider, ok := provider.(ObrimRetrieverJsonProvider)
if !ok {
return
}
obrimRetrieverJsonRegistry[resource] = jsonProvider
}
// ObrimRetrieverDbRegister registers a DB provider.
func ObrimRetrieverDbRegister(resource string, provider any) {
obrimRetrieverDbRegistry[resource] = provider
}
// obrimRetrieverValidateType validates the retrieval type.
func obrimRetrieverValidateType(retrievalType string) bool {
switch retrievalType {
case obrimRetrieverTypeJson:
return true
case obrimRetrieverTypeDb:
return true
default:
return false
}
}
// obrimRetrieverValidateConfig validates 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.
func obrimRetrieverResolveProvider(
retrievalType string,
resource string,
) (any, bool) {
switch retrievalType {
case obrimRetrieverTypeJson:
provider, ok := obrimRetrieverJsonRegistry[resource]
return provider, ok
case obrimRetrieverTypeDb:
provider, ok := obrimRetrieverDbRegistry[resource]
return provider, ok
}
return nil, false
}
// obrimRetrieverBuildResponse builds a standard 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)
providerAny, ok := obrimRetrieverResolveProvider(
obrimRetrieverTypeJson,
resource,
)
if !ok {
return obrimRetrieverBuildResponse(
false,
ObrimRetrieverCodeFailedResourceNotFound,
nil,
)
}
provider, ok := providerAny.(ObrimRetrieverJsonProvider)
if !ok {
return obrimRetrieverBuildResponse(
false,
ObrimRetrieverCodeFailedProviderUnavailable,
nil,
)
}
if fieldsValue, exists := config["fields"]; exists {
return obrimRetrieverJsonFields(provider, fieldsValue)
}
if pathValue, exists := config["path"]; exists {
return obrimRetrieverJsonPath(provider, pathValue.(string))
}
return obrimRetrieverJsonResource(provider)
}
// obrimRetrieverJsonResource retrieves an entire resource.
func obrimRetrieverJsonResource(
provider ObrimRetrieverJsonProvider,
) map[string]any {
data, err := provider.Retrieve()
if err != nil {
return obrimRetrieverBuildResponse(
false,
ObrimRetrieverCodeFailedResourceNotFound,
nil,
)
}
return obrimRetrieverBuildResponse(
true,
ObrimRetrieverCodeSuccessResource,
map[string]any{
"data": data,
},
)
}
// obrimRetrieverJsonPath retrieves a path value.
func obrimRetrieverJsonPath(
provider ObrimRetrieverJsonProvider,
path string,
) map[string]any {
data, err := provider.Retrieve()
if err != nil {
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 field values.
func obrimRetrieverJsonFields(
provider ObrimRetrieverJsonProvider,
fieldsValue any,
) map[string]any {
data, err := provider.Retrieve()
if err != nil {
return obrimRetrieverBuildResponse(
false,
ObrimRetrieverCodeFailedResourceNotFound,
nil,
)
}
fields, ok := obrimRetrieverNormalizeFields(fieldsValue)
if !ok {
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 configuration.
func obrimRetrieverJsonValidate(config map[string]any) string {
resourceValue, exists := config["resource"]
if !exists {
return ObrimRetrieverCodeFailedMissingConfig
}
resource, ok := resourceValue.(string)
if !ok || strings.TrimSpace(resource) == "" {
return ObrimRetrieverCodeFailedInvalidConfig
}
_, hasPath := config["path"]
_, hasFields := config["fields"]
if hasPath && hasFields {
return ObrimRetrieverCodeFailedInvalidConfig
}
if hasPath {
path, ok := config["path"].(string)
if !ok || strings.TrimSpace(path) == "" {
return ObrimRetrieverCodeFailedInvalidConfig
}
}
if hasFields {
fields, ok := obrimRetrieverNormalizeFields(config["fields"])
if !ok || len(fields) == 0 {
return ObrimRetrieverCodeFailedInvalidConfig
}
}
return ""
}
// obrimRetrieverDb processes DB retrieval requests.
func obrimRetrieverDb(config map[string]any) map[string]any {
return obrimRetrieverBuildResponse(
false,
ObrimRetrieverCodeFailedNotImplemented,
nil,
)
}
// obrimRetrieverDbValidate validates DB configuration.
func obrimRetrieverDbValidate(config map[string]any) string {
return ""
}
// obrimRetrieverJsonResolvePath resolves a dot path.
func obrimRetrieverJsonResolvePath(
data any,
path string,
) (any, bool) {
current := data
for _, segment := range strings.Split(path, ".") {
object, ok := current.(map[string]any)
if !ok {
return nil, false
}
value, exists := object[segment]
if !exists {
return nil, false
}
current = value
}
return current, true
}
// obrimRetrieverNormalizeFields normalizes field inputs.
func obrimRetrieverNormalizeFields(
value any,
) ([]string, bool) {
switch fields := value.(type) {
case []string:
return fields, true
case []any:
result := make([]string, 0, len(fields))
for _, field := range fields {
text, ok := field.(string)
if !ok {
return nil, false
}
result = append(result, text)
}
return result, true
default:
return nil, false
}
}
// obrimRetrieverError formats internal errors.
func obrimRetrieverError(message string) error {
return fmt.Errorf("%s", message)
}