github.com/ydb-platform/ydb-go-sdk/v3@v3.89.2/tests/integration/table_bulk_upsert_test.go (about) 1 //go:build integration 2 // +build integration 3 4 package integration 5 6 import ( 7 "context" 8 "fmt" 9 "os" 10 "testing" 11 12 "github.com/stretchr/testify/require" 13 14 "github.com/ydb-platform/ydb-go-sdk/v3" 15 "github.com/ydb-platform/ydb-go-sdk/v3/table" 16 "github.com/ydb-platform/ydb-go-sdk/v3/table/result/named" 17 "github.com/ydb-platform/ydb-go-sdk/v3/table/types" 18 ) 19 20 func TestTableBulkUpsertSession(t *testing.T) { 21 var ( 22 scope = newScope(t) 23 driver = scope.Driver() 24 tablePath = scope.TablePath() 25 ) 26 27 // upsert 28 var rows []types.Value 29 30 for i := int64(0); i < 10; i++ { 31 val := fmt.Sprintf("value for %v", i) 32 rows = append(rows, types.StructValue( 33 types.StructFieldValue("id", types.Int64Value(i)), 34 types.StructFieldValue("val", types.TextValue(val)), 35 )) 36 } 37 38 err := driver.Table().Do(scope.Ctx, func(ctx context.Context, s table.Session) error { 39 return s.BulkUpsert(ctx, tablePath, types.ListValue(rows...)) 40 }) 41 scope.Require.NoError(err) 42 43 for i := int64(0); i < 10; i++ { 44 val := fmt.Sprintf("value for %v", i) 45 assertIdValue(scope.Ctx, t, tablePath, i, val) 46 } 47 } 48 49 func TestTableBulkUpsert(t *testing.T) { 50 var ( 51 scope = newScope(t) 52 driver = scope.Driver() 53 tablePath = scope.TablePath() 54 ) 55 56 // upsert 57 var rows []types.Value 58 59 for i := int64(0); i < 10; i++ { 60 val := fmt.Sprintf("value for %v", i) 61 rows = append(rows, types.StructValue( 62 types.StructFieldValue("id", types.Int64Value(i)), 63 types.StructFieldValue("val", types.TextValue(val)), 64 )) 65 } 66 67 err := driver.Table().BulkUpsert(scope.Ctx, tablePath, table.BulkUpsertDataRows( 68 types.ListValue(rows...), 69 )) 70 scope.Require.NoError(err) 71 72 for i := int64(0); i < 10; i++ { 73 val := fmt.Sprintf("value for %v", i) 74 assertIdValue(scope.Ctx, t, tablePath, i, val) 75 } 76 } 77 78 func TestTableCsvBulkUpsert(t *testing.T) { 79 var ( 80 scope = newScope(t) 81 driver = scope.Driver() 82 tablePath = scope.TablePath() 83 ) 84 85 csv := `id,val 86 42,"text42" 87 43,"text43"` 88 89 err := driver.Table().BulkUpsert(scope.Ctx, tablePath, table.BulkUpsertDataCsv( 90 []byte(csv), 91 table.WithCsvHeader(), 92 )) 93 scope.Require.NoError(err) 94 95 assertIdValue(scope.Ctx, t, tablePath, 42, "text42") 96 assertIdValue(scope.Ctx, t, tablePath, 43, "text43") 97 } 98 99 func TestTableCsvBulkUpsertDelimiter(t *testing.T) { 100 var ( 101 scope = newScope(t) 102 driver = scope.Driver() 103 tablePath = scope.TablePath() 104 ) 105 106 csv := `id:val 107 42:"text42" 108 43:"text43"` 109 110 err := driver.Table().BulkUpsert(scope.Ctx, tablePath, table.BulkUpsertDataCsv( 111 []byte(csv), 112 table.WithCsvHeader(), 113 table.WithCsvDelimiter([]byte(":")), 114 )) 115 scope.Require.NoError(err) 116 117 assertIdValue(scope.Ctx, t, tablePath, 42, "text42") 118 assertIdValue(scope.Ctx, t, tablePath, 43, "text43") 119 } 120 121 func TestTableCsvBulkUpsertNullValue(t *testing.T) { 122 var ( 123 scope = newScope(t) 124 driver = scope.Driver() 125 tablePath = scope.TablePath() 126 ) 127 128 csv := `id,val 129 42,hello 130 43,hello world` 131 132 err := driver.Table().BulkUpsert(scope.Ctx, tablePath, table.BulkUpsertDataCsv( 133 []byte(csv), 134 table.WithCsvHeader(), 135 table.WithCsvNullValue([]byte("hello")), 136 )) 137 scope.Require.NoError(err) 138 139 assertIdValueNil(scope.Ctx, t, tablePath, 42) 140 assertIdValue(scope.Ctx, t, tablePath, 43, "hello world") 141 } 142 143 func TestTableCsvBulkUpsertSkipRows(t *testing.T) { 144 var ( 145 scope = newScope(t) 146 driver = scope.Driver() 147 tablePath = scope.TablePath() 148 ) 149 150 // Empty row are OK after skipped rows 151 csv := `First skip row 152 Second skip row 153 154 id,val 155 42,123 156 43,456 157 158 ` 159 160 err := driver.Table().BulkUpsert(scope.Ctx, tablePath, table.BulkUpsertDataCsv( 161 []byte(csv), 162 table.WithCsvHeader(), 163 table.WithCsvSkipRows(2), 164 )) 165 scope.Require.NoError(err) 166 167 assertIdValue(scope.Ctx, t, tablePath, 42, "123") 168 assertIdValue(scope.Ctx, t, tablePath, 43, "456") 169 } 170 171 func TestTableArrowBulkUpsert(t *testing.T) { 172 var ( 173 scope = newScope(t) 174 driver = scope.Driver() 175 tablePath = scope.TablePath() 176 ) 177 178 // data & schema generated with make_test_arrow.py script 179 data, err := os.ReadFile("testdata/bulk_upsert_test_data.arrow") 180 scope.Require.NoError(err) 181 182 schema, err := os.ReadFile("testdata/bulk_upsert_test_schema.arrow") 183 scope.Require.NoError(err) 184 185 err = driver.Table().BulkUpsert(scope.Ctx, tablePath, table.BulkUpsertDataArrow( 186 []byte(data), 187 table.WithArrowSchema(schema), 188 )) 189 scope.Require.NoError(err) 190 191 assertIdValue(scope.Ctx, t, tablePath, 123, "data1") 192 assertIdValue(scope.Ctx, t, tablePath, 234, "data2") 193 } 194 195 func assertIdValueImpl(ctx context.Context, t *testing.T, tableName string, id int64, val *string) { 196 ctx, cancel := context.WithCancel(context.Background()) 197 defer cancel() 198 199 db, err := ydb.Open(ctx, 200 os.Getenv("YDB_CONNECTION_STRING"), 201 // ydb.WithAccessTokenCredentials(os.Getenv("YDB_ACCESS_TOKEN_CREDENTIALS")), 202 ) 203 require.NoError(t, err) 204 err = db.Table().DoTx(ctx, func(ctx context.Context, tx table.TransactionActor) (err error) { 205 res, err := tx.Execute(ctx, fmt.Sprintf("SELECT val FROM `%s` WHERE id = %d", tableName, id), nil) 206 if err != nil { 207 return err 208 } 209 err = res.NextResultSetErr(ctx) 210 if err != nil { 211 return err 212 } 213 require.EqualValues(t, 1, res.ResultSetCount()) 214 if !res.NextRow() { 215 if err = res.Err(); err != nil { 216 return err 217 } 218 return fmt.Errorf("unexpected empty result set") 219 } 220 var resultVal *string 221 err = res.ScanNamed( 222 named.Optional("val", &resultVal), 223 ) 224 if err != nil { 225 return err 226 } 227 if val != nil { 228 require.NotEmpty(t, resultVal) 229 require.EqualValues(t, *val, *resultVal) 230 } else { 231 require.Nil(t, resultVal) 232 } 233 234 return res.Err() 235 }, table.WithTxSettings(table.TxSettings(table.WithSnapshotReadOnly())), table.WithIdempotent()) 236 require.NoError(t, err) 237 } 238 239 func assertIdValue(ctx context.Context, t *testing.T, tableName string, id int64, val string) { 240 assertIdValueImpl(ctx, t, tableName, id, &val) 241 } 242 243 func assertIdValueNil(ctx context.Context, t *testing.T, tableName string, id int64) { 244 assertIdValueImpl(ctx, t, tableName, id, nil) 245 }