diff --git a/pkg/iac/types/base_value.go b/pkg/iac/types/base_value.go new file mode 100644 index 0000000000..53628cd201 --- /dev/null +++ b/pkg/iac/types/base_value.go @@ -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 +} diff --git a/pkg/iac/types/bool.go b/pkg/iac/types/bool.go index 175df0904e..d9f4d72ebd 100755 --- a/pkg/iac/types/bool.go +++ b/pkg/iac/types/bool.go @@ -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. diff --git a/pkg/iac/types/bytes.go b/pkg/iac/types/bytes.go index 4ab6b42283..8697bc44a5 100755 --- a/pkg/iac/types/bytes.go +++ b/pkg/iac/types/bytes.go @@ -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) +} diff --git a/pkg/iac/types/int.go b/pkg/iac/types/int.go index 7e46f6899a..ae6ba74613 100755 --- a/pkg/iac/types/int.go +++ b/pkg/iac/types/int.go @@ -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 -} diff --git a/pkg/iac/types/map.go b/pkg/iac/types/map.go index dfa32a62cc..5055c7d4de 100755 --- a/pkg/iac/types/map.go +++ b/pkg/iac/types/map.go @@ -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 -} diff --git a/pkg/iac/types/metadata.go b/pkg/iac/types/metadata.go index c714604416..a7b6c0dc03 100755 --- a/pkg/iac/types/metadata.go +++ b/pkg/iac/types/metadata.go @@ -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 } diff --git a/pkg/iac/types/string.go b/pkg/iac/types/string.go index 739ade38a0..336f9674c2 100755 --- a/pkg/iac/types/string.go +++ b/pkg/iac/types/string.go @@ -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 +} diff --git a/pkg/iac/types/time.go b/pkg/iac/types/time.go index 6a79252aca..351408484d 100755 --- a/pkg/iac/types/time.go +++ b/pkg/iac/types/time.go @@ -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 -}