github.com/ydb-platform/ydb-go-sdk/v3@v3.57.0/internal/value/value_test.go (about)

     1  package value
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"math/big"
     7  	"reflect"
     8  	"strconv"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/stretchr/testify/require"
    13  	"google.golang.org/protobuf/proto"
    14  
    15  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
    16  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/types"
    17  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
    18  )
    19  
    20  func BenchmarkMemory(b *testing.B) {
    21  	b.ReportAllocs()
    22  	v := TupleValue(
    23  		VoidValue(),
    24  		BoolValue(true),
    25  		Int8Value(1),
    26  		Int16Value(1),
    27  		Int32Value(1),
    28  		Int64Value(1),
    29  		Uint8Value(1),
    30  		Uint16Value(1),
    31  		Uint32Value(1),
    32  		Uint64Value(1),
    33  		DateValue(1),
    34  		DatetimeValue(1),
    35  		TimestampValue(1),
    36  		IntervalValue(1),
    37  		VoidValue(),
    38  		FloatValue(1),
    39  		DoubleValue(1),
    40  		BytesValue([]byte("test")),
    41  		DecimalValue([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}, 22, 9),
    42  		DyNumberValue("123"),
    43  		JSONValue("{}"),
    44  		JSONDocumentValue("{}"),
    45  		TzDateValue("1"),
    46  		TzDatetimeValue("1"),
    47  		TzTimestampValue("1"),
    48  		TextValue("1"),
    49  		UUIDValue([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}),
    50  		YSONValue([]byte("{}")),
    51  		ListValue(
    52  			Int64Value(1),
    53  			Int64Value(2),
    54  			Int64Value(3),
    55  		),
    56  		SetValue(
    57  			Int64Value(1),
    58  			Int64Value(2),
    59  			Int64Value(3),
    60  		),
    61  		OptionalValue(IntervalValue(1)),
    62  		OptionalValue(OptionalValue(IntervalValue(1))),
    63  		StructValue(
    64  			StructValueField{"series_id", Uint64Value(1)},
    65  			StructValueField{"title", TextValue("test")},
    66  			StructValueField{"air_date", DateValue(1)},
    67  			StructValueField{"remove_date", OptionalValue(TzDatetimeValue("1234"))},
    68  		),
    69  		DictValue(
    70  			DictValueField{TextValue("series_id"), Uint64Value(1)},
    71  			DictValueField{TextValue("title"), Uint64Value(2)},
    72  			DictValueField{TextValue("air_date"), Uint64Value(3)},
    73  			DictValueField{TextValue("remove_date"), Uint64Value(4)},
    74  		),
    75  		NullValue(types.NewOptional(types.NewOptional(types.NewOptional(types.Bool)))),
    76  		VariantValueTuple(Int32Value(42), 1, types.NewTuple(
    77  			types.Bytes,
    78  			types.Int32,
    79  		)),
    80  		VariantValueStruct(Int32Value(42), "bar", types.NewStruct(
    81  			types.StructField{
    82  				Name: "foo",
    83  				T:    types.Bytes,
    84  			},
    85  			types.StructField{
    86  				Name: "bar",
    87  				T:    types.Int32,
    88  			},
    89  		)),
    90  		ZeroValue(types.Text),
    91  		ZeroValue(types.NewStruct()),
    92  		ZeroValue(types.NewTuple()),
    93  	)
    94  	for i := 0; i < b.N; i++ {
    95  		a := allocator.New()
    96  		_ = ToYDB(v, a)
    97  		a.Free()
    98  	}
    99  }
   100  
   101  func TestToYDBFromYDB(t *testing.T) {
   102  	for i, v := range []Value{
   103  		BoolValue(true),
   104  		Int8Value(1),
   105  		Int16Value(1),
   106  		Int32Value(1),
   107  		Int64Value(1),
   108  		Uint8Value(1),
   109  		Uint16Value(1),
   110  		Uint32Value(1),
   111  		Uint64Value(1),
   112  		DateValue(1),
   113  		DatetimeValue(1),
   114  		TimestampValue(1),
   115  		IntervalValue(1),
   116  		VoidValue(),
   117  		FloatValue(1),
   118  		DoubleValue(1),
   119  		BytesValue([]byte("test")),
   120  		DecimalValue([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}, 22, 9),
   121  		DyNumberValue("123"),
   122  		JSONValue("{}"),
   123  		JSONDocumentValue("{}"),
   124  		TzDateValue("1"),
   125  		TzDatetimeValue("1"),
   126  		TzTimestampValue("1"),
   127  		TextValue("1"),
   128  		UUIDValue([...]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6}),
   129  		YSONValue([]byte("{}")),
   130  		TupleValue(
   131  			Int64Value(1),
   132  			Int32Value(2),
   133  			Int16Value(3),
   134  			Int8Value(4),
   135  		),
   136  		ListValue(
   137  			Int64Value(1),
   138  			Int64Value(2),
   139  			Int64Value(3),
   140  		),
   141  		SetValue(
   142  			Int64Value(1),
   143  			Int64Value(2),
   144  			Int64Value(3),
   145  		),
   146  		OptionalValue(IntervalValue(1)),
   147  		OptionalValue(OptionalValue(IntervalValue(1))),
   148  		StructValue(
   149  			StructValueField{"series_id", Uint64Value(1)},
   150  			StructValueField{"title", TextValue("test")},
   151  			StructValueField{"air_date", DateValue(1)},
   152  			StructValueField{"remove_date", OptionalValue(TzDatetimeValue("1234"))},
   153  		),
   154  		DictValue(
   155  			DictValueField{TextValue("series_id"), Uint64Value(1)},
   156  			DictValueField{TextValue("title"), Uint64Value(2)},
   157  			DictValueField{TextValue("air_date"), Uint64Value(3)},
   158  			DictValueField{TextValue("remove_date"), Uint64Value(4)},
   159  		),
   160  		NullValue(types.Bool),
   161  		NullValue(types.NewOptional(types.Bool)),
   162  		VariantValueTuple(Int32Value(42), 1, types.NewTuple(
   163  			types.Bytes,
   164  			types.Int32,
   165  		)),
   166  		VariantValueStruct(Int32Value(42), "bar", types.NewStruct(
   167  			types.StructField{
   168  				Name: "foo",
   169  				T:    types.Bytes,
   170  			},
   171  			types.StructField{
   172  				Name: "bar",
   173  				T:    types.Int32,
   174  			},
   175  		)),
   176  		ZeroValue(types.Text),
   177  		ZeroValue(types.NewStruct()),
   178  		ZeroValue(types.NewTuple()),
   179  	} {
   180  		t.Run(strconv.Itoa(i)+"."+v.Yql(), func(t *testing.T) {
   181  			a := allocator.New()
   182  			defer a.Free()
   183  			value := ToYDB(v, a)
   184  			dualConversedValue, err := fromYDB(value.GetType(), value.GetValue())
   185  			require.NoError(t, err)
   186  			if !proto.Equal(value, ToYDB(dualConversedValue, a)) {
   187  				t.Errorf("dual conversion failed:\n\n - got:  %v\n\n - want: %v", ToYDB(dualConversedValue, a), value)
   188  			}
   189  		})
   190  	}
   191  }
   192  
   193  func TestValueYql(t *testing.T) {
   194  	for i, tt := range []struct {
   195  		value   Value
   196  		literal string
   197  	}{
   198  		{
   199  			value:   VoidValue(),
   200  			literal: `Void()`,
   201  		},
   202  		{
   203  			value:   TextValue("some\"text\"with brackets"),
   204  			literal: `"some\"text\"with brackets"u`,
   205  		},
   206  		{
   207  			value:   TextValue(`some text with slashes \ \\ \\\`),
   208  			literal: `"some text with slashes \\ \\\\ \\\\\\"u`,
   209  		},
   210  		{
   211  			value:   BytesValue([]byte("foo")),
   212  			literal: `"foo"`,
   213  		},
   214  		{
   215  			value:   BytesValue([]byte("\xFE\xFF")),
   216  			literal: `"\xfe\xff"`,
   217  		},
   218  		{
   219  			value:   OptionalValue(BytesValue([]byte{0, 1, 2, 3, 4, 5, 6})),
   220  			literal: `Just("\x00\x01\x02\x03\x04\x05\x06")`,
   221  		},
   222  		{
   223  			value:   BoolValue(true),
   224  			literal: `true`,
   225  		},
   226  		{
   227  			value:   Int8Value(42),
   228  			literal: `42t`,
   229  		},
   230  		{
   231  			value:   Uint8Value(42),
   232  			literal: `42ut`,
   233  		},
   234  		{
   235  			value:   Int16Value(42),
   236  			literal: `42s`,
   237  		},
   238  		{
   239  			value:   Uint16Value(42),
   240  			literal: `42us`,
   241  		},
   242  		{
   243  			value:   Int32Value(42),
   244  			literal: `42`,
   245  		},
   246  		{
   247  			value:   Uint32Value(42),
   248  			literal: `42u`,
   249  		},
   250  		{
   251  			value:   Int64Value(42),
   252  			literal: `42l`,
   253  		},
   254  		{
   255  			value:   Uint64Value(42),
   256  			literal: `42ul`,
   257  		},
   258  		{
   259  			value:   Uint64Value(200000000000),
   260  			literal: `200000000000ul`,
   261  		},
   262  		{
   263  			value:   FloatValue(42.2121236),
   264  			literal: `Float("42.212124")`,
   265  		},
   266  		{
   267  			value:   FloatValue(float32(math.Inf(+1))),
   268  			literal: `Float("+Inf")`,
   269  		},
   270  		{
   271  			value:   FloatValue(float32(math.Inf(-1))),
   272  			literal: `Float("-Inf")`,
   273  		},
   274  		{
   275  			value:   FloatValue(float32(math.NaN())),
   276  			literal: `Float("NaN")`,
   277  		},
   278  		{
   279  			value:   DoubleValue(42.2121236192),
   280  			literal: `Double("42.2121236192")`,
   281  		},
   282  		{
   283  			value:   DoubleValue(math.Inf(+1)),
   284  			literal: `Double("+Inf")`,
   285  		},
   286  		{
   287  			value:   DoubleValue(math.Inf(-1)),
   288  			literal: `Double("-Inf")`,
   289  		},
   290  		{
   291  			value:   DoubleValue(math.NaN()),
   292  			literal: `Double("NaN")`,
   293  		},
   294  		{
   295  			value: DateValue(func() uint32 {
   296  				v, _ := time.Parse("2006-01-02", "2022-06-17")
   297  
   298  				return uint32(v.Sub(time.Unix(0, 0)) / time.Hour / 24)
   299  			}()),
   300  			literal: `Date("2022-06-17")`,
   301  		},
   302  		{
   303  			value: DatetimeValue(func() uint32 {
   304  				v, _ := time.Parse("2006-01-02 15:04:05", "2022-06-17 05:19:20")
   305  
   306  				return uint32(v.UTC().Sub(time.Unix(0, 0)).Seconds())
   307  			}()),
   308  			literal: `Datetime("2022-06-17T05:19:20Z")`,
   309  		},
   310  		{
   311  			value:   TzDateValue("2022-06-17,Europe/Berlin"),
   312  			literal: `TzDate("2022-06-17,Europe/Berlin")`,
   313  		},
   314  		{
   315  			value:   TzDatetimeValue("2022-06-17T05:19:20,Europe/Berlin"),
   316  			literal: `TzDatetime("2022-06-17T05:19:20,Europe/Berlin")`,
   317  		},
   318  		{
   319  			value:   IntervalValueFromDuration(time.Duration(42) * time.Millisecond),
   320  			literal: `Interval("PT0.042000S")`,
   321  		},
   322  		{
   323  			value: TimestampValueFromTime(func() time.Time {
   324  				tt, err := time.Parse(LayoutTimestamp, "1997-12-14T03:09:42.123456Z")
   325  				require.NoError(t, err)
   326  
   327  				return tt.UTC()
   328  			}()),
   329  			literal: `Timestamp("1997-12-14T03:09:42.123456Z")`,
   330  		},
   331  		{
   332  			value:   TzTimestampValue("1997-12-14T03:09:42.123456,Europe/Berlin"),
   333  			literal: `TzTimestamp("1997-12-14T03:09:42.123456,Europe/Berlin")`,
   334  		},
   335  		{
   336  			value:   NullValue(types.Int32),
   337  			literal: `Nothing(Optional<Int32>)`,
   338  		},
   339  		{
   340  			value:   NullValue(types.NewOptional(types.Bool)),
   341  			literal: `Nothing(Optional<Optional<Bool>>)`,
   342  		},
   343  		{
   344  			value:   Int32Value(42),
   345  			literal: `42`,
   346  		},
   347  		{
   348  			value:   OptionalValue(Int32Value(42)),
   349  			literal: `Just(42)`,
   350  		},
   351  		{
   352  			value:   OptionalValue(OptionalValue(Int32Value(42))),
   353  			literal: `Just(Just(42))`,
   354  		},
   355  		{
   356  			value:   OptionalValue(OptionalValue(OptionalValue(Int32Value(42)))),
   357  			literal: `Just(Just(Just(42)))`,
   358  		},
   359  		{
   360  			value: ListValue(
   361  				Int32Value(-1),
   362  				Int32Value(0),
   363  				Int32Value(1),
   364  				Int32Value(2),
   365  				Int32Value(3),
   366  			),
   367  			literal: `[-1,0,1,2,3]`,
   368  		},
   369  		{
   370  			value: ListValue(
   371  				Int64Value(0),
   372  				Int64Value(1),
   373  				Int64Value(2),
   374  				Int64Value(3),
   375  			),
   376  			literal: `[0l,1l,2l,3l]`,
   377  		},
   378  		{
   379  			value: SetValue(
   380  				Int64Value(0),
   381  				Int64Value(1),
   382  				Int64Value(2),
   383  				Int64Value(3),
   384  			),
   385  			literal: `{0l,1l,2l,3l}`,
   386  		},
   387  		{
   388  			value: TupleValue(
   389  				Int32Value(0),
   390  				Int64Value(1),
   391  				FloatValue(2),
   392  				TextValue("3"),
   393  			),
   394  			literal: `(0,1l,Float("2"),"3"u)`,
   395  		},
   396  		{
   397  			value: VariantValueTuple(Int32Value(42), 1, types.NewTuple(
   398  				types.Bytes,
   399  				types.Int32,
   400  			)),
   401  			literal: `Variant(42,"1",Variant<String,Int32>)`,
   402  		},
   403  		{
   404  			value: VariantValueTuple(TextValue("foo"), 1, types.NewTuple(
   405  				types.Bytes,
   406  				types.Text,
   407  			)),
   408  			literal: `Variant("foo"u,"1",Variant<String,Utf8>)`,
   409  		},
   410  		{
   411  			value: VariantValueTuple(BoolValue(true), 0, types.NewTuple(
   412  				types.Bytes,
   413  				types.Int32,
   414  			)),
   415  			literal: `Variant(true,"0",Variant<String,Int32>)`,
   416  		},
   417  		{
   418  			value: VariantValueStruct(Int32Value(42), "bar", types.NewStruct(
   419  				types.StructField{
   420  					Name: "foo",
   421  					T:    types.Bytes,
   422  				},
   423  				types.StructField{
   424  					Name: "bar",
   425  					T:    types.Int32,
   426  				},
   427  			)),
   428  			literal: `Variant(42,"bar",Variant<'bar':Int32,'foo':String>)`,
   429  		},
   430  		{
   431  			value: StructValue(
   432  				StructValueField{"series_id", Uint64Value(1)},
   433  				StructValueField{"title", TextValue("test")},
   434  				StructValueField{"air_date", DateValue(1)},
   435  			),
   436  			literal: "<|`air_date`:Date(\"1970-01-02\"),`series_id`:1ul,`title`:\"test\"u|>",
   437  		},
   438  		{
   439  			value: DictValue(
   440  				DictValueField{TextValue("foo"), Int32Value(42)},
   441  				DictValueField{TextValue("bar"), Int32Value(43)},
   442  			),
   443  			literal: `{"bar"u:43,"foo"u:42}`,
   444  		},
   445  		{
   446  			value: DictValue(
   447  				DictValueField{TextValue("foo"), VoidValue()},
   448  				DictValueField{TextValue("bar"), VoidValue()},
   449  			),
   450  			literal: `{"bar"u:Void(),"foo"u:Void()}`,
   451  		},
   452  		{
   453  			value:   ZeroValue(types.Bool),
   454  			literal: `false`,
   455  		},
   456  		{
   457  			value:   ZeroValue(types.NewOptional(types.Bool)),
   458  			literal: `Nothing(Optional<Bool>)`,
   459  		},
   460  		{
   461  			value:   ZeroValue(types.NewTuple(types.Bool, types.Double)),
   462  			literal: `(false,Double("0"))`,
   463  		},
   464  		{
   465  			value: ZeroValue(types.NewStruct(
   466  				types.StructField{
   467  					Name: "foo",
   468  					T:    types.Bool,
   469  				},
   470  				types.StructField{
   471  					Name: "bar",
   472  					T:    types.Text,
   473  				},
   474  			)),
   475  			literal: "<|`bar`:\"\"u,`foo`:false|>",
   476  		},
   477  		{
   478  			value:   ZeroValue(types.UUID),
   479  			literal: `Uuid("00000000-0000-0000-0000-000000000000")`,
   480  		},
   481  		{
   482  			value:   DecimalValueFromBigInt(big.NewInt(-1234567890123456), 22, 9),
   483  			literal: `Decimal("-1234567.890123456",22,9)`,
   484  		},
   485  		{
   486  			value:   DyNumberValue("-1234567890123456"),
   487  			literal: `DyNumber("-1234567890123456")`,
   488  		},
   489  		{
   490  			value:   JSONValue("{\"a\":-1234567890123456}"),
   491  			literal: `Json(@@{"a":-1234567890123456}@@)`,
   492  		},
   493  		{
   494  			value:   JSONDocumentValue("{\"a\":-1234567890123456}"),
   495  			literal: `JsonDocument(@@{"a":-1234567890123456}@@)`,
   496  		},
   497  		{
   498  			value:   YSONValue([]byte("<a=1>[3;%false]")),
   499  			literal: `Yson("<a=1>[3;%false]")`,
   500  		},
   501  	} {
   502  		t.Run(strconv.Itoa(i)+"."+tt.literal, func(t *testing.T) {
   503  			require.Equal(t, tt.literal, tt.value.Yql())
   504  		})
   505  	}
   506  }
   507  
   508  func TestOptionalValueCastTo(t *testing.T) {
   509  	for _, tt := range []struct {
   510  		name string
   511  		v    *optionalValue
   512  		dst  **string
   513  		exp  interface{}
   514  		err  error
   515  	}{
   516  		{
   517  			name: xtest.CurrentFileLine(),
   518  			v:    OptionalValue(TextValue("test")),
   519  			dst:  func(v *string) **string { return &v }(func(s string) *string { return &s }("")),
   520  			exp:  func(v *string) **string { return &v }(func(s string) *string { return &s }("test")),
   521  			err:  nil,
   522  		},
   523  		{
   524  			name: xtest.CurrentFileLine(),
   525  			v:    OptionalValue(TextValue("test")),
   526  			dst:  func(v *string) **string { return &v }(func() *string { return nil }()),
   527  			exp:  func(v *string) **string { return &v }(func(s string) *string { return &s }("test")),
   528  			err:  nil,
   529  		},
   530  		{
   531  			name: xtest.CurrentFileLine(),
   532  			v:    NullValue(types.Text),
   533  			dst:  func(v *string) **string { return &v }(func(s string) *string { return &s }("")),
   534  			exp:  func(v *string) **string { return &v }(func() *string { return nil }()),
   535  			err:  nil,
   536  		},
   537  		{
   538  			name: xtest.CurrentFileLine(),
   539  			v:    NullValue(types.Text),
   540  			dst:  func(v *string) **string { return &v }(func() *string { return nil }()),
   541  			exp:  func(v *string) **string { return &v }(func() *string { return nil }()),
   542  			err:  nil,
   543  		},
   544  	} {
   545  		t.Run(tt.name, func(t *testing.T) {
   546  			err := tt.v.castTo(tt.dst)
   547  			if tt.err != nil {
   548  				require.ErrorIs(t, err, tt.err)
   549  			} else {
   550  				require.NoError(t, err)
   551  				require.Equal(t, tt.exp, tt.dst)
   552  			}
   553  		})
   554  	}
   555  }
   556  
   557  func TestNullable(t *testing.T) {
   558  	for _, test := range []struct {
   559  		name string
   560  		t    types.Type
   561  		v    interface{}
   562  		exp  Value
   563  	}{
   564  		{
   565  			name: "bool",
   566  			t:    types.Bool,
   567  			v:    func(v bool) *bool { return &v }(true),
   568  			exp:  OptionalValue(BoolValue(true)),
   569  		},
   570  		{
   571  			name: "nil bool",
   572  			t:    types.Bool,
   573  			v:    func() *bool { return nil }(),
   574  			exp:  NullValue(types.Bool),
   575  		},
   576  		{
   577  			name: "int8",
   578  			t:    types.Int8,
   579  			v:    func(v int8) *int8 { return &v }(123),
   580  			exp:  OptionalValue(Int8Value(123)),
   581  		},
   582  		{
   583  			name: "nil int8",
   584  			t:    types.Int8,
   585  			v:    func() *int8 { return nil }(),
   586  			exp:  NullValue(types.Int8),
   587  		},
   588  		{
   589  			name: "uint8",
   590  			t:    types.Uint8,
   591  			v:    func(v uint8) *uint8 { return &v }(123),
   592  			exp:  OptionalValue(Uint8Value(123)),
   593  		},
   594  		{
   595  			name: "nil uint8",
   596  			t:    types.Uint8,
   597  			v:    func() *uint8 { return nil }(),
   598  			exp:  NullValue(types.Uint8),
   599  		},
   600  		{
   601  			name: "int16",
   602  			t:    types.Int16,
   603  			v:    func(v int16) *int16 { return &v }(123),
   604  			exp:  OptionalValue(Int16Value(123)),
   605  		},
   606  		{
   607  			name: "nil int16",
   608  			t:    types.Int16,
   609  			v:    func() *int16 { return nil }(),
   610  			exp:  NullValue(types.Int16),
   611  		},
   612  		{
   613  			name: "uint16",
   614  			t:    types.Uint16,
   615  			v:    func(v uint16) *uint16 { return &v }(123),
   616  			exp:  OptionalValue(Uint16Value(123)),
   617  		},
   618  		{
   619  			name: "nil uint16",
   620  			t:    types.Uint16,
   621  			v:    func() *uint16 { return nil }(),
   622  			exp:  NullValue(types.Uint16),
   623  		},
   624  		{
   625  			name: "int32",
   626  			t:    types.Int32,
   627  			v:    func(v int32) *int32 { return &v }(123),
   628  			exp:  OptionalValue(Int32Value(123)),
   629  		},
   630  		{
   631  			name: "nil int32",
   632  			t:    types.Int32,
   633  			v:    func() *int32 { return nil }(),
   634  			exp:  NullValue(types.Int32),
   635  		},
   636  		{
   637  			name: "uint32",
   638  			t:    types.Uint32,
   639  			v:    func(v uint32) *uint32 { return &v }(123),
   640  			exp:  OptionalValue(Uint32Value(123)),
   641  		},
   642  		{
   643  			name: "nil uint32",
   644  			t:    types.Uint32,
   645  			v:    func() *uint32 { return nil }(),
   646  			exp:  NullValue(types.Uint32),
   647  		},
   648  		{
   649  			name: "int64",
   650  			t:    types.Int64,
   651  			v:    func(v int64) *int64 { return &v }(123),
   652  			exp:  OptionalValue(Int64Value(123)),
   653  		},
   654  		{
   655  			name: "nil int64",
   656  			t:    types.Int64,
   657  			v:    func() *int64 { return nil }(),
   658  			exp:  NullValue(types.Int64),
   659  		},
   660  		{
   661  			name: "uint64",
   662  			t:    types.Uint64,
   663  			v:    func(v uint64) *uint64 { return &v }(123),
   664  			exp:  OptionalValue(Uint64Value(123)),
   665  		},
   666  		{
   667  			name: "nil uint64",
   668  			t:    types.Uint64,
   669  			v:    func() *uint64 { return nil }(),
   670  			exp:  NullValue(types.Uint64),
   671  		},
   672  		{
   673  			name: "float",
   674  			t:    types.Float,
   675  			v:    func(v float32) *float32 { return &v }(123),
   676  			exp:  OptionalValue(FloatValue(123)),
   677  		},
   678  		{
   679  			name: "nil float",
   680  			t:    types.Float,
   681  			v:    func() *float32 { return nil }(),
   682  			exp:  NullValue(types.Float),
   683  		},
   684  		{
   685  			name: "double",
   686  			t:    types.Double,
   687  			v:    func(v float64) *float64 { return &v }(123),
   688  			exp:  OptionalValue(DoubleValue(123)),
   689  		},
   690  		{
   691  			name: "nil float",
   692  			t:    types.Double,
   693  			v:    func() *float64 { return nil }(),
   694  			exp:  NullValue(types.Double),
   695  		},
   696  		{
   697  			name: "date from int32",
   698  			t:    types.Date,
   699  			v:    func(v uint32) *uint32 { return &v }(123),
   700  			exp:  OptionalValue(DateValue(123)),
   701  		},
   702  		{
   703  			name: "date from time.Time",
   704  			t:    types.Date,
   705  			v:    func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)),
   706  			exp:  OptionalValue(DateValueFromTime(time.Unix(123, 456))),
   707  		},
   708  		{
   709  			name: "nil date",
   710  			t:    types.Date,
   711  			v:    func() *uint32 { return nil }(),
   712  			exp:  NullValue(types.Date),
   713  		},
   714  		{
   715  			name: "datetime from int32",
   716  			t:    types.Datetime,
   717  			v:    func(v uint32) *uint32 { return &v }(123),
   718  			exp:  OptionalValue(DatetimeValue(123)),
   719  		},
   720  		{
   721  			name: "datetime from time.Time",
   722  			t:    types.Datetime,
   723  			v:    func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)),
   724  			exp:  OptionalValue(DatetimeValueFromTime(time.Unix(123, 456))),
   725  		},
   726  		{
   727  			name: "nil datetime",
   728  			t:    types.Datetime,
   729  			v:    func() *uint32 { return nil }(),
   730  			exp:  NullValue(types.Datetime),
   731  		},
   732  		{
   733  			name: "timestamp from int32",
   734  			t:    types.Timestamp,
   735  			v:    func(v uint64) *uint64 { return &v }(123),
   736  			exp:  OptionalValue(TimestampValue(123)),
   737  		},
   738  		{
   739  			name: "timestamp from time.Time",
   740  			t:    types.Timestamp,
   741  			v:    func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)),
   742  			exp:  OptionalValue(TimestampValueFromTime(time.Unix(123, 456))),
   743  		},
   744  		{
   745  			name: "nil timestamp",
   746  			t:    types.Timestamp,
   747  			v:    func() *uint64 { return nil }(),
   748  			exp:  NullValue(types.Timestamp),
   749  		},
   750  		{
   751  			name: "tzDate from int32",
   752  			t:    types.TzDate,
   753  			v:    func(v string) *string { return &v }(""),
   754  			exp:  OptionalValue(TzDateValue("")),
   755  		},
   756  		{
   757  			name: "tzDate from time.Time",
   758  			t:    types.TzDate,
   759  			v:    func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)),
   760  			exp:  OptionalValue(TzDateValueFromTime(time.Unix(123, 456))),
   761  		},
   762  		{
   763  			name: "nil tzDate",
   764  			t:    types.TzDate,
   765  			v:    func() *string { return nil }(),
   766  			exp:  NullValue(types.TzDate),
   767  		},
   768  		{
   769  			name: "interval from int64",
   770  			t:    types.Interval,
   771  			v:    func(v int64) *int64 { return &v }(123),
   772  			exp:  OptionalValue(IntervalValue(123)),
   773  		},
   774  		{
   775  			name: "interval from time.Time",
   776  			t:    types.Interval,
   777  			v:    func(v time.Duration) *time.Duration { return &v }(time.Second),
   778  			exp:  OptionalValue(IntervalValueFromDuration(time.Second)),
   779  		},
   780  		{
   781  			name: "nil interval",
   782  			t:    types.Interval,
   783  			v:    func() *int64 { return nil }(),
   784  			exp:  NullValue(types.Interval),
   785  		},
   786  		{
   787  			name: "tzDatetime from int32",
   788  			t:    types.TzDatetime,
   789  			v:    func(v string) *string { return &v }(""),
   790  			exp:  OptionalValue(TzDatetimeValue("")),
   791  		},
   792  		{
   793  			name: "tzTzDatetime from time.Time",
   794  			t:    types.TzDatetime,
   795  			v:    func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)),
   796  			exp:  OptionalValue(TzDatetimeValueFromTime(time.Unix(123, 456))),
   797  		},
   798  		{
   799  			name: "nil tzTzDatetime",
   800  			t:    types.TzDatetime,
   801  			v:    func() *string { return nil }(),
   802  			exp:  NullValue(types.TzDatetime),
   803  		},
   804  		{
   805  			name: "tzTimestamp from int32",
   806  			t:    types.TzTimestamp,
   807  			v:    func(v string) *string { return &v }(""),
   808  			exp:  OptionalValue(TzTimestampValue("")),
   809  		},
   810  		{
   811  			name: "TzTimestamp from time.Time",
   812  			t:    types.TzTimestamp,
   813  			v:    func(v time.Time) *time.Time { return &v }(time.Unix(123, 456)),
   814  			exp:  OptionalValue(TzTimestampValueFromTime(time.Unix(123, 456))),
   815  		},
   816  		{
   817  			name: "nil TzTimestamp",
   818  			t:    types.TzTimestamp,
   819  			v:    func() *string { return nil }(),
   820  			exp:  NullValue(types.TzTimestamp),
   821  		},
   822  		{
   823  			name: "string",
   824  			t:    types.Bytes,
   825  			v:    func(v string) *string { return &v }("test"),
   826  			exp:  OptionalValue(BytesValue([]byte("test"))),
   827  		},
   828  		{
   829  			name: "string",
   830  			t:    types.Bytes,
   831  			v:    func(v []byte) *[]byte { return &v }([]byte("test")),
   832  			exp:  OptionalValue(BytesValue([]byte("test"))),
   833  		},
   834  		{
   835  			name: "nil string",
   836  			t:    types.Bytes,
   837  			v:    func() *string { return nil }(),
   838  			exp:  NullValue(types.Bytes),
   839  		},
   840  		{
   841  			name: "utf8",
   842  			t:    types.Text,
   843  			v:    func(v string) *string { return &v }("test"),
   844  			exp:  OptionalValue(TextValue("test")),
   845  		},
   846  		{
   847  			name: "nil utf8",
   848  			t:    types.Text,
   849  			v:    func() *string { return nil }(),
   850  			exp:  NullValue(types.Text),
   851  		},
   852  		{
   853  			name: "yson",
   854  			t:    types.YSON,
   855  			v:    func(v string) *string { return &v }("test"),
   856  			exp:  OptionalValue(YSONValue([]byte("test"))),
   857  		},
   858  		{
   859  			name: "yson",
   860  			t:    types.YSON,
   861  			v:    func(v []byte) *[]byte { return &v }([]byte("test")),
   862  			exp:  OptionalValue(YSONValue([]byte("test"))),
   863  		},
   864  		{
   865  			name: "nil yson",
   866  			t:    types.YSON,
   867  			v:    func() *string { return nil }(),
   868  			exp:  NullValue(types.YSON),
   869  		},
   870  		{
   871  			name: "json",
   872  			t:    types.JSON,
   873  			v:    func(v string) *string { return &v }("test"),
   874  			exp:  OptionalValue(JSONValue("test")),
   875  		},
   876  		{
   877  			name: "json",
   878  			t:    types.JSON,
   879  			v:    func(v []byte) *[]byte { return &v }([]byte("test")),
   880  			exp:  OptionalValue(JSONValue("test")),
   881  		},
   882  		{
   883  			name: "nil json",
   884  			t:    types.JSON,
   885  			v:    func() *string { return nil }(),
   886  			exp:  NullValue(types.JSON),
   887  		},
   888  		{
   889  			name: "uuid",
   890  			t:    types.UUID,
   891  			v:    func(v [16]byte) *[16]byte { return &v }([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}),
   892  			exp:  OptionalValue(UUIDValue([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16})),
   893  		},
   894  		{
   895  			name: "jsonDocument",
   896  			t:    types.JSONDocument,
   897  			v:    func(v string) *string { return &v }("test"),
   898  			exp:  OptionalValue(JSONDocumentValue("test")),
   899  		},
   900  		{
   901  			name: "jsonDocument",
   902  			t:    types.JSONDocument,
   903  			v:    func(v []byte) *[]byte { return &v }([]byte("test")),
   904  			exp:  OptionalValue(JSONDocumentValue("test")),
   905  		},
   906  		{
   907  			name: "nil jsonDocument",
   908  			t:    types.JSONDocument,
   909  			v:    func() *string { return nil }(),
   910  			exp:  NullValue(types.JSONDocument),
   911  		},
   912  		{
   913  			name: "dyNumber",
   914  			t:    types.DyNumber,
   915  			v:    func(v string) *string { return &v }("test"),
   916  			exp:  OptionalValue(DyNumberValue("test")),
   917  		},
   918  		{
   919  			name: "nil dyNumber",
   920  			t:    types.DyNumber,
   921  			v:    func() *string { return nil }(),
   922  			exp:  NullValue(types.DyNumber),
   923  		},
   924  	} {
   925  		t.Run(test.name, func(t *testing.T) {
   926  			a := allocator.New()
   927  			defer a.Free()
   928  			v := Nullable(test.t, test.v)
   929  			if !proto.Equal(ToYDB(v, a), ToYDB(test.exp, a)) {
   930  				t.Fatalf("unexpected value: %v, exp: %v", v, test.exp)
   931  			}
   932  		})
   933  	}
   934  }
   935  
   936  func TestCastNumbers(t *testing.T) {
   937  	numberValues := []struct {
   938  		value  Value
   939  		signed bool
   940  		len    int
   941  	}{
   942  		{
   943  			value:  Uint64Value(1),
   944  			signed: false,
   945  			len:    8,
   946  		},
   947  		{
   948  			value:  Int64Value(2),
   949  			signed: true,
   950  			len:    8,
   951  		},
   952  		{
   953  			value:  Uint32Value(3),
   954  			signed: false,
   955  			len:    4,
   956  		},
   957  		{
   958  			value:  Int32Value(4),
   959  			signed: true,
   960  			len:    4,
   961  		},
   962  		{
   963  			value:  Uint16Value(5),
   964  			signed: false,
   965  			len:    2,
   966  		},
   967  		{
   968  			value:  Int16Value(6),
   969  			signed: true,
   970  			len:    2,
   971  		},
   972  		{
   973  			value:  Uint8Value(7),
   974  			signed: false,
   975  			len:    1,
   976  		},
   977  		{
   978  			value:  Int8Value(8),
   979  			signed: true,
   980  			len:    1,
   981  		},
   982  	}
   983  	numberDestinations := []struct {
   984  		destination interface{}
   985  		signed      bool
   986  		len         int
   987  	}{
   988  		{
   989  			destination: func(v uint64) *uint64 { return &v }(1),
   990  			signed:      false,
   991  			len:         8,
   992  		},
   993  		{
   994  			destination: func(v int64) *int64 { return &v }(2),
   995  			signed:      true,
   996  			len:         8,
   997  		},
   998  		{
   999  			destination: func(v uint32) *uint32 { return &v }(3),
  1000  			signed:      false,
  1001  			len:         4,
  1002  		},
  1003  		{
  1004  			destination: func(v int32) *int32 { return &v }(4),
  1005  			signed:      true,
  1006  			len:         4,
  1007  		},
  1008  		{
  1009  			destination: func(v uint16) *uint16 { return &v }(5),
  1010  			signed:      false,
  1011  			len:         2,
  1012  		},
  1013  		{
  1014  			destination: func(v int16) *int16 { return &v }(6),
  1015  			signed:      true,
  1016  			len:         2,
  1017  		},
  1018  		{
  1019  			destination: func(v uint8) *uint8 { return &v }(7),
  1020  			signed:      false,
  1021  			len:         1,
  1022  		},
  1023  		{
  1024  			destination: func(v int8) *int8 { return &v }(8),
  1025  			signed:      true,
  1026  			len:         1,
  1027  		},
  1028  		{
  1029  			destination: func(v float32) *float32 { return &v }(7),
  1030  			signed:      true,
  1031  			len:         4,
  1032  		},
  1033  		{
  1034  			destination: func(v float64) *float64 { return &v }(8),
  1035  			signed:      true,
  1036  			len:         8,
  1037  		},
  1038  	}
  1039  	for _, dst := range numberDestinations {
  1040  		for _, src := range numberValues {
  1041  			t.Run(fmt.Sprintf("%sā†’%s",
  1042  				src.value.Yql(), reflect.ValueOf(dst.destination).Type().Elem().String(),
  1043  			), func(t *testing.T) {
  1044  				mustErr := false
  1045  				switch {
  1046  				case src.len == dst.len && src.signed != dst.signed,
  1047  					src.len > dst.len,
  1048  					src.signed && !dst.signed:
  1049  					mustErr = true
  1050  				}
  1051  				err := CastTo(src.value, dst.destination)
  1052  				if mustErr {
  1053  					require.Error(t, err)
  1054  				} else {
  1055  					require.NoError(t, err)
  1056  				}
  1057  			})
  1058  			t.Run(fmt.Sprintf("Optional(%s)ā†’%s",
  1059  				src.value.Yql(), reflect.ValueOf(dst.destination).Type().Elem().String(),
  1060  			), func(t *testing.T) {
  1061  				mustErr := false
  1062  				switch {
  1063  				case src.len == dst.len && src.signed != dst.signed,
  1064  					src.len > dst.len,
  1065  					src.signed && !dst.signed:
  1066  					mustErr = true
  1067  				}
  1068  				err := CastTo(OptionalValue(src.value), dst.destination)
  1069  				if mustErr {
  1070  					require.Error(t, err)
  1071  				} else {
  1072  					require.NoError(t, err)
  1073  				}
  1074  			})
  1075  		}
  1076  	}
  1077  }
  1078  
  1079  func TestCastOtherTypes(t *testing.T) {
  1080  	for _, tt := range []struct {
  1081  		v      Value
  1082  		dst    interface{}
  1083  		result interface{}
  1084  		error  bool
  1085  	}{
  1086  		{
  1087  			v:      BytesValue([]byte("test")),
  1088  			dst:    func(v []byte) *[]byte { return &v }(make([]byte, 0, 10)),
  1089  			result: func(v []byte) *[]byte { return &v }([]byte("test")),
  1090  			error:  false,
  1091  		},
  1092  		{
  1093  			v:      TextValue("test"),
  1094  			dst:    func(v []byte) *[]byte { return &v }(make([]byte, 0, 10)),
  1095  			result: func(v []byte) *[]byte { return &v }([]byte("test")),
  1096  			error:  false,
  1097  		},
  1098  		{
  1099  			v:      BytesValue([]byte("test")),
  1100  			dst:    func(v string) *string { return &v }(""),
  1101  			result: func(v string) *string { return &v }("test"),
  1102  			error:  false,
  1103  		},
  1104  		{
  1105  			v:      DoubleValue(123),
  1106  			dst:    func(v float64) *float64 { return &v }(9),
  1107  			result: func(v float64) *float64 { return &v }(123),
  1108  			error:  false,
  1109  		},
  1110  		{
  1111  			v:      DoubleValue(123),
  1112  			dst:    func(v float32) *float32 { return &v }(9),
  1113  			result: func(v float32) *float32 { return &v }(9),
  1114  			error:  true,
  1115  		},
  1116  		{
  1117  			v:      FloatValue(123),
  1118  			dst:    func(v float64) *float64 { return &v }(9),
  1119  			result: func(v float64) *float64 { return &v }(123),
  1120  			error:  false,
  1121  		},
  1122  		{
  1123  			v:      FloatValue(123),
  1124  			dst:    func(v float32) *float32 { return &v }(9),
  1125  			result: func(v float32) *float32 { return &v }(123),
  1126  			error:  false,
  1127  		},
  1128  		{
  1129  			v:      Uint64Value(123),
  1130  			dst:    func(v float32) *float32 { return &v }(9),
  1131  			result: func(v float32) *float32 { return &v }(9),
  1132  			error:  true,
  1133  		},
  1134  		{
  1135  			v:      Uint64Value(123),
  1136  			dst:    func(v float64) *float64 { return &v }(9),
  1137  			result: func(v float64) *float64 { return &v }(9),
  1138  			error:  true,
  1139  		},
  1140  		{
  1141  			v:      OptionalValue(DoubleValue(123)),
  1142  			dst:    func(v float64) *float64 { return &v }(9),
  1143  			result: func(v float64) *float64 { return &v }(123),
  1144  			error:  false,
  1145  		},
  1146  	} {
  1147  		t.Run(fmt.Sprintf("%sā†’%v", tt.v.Type().Yql(), reflect.ValueOf(tt.dst).Type().Elem()),
  1148  			func(t *testing.T) {
  1149  				if err := CastTo(tt.v, tt.dst); (err != nil) != tt.error {
  1150  					t.Errorf("castTo() error = %v, want %v", err, tt.error)
  1151  				} else if !reflect.DeepEqual(tt.dst, tt.result) {
  1152  					t.Errorf("castTo() result = %+v, want %+v",
  1153  						reflect.ValueOf(tt.dst).Elem(),
  1154  						reflect.ValueOf(tt.result).Elem(),
  1155  					)
  1156  				}
  1157  			},
  1158  		)
  1159  	}
  1160  }