From 79e2c770c17894daa61d01c55cef5b6f9249519b Mon Sep 17 00:00:00 2001 From: sfc-gh-astachowski Date: Tue, 9 Jul 2024 11:21:29 +0200 Subject: [PATCH 1/3] Test --- converter_test.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/converter_test.go b/converter_test.go index f94a4e81a..716e816e8 100644 --- a/converter_test.go +++ b/converter_test.go @@ -363,6 +363,30 @@ func TestStringToValue(t *testing.T) { } else if ts.UnixNano() != 1549491451123456789 { t.Errorf("expected unix timestamp: 1549491451123456789, got %v", ts.UnixNano()) } + + rowType = &execResponseRowType{Type: "array", Fields: []fieldMetadata{{Type: "array", Fields: []fieldMetadata{{Type: "fixed"}}}}} + src = "[[3]]" + if err = stringToValue(context.Background(), &dest, *rowType, &src, nil, nil); err != nil { + t.Errorf("unexpected error: %v", err) + } else if arr, ok := dest.([]any); !ok { + t.Errorf("expected type: '[][]int64', got '%v'", reflect.TypeOf(dest)) + } else if arr1, ok := arr[0].([]int64); !ok { + t.Errorf("expected value 3, got '%v'", arr1[0]) + } + + rowType = &execResponseRowType{Type: "array", Fields: []fieldMetadata{{Type: "array", Fields: []fieldMetadata{{Type: "array", Fields: []fieldMetadata{{Type: "array", Fields: []fieldMetadata{{Type: "fixed"}}}}}}}}} + src = "[[[[3]]]]" + if err = stringToValue(context.Background(), &dest, *rowType, &src, nil, nil); err != nil { + t.Errorf("unexpected error: %v", err) + } else if arr, ok := dest.([]any); !ok { + t.Errorf("expected type: '[][][]int64', got '%v'", reflect.TypeOf(dest)) + } else if arr1, ok := arr[0].([]any); !ok { + t.Errorf("todo") + } else if arr2, ok := arr1[0].([]any); !ok { + t.Errorf("todo") + } else if arr3, ok := arr2[0].([]int64); !ok { + t.Errorf("todo %v", arr3[0]) + } } type tcArrayToString struct { From 112ffe80a178fae406f4fe27bd7788f3cceb1bc0 Mon Sep 17 00:00:00 2001 From: sfc-gh-astachowski Date: Tue, 9 Jul 2024 13:01:04 +0200 Subject: [PATCH 2/3] Prototype solution --- converter.go | 10 ++++++++++ converter_test.go | 18 +++++++++--------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/converter.go b/converter.go index f16f9ea4a..728f6bc06 100644 --- a/converter.go +++ b/converter.go @@ -942,6 +942,16 @@ func buildStructuredArray(ctx context.Context, fieldMetadata fieldMetadata, srcV return buildStructuredArrayRecursive[[]byte](ctx, fieldMetadata.Fields[0], srcValue, params) case "date", "time", "timestamp_ltz", "timestamp_ntz", "timestamp_tz": return buildStructuredArrayRecursive[time.Time](ctx, fieldMetadata.Fields[0], srcValue, params) + case "array": + arr := make([]any, len(srcValue)) + for i, v := range srcValue { + structuredArray, err := buildStructuredArray(ctx, fieldMetadata.Fields[0], v.([]any), params) + if err != nil { + return nil, err + } + arr[i] = structuredArray + } + return arr, nil } } return srcValue, nil diff --git a/converter_test.go b/converter_test.go index 716e816e8..ad9537f74 100644 --- a/converter_test.go +++ b/converter_test.go @@ -368,10 +368,10 @@ func TestStringToValue(t *testing.T) { src = "[[3]]" if err = stringToValue(context.Background(), &dest, *rowType, &src, nil, nil); err != nil { t.Errorf("unexpected error: %v", err) - } else if arr, ok := dest.([]any); !ok { + } else if arr, ok := dest.([][]int64); !ok { t.Errorf("expected type: '[][]int64', got '%v'", reflect.TypeOf(dest)) - } else if arr1, ok := arr[0].([]int64); !ok { - t.Errorf("expected value 3, got '%v'", arr1[0]) + } else if arr[0][0] != 3 { + t.Errorf("expected value: 3, got '%v'", arr[0][0]) } rowType = &execResponseRowType{Type: "array", Fields: []fieldMetadata{{Type: "array", Fields: []fieldMetadata{{Type: "array", Fields: []fieldMetadata{{Type: "array", Fields: []fieldMetadata{{Type: "fixed"}}}}}}}}} @@ -379,13 +379,13 @@ func TestStringToValue(t *testing.T) { if err = stringToValue(context.Background(), &dest, *rowType, &src, nil, nil); err != nil { t.Errorf("unexpected error: %v", err) } else if arr, ok := dest.([]any); !ok { - t.Errorf("expected type: '[][][]int64', got '%v'", reflect.TypeOf(dest)) + t.Errorf("expected type: '[]any', got '%v'", reflect.TypeOf(dest)) } else if arr1, ok := arr[0].([]any); !ok { - t.Errorf("todo") - } else if arr2, ok := arr1[0].([]any); !ok { - t.Errorf("todo") - } else if arr3, ok := arr2[0].([]int64); !ok { - t.Errorf("todo %v", arr3[0]) + t.Errorf("expected type: '[]any', got '%v'", reflect.TypeOf(arr[0])) + } else if arr2, ok := arr1[0].([][]int64); !ok { + t.Errorf("expected type: '[][]int64', got '%v'", reflect.TypeOf(arr1[0])) + } else if arr2[0][0] != 3 { + t.Errorf("expected value: 3, got '%v'", arr2[0][0]) } } From 4c095c5e1b779c7f33a5a959f90ac7e253463942 Mon Sep 17 00:00:00 2001 From: sfc-gh-astachowski Date: Wed, 10 Jul 2024 14:27:57 +0200 Subject: [PATCH 3/3] End-to-end test --- structured_type_read_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/structured_type_read_test.go b/structured_type_read_test.go index efedecbcd..6d0709904 100644 --- a/structured_type_read_test.go +++ b/structured_type_read_test.go @@ -1023,6 +1023,12 @@ func TestArrayOfArrays(t *testing.T) { actual: make([][]time.Time, 2), expected: [][]time.Time{{time.Date(2024, time.January, 5, 11, 22, 33, 0, warsawTz)}, {time.Date(2001, time.November, 12, 11, 22, 33, 0, warsawTz)}}, }, + { + name: "3D_bool", + query: "SELECT ARRAY_CONSTRUCT(ARRAY_CONSTRUCT(ARRAY_CONSTRUCT(true, false), ARRAY_CONSTRUCT(false)), ARRAY_CONSTRUCT(ARRAY_CONSTRUCT(false, true), ARRAY_CONSTRUCT(true, true)))::ARRAY(ARRAY(ARRAY(BOOLEAN)))", + actual: make([][][]bool, 2), + expected: []any{[][]bool{{true, false}, {false}}, [][]bool{{false, true}, {true, true}}}, + }, } runDBTest(t, func(dbt *DBTest) { dbt.mustExec("ALTER SESSION SET TIMEZONE = 'Europe/Warsaw'")