github.com/RevenueMonster/sqlike@v1.0.6/examples/find.go (about) 1 package examples 2 3 import ( 4 "context" 5 "encoding/json" 6 "sort" 7 "strconv" 8 "testing" 9 "time" 10 11 "cloud.google.com/go/civil" 12 "github.com/RevenueMonster/sqlike/sql/expr" 13 "github.com/RevenueMonster/sqlike/sqlike" 14 "github.com/RevenueMonster/sqlike/sqlike/actions" 15 "github.com/RevenueMonster/sqlike/sqlike/options" 16 "github.com/RevenueMonster/sqlike/types" 17 "github.com/google/uuid" 18 "github.com/stretchr/testify/require" 19 "golang.org/x/text/language" 20 ) 21 22 // FindExamples : 23 func FindExamples(ctx context.Context, t *testing.T, db *sqlike.Database) { 24 var ( 25 // result sql.Result 26 result *sqlike.Result 27 ns normalStruct 28 err error 29 ) 30 31 emoji := `๐ค` 32 long := `ใใญใฐใฉใใณใฐใฏ็ด ๆดใใใๅใงใใ 33 ใใใชใใฎใฏใใฃใใใชใใ 34 ๆฉใใงใใใชใใProgateใงใใฃใฆใฟใใใ 35 ็กๆใงๅงใใใใใๅๅฟ่ ๅใๅญฆ็ฟใตใคใใ 36 ` 37 38 uid, _ := uuid.Parse("e7977246-910a-11e9-844d-6c96cfd87a51") 39 ts, _ := time.Parse("2006-01-02 15:04:05", "2008-01-28 10:25:33") 40 b := []byte(`abcd1234`) 41 jsonRaw := json.RawMessage(`{"test":"hello world"}`) 42 lang := language.Japanese 43 langs := []language.Tag{ 44 language.AmericanEnglish, 45 language.BrazilianPortuguese, 46 language.Malay, 47 language.ModernStandardArabic, 48 language.Korean, 49 language.Japanese, 50 } 51 virtualColumn := "virtual column" 52 numMap := map[string]int{ 53 "one": 1, 54 "three": 3, 55 "eleven": 11, 56 } 57 58 table := db.Table("NormalStruct") 59 60 // insert record before find 61 { 62 now := time.Now() 63 ns = normalStruct{} 64 ns.ID = uid 65 ns.Emoji = emoji 66 ns.Byte = b 67 ns.LongStr = long 68 ns.TinyInt = -88 69 ns.SmallInt = -16829 70 ns.BigInt = -1298738901289381212 71 ns.Uint = 1683904243 72 ns.SmallUint = 188 73 ns.MediumUint = 121373123 74 ns.BigUint = 1298738901289381212 75 ns.Float32 = 10.6789 76 ns.Float64 = 19833.6789 77 ns.JSONRaw = jsonRaw 78 ns.Enum = Failed 79 ns.Map = make(map[string]int) 80 ns.Map["one"] = 1 81 ns.Map["three"] = 3 82 ns.Map["eleven"] = 11 83 ns.Struct.VirtualStr = virtualColumn 84 ns.Date = civil.DateOf(now) 85 ns.DateTime = ts 86 ns.Timestamp = ts 87 ns.Language = lang 88 ns.Languages = langs 89 ns.Set = append(ns.Set, "A", "A", "B") 90 ns.CreatedAt = now 91 ns.UpdatedAt = now 92 93 _, err = table.InsertOne( 94 ctx, &ns, 95 ) 96 require.NoError(t, err) 97 } 98 99 // Find one record by primary key 100 { 101 ns = normalStruct{} 102 result := table.FindOne( 103 ctx, 104 actions.FindOne(). 105 Where( 106 expr.Equal("$Key", uid), 107 ), 108 options.FindOne().SetDebug(true), 109 ) 110 111 err = result.Decode(&ns) 112 require.NoError(t, err) 113 require.Equal(t, uid, ns.ID) 114 require.Equal(t, emoji, ns.Emoji) 115 require.Equal(t, long, ns.LongStr) 116 require.Equal(t, ts, ns.Timestamp) 117 require.Equal(t, b, ns.Byte) 118 require.Equal(t, int8(-88), ns.TinyInt) 119 require.Equal(t, int16(-16829), ns.SmallInt) 120 require.Equal(t, int64(-1298738901289381212), ns.BigInt) 121 require.Equal(t, uint(1683904243), ns.Uint) 122 require.Equal(t, uint16(188), ns.SmallUint) 123 require.Equal(t, uint32(121373123), ns.MediumUint) 124 require.Equal(t, uint64(1298738901289381212), ns.BigUint) 125 require.Equal(t, float32(10.6789), ns.Float32) 126 require.Equal(t, float64(19833.6789), ns.Float64) 127 require.Equal(t, Enum("FAILED"), ns.Enum) 128 require.Equal(t, virtualColumn, ns.Struct.VirtualStr) 129 130 require.Nil(t, ns.Struct.NestedNullInt) 131 require.Nil(t, ns.Struct.Key) 132 require.Nil(t, ns.PtrUUID) 133 var nilKey *types.Key 134 require.Equal(t, nilKey, ns.Struct.Key) 135 require.True(t, ns.Struct.Key == nil) 136 require.True(t, ns.Struct.Key == nilKey) 137 138 require.Equal(t, numMap, ns.Map) 139 require.Equal(t, lang, ns.Language) 140 require.Equal(t, langs, ns.Languages) 141 require.ElementsMatch(t, types.Set{"A", "B"}, ns.Set) 142 require.Equal(t, json.RawMessage(`{"test":"hello world"}`), ns.JSONRaw) 143 144 columns := []string{ 145 "$Key", "Key", "PtrUUID", "Date", 146 "SID", "Emoji", "FullText", "LongStr", "CustomStrType", 147 "EmptyByte", "Byte", "Bool", 148 "Int", "TinyInt", "SmallInt", "MediumInt", "BigInt", 149 "Uint", "TinyUint", "SmallUint", "MediumUint", "BigUint", 150 "Float32", "Float64", "UFloat32", 151 "EmptyStruct", "Struct", "VirtualColumn", 152 "Struct.StoredStr", "JSONRaw", "Map", 153 "DateTime", "Timestamp", "Location", "Language", "Languages", 154 "Currency", "Currencies", 155 "Enum", "Set", 156 "CreatedAt", "UpdatedAt", 157 } 158 cols := result.Columns() 159 sort.Strings(columns) 160 sort.Strings(cols) 161 require.True(t, len(cols) > 0) 162 require.ElementsMatch(t, columns, cols) 163 } 164 165 // Find one with scan 166 { 167 var i struct { 168 skip string 169 count uint 170 id *string 171 emoji string 172 customStr string 173 boolean bool 174 jsonRaw json.RawMessage 175 numMap map[string]int 176 } 177 ns = normalStruct{} 178 179 /* 180 SELECT 181 COUNT(`$Key`) AS `c` 182 FROM `sqlike`.`NormalStruct` 183 WHERE 184 `$Key` = "e7977246-910a-11e9-844d-6c96cfd87a51" 185 LIMIT 1; 186 */ 187 // Scan with unmatched number of fields 188 err = table.FindOne( 189 ctx, 190 actions.FindOne(). 191 Select( 192 expr.As(expr.Count("$Key"), "c"), 193 ). 194 Where( 195 expr.Equal("$Key", uid), 196 ), 197 options.FindOne().SetDebug(true), 198 ).Scan(&i.count, i.skip, &i.id, &i.emoji) 199 require.NoError(t, err) 200 require.True(t, i.count > 0) 201 202 /* 203 SELECT 204 `$Key`,`Emoji`,`CustomStrType`,`Bool`,`JSONRaw`,`Map`,`Language` 205 FROM `sqlike`.`NormalStruct` 206 WHERE 207 `$Key` = "e7977246-910a-11e9-844d-6c96cfd87a51" 208 LIMIT 1; 209 */ 210 // Scan with fields 211 err = table.FindOne( 212 ctx, 213 actions.FindOne(). 214 Select( 215 "$Key", "Emoji", "CustomStrType", "Bool", 216 "JSONRaw", "Map", "Language", 217 ). 218 Where( 219 expr.Equal("$Key", uid), 220 ), 221 options.FindOne().SetDebug(true), 222 ).Scan(&i.id, &i.emoji, &i.customStr, &i.boolean, &i.jsonRaw, &i.numMap) 223 require.NoError(t, err) 224 require.NotNil(t, i.id) 225 require.Equal(t, uid.String(), *i.id) 226 require.Equal(t, emoji, i.emoji) 227 require.Equal(t, jsonRaw, i.jsonRaw) 228 require.Equal(t, numMap, i.numMap) 229 230 // Scan error 231 err = table.FindOne( 232 ctx, 233 actions.FindOne(). 234 Select( 235 "$Key", 236 ). 237 Where( 238 expr.Equal("$Key", uid), 239 ), 240 options.FindOne().SetDebug(true), 241 ).Scan(i.skip) 242 require.Error(t, err) 243 } 244 245 // Find one record by primary key 246 { 247 /* 248 SELECT * FROM `sqlike`.`NormalStruct` 249 WHERE 250 `$Key` = "1000" 251 LIMIT 1; 252 */ 253 ns = normalStruct{} 254 err = table.FindOne( 255 ctx, 256 actions.FindOne(). 257 Where( 258 expr.Equal("$Key", "1000"), 259 ), 260 ).Decode(&ns) 261 require.Equal(t, err, sqlike.ErrNoRows) 262 263 } 264 265 // Find multiple records by where condition 266 { 267 /* 268 SELECT * FROM `sqlike`.`NormalStruct` 269 WHERE 270 ( 271 `TinyInt` BETWEEN 1 AND 100 AND 272 `Enum` IN ("SUCCESS","FAILED","UNKNOWN") 273 ) 274 LIMIT 100; 275 */ 276 ns = normalStruct{} 277 nss := []normalStruct{} 278 result, err = table.Find( 279 ctx, 280 actions.Find(). 281 Where( 282 expr.Between("TinyInt", 1, 100), 283 expr.In("Enum", []Enum{ 284 Success, 285 Failed, 286 Unknown, 287 }), 288 ), 289 options.Find().SetDebug(true), 290 ) 291 require.NoError(t, err) 292 err = result.All(&nss) 293 require.NoError(t, err) 294 295 } 296 297 // Find with scan slice 298 { 299 /* 300 SELECT `Emoji` FROM `sqlike`.`NormalStruct` LIMIT 100; 301 */ 302 ns = normalStruct{} 303 result, err = table.Find( 304 ctx, 305 actions.Find().Select("Emoji"), 306 ) 307 require.NoError(t, err) 308 var emojis []string 309 err = result.ScanSlice(&emojis) 310 require.NoError(t, err) 311 require.ElementsMatch(t, []string{ 312 `๐ค`, 313 `๐ฅถ ๐ฑ ๐จ ๐ฐ`, 314 `๐ ๐ ๐ ๐คฃ ๐ ๐ ๐ ๐ ๐ ๐`, 315 `๐ ๐ ๐ ๐คฃ ๐ ๐ ๐ ๐ ๐ ๐`, 316 `๐ ๐ ๐ ๐คฃ ๐ ๐ ๐ ๐ ๐ ๐`, 317 `๐ค`, 318 }, emojis) 319 } 320 321 // Find with subquery 322 { 323 /* 324 SELECT * FROM `sqlike`.`NormalStruct` 325 WHERE ( 326 `$Key` IN ( 327 SELECT `$Key` FROM `sqlike`.`NormalStruct` 328 WHERE `Tinyint` BETWEEN 1 AND 100 329 ORDER BY `Timestamp` DESC 330 ) AND 331 EXISTS (SELECT 1 FROM `sqlike`.`NormalStruct`) 332 ) 333 ORDER BY FIELD(`Enum`,"SUCCESS","FAILED","UNKNOWN") 334 LIMIT 100; 335 */ 336 ns = normalStruct{} 337 result, err = table.Find( 338 ctx, 339 actions.Find(). 340 Where( 341 expr.In("$Key", actions.Find(). 342 Select("$Key"). 343 From("sqlike", "NormalStruct"). 344 Where( 345 expr.Between("Tinyint", 1, 100), 346 ). 347 OrderBy( 348 expr.Desc("Timestamp"), 349 ), 350 ), 351 expr.Exists( 352 actions.Find(). 353 Select(expr.Raw("1")). 354 From("sqlike", "NormalStruct"), 355 ), 356 ). 357 OrderBy( 358 expr.Field("Enum", []Enum{ 359 Success, 360 Failed, 361 Unknown, 362 }), 363 ), 364 options.Find().SetDebug(true), 365 ) 366 require.NoError(t, err) 367 nss := []normalStruct{} 368 369 err = result.All(&nss) 370 require.NoError(t, err) 371 } 372 373 // Query with Like expression 374 { 375 /* 376 SELECT * FROM `sqlike`.`NormalStruct` 377 WHERE `FullText` LIKE "Hal\\%o\\%()#$\\\\\\%^&\\_%" 378 LIMIT 1; 379 */ 380 symbol := "Hal%o%()#$\\%^&_" 381 ns = normalStruct{} 382 err = table.FindOne( 383 ctx, 384 actions.FindOne(). 385 Where( 386 expr.Or( 387 expr.Like("FullText", symbol+"%"), 388 expr.Like("FullText", expr.Raw(strconv.Quote("%"+symbol+"%"))), 389 ), 390 ), 391 options.FindOne().SetDebug(true), 392 ).Decode(&ns) 393 require.NoError(t, err) 394 require.Equal(t, symbol, ns.FullText) 395 } 396 397 // Aggregation 398 { 399 /* 400 SELECT 401 `Enum` AS `A`, 402 COUNT(`$Key`) AS `B`, 403 AVG(`MediumInt`), 404 COALESCE(SUM(`SmallInt`),0) AS `C`, 405 MAX(`BigInt`), 406 MIN(`BigInt`) AS `D` 407 FROM `sqlike`.`NormalStruct` 408 GROUP BY 409 `Enum`, 410 `$Key` 411 ORDER BY `$Key` DESC; 412 */ 413 ns = normalStruct{} 414 result, err = table.Find( 415 ctx, 416 actions.Find(). 417 Select( 418 expr.As("Enum", "A"), 419 expr.As(expr.Count("$Key"), "B"), 420 expr.Average("MediumInt"), 421 expr.As(expr.Sum("SmallInt"), "C"), 422 expr.Max("BigInt"), 423 expr.As(expr.Min("BigInt"), "D"), 424 ). 425 GroupBy( 426 "Enum", 427 "$Key", 428 ). 429 OrderBy( 430 expr.Desc("$Key"), 431 ), 432 options.Find(). 433 SetDebug(true). 434 SetNoLimit(true), 435 ) 436 require.NoError(t, err) 437 require.ElementsMatch(t, 438 []string{ 439 "A", "B", "AVG(`MediumInt`)", 440 "C", "MAX(`BigInt`)", "D", 441 }, result.Columns(), 442 ) 443 } 444 445 { 446 table := db.Table("GeneratedStruct") 447 448 first := newGeneratedStruct() 449 cols := []*generatedStruct{ 450 first, 451 newGeneratedStruct(), 452 } 453 _, err = table.Insert( 454 ctx, 455 &cols, 456 options.Insert().SetDebug(true), 457 ) 458 require.NoError(t, err) 459 require.Empty(t, first.ID) 460 461 var result generatedStruct 462 463 err = table.FindOne( 464 ctx, 465 actions.FindOne(). 466 Where( 467 expr.Equal("NestedID", first.Nested.ID), 468 ), 469 options.FindOne().SetDebug(true), 470 ).Decode(&result) 471 require.NoError(t, err) 472 require.Equal(t, first.Nested.ID, result.ID) 473 require.True(t, result.Amount > 0) 474 } 475 476 } 477 478 // FindErrorExamples : 479 func FindErrorExamples(ctx context.Context, t *testing.T, db *sqlike.Database) { 480 var ( 481 err error 482 ) 483 484 { 485 _, err = db.Table("unknown_table").Find( 486 ctx, 487 nil, 488 options.Find().SetDebug(true), 489 ) 490 require.Error(t, err) 491 492 err = db.Table("NormalStruct").FindOne( 493 ctx, 494 nil, 495 options.FindOne().SetDebug(true), 496 ).Decode(nil) 497 require.Error(t, err) 498 } 499 }