modelRT/database/query_parameter_initializat...

142 lines
4.5 KiB
Go

// Package database define database operation functions
package database
import (
"context"
"fmt"
"modelRT/constants"
"modelRT/model"
"modelRT/sql"
"gorm.io/gorm"
)
type parameterInitializationRoute struct {
TableName string `gorm:"column:name"`
ModelName string `gorm:"column:tag"`
AttributeGroup string `gorm:"column:group_name"`
}
// QueryParameterInitializationRecords loads every parameter accepted by the
// data-object query API. Dynamic parameters are resolved through
// project_manager; component parameters are read directly from component.
func QueryParameterInitializationRecords(ctx context.Context, db *gorm.DB) ([]model.ParameterInitializationRecord, error) {
if db == nil {
return nil, fmt.Errorf("postgres client is nil")
}
var routes []parameterInitializationRoute
if err := db.WithContext(ctx).
Raw(
compactParameterSQL(sql.ParameterInitializationRoutes),
constants.SupportedDynamicParameterAttributeGroups(),
).
Scan(&routes).Error; err != nil {
return nil, fmt.Errorf("query parameter initialization routes: %w", err)
}
if err := validateParameterInitializationRoutes(routes); err != nil {
return nil, err
}
records := make([]model.ParameterInitializationRecord, 0)
for _, route := range routes {
quotedTableName := `"` + route.TableName + `"`
query := compactParameterSQL(
fmt.Sprintf(sql.DynamicParameterInitializationRows, quotedTableName),
)
var tableRecords []model.ParameterInitializationRecord
if err := db.WithContext(ctx).
Raw(query, route.TableName, route.ModelName, route.AttributeGroup).
Scan(&tableRecords).Error; err != nil {
return nil, fmt.Errorf(
"query parameter initialization table %q for model %q group %q: %w",
route.TableName,
route.ModelName,
route.AttributeGroup,
err,
)
}
if err := validateParameterInitializationRecords(tableRecords); err != nil {
return nil, fmt.Errorf("validate parameter initialization table %q: %w", route.TableName, err)
}
records = append(records, tableRecords...)
}
var componentRecords []model.ParameterInitializationRecord
if err := db.WithContext(ctx).
Raw(compactParameterSQL(sql.ComponentParameterInitializationRows)).
Scan(&componentRecords).Error; err != nil {
return nil, fmt.Errorf("query component parameter initialization records: %w", err)
}
if err := validateParameterInitializationRecords(componentRecords); err != nil {
return nil, fmt.Errorf("validate component parameter initialization records: %w", err)
}
records = append(records, componentRecords...)
return records, nil
}
func validateParameterInitializationRoutes(routes []parameterInitializationRoute) error {
seen := make(map[string]struct{}, len(routes))
for _, route := range routes {
if !validParameterTableName(route.TableName) {
return fmt.Errorf("project_manager contains unsupported parameter table name %q", route.TableName)
}
if !constants.IsSupportedParameterAttributeGroup(route.AttributeGroup) ||
route.AttributeGroup == constants.ComponentParameterAttributeGroup {
return fmt.Errorf("project_manager contains unsupported dynamic attribute group %q", route.AttributeGroup)
}
key := route.ModelName + "\x00" + route.AttributeGroup
if _, exists := seen[key]; exists {
return fmt.Errorf(
"model %q and attribute group %q match more than one project_manager record",
route.ModelName,
route.AttributeGroup,
)
}
seen[key] = struct{}{}
}
return nil
}
func validateParameterInitializationRecords(records []model.ParameterInitializationRecord) error {
for _, record := range records {
switch record.DynamicRecordCount {
case 1:
case 0:
return fmt.Errorf(
"component %q has no %q parameter record",
record.ComponentTag,
record.AttributeGroup,
)
default:
return fmt.Errorf(
"component %q has %d %q parameter records",
record.ComponentTag,
record.DynamicRecordCount,
record.AttributeGroup,
)
}
if record.AttributeName == "" || record.AttributeType == "" {
return fmt.Errorf(
"component %q group %q contains an invalid parameter column",
record.ComponentTag,
record.AttributeGroup,
)
}
switch record.DescriptionCount {
case 0:
return fmt.Errorf("parameter description not found for attribute %q", record.AttributeName)
case 1:
if !record.Description.Valid {
return fmt.Errorf("parameter description is null for attribute %q", record.AttributeName)
}
default:
return fmt.Errorf("ambiguous parameter description for attribute %q", record.AttributeName)
}
}
return nil
}