diff --git a/app_config.go b/app_config.go index 665d5be..229d7d9 100644 --- a/app_config.go +++ b/app_config.go @@ -480,8 +480,8 @@ func (c *AppConfig) checkForFieldSetDependencies(fieldSet *FieldSet) []error { errs := []error{} for _, loadCondition := range fieldSet.LoadConditions { - fieldSetKey, fieldKey := loadCondition.FieldDependency() - if fieldSetKey == "" && fieldKey == "" { + fieldSetKey, fieldKeys := loadCondition.FieldDependency() + if fieldSetKey == "" && len(fieldKeys) == 0 { continue } @@ -495,15 +495,17 @@ func (c *AppConfig) checkForFieldSetDependencies(fieldSet *FieldSet) []error { continue } - _, found = fieldSetDependency.fieldMap[fieldKey] - if !found { - errs = append( - errs, - fmt.Errorf( - "field-set '%s' field-set dependency field not found: %s_%s", - fieldSet.Key, fieldSetKey, fieldKey, - ), - ) + for _, fieldKey := range fieldKeys { + _, found = fieldSetDependency.fieldMap[fieldKey] + if !found { + errs = append( + errs, + fmt.Errorf( + "field-set '%s' field-set dependency field not found: %s_%s", + fieldSet.Key, fieldSetKey, fieldKey, + ), + ) + } } } @@ -523,9 +525,9 @@ func (c *AppConfig) checkForFieldDependencies(field *Field, parent *FieldSet) er var found bool - fieldSetKey, fieldKey := loadCondition.FieldDependency() + fieldSetKey, fieldKeys := loadCondition.FieldDependency() - if fieldSetKey == "" && fieldKey == "" { + if fieldSetKey == "" && len(fieldKeys) == 0 { continue } @@ -543,11 +545,13 @@ func (c *AppConfig) checkForFieldDependencies(field *Field, parent *FieldSet) er } } - if _, found = fieldSetDependency.fieldMap[fieldKey]; !found { - return fmt.Errorf( - "field-set '%s' field '%s' field-set field not found: %s_%s", - parent.Key, field.Key, fieldSetKey, fieldKey, - ) + for _, fieldKey := range fieldKeys { + if _, found = fieldSetDependency.fieldMap[fieldKey]; !found { + return fmt.Errorf( + "field-set '%s' field '%s' field-set field not found: %s_%s", + parent.Key, field.Key, fieldSetKey, fieldKey, + ) + } } } } @@ -648,14 +652,19 @@ func (c *AppConfig) shouldLoadFieldSet(fieldSet *FieldSet) (bool, error) { break } - conditionFieldSetKey, conditionFieldSetFieldKey := loadCondition.FieldDependency() - if conditionFieldSetKey != "" && conditionFieldSetFieldKey != "" { - fieldValue, err := c.getFieldValue(conditionFieldSetKey, conditionFieldSetFieldKey, "any") - if err != nil { - return false, fmt.Errorf("problem getting field value for load condition: %w", err) + conditionFieldSetKey, conditionFieldSetFieldKeys := loadCondition.FieldDependency() + if conditionFieldSetKey != "" && len(conditionFieldSetFieldKeys) > 0 { + var err error + fieldValues := map[string]any{} + + for _, conditionFieldSetFieldKey := range conditionFieldSetFieldKeys { + fieldValues[conditionFieldSetFieldKey], err = c.getFieldValue(conditionFieldSetKey, conditionFieldSetFieldKey, "any") + if err != nil { + return false, fmt.Errorf("problem getting field value for load condition: %w", err) + } } - loadFieldSet, err = loadCondition.Load(fieldValue) + loadFieldSet, err = loadCondition.Load(fieldValues) if err != nil { return false, fmt.Errorf("problem getting load condition outcome: %w", err) } @@ -686,18 +695,23 @@ func (c *AppConfig) shouldLoadField(field *Field, fieldSetKey string) (bool, err break } - conditionFieldSetKey, conditionFieldSetFieldKey := loadCondition.FieldDependency() + conditionFieldSetKey, conditionFieldSetFieldKeys := loadCondition.FieldDependency() if conditionFieldSetKey == "" { conditionFieldSetKey = fieldSetKey } - if conditionFieldSetKey != "" && conditionFieldSetFieldKey != "" { - fieldValue, err := c.getFieldValue(conditionFieldSetKey, conditionFieldSetFieldKey, "any") - if err != nil { - return false, fmt.Errorf("problem getting field value for load condition: %w", err) + if conditionFieldSetKey != "" && len(conditionFieldSetFieldKeys) > 0 { + var err error + fieldValues := map[string]any{} + + for _, conditionFieldSetFieldKey := range conditionFieldSetFieldKeys { + fieldValues[conditionFieldSetFieldKey], err = c.getFieldValue(conditionFieldSetKey, conditionFieldSetFieldKey, "any") + if err != nil { + return false, fmt.Errorf("problem getting field value for load condition: %w", err) + } } - loadField, err = loadCondition.Load(fieldValue) + loadField, err = loadCondition.Load(fieldValues) if err != nil { return false, fmt.Errorf("problem getting load condition outcome: %w", err) } @@ -867,11 +881,11 @@ func (c *AppConfig) fieldHelpString(fields map[string]*fieldEntry, key string) s } for _, condition := range loadConditions { - fieldSetDependency, fieldDependency := condition.FieldDependency() - if fieldSetDependency != "" && fieldDependency != "" { + fieldSetDependency, fieldDependencies := condition.FieldDependency() + if fieldSetDependency != "" && len(fieldDependencies) > 0 { builder.WriteString(spaceBuffer) builder.WriteString( - fmt.Sprintf("Loading depends on field: '%s_%s'\n", fieldSetDependency, fieldDependency), + fmt.Sprintf("Loading depends on field: '%s_%s'\n", fieldSetDependency, fieldDependencies), ) } else { builder.WriteString(spaceBuffer) diff --git a/app_config_test.go b/app_config_test.go index 6148b75..18a0f4f 100644 --- a/app_config_test.go +++ b/app_config_test.go @@ -70,9 +70,9 @@ func TestAppConfigHelpString(t *testing.T) { LoadConditions: bconf.LoadConditions{ &bconf.FieldCondition{ FieldSetKey: defaultFieldSetKey, - FieldKey: stringFieldKey, - Condition: func(fieldValue any) (bool, error) { - val, ok := fieldValue.(string) + FieldKeys: []string{stringFieldKey}, + Condition: func(fieldValues map[string]any) (bool, error) { + val, ok := fieldValues[stringFieldKey].(string) if !ok { return false, fmt.Errorf("unexpected field value type") } @@ -159,9 +159,9 @@ func TestAppConfig(t *testing.T) { LoadConditions: bconf.LoadConditions{ &bconf.FieldCondition{ FieldSetKey: "app", - FieldKey: "connect_sqlite", - Condition: func(fieldValue any) (bool, error) { - val, ok := fieldValue.(bool) + FieldKeys: []string{"connect_sqlite"}, + Condition: func(fieldValues map[string]any) (bool, error) { + val, ok := fieldValues["connect_sqlite"].(bool) if !ok { return false, fmt.Errorf("unexpected field-type value") } @@ -342,8 +342,8 @@ func TestAppConfigWithLoadConditions(t *testing.T) { LoadConditions: bconf.LoadConditions{ &bconf.FieldCondition{ FieldSetKey: defaultFieldSetKey, - FieldKey: defaultFieldSetLoadAppOneKey, - Condition: func(fieldValue any) (bool, error) { + FieldKeys: []string{defaultFieldSetLoadAppOneKey}, + Condition: func(fieldValues map[string]any) (bool, error) { return true, nil }, }, @@ -356,8 +356,8 @@ func TestAppConfigWithLoadConditions(t *testing.T) { LoadConditions: bconf.LoadConditions{ &bconf.FieldCondition{ FieldSetKey: defaultFieldSetKey, - FieldKey: defaultFieldSetLoadAppTwoKey, - Condition: func(fieldValue any) (bool, error) { + FieldKeys: []string{defaultFieldSetLoadAppTwoKey}, + Condition: func(fieldValues map[string]any) (bool, error) { return true, nil }, }, @@ -370,7 +370,7 @@ func TestAppConfigWithLoadConditions(t *testing.T) { LoadConditions: bconf.LoadConditions{ &bconf.FieldCondition{ FieldSetKey: defaultFieldSetKey, - Condition: func(fieldValue any) (bool, error) { + Condition: func(fieldValues map[string]any) (bool, error) { return true, nil }, }, @@ -444,21 +444,21 @@ func TestAppConfigWithFieldLoadConditions(t *testing.T) { fieldSetWithInternalFieldDependencies := bconf.FSB().Key(fieldSetOneKey).Fields( bconf.FB().Key(fieldAKey).Type(bconf.String).Default("postgres").Create(), bconf.FB().Key(fieldBKey).Type(bconf.String).LoadConditions( - bconf.FCB().FieldKey(fieldAKey).Condition(func(val any) (bool, error) { + bconf.FCB().AddFieldKey(fieldAKey).Condition(func(_ map[string]any) (bool, error) { return true, nil }).Create(), ).Create(), bconf.FB().Key(fieldCKey).Type(bconf.String).LoadConditions( bconf. FCB(). - FieldKey(fieldAKey). + AddFieldKey(fieldAKey). FieldSetKey(fieldSetOneKey). - Condition(func(val any) (bool, error) { + Condition(func(_ map[string]any) (bool, error) { return true, nil }).Create(), ).Create(), bconf.FB().Key(fieldDKey).Type(bconf.String).Default("should_not_be_overridden").LoadConditions( - bconf.FCB().FieldKey(fieldAKey).Condition(func(val any) (bool, error) { + bconf.FCB().AddFieldKey(fieldAKey).Condition(func(_ map[string]any) (bool, error) { return false, nil }).Create(), ).Create(), @@ -490,7 +490,7 @@ func TestAppConfigWithFieldLoadConditions(t *testing.T) { fieldSetWithMissingInternalFieldDependencies := bconf.FSB().Key(fieldSetThreeKey).Fields( bconf.FB().Key(fieldFKey).Type(bconf.String).Create(), bconf.FB().Key(fieldGKey).Type(bconf.String).LoadConditions( - bconf.FCB().FieldKey(fieldAKey).Condition(func(val any) (bool, error) { + bconf.FCB().AddFieldKey(fieldAKey).Condition(func(_ map[string]any) (bool, error) { return true, nil }).Create(), ).Create(), @@ -498,7 +498,7 @@ func TestAppConfigWithFieldLoadConditions(t *testing.T) { fieldSetWithMissingExternalFieldDependencies := bconf.FSB().Key(fieldSetFourKey).Fields( bconf.FB().Key(fieldAKey).Type(bconf.String).LoadConditions( - bconf.FCB().FieldSetKey("missing").FieldKey(fieldBKey).Condition(func(val any) (bool, error) { + bconf.FCB().FieldSetKey("missing").AddFieldKey(fieldBKey).Condition(func(_ map[string]any) (bool, error) { return true, nil }).Create(), ).Create(), @@ -583,8 +583,8 @@ func TestAppConfigAddField(t *testing.T) { } fieldMissingLoadCondition := bconf.FB().Key("field_missing_load_condition").Type(bconf.String).LoadConditions( - bconf.FCB().FieldKey("missing_key").Condition( - func(val any) (bool, error) { + bconf.FCB().AddFieldKey("missing_key").Condition( + func(_ map[string]any) (bool, error) { return true, nil }, ).Create(), @@ -644,8 +644,8 @@ func TestAppConfigLoadFieldSet(t *testing.T) { errs = appConfig.AddFieldSet(bconf.FSB().Key("bad_field_condition_conditional").Fields( bconf.FB().Key("some_key").Type(bconf.String).Default("value").Create(), ).LoadConditions( - bconf.NewFieldConditionBuilder().FieldSetKey("default").FieldKey("field_key").Condition( - func(fieldValue any) (bool, error) { + bconf.NewFieldConditionBuilder().FieldSetKey("default").AddFieldKey("field_key").Condition( + func(_ map[string]any) (bool, error) { return true, fmt.Errorf("condition error") }, ).Create(), @@ -715,7 +715,7 @@ func TestAppConfigLoadField(t *testing.T) { } addedFieldC := bconf.FB().Key("field_c").Type(bconf.String).LoadConditions( - bconf.FCB().FieldKey("field_b").Condition(func(val any) (bool, error) { + bconf.FCB().AddFieldKey("field_b").Condition(func(_ map[string]any) (bool, error) { return true, nil }).Create(), ).Create() @@ -738,7 +738,7 @@ func TestAppConfigLoadField(t *testing.T) { os.Setenv("STANDARD_D_FIELD_D", "expected_value") addedFieldD := bconf.FB().Key("field_d").Type(bconf.String).LoadConditions( - bconf.FCB().FieldKey("field_a").Condition(func(val any) (bool, error) { + bconf.FCB().AddFieldKey("field_a").Condition(func(_ map[string]any) (bool, error) { return true, nil }).Create(), ).Create() @@ -762,7 +762,7 @@ func TestAppConfigLoadField(t *testing.T) { // A test case for loading a field with a falsy field load condition addedFieldE := bconf.FB().Key("field_e").Type(bconf.String).LoadConditions( - bconf.FCB().FieldKey("field_a").Condition(func(val any) (bool, error) { + bconf.FCB().AddFieldKey("field_a").Condition(func(_ map[string]any) (bool, error) { return false, nil }).Create(), ).Create() diff --git a/field_condition.go b/field_condition.go index 3e72437..d8ed964 100644 --- a/field_condition.go +++ b/field_condition.go @@ -3,9 +3,9 @@ package bconf import "fmt" type FieldCondition struct { - Condition func(fieldValue any) (bool, error) + Condition func(fieldValues map[string]any) (bool, error) FieldSetKey string - FieldKey string + FieldKeys []string } func (c *FieldCondition) Clone() LoadCondition { @@ -14,12 +14,12 @@ func (c *FieldCondition) Clone() LoadCondition { return &clone } -func (c *FieldCondition) FieldDependency() (fieldSetKey, fieldKey string) { - return c.FieldSetKey, c.FieldKey +func (c *FieldCondition) FieldDependency() (fieldSetKey string, fieldKeys []string) { + return c.FieldSetKey, c.FieldKeys } -func (c *FieldCondition) Load(value any) (bool, error) { - return c.Condition(value) +func (c *FieldCondition) Load(values map[string]any) (bool, error) { + return c.Condition(values) } func (c *FieldCondition) Validate() []error { @@ -29,8 +29,8 @@ func (c *FieldCondition) Validate() []error { errs = append(errs, fmt.Errorf("field-set key required for field condition")) } - if c.FieldKey == "" { - errs = append(errs, fmt.Errorf("field key required for field condition")) + if len(c.FieldKeys) == 0 { + errs = append(errs, fmt.Errorf("at least one field key required for field condition")) } return errs diff --git a/field_condition_builder.go b/field_condition_builder.go index b6c31ad..af18b4a 100644 --- a/field_condition_builder.go +++ b/field_condition_builder.go @@ -19,14 +19,14 @@ func (b *FieldConditionBuilder) FieldSetKey(value string) *FieldConditionBuilder return b } -func (b *FieldConditionBuilder) FieldKey(value string) *FieldConditionBuilder { +func (b *FieldConditionBuilder) AddFieldKey(value string) *FieldConditionBuilder { b.init() - b.condition.FieldKey = value + b.condition.FieldKeys = append(b.condition.FieldKeys, value) return b } -func (b *FieldConditionBuilder) Condition(value func(fieldValue any) (bool, error)) *FieldConditionBuilder { +func (b *FieldConditionBuilder) Condition(value func(fieldValues map[string]any) (bool, error)) *FieldConditionBuilder { b.init() b.condition.Condition = value diff --git a/field_condition_builder_test.go b/field_condition_builder_test.go index 2943b38..a7e0ad9 100644 --- a/field_condition_builder_test.go +++ b/field_condition_builder_test.go @@ -35,14 +35,14 @@ func TestFieldConditionBuilderKeys(t *testing.T) { t.Fatalf("unexpected field-set key value '%s', expected '%s'", fsKey, fieldSetKey) } - condition = bconf.FCB().FieldKey(fieldKey).Create() - if _, fKey := condition.FieldDependency(); fKey != fieldKey { - t.Fatalf("unexpected field key value '%s', expected '%s'", fKey, fieldKey) + condition = bconf.FCB().AddFieldKey(fieldKey).Create() + if _, fKeys := condition.FieldDependency(); fKeys[0] != fieldKey { + t.Fatalf("unexpected field key value '%s', expected '%s'", fKeys[0], fieldKey) } } func TestFieldConditionBuilderCondition(t *testing.T) { - condition := func(fieldValue any) (bool, error) { + condition := func(_ map[string]any) (bool, error) { return true, nil } fieldCondition := bconf.FCB().Condition(condition).Create() diff --git a/field_set_builder_test.go b/field_set_builder_test.go index 2b32546..227d5c9 100644 --- a/field_set_builder_test.go +++ b/field_set_builder_test.go @@ -53,19 +53,19 @@ func TestFieldSetBuilderLoadConditions(t *testing.T) { loadConditionFieldKey := "test_field_key" fieldSet := bconf.FSB().LoadConditions( - bconf.FCB().FieldSetKey(loadConditionFieldSetKey).FieldKey(loadConditionFieldKey).Create(), + bconf.FCB().FieldSetKey(loadConditionFieldSetKey).AddFieldKey(loadConditionFieldKey).Create(), ).Create() if len(fieldSet.LoadConditions) != 1 { t.Fatalf("unexpected load-conditions length '%d', expected 1", len(fieldSet.LoadConditions)) } - fieldSetKey, fieldKey := fieldSet.LoadConditions[0].FieldDependency() + fieldSetKey, fieldKeys := fieldSet.LoadConditions[0].FieldDependency() if fieldSetKey != loadConditionFieldSetKey { t.Fatalf("unexpected field-set key '%s', expected '%s'", fieldSetKey, loadConditionFieldSetKey) } - if fieldKey != loadConditionFieldKey { - t.Fatalf("unexpected field key '%s', expected '%s'", fieldKey, loadConditionFieldKey) + if fieldKeys[0] != loadConditionFieldKey { + t.Fatalf("unexpected field key '%s', expected '%s'", fieldKeys, loadConditionFieldKey) } } diff --git a/load_condition.go b/load_condition.go index af97760..e709c8d 100644 --- a/load_condition.go +++ b/load_condition.go @@ -4,7 +4,7 @@ type LoadConditions []LoadCondition type LoadCondition interface { Clone() LoadCondition - FieldDependency() (fieldSetKey string, fieldKey string) - Load(value any) (bool, error) + FieldDependency() (fieldSetKey string, fieldKeys []string) + Load(values map[string]any) (bool, error) Validate() []error }