github.com/aacfactory/fns-contrib/databases/sql@v1.2.84/rows.go (about) 1 package sql 2 3 import ( 4 "database/sql" 5 stdJson "encoding/json" 6 "fmt" 7 "github.com/aacfactory/avro" 8 "github.com/aacfactory/errors" 9 "github.com/aacfactory/fns-contrib/databases/sql/databases" 10 "github.com/aacfactory/fns/commons/times" 11 "github.com/aacfactory/json" 12 "reflect" 13 "strings" 14 "time" 15 ) 16 17 type Row []Column 18 19 func NewRows(rows databases.Rows) (v Rows, err error) { 20 names, namesErr := rows.Columns() 21 if namesErr != nil { 22 _ = rows.Close() 23 err = errors.Warning("sql: new rows failed").WithCause(namesErr) 24 return 25 } 26 cts, ctsErr := rows.ColumnTypes() 27 if ctsErr != nil { 28 _ = rows.Close() 29 err = errors.Warning("sql: new rows failed").WithCause(ctsErr) 30 return 31 } 32 columnLen := len(cts) 33 columnTypes := make([]ColumnType, 0, columnLen) 34 for i, ct := range cts { 35 columnTypes = append(columnTypes, NewColumnType(names[i], strings.ToUpper(ct.DatabaseType), ct.ScanType)) 36 } 37 v = Rows{ 38 idx: 0, 39 rows: rows, 40 columnTypes: columnTypes, 41 columnLen: columnLen, 42 values: nil, 43 size: 0, 44 } 45 return 46 } 47 48 type Rows struct { 49 idx int 50 rows databases.Rows 51 columnTypes []ColumnType 52 columnLen int 53 values []Row 54 size int 55 } 56 57 func (rows *Rows) Columns() []ColumnType { 58 return rows.columnTypes 59 } 60 61 func (rows *Rows) Close() error { 62 if rows.rows == nil { 63 return nil 64 } 65 return rows.rows.Close() 66 } 67 68 func (rows *Rows) Next() (ok bool) { 69 if rows.rows != nil { 70 ok = rows.rows.Next() 71 return 72 } 73 ok = rows.idx < rows.size 74 if ok { 75 rows.idx++ 76 } 77 return 78 } 79 80 // Scan 81 // element of dst must be scanned. 82 // in dac case, when field is json kind and type does not implement sql.NullJson, 83 // then wrap field value by sql.NullJson 84 func (rows *Rows) Scan(dst ...any) (err error) { 85 if rows.rows != nil { 86 err = rows.rows.Scan(dst...) 87 return 88 } 89 if rows.idx > rows.size { 90 err = sql.ErrNoRows 91 return 92 } 93 dstLen := len(dst) 94 if dstLen == 0 { 95 return 96 } 97 if dstLen != rows.columnLen { 98 err = errors.Warning("sql: scan failed").WithCause(fmt.Errorf("size is not matched")) 99 return 100 } 101 row := rows.values[rows.idx-1] 102 for i := 0; i < rows.columnLen; i++ { 103 item := dst[i] 104 if item == nil { 105 err = errors.Warning("sql: scan failed").WithCause(fmt.Errorf("some of dst is nil")) 106 return 107 } 108 column := row[i] 109 if !column.Valid { 110 continue 111 } 112 ct := rows.columnTypes[i] 113 switch d := item.(type) { 114 case *string: 115 cv, cvErr := column.String() 116 if cvErr != nil { 117 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 118 return 119 } 120 *d = cv 121 break 122 case *NullString: 123 cv, cvErr := column.String() 124 if cvErr != nil { 125 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 126 return 127 } 128 d.Valid = len(cv) > 0 129 d.String = cv 130 break 131 case *sql.NullString: 132 cv, cvErr := column.String() 133 if cvErr != nil { 134 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 135 return 136 } 137 d.Valid = len(cv) > 0 138 d.String = cv 139 break 140 case *bool: 141 cv, cvErr := column.Bool() 142 if cvErr != nil { 143 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 144 return 145 } 146 *d = cv 147 break 148 case *NullBool: 149 cv, cvErr := column.Bool() 150 if cvErr != nil { 151 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 152 return 153 } 154 d.Valid = true 155 d.Bool = cv 156 break 157 case *sql.NullBool: 158 cv, cvErr := column.Bool() 159 if cvErr != nil { 160 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 161 return 162 } 163 d.Valid = true 164 d.Bool = cv 165 break 166 case *int64: 167 cv, cvErr := column.Int() 168 if cvErr != nil { 169 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 170 return 171 } 172 *d = cv 173 break 174 case *int32: 175 cv, cvErr := column.Int() 176 if cvErr != nil { 177 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 178 return 179 } 180 *d = int32(cv) 181 break 182 case *int16: 183 cv, cvErr := column.Int() 184 if cvErr != nil { 185 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 186 return 187 } 188 *d = int16(cv) 189 break 190 case NullInt64: 191 cv, cvErr := column.Int() 192 if cvErr != nil { 193 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 194 return 195 } 196 d.Valid = true 197 d.Int64 = cv 198 break 199 case *sql.NullInt64: 200 cv, cvErr := column.Int() 201 if cvErr != nil { 202 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 203 return 204 } 205 d.Valid = true 206 d.Int64 = cv 207 break 208 case NullInt32: 209 cv, cvErr := column.Int() 210 if cvErr != nil { 211 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 212 return 213 } 214 d.Valid = true 215 d.Int32 = int32(cv) 216 break 217 case *sql.NullInt32: 218 cv, cvErr := column.Int() 219 if cvErr != nil { 220 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 221 return 222 } 223 d.Valid = true 224 d.Int32 = int32(cv) 225 break 226 case NullInt16: 227 cv, cvErr := column.Int() 228 if cvErr != nil { 229 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 230 return 231 } 232 d.Valid = true 233 d.Int16 = int16(cv) 234 break 235 case *sql.NullInt16: 236 cv, cvErr := column.Int() 237 if cvErr != nil { 238 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 239 return 240 } 241 d.Valid = true 242 d.Int16 = int16(cv) 243 break 244 case *float64: 245 cv, cvErr := column.Float() 246 if cvErr != nil { 247 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 248 return 249 } 250 *d = cv 251 break 252 case *float32: 253 cv, cvErr := column.Float() 254 if cvErr != nil { 255 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 256 return 257 } 258 *d = float32(cv) 259 break 260 case sql.NullFloat64: 261 cv, cvErr := column.Float() 262 if cvErr != nil { 263 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 264 return 265 } 266 d.Valid = true 267 d.Float64 = cv 268 break 269 case *sql.NullFloat64: 270 cv, cvErr := column.Float() 271 if cvErr != nil { 272 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 273 return 274 } 275 d.Valid = true 276 d.Float64 = cv 277 break 278 case *time.Time: 279 cv, cvErr := column.Datetime() 280 if cvErr != nil { 281 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 282 return 283 } 284 *d = cv 285 break 286 case *NullDatetime: 287 cv, cvErr := column.Datetime() 288 if cvErr != nil { 289 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 290 return 291 } 292 d.Valid = true 293 d.Time = cv 294 break 295 case *sql.NullTime: 296 cv, cvErr := column.Datetime() 297 if cvErr != nil { 298 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 299 return 300 } 301 d.Valid = !cv.IsZero() 302 d.Time = cv 303 break 304 case *times.Date: 305 cv, cvErr := column.Date() 306 if cvErr != nil { 307 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 308 return 309 } 310 *d = cv 311 break 312 case *NullDate: 313 cv, cvErr := column.Date() 314 if cvErr != nil { 315 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 316 return 317 } 318 d.Valid = !cv.IsZero() 319 d.Date = cv 320 break 321 case *times.Time: 322 cv, cvErr := column.Time() 323 if cvErr != nil { 324 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 325 return 326 } 327 *d = cv 328 break 329 case *NullTime: 330 cv, cvErr := column.Time() 331 if cvErr != nil { 332 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 333 return 334 } 335 d.Valid = !cv.IsZero() 336 d.Time = cv 337 break 338 case *[]byte: 339 cv, cvErr := column.Bytes() 340 if cvErr != nil { 341 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 342 return 343 } 344 *d = cv 345 break 346 case *NullBytes: 347 cv, cvErr := column.Bytes() 348 if cvErr != nil { 349 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 350 return 351 } 352 d.Valid = true 353 d.Bytes = cv 354 break 355 case *json.RawMessage: 356 cv, cvErr := column.Bytes() 357 if cvErr != nil { 358 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 359 return 360 } 361 *d = cv 362 break 363 case *stdJson.RawMessage: 364 cv, cvErr := column.Bytes() 365 if cvErr != nil { 366 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 367 return 368 } 369 *d = cv 370 break 371 case *sql.RawBytes: 372 cv, cvErr := column.Bytes() 373 if cvErr != nil { 374 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 375 return 376 } 377 *d = cv 378 break 379 case *byte: 380 cv, cvErr := column.Byte() 381 if cvErr != nil { 382 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 383 return 384 } 385 *d = cv 386 break 387 case *sql.NullByte: 388 cv, cvErr := column.Byte() 389 if cvErr != nil { 390 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 391 return 392 } 393 d.Valid = true 394 d.Byte = cv 395 break 396 case *json.Date: 397 cv, cvErr := column.Date() 398 if cvErr != nil { 399 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 400 return 401 } 402 *d = json.NewDate(cv.Year, cv.Month, cv.Day) 403 break 404 case *json.Time: 405 cv, cvErr := column.Time() 406 if cvErr != nil { 407 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 408 return 409 } 410 *d = json.NewTime(cv.Hour, cv.Minutes, cv.Second) 411 break 412 default: 413 scanner, isScanner := item.(sql.Scanner) 414 if isScanner { 415 var scanErr error 416 switch ct.Type { 417 case "string": 418 cv, cvErr := column.String() 419 if cvErr != nil { 420 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 421 return 422 } 423 scanErr = scanner.Scan(cv) 424 break 425 case "bool": 426 cv, cvErr := column.Bool() 427 if cvErr != nil { 428 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 429 return 430 } 431 scanErr = scanner.Scan(cv) 432 break 433 case "int": 434 cv, cvErr := column.Int() 435 if cvErr != nil { 436 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 437 return 438 } 439 scanErr = scanner.Scan(cv) 440 break 441 case "float": 442 cv, cvErr := column.Float() 443 if cvErr != nil { 444 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 445 return 446 } 447 scanErr = scanner.Scan(cv) 448 break 449 case "datetime": 450 cv, cvErr := column.Datetime() 451 if cvErr != nil { 452 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 453 return 454 } 455 scanErr = scanner.Scan(cv) 456 break 457 case "date": 458 cv, cvErr := column.Datetime() 459 if cvErr != nil { 460 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 461 return 462 } 463 scanErr = scanner.Scan(cv) 464 break 465 case "time": 466 cv, cvErr := column.Datetime() 467 if cvErr != nil { 468 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 469 return 470 } 471 scanErr = scanner.Scan(cv) 472 break 473 case "bytes": 474 cv, cvErr := column.Bytes() 475 if cvErr != nil { 476 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 477 return 478 } 479 scanErr = scanner.Scan(cv) 480 break 481 case "byte": 482 cv, cvErr := column.Byte() 483 if cvErr != nil { 484 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 485 return 486 } 487 scanErr = scanner.Scan(cv) 488 break 489 default: 490 err = errors.Warning("sql: scan failed").WithCause(fmt.Errorf("type is unsupported")).WithMeta("column", ct.Name) 491 return 492 } 493 if scanErr != nil { 494 err = errors.Warning("sql: scan failed").WithCause(scanErr).WithMeta("column", ct.Name) 495 return 496 } 497 return 498 } 499 if ct.Type == "json" { 500 decodeErr := json.Unmarshal(column.Value, item) 501 if decodeErr != nil { 502 err = errors.Warning("sql: scan failed").WithCause(decodeErr).WithMeta("column", ct.Name) 503 return 504 } 505 return 506 } 507 rv := reflect.ValueOf(item).Elem() 508 switch rv.Type().Kind() { 509 case reflect.String: 510 cv, cvErr := column.String() 511 if cvErr != nil { 512 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 513 return 514 } 515 rv.SetString(cv) 516 break 517 case reflect.Bool: 518 cv, cvErr := column.Bool() 519 if cvErr != nil { 520 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 521 return 522 } 523 rv.SetBool(cv) 524 break 525 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 526 cv, cvErr := column.Int() 527 if cvErr != nil { 528 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 529 return 530 } 531 rv.SetInt(cv) 532 break 533 case reflect.Float32, reflect.Float64: 534 cv, cvErr := column.Float() 535 if cvErr != nil { 536 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 537 return 538 } 539 rv.SetFloat(cv) 540 break 541 case reflect.Uint8: 542 cv, cvErr := column.Byte() 543 if cvErr != nil { 544 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 545 return 546 } 547 rv.SetUint(uint64(cv)) 548 break 549 default: 550 rt := rv.Type() 551 if rt.ConvertibleTo(datetimeType) { 552 cv, cvErr := column.Datetime() 553 if cvErr != nil { 554 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 555 return 556 } 557 rv.Set(reflect.ValueOf(cv).Convert(rt)) 558 } else if rt.ConvertibleTo(dateType) { 559 cv, cvErr := column.Date() 560 if cvErr != nil { 561 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 562 return 563 } 564 rv.Set(reflect.ValueOf(cv).Convert(rt)) 565 } else if rt.ConvertibleTo(timeType) { 566 cv, cvErr := column.Time() 567 if cvErr != nil { 568 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 569 return 570 } 571 rv.Set(reflect.ValueOf(cv).Convert(rt)) 572 } else if rt.ConvertibleTo(rawType) { 573 cv, cvErr := column.Bytes() 574 if cvErr != nil { 575 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 576 return 577 } 578 rv.Set(reflect.ValueOf(cv).Convert(rt)) 579 } else if rt.ConvertibleTo(bytesType) { 580 cv, cvErr := column.Bytes() 581 if cvErr != nil { 582 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 583 return 584 } 585 rv.Set(reflect.ValueOf(cv).Convert(rt)) 586 } else if rt.ConvertibleTo(jsonDateType) { 587 cv, cvErr := column.Date() 588 if cvErr != nil { 589 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 590 return 591 } 592 rv.Set(reflect.ValueOf(cv).Convert(rt)) 593 } else if rt.ConvertibleTo(jsonTimeType) { 594 cv, cvErr := column.Time() 595 if cvErr != nil { 596 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 597 return 598 } 599 rv.Set(reflect.ValueOf(cv).Convert(rt)) 600 } else { 601 unmarshaler, isUnmarshaler := item.(json.Unmarshaler) 602 if isUnmarshaler { 603 cv, cvErr := column.Bytes() 604 if cvErr != nil { 605 err = errors.Warning("sql: scan failed").WithCause(cvErr).WithMeta("column", ct.Name) 606 return 607 } 608 decodeErr := unmarshaler.UnmarshalJSON(cv) 609 if decodeErr != nil { 610 err = errors.Warning("sql: scan failed").WithCause(decodeErr).WithMeta("column", ct.Name) 611 return 612 } 613 return 614 } 615 cv, cvErr := column.Bytes() 616 if cvErr != nil { 617 err = errors.Warning("sql: scan failed").WithCause(fmt.Errorf("unsupported type")).WithMeta("column", ct.Name) 618 return 619 } 620 decodeErr := json.Unmarshal(cv, item) 621 if decodeErr != nil { 622 err = errors.Warning("sql: scan failed").WithCause(decodeErr).WithMeta("column", ct.Name) 623 return 624 } 625 return 626 } 627 } 628 break 629 } 630 } 631 return 632 } 633 634 func (rows Rows) MarshalAvro() (p []byte, err error) { 635 if len(rows.values) > 0 { 636 tr := transferRows{ 637 ColumnTypes: rows.columnTypes, 638 Values: rows.values, 639 } 640 p, err = avro.Marshal(tr) 641 return 642 } 643 if rows.idx != 0 { 644 err = errors.Warning("sql: encode rows failed").WithCause(fmt.Errorf("rows has been used")) 645 return 646 } 647 mc := newMultiColumns(rows.columnLen) 648 for rows.rows.Next() { 649 scanners := mc.Next() 650 scanErr := rows.rows.Scan(scanners...) 651 if scanErr != nil { 652 _ = rows.rows.Close() 653 mc.Release() 654 err = errors.Warning("sql: encode rows failed").WithCause(scanErr) 655 return 656 } 657 } 658 _ = rows.rows.Close() 659 rows.values = mc.Rows() 660 rows.size = len(rows.values) 661 tr := transferRows{ 662 ColumnTypes: rows.columnTypes, 663 Values: rows.values, 664 } 665 p, err = avro.Marshal(tr) 666 mc.Release() 667 return 668 } 669 670 func (rows *Rows) UnmarshalAvro(p []byte) (err error) { 671 if len(p) == 0 { 672 return 673 } 674 tr := transferRows{} 675 err = avro.Unmarshal(p, &tr) 676 if err != nil { 677 return 678 } 679 rows.idx = 0 680 rows.columnTypes = tr.ColumnTypes 681 rows.columnLen = len(rows.columnTypes) 682 rows.values = tr.Values 683 rows.size = len(rows.values) 684 return 685 } 686 687 func (rows Rows) MarshalJSON() (p []byte, err error) { 688 if len(rows.values) > 0 { 689 tr := transferRows{ 690 ColumnTypes: rows.columnTypes, 691 Values: rows.values, 692 } 693 p, err = json.Marshal(tr) 694 return 695 } 696 if rows.idx != 0 { 697 err = errors.Warning("sql: encode rows failed").WithCause(fmt.Errorf("rows has been used")) 698 return 699 } 700 mc := newMultiColumns(rows.columnLen) 701 for rows.rows.Next() { 702 scanners := mc.Next() 703 scanErr := rows.rows.Scan(scanners...) 704 if scanErr != nil { 705 _ = rows.rows.Close() 706 mc.Release() 707 err = errors.Warning("sql: encode rows failed").WithCause(scanErr) 708 return 709 } 710 } 711 _ = rows.rows.Close() 712 rows.values = mc.Rows() 713 rows.size = len(rows.values) 714 tr := transferRows{ 715 ColumnTypes: rows.columnTypes, 716 Values: rows.values, 717 } 718 p, err = json.Marshal(tr) 719 mc.Release() 720 return 721 } 722 723 func (rows *Rows) UnmarshalJSON(p []byte) (err error) { 724 tr := transferRows{} 725 err = json.Unmarshal(p, &tr) 726 if err != nil { 727 return 728 } 729 rows.idx = 0 730 rows.columnTypes = tr.ColumnTypes 731 rows.columnLen = len(rows.columnTypes) 732 rows.values = tr.Values 733 rows.size = len(rows.values) 734 return 735 } 736 737 type transferRows struct { 738 ColumnTypes []ColumnType `json:"columnTypes" avro:"columnTypes"` 739 Values []Row `json:"values" avro:"values"` 740 }