diff --git a/format/bson/bson.go b/format/bson/bson.go index e6b75bef..d8fbeb0e 100644 --- a/format/bson/bson.go +++ b/format/bson/bson.go @@ -82,6 +82,7 @@ func decodeBSONDocument(d *decode.D) { d.FieldU8("subtype") d.FieldRawLen("value", int64(length)*8) case elementTypeUndefined: + //deprecated case elementTypeObjectID: d.FieldRawLen("value", 12*8) case elementTypeBoolean: @@ -89,6 +90,7 @@ func decodeBSONDocument(d *decode.D) { case elementTypeDatatime: d.FieldS32("value") case elementTypeNull: + d.FieldValueNil("value") case elementTypeRegexp: d.FieldUTF8Null("value") d.FieldUTF8Null("options") diff --git a/format/bson/testdata/test.fqtest b/format/bson/testdata/test.fqtest index e90ec352..c555a632 100644 --- a/format/bson/testdata/test.fqtest +++ b/format/bson/testdata/test.fqtest @@ -59,6 +59,7 @@ $ fq -d bson verbose /test.bson 0x60| 0a | . | type: "null" (10) (Null value) 0x6c-0x6c.7 (1) 0x60| 6e 75 6c| nul| name: "null" 0x6d-0x71.7 (5) 0x70|6c 00 |l. | + | | | value: null 0x72-NA (0) 0x70| 00| | .| | terminator: 0 (valid) 0x72-0x72.7 (1) $ fq -d bson torepr /test.bson { diff --git a/format/cbor/cbor.go b/format/cbor/cbor.go index 2edfb049..84aa3a4f 100644 --- a/format/cbor/cbor.go +++ b/format/cbor/cbor.go @@ -218,7 +218,7 @@ func decodeCBORValue(d *decode.D) interface{} { case shortCountSpecialTrue: d.FieldValueBool("value", true) case shortCountSpecialNull: - // TODO: null + d.FieldValueNil("value") case shortCountSpecialUndefined: // TODO: undefined case 24: diff --git a/format/msgpack/msgpack.go b/format/msgpack/msgpack.go index d81467ae..50462189 100644 --- a/format/msgpack/msgpack.go +++ b/format/msgpack/msgpack.go @@ -100,7 +100,7 @@ func decodeMsgPackValue(d *decode.D) { d.FieldUTF8("value", int(length)) }}, {r: [2]byte{0xc0, 0xc0}, s: scalar.S{Sym: "nil"}, d: func(d *decode.D) { - // TODO: fq has no good null type atm + d.FieldValueNil("value") }}, {r: [2]byte{0xc1, 0xc1}, s: scalar.S{Sym: "never_used"}, d: func(d *decode.D) { d.Fatalf("0xc1 never used") diff --git a/format/msgpack/testdata/test.fqtest b/format/msgpack/testdata/test.fqtest index 0eecddca..66bc93bc 100644 --- a/format/msgpack/testdata/test.fqtest +++ b/format/msgpack/testdata/test.fqtest @@ -84,6 +84,7 @@ $ fq -d msgpack v test.msgpack 0x40|6c 6c |ll | | | | value{}: 0x42-0x42.7 (1) 0x40| c0| | .| | type: "nil" (0xc0) 0x42-0x42.7 (1) + | | | value: null 0x43-NA (0) $ fq -d msgpack torepr test.msgpack { "array": [ diff --git a/internal/gojqextra/totype.go b/internal/gojqextra/totype.go index 631f8598..cae17ee7 100644 --- a/internal/gojqextra/totype.go +++ b/internal/gojqextra/totype.go @@ -87,6 +87,7 @@ func ToInt(x interface{}) (int, bool) { case gojq.JQValue: return ToInt(x.JQValueToGoJQ()) default: + // nil and other should fail, "null | tonumber" in jq is an error return 0, false } } @@ -112,6 +113,7 @@ func ToFloat(x interface{}) (float64, bool) { case gojq.JQValue: return ToFloat(x.JQValueToGoJQ()) default: + // nil and other should fail, "null | tonumber" in jq is an error return 0.0, false } } diff --git a/pkg/decode/decode.go b/pkg/decode/decode.go index b467ec75..5e24d9f3 100644 --- a/pkg/decode/decode.go +++ b/pkg/decode/decode.go @@ -653,6 +653,10 @@ func (d *D) FieldValueStr(name string, a string, sms ...scalar.Mapper) { d.FieldScalarFn(name, func(_ scalar.S) (scalar.S, error) { return scalar.S{Actual: a}, nil }, sms...) } +func (d *D) FieldValueNil(name string, sms ...scalar.Mapper) { + d.FieldScalarFn(name, func(_ scalar.S) (scalar.S, error) { return scalar.S{Actual: nil}, nil }, sms...) +} + func (d *D) FieldValueRaw(name string, a []byte, sms ...scalar.Mapper) { d.FieldScalarFn(name, func(_ scalar.S) (scalar.S, error) { return scalar.S{Actual: bitio.NewBufferFromBytes(a, -1)}, nil diff --git a/pkg/interp/preview.go b/pkg/interp/preview.go index 8bde12f9..24be0a1f 100644 --- a/pkg/interp/preview.go +++ b/pkg/interp/preview.go @@ -33,6 +33,8 @@ func previewValue(v interface{}, df scalar.DisplayFormat) string { return fmt.Sprintf("%q", vv[0:50]) + "..." } return fmt.Sprintf("%q", vv) + case nil: + return "null" case *bitio.Buffer: return "raw bits" case *big.Int: