Skip to content

Commit bff3a72

Browse files
Expose the CEL JSON types to assist with conversion to native values (#1261)
1 parent 559cbc9 commit bff3a72

28 files changed

Lines changed: 109 additions & 64 deletions

cel/cel_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package cel
1717
import (
1818
"bytes"
1919
"context"
20+
"encoding/json"
2021
"errors"
2122
"fmt"
2223
"os"
@@ -239,6 +240,43 @@ func TestAbbrevsDisambiguation(t *testing.T) {
239240
}
240241
}
241242

243+
func TestConvertToNativeJSONStructure(t *testing.T) {
244+
env, err := NewEnv()
245+
if err != nil {
246+
t.Fatalf("NewEnv() failed: %v", err)
247+
}
248+
ast, issues := env.Compile(`{
249+
"parts": [{"kind": "text"}]
250+
}`)
251+
if issues != nil && issues.Err() != nil {
252+
t.Fatal(issues.Err())
253+
}
254+
255+
prg, err := env.Program(ast)
256+
if err != nil {
257+
t.Fatal(err)
258+
}
259+
260+
result, _, err := prg.Eval(map[string]any{})
261+
if err != nil {
262+
t.Fatal(err)
263+
}
264+
265+
native, err := result.ConvertToNative(types.JSONValueType)
266+
if err != nil {
267+
t.Fatal(err)
268+
}
269+
270+
jsonBytes, err := json.Marshal(native)
271+
if err != nil {
272+
t.Fatalf("json.Marshal failed: %v", err)
273+
}
274+
want := `{"parts":[{"kind":"text"}]}`
275+
if string(jsonBytes) != want {
276+
t.Errorf("json.Marshal() failed, got : %s, wanted ", jsonBytes)
277+
}
278+
}
279+
242280
func TestCustomEnvError(t *testing.T) {
243281
env, err := NewCustomEnv(StdLib(), StdLib())
244282
if err != nil {

common/types/bool.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ func (b Bool) ConvertToNative(typeDesc reflect.Type) (any, error) {
6969
case boolWrapperType:
7070
// Convert the bool to a wrapperspb.BoolValue.
7171
return wrapperspb.Bool(bool(b)), nil
72-
case jsonValueType:
72+
case JSONValueType:
7373
// Return the bool as a new structpb.Value.
7474
return structpb.NewBoolValue(bool(b)), nil
7575
default:

common/types/bool_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func TestBoolConvertToNative_Error(t *testing.T) {
7676
}
7777

7878
func TestBoolConvertToNative_Json(t *testing.T) {
79-
val, err := True.ConvertToNative(jsonValueType)
79+
val, err := True.ConvertToNative(JSONValueType)
8080
pbVal := &structpb.Value{Kind: &structpb.Value_BoolValue{BoolValue: true}}
8181
if err != nil {
8282
t.Error(err)

common/types/bytes.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func (b Bytes) ConvertToNative(typeDesc reflect.Type) (any, error) {
7979
case byteWrapperType:
8080
// Convert the bytes to a wrapperspb.BytesValue.
8181
return wrapperspb.Bytes([]byte(b)), nil
82-
case jsonValueType:
82+
case JSONValueType:
8383
// CEL follows the proto3 to JSON conversion by encoding bytes to a string via base64.
8484
// The encoding below matches the golang 'encoding/json' behavior during marshaling,
8585
// which uses base64.StdEncoding.

common/types/bytes_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ func TestBytesConvertToNative_Error(t *testing.T) {
9797
}
9898

9999
func TestBytesConvertToNative_Json(t *testing.T) {
100-
val, err := Bytes("123").ConvertToNative(jsonValueType)
100+
val, err := Bytes("123").ConvertToNative(JSONValueType)
101101
if err != nil {
102102
t.Error(err)
103103
}

common/types/double.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ func (d Double) ConvertToNative(typeDesc reflect.Type) (any, error) {
8989
case floatWrapperType:
9090
// Convert to a wrapperspb.FloatValue (with truncation).
9191
return wrapperspb.Float(float32(d)), nil
92-
case jsonValueType:
92+
case JSONValueType:
9393
// Note, there are special cases for proto3 to json conversion that
9494
// expect the floating point value to be converted to a NaN,
9595
// Infinity, or -Infinity string values, but the jsonpb string

common/types/double_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -171,15 +171,15 @@ func TestDoubleConvertToNative_Float64(t *testing.T) {
171171
}
172172

173173
func TestDoubleConvertToNative_Json(t *testing.T) {
174-
val, err := Double(-1.4).ConvertToNative(jsonValueType)
174+
val, err := Double(-1.4).ConvertToNative(JSONValueType)
175175
pbVal := structpb.NewNumberValue(-1.4)
176176
if err != nil {
177177
t.Error(err)
178178
} else if !proto.Equal(val.(proto.Message), pbVal) {
179179
t.Errorf("Got '%v', expected -1.4", val)
180180
}
181181

182-
val, err = Double(math.NaN()).ConvertToNative(jsonValueType)
182+
val, err = Double(math.NaN()).ConvertToNative(JSONValueType)
183183
if err != nil {
184184
t.Error(err)
185185
} else {
@@ -189,14 +189,14 @@ func TestDoubleConvertToNative_Json(t *testing.T) {
189189
}
190190
}
191191

192-
val, err = Double(math.Inf(-1)).ConvertToNative(jsonValueType)
192+
val, err = Double(math.Inf(-1)).ConvertToNative(JSONValueType)
193193
pbVal = structpb.NewNumberValue(math.Inf(-1))
194194
if err != nil {
195195
t.Error(err)
196196
} else if !proto.Equal(val.(proto.Message), pbVal) {
197197
t.Errorf("Got '%v', expected -Infinity", val)
198198
}
199-
val, err = Double(math.Inf(0)).ConvertToNative(jsonValueType)
199+
val, err = Double(math.Inf(0)).ConvertToNative(JSONValueType)
200200
pbVal = structpb.NewNumberValue(math.Inf(0))
201201
if err != nil {
202202
t.Error(err)

common/types/duration.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ func (d Duration) ConvertToNative(typeDesc reflect.Type) (any, error) {
106106
case durationValueType:
107107
// Unwrap the CEL value to its underlying proto value.
108108
return dpb.New(d.Duration), nil
109-
case jsonValueType:
109+
case JSONValueType:
110110
// CEL follows the proto3 to JSON conversion.
111111
// Note, using jsonpb would wrap the result in extra double quotes.
112112
v := d.ConvertToType(StringType)

common/types/duration_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ func TestDurationConvertToNative_Any(t *testing.T) {
166166
}
167167

168168
func TestDurationConvertToNative_Error(t *testing.T) {
169-
val, err := Duration{Duration: duration(7506, 1000)}.ConvertToNative(jsonValueType)
169+
val, err := Duration{Duration: duration(7506, 1000)}.ConvertToNative(JSONValueType)
170170
if err != nil {
171171
t.Errorf("Got error: '%v', expected value", err)
172172
}
@@ -178,7 +178,7 @@ func TestDurationConvertToNative_Error(t *testing.T) {
178178
}
179179

180180
func TestDurationConvertToNative_Json(t *testing.T) {
181-
val, err := Duration{Duration: duration(7506, 1000)}.ConvertToNative(jsonValueType)
181+
val, err := Duration{Duration: duration(7506, 1000)}.ConvertToNative(JSONValueType)
182182
if err != nil {
183183
t.Error(err)
184184
}

common/types/int.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ func (i Int) ConvertToNative(typeDesc reflect.Type) (any, error) {
120120
case int64WrapperType:
121121
// Convert the value to a wrapperspb.Int64Value.
122122
return wrapperspb.Int64(int64(i)), nil
123-
case jsonValueType:
123+
case JSONValueType:
124124
// The proto-to-JSON conversion rules would convert all 64-bit integer values to JSON
125125
// decimal strings. Because CEL ints might come from the automatic widening of 32-bit
126126
// values in protos, the JSON type is chosen dynamically based on the value.

0 commit comments

Comments
 (0)