github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/sys/it/impl_sqlquery_test.go (about) 1 /* 2 * Copyright (c) 2022-present unTill Pro, Ltd. 3 */ 4 5 package sys_it 6 7 import ( 8 "encoding/json" 9 "fmt" 10 "log" 11 "testing" 12 "time" 13 14 "github.com/stretchr/testify/require" 15 16 "github.com/voedger/voedger/pkg/appdef" 17 "github.com/voedger/voedger/pkg/istructs" 18 "github.com/voedger/voedger/pkg/processors" 19 "github.com/voedger/voedger/pkg/sys/sqlquery" 20 coreutils "github.com/voedger/voedger/pkg/utils" 21 it "github.com/voedger/voedger/pkg/vit" 22 ) 23 24 func TestBasicUsage_SqlQuery(t *testing.T) { 25 require := require.New(t) 26 vit := it.NewVIT(t, &it.SharedConfig_App1) 27 defer vit.TearDown() 28 29 ws := vit.WS(istructs.AppQName_test1_app1, "test_ws") 30 idUntillUsers := vit.GetAny("app1pkg.untill_users", ws) 31 32 findPLogOffsetByWLogOffset := func(wLogOffset istructs.Offset) istructs.Offset { 33 type row struct { 34 Workspace istructs.WSID 35 PlogOffset istructs.Offset 36 WLogOffset istructs.Offset 37 } 38 body := `{"args":{"Query":"select Workspace, PlogOffset, WLogOffset from sys.plog limit -1"},"elements":[{"fields":["Result"]}]}` 39 resp := vit.PostWS(ws, "q.sys.SqlQuery", body) 40 for _, element := range resp.Sections[0].Elements { 41 r := new(row) 42 require.NoError(json.Unmarshal([]byte(element[0][0][0].(string)), r)) 43 if r.Workspace == ws.WSID && r.WLogOffset == wLogOffset { 44 return r.PlogOffset 45 } 46 } 47 panic("PlogOffset not found") 48 } 49 50 tableNum := vit.NextNumber() 51 52 body := `{"cuds":[{"fields":{"sys.ID":1,"sys.QName":"app1pkg.category","name":"Awesome food"}}]}` 53 vit.PostWS(ws, "c.sys.CUD", body) 54 body = fmt.Sprintf(`{"cuds":[{"fields":{"sys.ID":1,"sys.QName":"app1pkg.bill","tableno":%d,"id_untill_users":%d,"table_part":"a","proforma":0,"working_day":"20230227"}}]}`, tableNum, idUntillUsers) 55 vit.PostWS(ws, "c.sys.CUD", body) 56 body = `{"cuds":[{"fields":{"sys.ID":1,"sys.QName":"app1pkg.payments","name":"EFT","guid":"0a53b7c6-2c47-491c-ac00-307b8d5ba6f2"}}]}` 57 resp := vit.PostWS(ws, "c.sys.CUD", body) 58 59 body = fmt.Sprintf(`{"args":{"Query":"select CUDs from sys.plog where Offset>=%d"},"elements":[{"fields":["Result"]}]}`, findPLogOffsetByWLogOffset(resp.CurrentWLogOffset)) 60 resp = vit.PostWS(ws, "q.sys.SqlQuery", body) 61 62 require.Contains(resp.SectionRow()[0], "0a53b7c6-2c47-491c-ac00-307b8d5ba6f2") 63 } 64 65 func TestSqlQuery_plog(t *testing.T) { 66 vit := it.NewVIT(t, &it.SharedConfig_App1) 67 defer vit.TearDown() 68 69 ws := vit.WS(istructs.AppQName_test1_app1, "test_ws") 70 idUntillUsers := vit.GetAny("app1pkg.untill_users", ws) 71 72 pLogSize := 0 73 // it is wrong to consider last resp.CurrentWLogOffset as the pLog events amount because pLog contains events from different workspaces 74 // currently log of partition 0 contains events from 2 workspaces: pseudo 140737488420870 and newely created 140737488486400 75 // following util shows the initial content on pLog of partition 0: 76 t.Run("print the pLog content", func(t *testing.T) { 77 require := require.New(t) 78 body := `{"args":{"Query":"select * from sys.plog limit -1"},"elements":[{"fields":["Result"]}]}` 79 resp := vit.PostWS(ws, "q.sys.SqlQuery", body) 80 81 for _, intf := range resp.Sections[0].Elements { 82 m := map[string]interface{}{} 83 require.NoError(json.Unmarshal([]byte(intf[0][0][0].(string)), &m)) 84 log.Println(int(m["Workspace"].(float64)), m["PlogOffset"], m["WLogOffset"]) 85 } 86 pLogSize = len(resp.Sections[0].Elements) 87 }) 88 // note that we have wlogOffset 7 twice, so the last resp.CurrentWLogOffset is not the amount of events in pLog 89 // currently events amount is 13, the last resp.CurrentWLogOffset is 12: 90 /* 91 140737488420870 1 7 92 140737488486400 2 1 93 140737488486400 3 2 94 140737488486400 4 3 95 140737488486400 5 4 96 140737488486400 6 5 97 140737488486400 7 6 98 140737488486400 8 7 99 140737488486400 9 8 100 140737488486400 10 9 101 140737488486400 11 10 102 140737488486400 12 11 103 140737488486400 13 12 104 */ 105 106 for i := 1; i <= 101; i++ { 107 tableno := vit.NextNumber() 108 body := fmt.Sprintf(`{"cuds":[{"fields":{"sys.ID":%d,"sys.QName":"app1pkg.bill","tableno":%d,"id_untill_users":%d,"table_part":"a","proforma":0,"working_day":"20230227"}}]}`, i, tableno, idUntillUsers) 109 vit.PostWS(ws, "c.sys.CUD", body) 110 pLogSize++ 111 } 112 113 time.Sleep(ProjectionAwaitTime) 114 115 t.Run("Should read events with default Offset and limit", func(t *testing.T) { 116 require := require.New(t) 117 body := `{"args":{"Query":"select * from sys.plog"},"elements":[{"fields":["Result"]}]}` 118 resp := vit.PostWS(ws, "q.sys.SqlQuery", body) 119 120 m := map[string]interface{}{} 121 require.NoError(json.Unmarshal([]byte(resp.SectionRow()[0].(string)), &m)) 122 require.Equal(sqlquery.DefaultOffset, istructs.Offset(m["PlogOffset"].(float64))) 123 require.Len(resp.Sections[0].Elements, sqlquery.DefaultLimit) 124 }) 125 126 lastPLogOffset := 0 127 128 t.Run("Should read all events", func(t *testing.T) { 129 require := require.New(t) 130 body := `{"args":{"Query":"select * from sys.plog limit -1"},"elements":[{"fields":["Result"]}]}` 131 resp := vit.PostWS(ws, "q.sys.SqlQuery", body) 132 133 m := map[string]interface{}{} 134 require.NoError(json.Unmarshal([]byte(resp.SectionRow()[0].(string)), &m)) 135 require.Equal(sqlquery.DefaultOffset, istructs.Offset(m["PlogOffset"].(float64))) 136 require.GreaterOrEqual(len(resp.Sections[0].Elements), pLogSize) 137 138 m = map[string]interface{}{} 139 require.NoError(json.Unmarshal([]byte(resp.SectionRow(len(resp.Sections[0].Elements) - 1)[0].(string)), &m)) 140 lastPLogOffset = int(m["PlogOffset"].(float64)) 141 142 }) 143 t.Run("Should read one event by limit", func(t *testing.T) { 144 require := require.New(t) 145 body := `{"args":{"Query":"select * from sys.plog limit 1"},"elements":[{"fields":["Result"]}]}` 146 resp := vit.PostWS(ws, "q.sys.SqlQuery", body) 147 148 require.Len(resp.Sections[0].Elements, 1) 149 }) 150 t.Run("Should read one event by Offset", func(t *testing.T) { 151 require := require.New(t) 152 body := fmt.Sprintf(`{"args":{"Query":"select * from sys.plog where Offset > %d"},"elements":[{"fields":["Result"]}]}`, lastPLogOffset-1) 153 resp := vit.PostWS(ws, "q.sys.SqlQuery", body) 154 155 m := map[string]interface{}{} 156 require.NoError(json.Unmarshal([]byte(resp.SectionRow()[0].(string)), &m)) 157 require.Equal(lastPLogOffset, int(m["PlogOffset"].(float64))) 158 require.Len(resp.Sections[0].Elements, 1) 159 }) 160 t.Run("Should read two events by Offset", func(t *testing.T) { 161 require := require.New(t) 162 body := fmt.Sprintf(`{"args":{"Query":"select * from sys.plog where Offset >= %d"},"elements":[{"fields":["Result"]}]}`, lastPLogOffset-1) 163 resp := vit.PostWS(ws, "q.sys.SqlQuery", body) 164 165 require.Len(resp.Sections[0].Elements, 2) 166 167 m := map[string]interface{}{} 168 require.NoError(json.Unmarshal([]byte(resp.SectionRow()[0].(string)), &m)) 169 require.Equal(lastPLogOffset-1, int(m["PlogOffset"].(float64))) 170 m = map[string]interface{}{} 171 require.NoError(json.Unmarshal([]byte(resp.SectionRow(1)[0].(string)), &m)) 172 require.Equal(lastPLogOffset, int(m["PlogOffset"].(float64))) 173 }) 174 t.Run("Should read event with specified Offset", func(t *testing.T) { 175 require := require.New(t) 176 specifiedOffset := lastPLogOffset - 52 177 body := fmt.Sprintf(`{"args":{"Query":"select * from sys.plog where Offset = %d"},"elements":[{"fields":["Result"]}]}`, specifiedOffset) 178 resp := vit.PostWS(ws, "q.sys.SqlQuery", body) 179 180 require.Len(resp.Sections[0].Elements, 1) 181 require.Contains(resp.SectionRow()[0], fmt.Sprintf(`"PlogOffset":%d`, specifiedOffset)) 182 }) 183 t.Run("Should return error when field not found in def", func(t *testing.T) { 184 body := `{"args":{"Query":"select abracadabra from sys.plog"}}` 185 resp := vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 186 187 resp.RequireError(t, "field 'abracadabra' not found in def") 188 }) 189 } 190 191 func TestSqlQuery_wlog(t *testing.T) { 192 vit := it.NewVIT(t, &it.SharedConfig_App1) 193 defer vit.TearDown() 194 195 ws := vit.WS(istructs.AppQName_test1_app1, "test_ws") 196 idUntillUsers := vit.GetAny("app1pkg.untill_users", ws) 197 198 var lastWLogOffset istructs.Offset 199 for i := 1; i <= 101; i++ { 200 tableno := vit.NextNumber() 201 body := fmt.Sprintf(`{"cuds":[{"fields":{"sys.ID":%d,"sys.QName":"app1pkg.bill","tableno":%d,"id_untill_users":%d,"table_part":"a","proforma":0,"working_day":"20230227"}}]}`, i, tableno, idUntillUsers) 202 resp := vit.PostWS(ws, "c.sys.CUD", body) 203 lastWLogOffset = resp.CurrentWLogOffset 204 } 205 wLogEventsAmount := int(lastWLogOffset) 206 207 t.Run("Should read events with default Offset and limit", func(t *testing.T) { 208 require := require.New(t) 209 210 body := `{"args":{"Query":"select * from sys.wlog"},"elements":[{"fields":["Result"]}]}` 211 resp := vit.PostWS(ws, "q.sys.SqlQuery", body) 212 213 require.Len(resp.Sections[0].Elements, 100) 214 }) 215 t.Run("Should read all events", func(t *testing.T) { 216 require := require.New(t) 217 218 body := `{"args":{"Query":"select * from sys.wlog limit -1"},"elements":[{"fields":["Result"]}]}` 219 resp := vit.PostWS(ws, "q.sys.SqlQuery", body) 220 221 require.Len(resp.Sections[0].Elements, wLogEventsAmount) 222 }) 223 t.Run("Should read one event by limit", func(t *testing.T) { 224 require := require.New(t) 225 226 body := `{"args":{"Query":"select * from sys.wlog limit 1"},"elements":[{"fields":["Result"]}]}` 227 resp := vit.PostWS(ws, "q.sys.SqlQuery", body) 228 229 require.Len(resp.Sections[0].Elements, 1) 230 }) 231 t.Run("Should read one event by Offset", func(t *testing.T) { 232 require := require.New(t) 233 234 body := fmt.Sprintf(`{"args":{"Query":"select * from sys.wlog where Offset > %d"},"elements":[{"fields":["Result"]}]}`, lastWLogOffset-1) 235 resp := vit.PostWS(ws, "q.sys.SqlQuery", body) 236 237 require.Len(resp.Sections[0].Elements, 1) 238 }) 239 t.Run("Should read two events by Offset", func(t *testing.T) { 240 require := require.New(t) 241 242 body := fmt.Sprintf(`{"args":{"Query":"select * from sys.wlog where Offset >= %d"},"elements":[{"fields":["Result"]}]}`, lastWLogOffset-1) 243 resp := vit.PostWS(ws, "q.sys.SqlQuery", body) 244 245 require.Len(resp.Sections[0].Elements, 2) 246 }) 247 t.Run("Should return error when field not found in def", func(t *testing.T) { 248 body := `{"args":{"Query":"select abracadabra from sys.wlog"}}` 249 resp := vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 250 251 resp.RequireError(t, "field 'abracadabra' not found in def") 252 }) 253 } 254 255 func TestSqlQuery_readLogParams(t *testing.T) { 256 vit := it.NewVIT(t, &it.SharedConfig_App1) 257 defer vit.TearDown() 258 259 ws := vit.WS(istructs.AppQName_test1_app1, "test_ws") 260 261 t.Run("Should return error when limit value not parsable", func(t *testing.T) { 262 body := `{"args":{"Query":"select * from sys.plog limit 7.1"}}` 263 resp := vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 264 265 resp.RequireError(t, `strconv.ParseInt: parsing "7.1": invalid syntax`) 266 }) 267 t.Run("Should return error when limit value invalid", func(t *testing.T) { 268 body := `{"args":{"Query":"select * from sys.plog limit -3"}}` 269 resp := vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 270 271 resp.RequireError(t, "limit must be greater than -2") 272 }) 273 t.Run("Should return error when Offset value not parsable", func(t *testing.T) { 274 body := `{"args":{"Query":"select * from sys.plog where Offset >= 2.1"}}` 275 resp := vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 276 277 resp.RequireError(t, `strconv.ParseInt: parsing "2.1": invalid syntax`) 278 }) 279 t.Run("Should return error when Offset value invalid", func(t *testing.T) { 280 body := `{"args":{"Query":"select * from sys.plog where Offset >= 0"}}` 281 resp := vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 282 283 resp.RequireError(t, "offset must be greater than zero") 284 }) 285 t.Run("Should return error when Offset operation not supported", func(t *testing.T) { 286 body := `{"args":{"Query":"select * from sys.plog where Offset < 2"}}` 287 resp := vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 288 289 resp.RequireError(t, "unsupported operation: <") 290 }) 291 t.Run("Should return error when column name not supported", func(t *testing.T) { 292 body := `{"args":{"Query":"select * from sys.plog where something >= 1"}}` 293 resp := vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 294 295 resp.RequireError(t, "unsupported column name: something") 296 }) 297 t.Run("Should return error when expression not supported", func(t *testing.T) { 298 body := `{"args":{"Query":"select * from sys.wlog where Offset >= 1 and something >= 5"}}` 299 resp := vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 300 301 resp.RequireError(t, "unsupported expression: *sqlparser.AndExpr") 302 }) 303 } 304 305 func TestSqlQuery_records(t *testing.T) { 306 vit := it.NewVIT(t, &it.SharedConfig_App1) 307 defer vit.TearDown() 308 309 ws := vit.WS(istructs.AppQName_test1_app1, "test_ws") 310 311 body := `{"cuds":[{"fields":{"sys.ID":1,"sys.QName":"app1pkg.payments","name":"EFT","guid":"guidEFT"}}, 312 {"fields":{"sys.ID":2,"sys.QName":"app1pkg.payments","name":"Cash","guid":"guidCash"}}, 313 {"fields":{"sys.ID":3,"sys.QName":"app1pkg.pos_emails","description":"invite"}}]}` 314 res := vit.PostWS(ws, "c.sys.CUD", body) 315 316 eftId := res.NewID() 317 cashId := res.NewIDs["2"] 318 emailId := res.NewIDs["3"] 319 320 t.Run("Should read record with all fields by ID", func(t *testing.T) { 321 require := require.New(t) 322 body = fmt.Sprintf(`{"args":{"Query":"select * from app1pkg.payments where id = %d"},"elements":[{"fields":["Result"]}]}`, eftId) 323 resp := vit.PostWS(ws, "q.sys.SqlQuery", body) 324 325 resStr := resp.SectionRow(len(resp.Sections[0].Elements) - 1)[0].(string) 326 require.Contains(resStr, `"sys.QName":"app1pkg.payments"`) 327 require.Contains(resStr, fmt.Sprintf(`"sys.ID":%d`, eftId)) 328 require.Contains(resStr, `"guid":"guidEFT"`) 329 require.Contains(resStr, `"name":"EFT"`) 330 require.Contains(resStr, `"sys.IsActive":true`) 331 }) 332 t.Run("Should read records with one field by IDs range", func(t *testing.T) { 333 require := require.New(t) 334 body = fmt.Sprintf(`{"args":{"Query":"select name, sys.IsActive from app1pkg.payments where id in (%d,%d)"}, "elements":[{"fields":["Result"]}]}`, eftId, cashId) 335 resp := vit.PostWS(ws, "q.sys.SqlQuery", body) 336 337 require.Equal(`{"name":"EFT","sys.IsActive":true}`, resp.SectionRow()[0]) 338 require.Equal(`{"name":"Cash","sys.IsActive":true}`, resp.SectionRow(1)[0]) 339 }) 340 t.Run("Should return error when column name not supported", func(t *testing.T) { 341 body = `{"args":{"Query":"select * from app1pkg.payments where something = 1"}}` 342 resp := vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 343 344 resp.RequireError(t, "unsupported column name: something") 345 }) 346 t.Run("Should return error when ID not parsable", func(t *testing.T) { 347 body = `{"args":{"Query":"select * from app1pkg.payments where id = 2.3"}}` 348 resp := vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 349 350 resp.RequireError(t, `strconv.ParseInt: parsing "2.3": invalid syntax`) 351 }) 352 t.Run("Should return error when ID from IN clause not parsable", func(t *testing.T) { 353 body = `{"args":{"Query":"select * from app1pkg.payments where id in (1.3)"}}` 354 resp := vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 355 356 resp.RequireError(t, `strconv.ParseInt: parsing "1.3": invalid syntax`) 357 }) 358 t.Run("Should return error when ID operation not supported", func(t *testing.T) { 359 body = `{"args":{"Query":"select * from app1pkg.payments where id >= 2"}}` 360 resp := vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 361 362 resp.RequireError(t, "unsupported operation: >=") 363 }) 364 t.Run("Should return error when expression not supported", func(t *testing.T) { 365 body = `{"args":{"Query":"select * from app1pkg.payments where id = 2 and something = 2"}}` 366 resp := vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 367 368 resp.RequireError(t, "unsupported expression: *sqlparser.AndExpr") 369 }) 370 t.Run("Should return error when ID not present", func(t *testing.T) { 371 body = `{"args":{"Query":"select * from app1pkg.payments"}}` 372 resp := vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 373 374 resp.RequireError(t, "unable to find singleton ID for type «app1pkg.payments»: name not found") 375 }) 376 t.Run("Should return error when requested record has mismatching QName", func(t *testing.T) { 377 body = fmt.Sprintf(`{"args":{"Query":"select * from app1pkg.payments where id = %d"}}`, emailId) 378 resp := vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 379 380 resp.RequireError(t, fmt.Sprintf("record with ID '%d' has mismatching QName 'app1pkg.pos_emails'", emailId)) 381 }) 382 t.Run("Should return error when record not found", func(t *testing.T) { 383 body = fmt.Sprintf(`{"args":{"Query":"select * from app1pkg.payments where id = %d"}}`, istructs.NonExistingRecordID) 384 resp := vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 385 386 resp.RequireError(t, fmt.Sprintf("record with ID '%d' not found", istructs.NonExistingRecordID)) 387 }) 388 t.Run("Should return error when field not found in def", func(t *testing.T) { 389 body = fmt.Sprintf(`{"args":{"Query":"select abracadabra from app1pkg.pos_emails where id = %d"}}`, emailId) 390 resp := vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 391 392 resp.RequireError(t, "field 'abracadabra' not found in def") 393 }) 394 t.Run("Should read singleton", func(t *testing.T) { 395 require := require.New(t) 396 body = `{"args":{"Query":"select sys.QName from app1pkg.test_ws"},"elements":[{"fields":["Result"]}]}` 397 restaurant := vit.PostWS(ws, "q.sys.SqlQuery", body).SectionRow(0) 398 399 require.Equal(`{"sys.QName":"app1pkg.test_ws"}`, restaurant[0]) 400 }) 401 } 402 403 func TestSqlQuery_view_records(t *testing.T) { 404 vit := it.NewVIT(t, &it.SharedConfig_App1) 405 defer vit.TearDown() 406 407 ws := vit.WS(istructs.AppQName_test1_app1, "test_ws") 408 409 body := `{"cuds":[{"fields":{"sys.ID":1,"sys.QName":"app1pkg.payments","name":"EFT","guid":"guidEFT"}}, 410 {"fields":{"sys.ID":2,"sys.QName":"app1pkg.pos_emails","description":"invite"}}]}` 411 resp := vit.PostWS(ws, "c.sys.CUD", body) 412 paymentsID := resp.NewID() 413 lastWLogOffset := resp.CurrentWLogOffset 414 415 t.Run("Should read record with all fields", func(t *testing.T) { 416 require := require.New(t) 417 body = `{"args":{"Query":"select * from sys.CollectionView where PartKey = 1 and DocQName = 'app1pkg.payments'"}, "elements":[{"fields":["Result"]}]}` 418 resp = vit.PostWS(ws, "q.sys.SqlQuery", body) 419 420 respStr := resp.SectionRow(len(resp.Sections[0].Elements) - 1)[0].(string) 421 require.Contains(respStr, fmt.Sprintf(`"DocID":%d`, paymentsID)) 422 require.Contains(respStr, `"DocQName":"app1pkg.payments"`) 423 require.Contains(respStr, `"ElementID":0`) 424 require.Contains(respStr, fmt.Sprintf(`"offs":%d`, lastWLogOffset)) 425 require.Contains(respStr, `"PartKey":1`) 426 require.Contains(respStr, `"Record":{`) 427 require.Contains(respStr, `"sys.QName":"sys.CollectionView"`) 428 }) 429 t.Run("Should return error when operator not supported", func(t *testing.T) { 430 body = `{"args":{"Query":"select * from sys.CollectionView where partKey > 1"}}` 431 resp = vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 432 433 resp.RequireError(t, "unsupported operator: >") 434 }) 435 t.Run("Should return error when expression not supported", func(t *testing.T) { 436 body = `{"args":{"Query":"select * from sys.CollectionView where partKey = 1 or docQname = 'app1pkg.payments'"}}` 437 resp = vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 438 439 resp.RequireError(t, "unsupported expression: *sqlparser.OrExpr") 440 }) 441 t.Run("Should return error when field does not exist in value def", func(t *testing.T) { 442 body = `{"args":{"Query":"select abracadabra from sys.CollectionView where PartKey = 1"}}` 443 resp = vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 444 445 resp.RequireError(t, "field 'abracadabra' does not exist in 'sys.CollectionView' value def") 446 }) 447 t.Run("Should return error when field does not exist in key def", func(t *testing.T) { 448 body = `{"args":{"Query":"select * from sys.CollectionView where partKey = 1"}}` 449 resp = vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 450 451 resp.RequireError(t, "field 'partKey' does not exist in 'sys.CollectionView' key def") 452 }) 453 } 454 455 func TestSqlQuery(t *testing.T) { 456 vit := it.NewVIT(t, &it.SharedConfig_App1) 457 defer vit.TearDown() 458 459 ws := vit.WS(istructs.AppQName_test1_app1, "test_ws") 460 461 t.Run("Should return error when script invalid", func(t *testing.T) { 462 body := `{"args":{"Query":" "}}` 463 resp := vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 464 465 resp.RequireContainsError(t, "syntax error") 466 }) 467 t.Run("Should return error when source of data unsupported", func(t *testing.T) { 468 body := `{"args":{"Query":"select * from git.hub"}}` 469 resp := vit.PostWS(ws, "q.sys.SqlQuery", body, coreutils.Expect500()) 470 471 resp.RequireError(t, "unsupported source: git.hub") 472 }) 473 t.Run("Should read sys.wlog from other workspace", func(t *testing.T) { 474 wsOne := vit.PostWS(ws, "q.sys.SqlQuery", fmt.Sprintf(`{"args":{"Query":"select * from %d.sys.wlog"}}`, ws.Owner.ProfileWSID)) 475 wsTwo := vit.PostWS(ws, "q.sys.SqlQuery", `{"args":{"Query":"select * from sys.wlog"}}`) 476 477 require.NotEqual(t, len(wsOne.Sections[0].Elements), len(wsTwo.Sections[0].Elements)) 478 }) 479 480 t.Run("400 bad request on read from non-inited workspace", func(t *testing.T) { 481 vit.PostWS(ws, "q.sys.SqlQuery", `{"args":{"Query":"select * from 555.sys.wlog"}}`, coreutils.Expect400(processors.ErrWSNotInited.Message)) 482 }) 483 } 484 485 func TestReadFromWLogWithSysRawArg(t *testing.T) { 486 require := require.New(t) 487 vit := it.NewVIT(t, &it.SharedConfig_App1) 488 defer vit.TearDown() 489 490 ws := vit.WS(istructs.AppQName_test1_app1, "test_ws") 491 492 lastOffset := vit.PostWS(ws, "c.app1pkg.TestCmdRawArg", "hello world").CurrentWLogOffset 493 494 body := fmt.Sprintf(`{"args":{"Query":"select * from sys.wlog where Offset > %d"},"elements":[{"fields":["Result"]}]}`, lastOffset-1) 495 resp := vit.PostWS(ws, "q.sys.SqlQuery", body) 496 res := resp.SectionRow()[0].(string) 497 m := map[string]interface{}{} 498 require.NoError(json.Unmarshal([]byte(res), &m)) 499 rawArg := m["ArgumentObject"].(map[string]interface{})["Body"].(string) 500 require.Equal("hello world", rawArg) 501 } 502 503 func TestReadFromAnotherAppAnotherWSID(t *testing.T) { 504 //t.Skip("waiting for https://github.com/voedger/voedger/issues/1811") 505 vit := it.NewVIT(t, &it.SharedConfig_App1) 506 defer vit.TearDown() 507 508 oneAppWS := vit.WS(istructs.AppQName_test1_app1, "test_ws") 509 510 // create a record in one workspace of one app 511 categoryName := vit.NextName() 512 body := fmt.Sprintf(`{"cuds":[{"fields":{"sys.ID":1,"sys.QName":"app1pkg.category","name":"%s"}}]}`, categoryName) 513 categoryID := vit.PostWS(oneAppWS, "c.sys.CUD", body).NewID() 514 515 // create a workspace in another app 516 anotherAppWSOwner := vit.GetPrincipal(istructs.AppQName_test1_app2, "login") 517 qNameApp2_TestWSKind := appdef.NewQName("app2pkg", "test_ws") 518 anotherAppWS := vit.CreateWorkspace(it.WSParams{ 519 Name: "anotherAppWS", 520 Kind: qNameApp2_TestWSKind, 521 ClusterID: istructs.MainClusterID, 522 InitDataJSON: `{"IntFld":42}`, 523 }, anotherAppWSOwner) 524 525 // in the another app use sql to query the record from the first app 526 body = fmt.Sprintf(`{"args":{"Query":"select * from test1.app1.%d.app1pkg.category where id = %d"},"elements":[{"fields":["Result"]}]}`, oneAppWS.WSID, categoryID) 527 resp := vit.PostWS(anotherAppWS, "q.sys.SqlQuery", body) 528 resStr := resp.SectionRow(len(resp.Sections[0].Elements) - 1)[0].(string) 529 require.Contains(t, resStr, fmt.Sprintf(`"name":"%s"`, categoryName)) 530 }