refactor(misconf): move common logic to base value and simplify typed values (#9986)

Signed-off-by: nikpivkin <nikita.pivkin@smartforce.io>
This commit is contained in:
Nikita Pivkin
2026-01-16 11:03:13 +06:00
committed by GitHub
parent 809db46231
commit 56029517d6
8 changed files with 165 additions and 410 deletions

View File

@@ -0,0 +1,79 @@
package types
import (
"encoding/json"
)
type BaseValue[T any] struct {
metadata Metadata
value T
}
func defaultValue[T any](value T, m Metadata) BaseValue[T] {
m.isDefault = true
return newValue(value, m)
}
func unresolvableValue[T any](m Metadata) BaseValue[T] {
m.isUnresolvable = true
var zero T
return newValue(zero, m)
}
func explicitValue[T any](value T, m Metadata) BaseValue[T] {
m.isExplicit = true
return newValue(value, m)
}
func testValue[T any](value T) BaseValue[T] {
return newValue(value, NewTestMetadata())
}
func newValue[T any](val T, metadata Metadata) BaseValue[T] {
return BaseValue[T]{
metadata: metadata,
value: val,
}
}
func (v BaseValue[T]) GetMetadata() Metadata {
return v.metadata
}
func (v BaseValue[T]) Value() T {
return v.value
}
func (v BaseValue[T]) GetRawValue() any {
return v.value
}
func (v BaseValue[T]) ToRego() any {
m := v.metadata.ToRego().(map[string]any)
m["value"] = v.value
return m
}
type encodedValue[T any] struct {
Value T `json:"value"`
Metadata Metadata `json:"metadata"`
}
func (v BaseValue[T]) MarshalJSON() ([]byte, error) {
ev := encodedValue[T]{
Value: v.value,
Metadata: v.metadata,
}
return json.Marshal(ev)
}
func (v *BaseValue[T]) UnmarshalJSON(data []byte) error {
var ev encodedValue[T]
if err := json.Unmarshal(data, &ev); err != nil {
return err
}
v.value = ev.Value
v.metadata = ev.Metadata
return nil
}

View File

@@ -1,81 +1,33 @@
package types
import (
"encoding/json"
"strings"
"github.com/zclconf/go-cty/cty"
)
type BoolValue struct {
BaseAttribute
value bool
BaseValue[bool]
}
func (b BoolValue) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]any{
"value": b.value,
"metadata": b.metadata,
})
func Bool(value bool, m Metadata) BoolValue {
return BoolValue{newValue(value, m)}
}
func (b *BoolValue) UnmarshalJSON(data []byte) error {
var keys map[string]any
if err := json.Unmarshal(data, &keys); err != nil {
return err
}
if keys["value"] != nil {
b.value = keys["value"].(bool)
}
if keys["metadata"] != nil {
raw, err := json.Marshal(keys["metadata"])
if err != nil {
return err
}
var m Metadata
if err := json.Unmarshal(raw, &m); err != nil {
return err
}
b.metadata = m
}
return nil
}
func Bool(value bool, metadata Metadata) BoolValue {
return BoolValue{
value: value,
BaseAttribute: BaseAttribute{metadata: metadata},
}
}
func BoolTest(value bool) BoolValue {
return Bool(value, NewTestMetadata())
}
func BoolDefault(value bool, metadata Metadata) BoolValue {
b := Bool(value, metadata)
b.BaseAttribute.metadata.isDefault = true
return b
func BoolDefault(value bool, m Metadata) BoolValue {
return BoolValue{defaultValue(value, m)}
}
func BoolUnresolvable(m Metadata) BoolValue {
b := Bool(false, m)
b.BaseAttribute.metadata.isUnresolvable = true
return b
return BoolValue{unresolvableValue[bool](m)}
}
func BoolExplicit(value bool, metadata Metadata) BoolValue {
b := Bool(value, metadata)
b.BaseAttribute.metadata.isExplicit = true
return b
func BoolExplicit(value bool, m Metadata) BoolValue {
return BoolValue{explicitValue(value, m)}
}
func (b BoolValue) Value() bool {
return b.value
}
func (b BoolValue) GetRawValue() any {
return b.value
func BoolTest(value bool) BoolValue {
return BoolValue{testValue(value)}
}
func (b BoolValue) IsTrue() bool {
@@ -93,16 +45,7 @@ func (b BoolValue) IsFalse() bool {
}
func (b BoolValue) Invert() BoolValue {
return BoolValue{
BaseAttribute: b.BaseAttribute,
value: !b.value,
}
}
func (b BoolValue) ToRego() any {
m := b.metadata.ToRego().(map[string]any)
m["value"] = b.Value()
return m
return Bool(!b.value, b.metadata)
}
// BoolFromCtyValue converts a cty.Value to iacTypes.BoolValue.

View File

@@ -1,100 +1,35 @@
package types
import (
"encoding/json"
)
type BytesValue struct {
BaseAttribute
value []byte
}
func (b BytesValue) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]any{
"value": b.value,
"metadata": b.metadata,
})
}
func (b *BytesValue) UnmarshalJSON(data []byte) error {
var keys map[string]any
if err := json.Unmarshal(data, &keys); err != nil {
return err
}
if keys["value"] != nil {
raw, err := json.Marshal(keys["value"])
if err != nil {
return err
}
var m []byte
if err := json.Unmarshal(raw, &m); err != nil {
return err
}
b.value = m
}
if keys["metadata"] != nil {
raw, err := json.Marshal(keys["metadata"])
if err != nil {
return err
}
var m Metadata
if err := json.Unmarshal(raw, &m); err != nil {
return err
}
b.metadata = m
}
return nil
}
func (b BytesValue) Value() []byte {
return b.value
}
func (b BytesValue) GetRawValue() any {
return b.value
}
func (b BytesValue) Len() int {
return len(b.value)
}
func (b BytesValue) GetMetadata() Metadata {
return b.metadata
BaseValue[[]byte]
}
func Bytes(value []byte, m Metadata) BytesValue {
return BytesValue{
value: value,
BaseAttribute: BaseAttribute{metadata: m},
}
return BytesValue{newValue(value, m)}
}
func BytesDefault(value []byte, m Metadata) BytesValue {
b := Bytes(value, m)
b.BaseAttribute.metadata.isDefault = true
return b
return BytesValue{defaultValue(value, m)}
}
func BytesExplicit(value []byte, m Metadata) BytesValue {
b := Bytes(value, m)
b.BaseAttribute.metadata.isExplicit = true
return b
return BytesValue{explicitValue(value, m)}
}
func BytesUnresolvable(m Metadata) BytesValue {
b := Bytes(nil, m)
b.BaseAttribute.metadata.isUnresolvable = true
return b
return BytesValue{unresolvableValue[[]byte](m)}
}
func BytesTest(value []byte) BytesValue {
b := Bytes(value, NewTestMetadata())
b.BaseAttribute.metadata.isUnresolvable = true
return b
return BytesValue{testValue(value)}
}
func (b BytesValue) ToRego() any {
m := b.metadata.ToRego().(map[string]any)
m["value"] = string(b.Value())
func (v BytesValue) ToRego() any {
m := v.metadata.ToRego().(map[string]any)
m["value"] = string(v.value)
return m
}
func (v BytesValue) Len() int {
return len(v.value)
}

View File

@@ -1,86 +1,27 @@
package types
import (
"encoding/json"
)
type IntValue struct {
BaseAttribute
value int
}
func (b IntValue) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]any{
"value": b.value,
"metadata": b.metadata,
})
}
func (b *IntValue) UnmarshalJSON(data []byte) error {
var keys map[string]any
if err := json.Unmarshal(data, &keys); err != nil {
return err
}
if keys["value"] != nil {
b.value = int(keys["value"].(float64))
}
if keys["metadata"] != nil {
raw, err := json.Marshal(keys["metadata"])
if err != nil {
return err
}
var m Metadata
if err := json.Unmarshal(raw, &m); err != nil {
return err
}
b.metadata = m
}
return nil
BaseValue[int]
}
func Int(value int, m Metadata) IntValue {
return IntValue{
value: value,
BaseAttribute: BaseAttribute{metadata: m},
}
}
func IntTest(value int) IntValue {
return Int(value, NewTestMetadata())
}
func IntFromInt32(value int32, m Metadata) IntValue {
return Int(int(value), m)
return IntValue{newValue(value, m)}
}
func IntDefault(value int, m Metadata) IntValue {
b := Int(value, m)
b.BaseAttribute.metadata.isDefault = true
return b
return IntValue{defaultValue(value, m)}
}
func IntUnresolvable(m Metadata) IntValue {
b := Int(0, m)
b.BaseAttribute.metadata.isUnresolvable = true
return b
return IntValue{unresolvableValue[int](m)}
}
func IntExplicit(value int, m Metadata) IntValue {
b := Int(value, m)
b.BaseAttribute.metadata.isExplicit = true
return b
return IntValue{newValue(value, m)}
}
func (b IntValue) GetMetadata() Metadata {
return b.metadata
}
func (b IntValue) Value() int {
return b.value
}
func (b IntValue) GetRawValue() any {
return b.value
func IntTest(value int) IntValue {
return IntValue{testValue(value)}
}
func (b IntValue) EqualTo(i int) bool {
@@ -103,9 +44,3 @@ func (b IntValue) GreaterThan(i int) bool {
}
return b.value > i
}
func (b IntValue) ToRego() any {
m := b.metadata.ToRego().(map[string]any)
m["value"] = b.Value()
return m
}

View File

@@ -1,74 +1,23 @@
package types
import (
"encoding/json"
)
type MapValue struct {
BaseAttribute
value map[string]string
}
func (b MapValue) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]any{
"value": b.value,
"metadata": b.metadata,
})
}
func (b *MapValue) UnmarshalJSON(data []byte) error {
var keys map[string]any
if err := json.Unmarshal(data, &keys); err != nil {
return err
}
if keys["value"] != nil {
var target map[string]string
raw, err := json.Marshal(keys["value"])
if err != nil {
return err
}
if err := json.Unmarshal(raw, &target); err != nil {
return err
}
b.value = target
}
if keys["metadata"] != nil {
raw, err := json.Marshal(keys["metadata"])
if err != nil {
return err
}
var m Metadata
if err := json.Unmarshal(raw, &m); err != nil {
return err
}
b.metadata = m
}
return nil
BaseValue[map[string]string]
}
func Map(value map[string]string, m Metadata) MapValue {
return MapValue{
value: value,
BaseAttribute: BaseAttribute{metadata: m},
}
return MapValue{newValue(value, m)}
}
func MapDefault(value map[string]string, m Metadata) MapValue {
b := Map(value, m)
b.BaseAttribute.metadata.isDefault = true
return b
return MapValue{defaultValue(value, m)}
}
func MapExplicit(value map[string]string, m Metadata) MapValue {
b := Map(value, m)
b.BaseAttribute.metadata.isExplicit = true
return b
return MapValue{explicitValue(value, m)}
}
func MapTest(value map[string]string) MapValue {
b := Map(value, NewTestMetadata())
b.BaseAttribute.metadata.isUnresolvable = true
return b
return MapValue{testValue(value)}
}
func (b MapValue) Value() map[string]string {
@@ -90,9 +39,3 @@ func (b MapValue) HasKey(key string) bool {
_, ok := b.value[key]
return ok
}
func (b MapValue) ToRego() any {
m := b.metadata.ToRego().(map[string]any)
m["value"] = b.Value()
return m
}

View File

@@ -198,14 +198,6 @@ func (m Metadata) IsUnmanaged() bool {
return !m.isManaged
}
type BaseAttribute struct {
metadata Metadata
}
func (b BaseAttribute) GetMetadata() Metadata {
return b.metadata
}
func (m Metadata) GetMetadata() Metadata {
return m
}

View File

@@ -1,89 +1,34 @@
package types
import (
"encoding/json"
"slices"
"strings"
)
func String(str string, m Metadata) StringValue {
return StringValue{
value: str,
BaseAttribute: BaseAttribute{metadata: m},
}
type StringValue struct {
BaseValue[string]
}
func String(value string, m Metadata) StringValue {
return StringValue{newValue(value, m)}
}
func StringDefault(value string, m Metadata) StringValue {
b := String(value, m)
b.BaseAttribute.metadata.isDefault = true
return b
return StringValue{defaultValue(value, m)}
}
func StringUnresolvable(m Metadata) StringValue {
b := String("", m)
b.BaseAttribute.metadata.isUnresolvable = true
return b
return StringValue{unresolvableValue[string](m)}
}
func StringExplicit(value string, m Metadata) StringValue {
b := String(value, m)
b.BaseAttribute.metadata.isExplicit = true
return b
return StringValue{explicitValue(value, m)}
}
func StringTest(value string) StringValue {
return String(value, NewTestMetadata())
}
type StringValueList []StringValue
type StringValue struct {
BaseAttribute
value string
}
func (l StringValueList) AsStrings() (output []string) {
for _, item := range l {
output = append(output, item.Value())
}
return output
}
func (s StringValue) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]any{
"value": s.value,
"metadata": s.metadata,
})
}
func (s *StringValue) UnmarshalJSON(data []byte) error {
var keys map[string]any
if err := json.Unmarshal(data, &keys); err != nil {
return err
}
if keys["value"] != nil {
s.value = keys["value"].(string)
}
if keys["metadata"] != nil {
raw, err := json.Marshal(keys["metadata"])
if err != nil {
return err
}
var m Metadata
if err := json.Unmarshal(raw, &m); err != nil {
return err
}
s.metadata = m
}
return nil
}
func (s StringValue) ToRego() any {
m := s.metadata.ToRego().(map[string]any)
m["value"] = s.Value()
return m
}
func (s StringValue) IsOneOf(values ...string) bool {
if s.metadata.isUnresolvable {
return false
@@ -91,18 +36,6 @@ func (s StringValue) IsOneOf(values ...string) bool {
return slices.Contains(values, s.value)
}
func (s StringValue) GetMetadata() Metadata {
return s.metadata
}
func (s StringValue) Value() string {
return s.value
}
func (s StringValue) GetRawValue() any {
return s.value
}
func (s StringValue) IsEmpty() bool {
if s.metadata.isUnresolvable {
return false
@@ -154,3 +87,12 @@ func (s StringValue) Contains(value string) bool {
}
return strings.Contains(s.value, value)
}
type StringValueList []StringValue
func (l StringValueList) AsStrings() (output []string) {
for _, item := range l {
output = append(output, item.Value())
}
return output
}

View File

@@ -6,78 +6,70 @@ import (
)
type TimeValue struct {
BaseAttribute
value time.Time
BaseValue[RFC3339Time]
}
func (t TimeValue) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]any{
"value": t.value.Format(time.RFC3339),
"metadata": t.metadata,
})
type RFC3339Time struct {
time.Time
}
func (t *TimeValue) UnmarshalJSON(data []byte) error {
var keys map[string]any
if err := json.Unmarshal(data, &keys); err != nil {
func (t RFC3339Time) MarshalJSON() ([]byte, error) {
return json.Marshal(t.Format(time.RFC3339))
}
func (t *RFC3339Time) UnmarshalJSON(data []byte) error {
if string(data) == "null" {
t.Time = time.Time{}
return nil
}
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
if keys["value"] != nil {
if ti, err := time.Parse(time.RFC3339, keys["value"].(string)); err == nil {
t.value = ti
}
}
if keys["metadata"] != nil {
raw, err := json.Marshal(keys["metadata"])
if err != nil {
return err
}
var m Metadata
if err := json.Unmarshal(raw, &m); err != nil {
return err
}
t.metadata = m
ti, err := time.Parse(time.RFC3339, s)
if err != nil {
return err
}
t.Time = ti
return nil
}
func Time(value time.Time, m Metadata) TimeValue {
return TimeValue{
value: value,
BaseAttribute: BaseAttribute{metadata: m},
}
return TimeValue{newValue(RFC3339Time{value}, m)}
}
func TimeDefault(value time.Time, m Metadata) TimeValue {
b := Time(value, m)
b.BaseAttribute.metadata.isDefault = true
return b
return TimeValue{defaultValue(RFC3339Time{value}, m)}
}
func TimeExplicit(value time.Time, m Metadata) TimeValue {
b := Time(value, m)
b.BaseAttribute.metadata.isExplicit = true
return b
return TimeValue{explicitValue(RFC3339Time{value}, m)}
}
func TimeUnresolvable(m Metadata) TimeValue {
b := Time(time.Time{}, m)
b.BaseAttribute.metadata.isUnresolvable = true
return b
return TimeValue{unresolvableValue[RFC3339Time](m)}
}
func TimeTest(value time.Time) TimeValue {
return Time(value, NewTestMetadata())
return TimeValue{testValue(RFC3339Time{value})}
}
func (t TimeValue) Value() time.Time {
return t.value
return t.value.Time
}
func (t TimeValue) GetRawValue() any {
return t.value
}
func (t TimeValue) ToRego() any {
m := t.metadata.ToRego().(map[string]any)
m["value"] = t.value.Format(time.RFC3339)
return m
}
func (t TimeValue) IsNever() bool {
if t.GetMetadata().isUnresolvable {
return false
@@ -98,9 +90,3 @@ func (t TimeValue) After(i time.Time) bool {
}
return t.value.After(i)
}
func (t TimeValue) ToRego() any {
m := t.metadata.ToRego().(map[string]any)
m["value"] = t.Value().Format(time.RFC3339)
return m
}