upd: essential/file updated
helper retriever updated
This commit is contained in:
parent
69c58563a5
commit
d7d20533ca
@ -0,0 +1,400 @@
|
|||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Description
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Name:
|
||||||
|
| - Retriever
|
||||||
|
|
|
||||||
|
| Purpose:
|
||||||
|
| - Retrieve data from supported resource handlers through a unified
|
||||||
|
| retrieval interface.
|
||||||
|
|
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Instruction
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Guideline:
|
||||||
|
| - Use for retrieving data from registered JSON resource handlers.
|
||||||
|
| - Use type-based dispatching to route retrieval requests.
|
||||||
|
| - Use resource retrieval to obtain a complete JSON resource.
|
||||||
|
| - Use path retrieval to obtain a specific nested value.
|
||||||
|
| - Use fields retrieval to obtain multiple nested values.
|
||||||
|
| - Do not use path and fields retrieval together.
|
||||||
|
|
|
||||||
|
| Example:
|
||||||
|
| - ObrimRetriever("json", map[string]any{
|
||||||
|
| "resource": "metadata",
|
||||||
|
| })
|
||||||
|
|
|
||||||
|
| - ObrimRetriever("json", map[string]any{
|
||||||
|
| "resource": "metadata",
|
||||||
|
| "path": "app.name",
|
||||||
|
| })
|
||||||
|
|
|
||||||
|
| - ObrimRetriever("json", map[string]any{
|
||||||
|
| "resource": "metadata",
|
||||||
|
| "fields": []any{"app.name", "app.version"},
|
||||||
|
| })
|
||||||
|
|
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Credit
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Contributor:
|
||||||
|
| - Rajon Ahmed
|
||||||
|
| - Blockonite
|
||||||
|
|
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
package retriever
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Utility type identifiers define supported retriever input types.
|
||||||
|
obrimRetrieverTypeJSON = "json"
|
||||||
|
|
||||||
|
// Retriever result codes define successful execution outcomes.
|
||||||
|
obrimRetrieverSuccessResource = "SUCCESS_RESOURCE_RETRIEVED"
|
||||||
|
obrimRetrieverSuccessPath = "SUCCESS_PATH_RETRIEVED"
|
||||||
|
obrimRetrieverSuccessFields = "SUCCESS_FIELDS_RETRIEVED"
|
||||||
|
|
||||||
|
// Retriever result codes define failed execution outcomes.
|
||||||
|
obrimRetrieverFailureInvalidType = "FAILURE_INVALID_TYPE"
|
||||||
|
obrimRetrieverFailureInvalidConfig = "FAILURE_INVALID_CONFIG"
|
||||||
|
obrimRetrieverFailureResourceRequired = "FAILURE_RESOURCE_REQUIRED"
|
||||||
|
obrimRetrieverFailurePathAndFields = "FAILURE_PATH_AND_FIELDS"
|
||||||
|
obrimRetrieverFailureInvalidPath = "FAILURE_INVALID_PATH"
|
||||||
|
obrimRetrieverFailureInvalidFields = "FAILURE_INVALID_FIELDS"
|
||||||
|
obrimRetrieverFailureResourceNotFound = "FAILURE_RESOURCE_NOT_FOUND"
|
||||||
|
obrimRetrieverFailureHandlerFailed = "FAILURE_HANDLER_FAILED"
|
||||||
|
obrimRetrieverFailurePathNotFound = "FAILURE_PATH_NOT_FOUND"
|
||||||
|
obrimRetrieverFailureFieldNotFound = "FAILURE_FIELD_NOT_FOUND"
|
||||||
|
obrimRetrieverFailureUnsupportedConfig = "FAILURE_UNSUPPORTED_CONFIG"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// obrimRetrieverJsonHandlers stores registered JSON resource handlers.
|
||||||
|
obrimRetrieverJsonHandlers = map[string]func() map[string]any{}
|
||||||
|
|
||||||
|
// obrimRetrieverJsonHandlersMutex protects the JSON handler registry.
|
||||||
|
obrimRetrieverJsonHandlersMutex sync.RWMutex
|
||||||
|
)
|
||||||
|
|
||||||
|
// ObrimRetrieverResult represents the standardized retriever execution output.
|
||||||
|
type ObrimRetrieverResult struct {
|
||||||
|
Status bool `json:"status"`
|
||||||
|
Code string `json:"code"`
|
||||||
|
Payload map[string]any `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ObrimRetriever retrieves data from a supported resource handler.
|
||||||
|
func ObrimRetriever(
|
||||||
|
typ string,
|
||||||
|
config map[string]any,
|
||||||
|
) map[string]any {
|
||||||
|
if code := obrimRetrieverValidateInput(typ, config); code != "" {
|
||||||
|
return obrimRetrieverBuildOutput(false, code, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return obrimRetrieverRouteRequest(typ, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ObrimRetrieverJsonRegister registers a JSON resource handler.
|
||||||
|
func ObrimRetrieverJsonRegister(
|
||||||
|
resource string,
|
||||||
|
handler func() map[string]any,
|
||||||
|
) {
|
||||||
|
if strings.TrimSpace(resource) == "" || handler == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
obrimRetrieverJsonHandlersMutex.Lock()
|
||||||
|
defer obrimRetrieverJsonHandlersMutex.Unlock()
|
||||||
|
|
||||||
|
obrimRetrieverJsonHandlers[resource] = handler
|
||||||
|
}
|
||||||
|
|
||||||
|
// obrimRetrieverValidateInput validates the retriever type and configuration.
|
||||||
|
func obrimRetrieverValidateInput(
|
||||||
|
typ string,
|
||||||
|
config map[string]any,
|
||||||
|
) string {
|
||||||
|
switch typ {
|
||||||
|
case obrimRetrieverTypeJSON:
|
||||||
|
return obrimRetrieverValidateJSONConfig(config)
|
||||||
|
default:
|
||||||
|
return obrimRetrieverFailureInvalidType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// obrimRetrieverValidateJSONConfig validates JSON retriever configuration.
|
||||||
|
func obrimRetrieverValidateJSONConfig(config map[string]any) string {
|
||||||
|
if config == nil {
|
||||||
|
return obrimRetrieverFailureInvalidConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceValue, exists := config["resource"]
|
||||||
|
if !exists {
|
||||||
|
return obrimRetrieverFailureResourceRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
resource, ok := resourceValue.(string)
|
||||||
|
if !ok || strings.TrimSpace(resource) == "" {
|
||||||
|
return obrimRetrieverFailureResourceRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
_, hasPath := config["path"]
|
||||||
|
_, hasFields := config["fields"]
|
||||||
|
|
||||||
|
if hasPath && hasFields {
|
||||||
|
return obrimRetrieverFailurePathAndFields
|
||||||
|
}
|
||||||
|
|
||||||
|
for key := range config {
|
||||||
|
switch key {
|
||||||
|
case "resource", "path", "fields":
|
||||||
|
default:
|
||||||
|
return obrimRetrieverFailureUnsupportedConfig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasPath {
|
||||||
|
path, ok := config["path"].(string)
|
||||||
|
if !ok || strings.TrimSpace(path) == "" {
|
||||||
|
return obrimRetrieverFailureInvalidPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasFields {
|
||||||
|
fields, ok := config["fields"].([]string)
|
||||||
|
if !ok || len(fields) == 0 {
|
||||||
|
return obrimRetrieverFailureInvalidFields
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, field := range fields {
|
||||||
|
if strings.TrimSpace(field) == "" {
|
||||||
|
return obrimRetrieverFailureInvalidFields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// obrimRetrieverRouteRequest routes the request to its type-specific entry function.
|
||||||
|
func obrimRetrieverRouteRequest(
|
||||||
|
typ string,
|
||||||
|
config map[string]any,
|
||||||
|
) map[string]any {
|
||||||
|
switch typ {
|
||||||
|
case obrimRetrieverTypeJSON:
|
||||||
|
return obrimRetrieverJson(config)
|
||||||
|
default:
|
||||||
|
return obrimRetrieverBuildOutput(
|
||||||
|
false,
|
||||||
|
obrimRetrieverFailureInvalidType,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// obrimRetrieverBuildOutput builds the standardized retriever output.
|
||||||
|
func obrimRetrieverBuildOutput(
|
||||||
|
status bool,
|
||||||
|
code string,
|
||||||
|
payload map[string]any,
|
||||||
|
) map[string]any {
|
||||||
|
if !status {
|
||||||
|
payload = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]any{
|
||||||
|
"status": status,
|
||||||
|
"code": code,
|
||||||
|
"payload": payload,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// obrimRetrieverJson processes a JSON retrieval request.
|
||||||
|
func obrimRetrieverJson(config map[string]any) map[string]any {
|
||||||
|
resource := config["resource"].(string)
|
||||||
|
|
||||||
|
data, ok := obrimRetrieverJsonHandler(resource)
|
||||||
|
if !ok {
|
||||||
|
return obrimRetrieverBuildOutput(
|
||||||
|
false,
|
||||||
|
obrimRetrieverFailureResourceNotFound,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pathValue, exists := config["path"]; exists {
|
||||||
|
path := pathValue.(string)
|
||||||
|
|
||||||
|
value, ok := obrimRetrieverJsonPath(data, path)
|
||||||
|
if !ok {
|
||||||
|
return obrimRetrieverBuildOutput(
|
||||||
|
false,
|
||||||
|
obrimRetrieverFailurePathNotFound,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return obrimRetrieverBuildOutput(
|
||||||
|
true,
|
||||||
|
obrimRetrieverSuccessPath,
|
||||||
|
map[string]any{
|
||||||
|
"data": value,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if fieldsValue, exists := config["fields"]; exists {
|
||||||
|
fields := fieldsValue.([]string)
|
||||||
|
|
||||||
|
values, ok := obrimRetrieverJsonFields(data, fields)
|
||||||
|
if !ok {
|
||||||
|
return obrimRetrieverBuildOutput(
|
||||||
|
false,
|
||||||
|
obrimRetrieverFailureFieldNotFound,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return obrimRetrieverBuildOutput(
|
||||||
|
true,
|
||||||
|
obrimRetrieverSuccessFields,
|
||||||
|
map[string]any{
|
||||||
|
"data": values,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return obrimRetrieverBuildOutput(
|
||||||
|
true,
|
||||||
|
obrimRetrieverSuccessResource,
|
||||||
|
map[string]any{
|
||||||
|
"data": obrimRetrieverJsonResource(data),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// obrimRetrieverJsonHandler locates and invokes a registered JSON handler.
|
||||||
|
func obrimRetrieverJsonHandler(
|
||||||
|
resource string,
|
||||||
|
) (map[string]any, bool) {
|
||||||
|
obrimRetrieverJsonHandlersMutex.RLock()
|
||||||
|
handler, exists := obrimRetrieverJsonHandlers[resource]
|
||||||
|
obrimRetrieverJsonHandlersMutex.RUnlock()
|
||||||
|
|
||||||
|
if !exists || handler == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
data := handler()
|
||||||
|
if data == nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// obrimRetrieverJsonResource returns the complete JSON resource payload.
|
||||||
|
func obrimRetrieverJsonResource(
|
||||||
|
resource map[string]any,
|
||||||
|
) map[string]any {
|
||||||
|
return resource
|
||||||
|
}
|
||||||
|
|
||||||
|
// obrimRetrieverJsonPath retrieves a value using a dot-notation path.
|
||||||
|
func obrimRetrieverJsonPath(
|
||||||
|
resource map[string]any,
|
||||||
|
path string,
|
||||||
|
) (any, bool) {
|
||||||
|
parts := strings.Split(path, ".")
|
||||||
|
if len(parts) == 0 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
var current any = resource
|
||||||
|
|
||||||
|
for _, part := range parts {
|
||||||
|
if part == "" {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch value := current.(type) {
|
||||||
|
case map[string]any:
|
||||||
|
next, exists := value[part]
|
||||||
|
if !exists {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
current = next
|
||||||
|
|
||||||
|
case []any:
|
||||||
|
index := -1
|
||||||
|
|
||||||
|
for i, item := range value {
|
||||||
|
if part == strings.TrimSpace(part) {
|
||||||
|
var parsed int
|
||||||
|
if _, err := fmt.Sscanf(part, "%d", &parsed); err == nil {
|
||||||
|
index = parsed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if index >= 0 {
|
||||||
|
_ = item
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if index < 0 || index >= len(value) {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
current = value[index]
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return current, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// obrimRetrieverJsonFields retrieves multiple values using field selection.
|
||||||
|
func obrimRetrieverJsonFields(
|
||||||
|
resource map[string]any,
|
||||||
|
fields []string,
|
||||||
|
) (map[string]any, bool) {
|
||||||
|
values := make(map[string]any, len(fields))
|
||||||
|
|
||||||
|
for _, field := range fields {
|
||||||
|
value, ok := obrimRetrieverJsonPath(resource, field)
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
values[field] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
return values, true
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user