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