Skip to content

Commit 945f11d

Browse files
committed
refactor: Unify @merge with @project
1 parent 065ce99 commit 945f11d

9 files changed

Lines changed: 381 additions & 355 deletions

File tree

examples/endpointslice-controller/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ The pipeline is as follows.
126126
protocol: $.spec.ports.protocol
127127
address: $.endpoints.addresses
128128
- "@project":
129-
"@merge":
130-
metadata:
129+
- "$.": $.
130+
- metadata:
131131
name:
132132
"@concat":
133133
- $.spec.serviceName

examples/endpointslice-controller/endpointslice-controller-spec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ controllers:
6565
protocol: $.spec.ports.protocol
6666
address: $.endpoints.addresses
6767
- "@project":
68-
"@merge":
69-
metadata:
68+
- "$.": $.
69+
- metadata:
7070
name:
7171
"@concat":
7272
- $.spec.serviceName

pkg/expression/converter.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,3 +341,16 @@ func AsObjectList(d any) ([]Unstructured, error) {
341341
}
342342
return ret, nil
343343
}
344+
345+
// AsObjectOrObjectList returns an object or an expression list.
346+
func AsObjectOrObjectList(d any) ([]Unstructured, error) {
347+
if vs, err := AsObject(d); err == nil {
348+
return []Unstructured{vs}, nil
349+
}
350+
351+
if vs, err := AsObjectList(d); err == nil {
352+
return vs, nil
353+
}
354+
355+
return nil, fmt.Errorf("argument is not an object or an object list: %s", util.Stringify(d))
356+
}

pkg/expression/expression.go

Lines changed: 21 additions & 234 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import (
1111
"github.com/grokify/mogo/encoding/base36"
1212
"k8s.io/apimachinery/pkg/runtime/schema"
1313
"k8s.io/apimachinery/pkg/util/json"
14-
15-
"github.com/hsnlab/dcontroller/pkg/object"
1614
)
1715

1816
const ExpressionDumpMaxLevel = 10
@@ -210,27 +208,27 @@ func (e *Expression) Evaluate(ctx EvalCtx) (any, error) {
210208
// list commands: must eval the arg themselves
211209
if string(e.Op[0]) == "@" {
212210
switch e.Op {
213-
case "@merge":
214-
args, err := AsExpOrExpList(e.Arg)
215-
if err != nil {
216-
return nil, NewExpressionError(e, err)
217-
}
218-
219-
// evaluate expressons
220-
for _, arg := range args {
221-
res, err := arg.Evaluate(ctx)
222-
if err != nil {
223-
return nil, errors.New("failed to evaluate expression")
224-
}
225-
ctx.Object, err = object.MergeAny(ctx.Object, res)
226-
if err != nil {
227-
return nil, err
228-
}
229-
}
230-
231-
ctx.Log.V(8).Info("eval ready", "expression", e.String(), "result", ctx.Object)
232-
233-
return ctx.Object, nil
211+
// case "@merge":
212+
// args, err := AsExpOrExpList(e.Arg)
213+
// if err != nil {
214+
// return nil, NewExpressionError(e, err)
215+
// }
216+
217+
// // evaluate expressons
218+
// for _, arg := range args {
219+
// res, err := arg.Evaluate(ctx)
220+
// if err != nil {
221+
// return nil, errors.New("failed to evaluate expression")
222+
// }
223+
// ctx.Object, err = object.MergeAny(ctx.Object, res)
224+
// if err != nil {
225+
// return nil, err
226+
// }
227+
// }
228+
229+
// ctx.Log.V(8).Info("eval ready", "expression", e.String(), "result", ctx.Object)
230+
231+
// return ctx.Object, nil
234232

235233
case "@filter":
236234
args, err := AsExpOrExpList(e.Arg)
@@ -810,214 +808,3 @@ func (e *Expression) Evaluate(ctx EvalCtx) (any, error) {
810808
// literal map
811809
return Unstructured{e.Op: arg}, nil
812810
}
813-
814-
// unpacks the first-level list if any
815-
func unpackList(a any) []any {
816-
v := reflect.ValueOf(a)
817-
818-
// If it's not a slice, return nil
819-
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
820-
return []any{a}
821-
}
822-
823-
// If it's an empty slice, return nil
824-
if v.IsNil() || v.Len() == 0 {
825-
return []any{}
826-
}
827-
828-
// If it's [][]any, return the first slice
829-
elemKind := v.Type().Elem().Kind()
830-
if elemKind == reflect.Slice || elemKind == reflect.Array {
831-
return v.Index(0).Interface().([]any)
832-
}
833-
834-
// If it's []any{[]any, ...}, check if the first element is a slice
835-
first := v.Index(0)
836-
if !first.IsNil() {
837-
vs, ok := first.Interface().([]any)
838-
if ok {
839-
return vs
840-
}
841-
}
842-
843-
return a.([]any)
844-
}
845-
846-
func (e *Expression) UnmarshalJSON(b []byte) error {
847-
// cut raw content
848-
// try to unmarshal as a bool terminal expression
849-
bv := false
850-
if err := json.Unmarshal(b, &bv); err == nil {
851-
*e = Expression{Op: "@bool", Literal: bv}
852-
return nil
853-
}
854-
855-
// try to unmarshal as an int terminal expression
856-
var iv int64 = 0
857-
if err := json.Unmarshal(b, &iv); err == nil {
858-
*e = Expression{Op: "@int", Literal: iv}
859-
return nil
860-
}
861-
862-
// try to unmarshal as a float terminal expression
863-
fv := 0.0
864-
if err := json.Unmarshal(b, &fv); err == nil {
865-
*e = Expression{Op: "@float", Literal: fv}
866-
return nil
867-
}
868-
869-
// try to unmarshal as a string terminal expression
870-
sv := ""
871-
if err := json.Unmarshal(b, &sv); err == nil && sv != "" {
872-
*e = Expression{Op: "@string", Literal: sv}
873-
return nil
874-
}
875-
876-
// try to unmarshal as a literal list expression
877-
mv := []Expression{}
878-
if err := json.Unmarshal(b, &mv); err == nil {
879-
*e = Expression{Op: "@list", Literal: mv}
880-
return nil
881-
}
882-
883-
// try to unmarshal as a map expression
884-
cv := map[string]Expression{}
885-
if err := json.Unmarshal(b, &cv); err == nil {
886-
// specialcase operators: an op has a single key that starts with @
887-
if len(cv) == 1 {
888-
op := ""
889-
for k := range cv {
890-
op = k
891-
break
892-
}
893-
if string(op[0]) == "@" {
894-
exp := cv[op]
895-
*e = Expression{Op: op, Arg: &exp}
896-
return nil
897-
}
898-
}
899-
900-
// literal map: store as exp with op @dict and map as Literal
901-
*e = Expression{Op: "@dict", Literal: cv}
902-
return nil
903-
}
904-
905-
return NewUnmarshalError("expression", string(b))
906-
}
907-
908-
func (e *Expression) MarshalJSON() ([]byte, error) {
909-
switch e.Op {
910-
case "@any":
911-
return json.Marshal(e.Literal)
912-
913-
case "@bool":
914-
if e.Arg != nil {
915-
// keep the op for a correct round-trip and possible side-effects (conversion)
916-
ret := map[string]*Expression{e.Op: e.Arg}
917-
return json.Marshal(ret)
918-
}
919-
v, err := AsBool(e.Literal)
920-
if err != nil {
921-
return []byte(""), err
922-
}
923-
return json.Marshal(v)
924-
925-
case "@int":
926-
if e.Arg != nil {
927-
// keep the op for a correct round-trip and possible side-effects (conversion)
928-
ret := map[string]*Expression{e.Op: e.Arg}
929-
return json.Marshal(ret)
930-
}
931-
v, err := AsInt(e.Literal)
932-
if err != nil {
933-
return []byte(""), err
934-
}
935-
return json.Marshal(v)
936-
937-
case "@float":
938-
if e.Arg != nil {
939-
// keep the op for a correct round-trip and possible side-effects (conversion)
940-
ret := map[string]*Expression{e.Op: e.Arg}
941-
return json.Marshal(ret)
942-
}
943-
v, err := AsFloat(e.Literal)
944-
if err != nil {
945-
return []byte(""), err
946-
}
947-
return json.Marshal(v)
948-
949-
case "@string":
950-
if e.Arg != nil {
951-
// keep the op for a correct round-trip and possible side-effects (conversion)
952-
ret := map[string]*Expression{e.Op: e.Arg}
953-
return json.Marshal(ret)
954-
}
955-
v, err := AsString(e.Literal)
956-
if err != nil {
957-
return []byte(""), err
958-
}
959-
return json.Marshal(v)
960-
961-
case "@list":
962-
if e.Arg != nil {
963-
return json.Marshal(e.Arg)
964-
}
965-
es, ok := e.Literal.([]Expression)
966-
if !ok {
967-
return []byte(""), fmt.Errorf("invalid expression list: %#v", e)
968-
}
969-
return json.Marshal(es)
970-
971-
case "@dict":
972-
if e.Arg != nil {
973-
// can this ever happen?
974-
return json.Marshal(e.Arg)
975-
}
976-
977-
es, ok := e.Literal.(map[string]Expression)
978-
if !ok {
979-
return []byte(""), fmt.Errorf("invalid expression map: %#v", e)
980-
}
981-
// this is terribly stupid but here we go
982-
em := map[string]*Expression{}
983-
for k, v := range es {
984-
v := v
985-
em[k] = &v
986-
}
987-
return json.Marshal(em)
988-
989-
default:
990-
// everything else is a valid op
991-
if e.Op[0] != '@' {
992-
return []byte(""), fmt.Errorf("expected an op starting with @, got %#v", e)
993-
}
994-
995-
ret := map[string]*Expression{e.Op: e.Arg}
996-
return json.Marshal(ret)
997-
}
998-
// return []byte(""), fmt.Errorf("failed to JSON marshal expression %#v", e)
999-
}
1000-
1001-
func (e *Expression) String() string {
1002-
b, err := json.Marshal(e)
1003-
if err != nil {
1004-
return ""
1005-
}
1006-
return string(b)
1007-
}
1008-
1009-
func (e *Expression) DeepCopyInto(out *Expression) {
1010-
if e == nil || out == nil {
1011-
return
1012-
}
1013-
*out = *e
1014-
1015-
j, err := json.Marshal(e)
1016-
if err != nil {
1017-
return
1018-
}
1019-
1020-
if err := json.Unmarshal(j, out); err != nil {
1021-
return
1022-
}
1023-
}

0 commit comments

Comments
 (0)