github.com/mitranim/sqlb@v0.7.2/sqlb_util.go (about) 1 package sqlb 2 3 import ( 4 "database/sql" 5 "database/sql/driver" 6 "fmt" 7 r "reflect" 8 "regexp" 9 "strconv" 10 "strings" 11 "sync" 12 "time" 13 "unsafe" 14 ) 15 16 const ( 17 ordinalParamPrefix = '$' 18 namedParamPrefix = ':' 19 doubleColonPrefix = `::` 20 commentLinePrefix = `--` 21 commentBlockPrefix = `/*` 22 commentBlockSuffix = `*/` 23 quoteSingle = '\'' 24 quoteDouble = '"' 25 quoteGrave = '`' 26 27 byteLen = 1 28 expectedStructNestingDepth = 8 29 ) 30 31 var ( 32 typeTime = r.TypeOf((*time.Time)(nil)).Elem() 33 typeBytes = r.TypeOf((*[]byte)(nil)).Elem() 34 sqlScannerRtype = r.TypeOf((*sql.Scanner)(nil)).Elem() 35 36 charsetDigitDec = new(charset).addStr(`0123456789`) 37 charsetIdentStart = new(charset).addStr(`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_`) 38 charsetIdent = new(charset).addSet(charsetIdentStart).addSet(charsetDigitDec) 39 charsetSpace = new(charset).addStr(" \t\v") 40 charsetNewline = new(charset).addStr("\r\n") 41 charsetWhitespace = new(charset).addSet(charsetSpace).addSet(charsetNewline) 42 charsetDelimStart = new(charset).addSet(charsetWhitespace).addStr(`([{.`) 43 charsetDelimEnd = new(charset).addSet(charsetWhitespace).addStr(`,}])`) 44 ) 45 46 type charset [256]bool 47 48 func (self *charset) has(val byte) bool { return self[val] } 49 50 func (self *charset) addStr(vals string) *charset { 51 for _, val := range vals { 52 self[val] = true 53 } 54 return self 55 } 56 57 func (self *charset) addSet(vals *charset) *charset { 58 for ind, val := range vals { 59 if val { 60 self[ind] = true 61 } 62 } 63 return self 64 } 65 66 type structNestedDbField struct { 67 Field r.StructField 68 DbPath []string 69 } 70 71 type structPath struct { 72 Name string 73 FieldIndex []int 74 MethodIndex int 75 } 76 77 type structFieldValue struct { 78 Field r.StructField 79 Value r.Value 80 } 81 82 func cacheOf[Key, Val any](fun func(Key) Val) *cache[Key, Val] { 83 return &cache[Key, Val]{Func: fun} 84 } 85 86 type cache[Key, Val any] struct { 87 sync.Map 88 Func func(Key) Val 89 } 90 91 // Susceptible to "thundering herd". An improvement from no caching, but still 92 // not ideal. 93 func (self *cache[Key, Val]) Get(key Key) Val { 94 iface, ok := self.Load(key) 95 if ok { 96 return iface.(Val) 97 } 98 99 val := self.Func(key) 100 self.Store(key, val) 101 return val 102 } 103 104 func leadingNewlineSize(val string) int { 105 if len(val) >= 2 && val[0] == '\r' && val[1] == '\n' { 106 return 2 107 } 108 if len(val) >= 1 && (val[0] == '\r' || val[0] == '\n') { 109 return 1 110 } 111 return 0 112 } 113 114 /* 115 Allocation-free conversion. Reinterprets a byte slice as a string. Borrowed from 116 the standard library. Reasonably safe. Should not be used when the underlying 117 byte array is volatile, for example when it's part of a scratch buffer during 118 SQL scanning. 119 */ 120 func bytesToMutableString(bytes []byte) string { 121 return *(*string)(unsafe.Pointer(&bytes)) 122 } 123 124 /* 125 Allocation-free conversion. Returns a byte slice backed by the provided string. 126 Mutations are reflected in the source string, unless it's backed by constant 127 storage, in which case they trigger a segfault. Reslicing is ok. Should be safe 128 as long as the resulting bytes are not mutated. 129 */ 130 func stringToBytesUnsafe(val string) []byte { 131 type sliceHeader struct { 132 _ uintptr 133 len int 134 cap int 135 } 136 slice := *(*sliceHeader)(unsafe.Pointer(&val)) 137 slice.cap = slice.len 138 return *(*[]byte)(unsafe.Pointer(&slice)) 139 } 140 141 func isScannableRtype(typ r.Type) bool { 142 typ = typeDeref(typ) 143 return typ != nil && (typ == typeTime || r.PtrTo(typ).Implements(sqlScannerRtype)) 144 } 145 146 // WTB more specific name. 147 func isStructType(typ r.Type) bool { 148 return typ != nil && typ.Kind() == r.Struct && !isScannableRtype(typ) 149 } 150 151 func maybeAppendSpace(val []byte) []byte { 152 if hasDelimSuffix(bytesToMutableString(val)) { 153 return val 154 } 155 return append(val, ` `...) 156 } 157 158 func appendMaybeSpaced(text []byte, suffix string) []byte { 159 if !hasDelimSuffix(bytesToMutableString(text)) && !hasDelimPrefix(suffix) { 160 text = append(text, ` `...) 161 } 162 text = append(text, suffix...) 163 return text 164 } 165 166 func hasDelimPrefix(text string) bool { 167 return len(text) == 0 || charsetDelimEnd.has(text[0]) 168 } 169 170 func hasDelimSuffix(text string) bool { 171 return len(text) == 0 || charsetDelimStart.has(text[len(text)-1]) 172 } 173 174 var ordReg = regexp.MustCompile( 175 `^\s*((?:\w+\.)*\w+)(?i)(?:\s+(asc|desc))?(?:\s+nulls\s+(first|last))?\s*$`, 176 ) 177 178 func try(err error) { 179 if err != nil { 180 panic(err) 181 } 182 } 183 184 func try1[A any](val A, err error) A { 185 try(err) 186 return val 187 } 188 189 // Must be deferred. 190 func rec(ptr *error) { 191 val := recover() 192 if val == nil { 193 return 194 } 195 196 err, _ := val.(error) 197 if err != nil { 198 *ptr = err 199 return 200 } 201 202 panic(val) 203 } 204 205 /* 206 Questionable. Could be avoided by using `is [not] distinct from` which works for 207 both nulls and non-nulls, but at the time of writing, that operator doesn't 208 work on indexes in PG, resulting in atrocious performance. 209 */ 210 func norm(val any) any { 211 val = normNil(val) 212 if val == nil { 213 return nil 214 } 215 216 nullable, _ := val.(Nullable) 217 if nullable != nil { 218 if nullable.IsNull() { 219 return nil 220 } 221 return val 222 } 223 224 valuer, _ := val.(driver.Valuer) 225 if valuer != nil { 226 return try1(valuer.Value()) 227 } 228 229 return val 230 } 231 232 func normNil(val any) any { 233 if isNil(val) { 234 return nil 235 } 236 return val 237 } 238 239 func counter(val int) []struct{} { return make([]struct{}, val) } 240 241 // Generics when? 242 func resliceStrings(val *[]string, length int) { *val = (*val)[:length] } 243 244 // Generics when? 245 func resliceInts(val *[]int, length int) { *val = (*val)[:length] } 246 247 // Generics when? 248 func copyStrings(val []string) []string { 249 if val == nil { 250 return nil 251 } 252 out := make([]string, len(val)) 253 copy(out, val) 254 return out 255 } 256 257 // Generics when? 258 func copyInts(src []int) []int { 259 if src == nil { 260 return nil 261 } 262 out := make([]int, len(src)) 263 copy(out, src) 264 return out 265 } 266 267 func trimPrefixByte(val string, prefix byte) (string, error) { 268 if !(len(val) >= byteLen && val[0] == prefix) { 269 return ``, errf(`expected %q to begin with %q`, val, rune(prefix)) 270 } 271 return val[byteLen:], nil 272 } 273 274 func exprAppend[A Expr](expr A, text []byte) []byte { 275 text, _ = expr.AppendExpr(text, nil) 276 return text 277 } 278 279 func exprString[A Expr](expr A) string { 280 return bytesToMutableString(exprAppend(expr, nil)) 281 } 282 283 // Copied from `github.com/mitranim/gax` and tested there. 284 func growBytes(prev []byte, size int) []byte { 285 len, cap := len(prev), cap(prev) 286 if cap-len >= size { 287 return prev 288 } 289 290 next := make([]byte, len, 2*cap+size) 291 copy(next, prev) 292 return next 293 } 294 295 // Same as `growBytes`. WTB generics. 296 func growInterfaces(prev []any, size int) []any { 297 len, cap := len(prev), cap(prev) 298 if cap-len >= size { 299 return prev 300 } 301 302 next := make([]any, len, 2*cap+size) 303 copy(next, prev) 304 return next 305 } 306 307 // Same as `growBytes`. WTB generics. 308 func growExprs(prev []Expr, size int) []Expr { 309 len, cap := len(prev), cap(prev) 310 if cap-len >= size { 311 return prev 312 } 313 314 next := make([]Expr, len, 2*cap+size) 315 copy(next, prev) 316 return next 317 } 318 319 var argTrackerPool = sync.Pool{New: newArgTracker} 320 321 func newArgTracker() any { return new(argTracker) } 322 323 func getArgTracker() *argTracker { 324 return argTrackerPool.Get().(*argTracker) 325 } 326 327 /** 328 Should be pooled via `sync.Pool`. All fields should be allocated lazily on 329 demand, but only once. Pre-binding the methods is a one-time expense which 330 allows to avoid repeated allocs that would be caused by passing any 331 key-validating functions to the "ranger" interfaces. Because "range" methods 332 are dynamically-dispatched, Go can't perform escape analysis, and must assume 333 that any inputs will escape. 334 */ 335 type argTracker struct { 336 Ordinal map[OrdinalParam]OrdinalParam 337 Named map[NamedParam]OrdinalParam 338 ValidateOrdinal func(int) 339 ValidateNamed func(string) 340 } 341 342 func (self *argTracker) GotOrdinal(key OrdinalParam) (OrdinalParam, bool) { 343 val, ok := self.Ordinal[key] 344 return val, ok 345 } 346 347 func (self *argTracker) GotNamed(key NamedParam) (OrdinalParam, bool) { 348 val, ok := self.Named[key] 349 return val, ok 350 } 351 352 func (self *argTracker) SetOrdinal(key OrdinalParam, val OrdinalParam) { 353 if self.Ordinal == nil { 354 self.Ordinal = make(map[OrdinalParam]OrdinalParam, 16) 355 } 356 self.Ordinal[key] = val 357 } 358 359 func (self *argTracker) SetNamed(key NamedParam, val OrdinalParam) { 360 if self.Named == nil { 361 self.Named = make(map[NamedParam]OrdinalParam, 16) 362 } 363 self.Named[key] = val 364 } 365 366 func (self *argTracker) validateOrdinal(key int) { 367 param := OrdinalParam(key).FromIndex() 368 _, ok := self.Ordinal[param] 369 if !ok { 370 panic(errUnusedOrdinal(param)) 371 } 372 } 373 374 func (self *argTracker) validateNamed(key string) { 375 param := NamedParam(key) 376 _, ok := self.Named[param] 377 if !ok { 378 panic(errUnusedNamed(param)) 379 } 380 } 381 382 func (self *argTracker) validate(dict ArgDict) { 383 impl0, _ := dict.(OrdinalRanger) 384 if impl0 != nil { 385 if self.ValidateOrdinal == nil { 386 self.ValidateOrdinal = self.validateOrdinal 387 } 388 impl0.RangeOrdinal(self.ValidateOrdinal) 389 } 390 391 impl1, _ := dict.(NamedRanger) 392 if impl1 != nil { 393 if self.ValidateNamed == nil { 394 self.ValidateNamed = self.validateNamed 395 } 396 impl1.RangeNamed(self.ValidateNamed) 397 } 398 } 399 400 func (self *argTracker) put() { 401 for key := range self.Ordinal { 402 delete(self.Ordinal, key) 403 } 404 for key := range self.Named { 405 delete(self.Named, key) 406 } 407 argTrackerPool.Put(self) 408 } 409 410 func strDir(val string) Dir { 411 if strings.EqualFold(val, `asc`) { 412 return DirAsc 413 } 414 if strings.EqualFold(val, `desc`) { 415 return DirDesc 416 } 417 return DirNone 418 } 419 420 func strNulls(val string) Nulls { 421 if strings.EqualFold(val, `first`) { 422 return NullsFirst 423 } 424 if strings.EqualFold(val, `last`) { 425 return NullsLast 426 } 427 return NullsNone 428 } 429 430 func countNonEmptyStrings(vals []string) (count int) { 431 for _, val := range vals { 432 if val != `` { 433 count++ 434 } 435 } 436 return 437 } 438 439 func validateIdent(val string) { 440 if strings.ContainsRune(val, quoteDouble) { 441 panic(ErrInvalidInput{Err{ 442 `encoding ident`, 443 errf(`unexpected %q in SQL identifier %q`, rune(quoteDouble), val), 444 }}) 445 } 446 } 447 448 var prepCache = cacheOf(func(src string) Prep { 449 prep := Prep{Source: src} 450 prep.Parse() 451 return prep 452 }) 453 454 var colsCache = cacheOf(func(typ r.Type) string { 455 typ = typeElem(typ) 456 if isStructType(typ) { 457 return structCols(typ) 458 } 459 return `*` 460 }) 461 462 var colsDeepCache = cacheOf(func(typ r.Type) string { 463 typ = typeElem(typ) 464 if isStructType(typ) { 465 return structColsDeep(typ) 466 } 467 return `*` 468 }) 469 470 func loadStructDbFields(typ r.Type) []r.StructField { 471 return structDbFieldsCache.Get(typeElem(typ)) 472 } 473 474 var structDbFieldsCache = cacheOf(func(typ r.Type) []r.StructField { 475 // No `make` because `typ.NumField()` doesn't give us the full count. 476 var out []r.StructField 477 478 typ = typeElem(typ) 479 if typ == nil { 480 return out 481 } 482 483 reqStructType(`scanning DB-related struct fields`, typ) 484 485 path := make([]int, 0, expectedStructNestingDepth) 486 for ind := range counter(typ.NumField()) { 487 appendStructDbFields(&out, &path, typ, ind) 488 } 489 490 return out 491 }) 492 493 func loadStructPaths(typ r.Type) []structPath { 494 return structPathsCache.Get(typeElem(typ)) 495 } 496 497 var structPathsCache = cacheOf(func(typ r.Type) []structPath { 498 var out []structPath 499 500 typ = typeElem(typ) 501 if typ == nil { 502 return out 503 } 504 505 reqStructType(`scanning struct field and method paths`, typ) 506 507 path := make([]int, 0, expectedStructNestingDepth) 508 for ind := range counter(typ.NumField()) { 509 appendStructFieldPaths(&out, &path, typ, ind) 510 } 511 512 for ind := range counter(typ.NumMethod()) { 513 meth := typ.Method(ind) 514 if isPublic(meth.PkgPath) { 515 out = append(out, structPath{Name: meth.Name, MethodIndex: ind}) 516 } 517 } 518 519 return out 520 }) 521 522 func loadStructPathMap(typ r.Type) map[string]structPath { 523 return structPathMapCache.Get(typeElem(typ)) 524 } 525 526 var structPathMapCache = cacheOf(func(typ r.Type) map[string]structPath { 527 paths := loadStructPaths(typ) 528 out := make(map[string]structPath, len(paths)) 529 for _, val := range paths { 530 out[val.Name] = val 531 } 532 return out 533 }) 534 535 func loadStructJsonPathToNestedDbFieldMap(typ r.Type) map[string]structNestedDbField { 536 return structJsonPathToNestedDbFieldMapCache.Get(typeElem(typ)) 537 } 538 539 var structJsonPathToNestedDbFieldMapCache = cacheOf(func(typ r.Type) map[string]structNestedDbField { 540 typ = typeElem(typ) 541 if typ == nil { 542 return nil 543 } 544 545 reqStructType(`generating JSON-DB path mapping from struct type`, typ) 546 547 buf := map[string]structNestedDbField{} 548 jsonPath := make([]string, 0, expectedStructNestingDepth) 549 dbPath := make([]string, 0, expectedStructNestingDepth) 550 551 for ind := range counter(typ.NumField()) { 552 addJsonPathsToDbPaths(buf, &jsonPath, &dbPath, typ.Field(ind)) 553 } 554 return buf 555 }) 556 557 func loadStructJsonPathToDbPathFieldValueMap(typ r.Type) map[string]structFieldValue { 558 return structJsonPathToDbPathFieldValueMapCache.Get(typeElem(typ)) 559 } 560 561 var structJsonPathToDbPathFieldValueMapCache = cacheOf(func(typ r.Type) map[string]structFieldValue { 562 src := loadStructJsonPathToNestedDbFieldMap(typ) 563 out := make(map[string]structFieldValue, len(src)) 564 for key, val := range src { 565 out[key] = structFieldValue{val.Field, r.ValueOf(val.DbPath)} 566 } 567 return out 568 }) 569 570 func appendStructDbFields(buf *[]r.StructField, path *[]int, typ r.Type, index int) { 571 field := typ.Field(index) 572 if !isPublic(field.PkgPath) { 573 return 574 } 575 576 defer resliceInts(path, len(*path)) 577 *path = append(*path, index) 578 579 tag, ok := field.Tag.Lookup(TagNameDb) 580 if ok { 581 if tagIdent(tag) != `` { 582 field.Index = copyInts(*path) 583 *buf = append(*buf, field) 584 } 585 return 586 } 587 588 typ = typeDeref(field.Type) 589 if field.Anonymous && typ.Kind() == r.Struct { 590 for ind := range counter(typ.NumField()) { 591 appendStructDbFields(buf, path, typ, ind) 592 } 593 } 594 } 595 596 func appendStructFieldPaths(buf *[]structPath, path *[]int, typ r.Type, index int) { 597 field := typ.Field(index) 598 if !isPublic(field.PkgPath) { 599 return 600 } 601 602 defer resliceInts(path, len(*path)) 603 *path = append(*path, index) 604 *buf = append(*buf, structPath{Name: field.Name, FieldIndex: copyInts(*path)}) 605 606 typ = typeDeref(field.Type) 607 if field.Anonymous && typ.Kind() == r.Struct { 608 for ind := range counter(typ.NumField()) { 609 appendStructFieldPaths(buf, path, typ, ind) 610 } 611 } 612 } 613 614 func makeIter(val any) (out iter) { 615 out.init(val) 616 return 617 } 618 619 /* 620 Allows clearer code. Seems to incur no measurable overhead compared to 621 equivalent inline code. However, be aware that converting a stack-allocated 622 source value to `any` tends to involve copying. 623 */ 624 type iter struct { 625 field r.StructField 626 value r.Value 627 index int 628 count int 629 630 root r.Value 631 fields []r.StructField 632 filter Filter 633 } 634 635 func (self *iter) init(src any) { 636 if src == nil { 637 return 638 } 639 640 sparse, _ := src.(Sparse) 641 if sparse != nil { 642 self.root = valueOf(sparse.Get()) 643 self.filter = sparse 644 } else { 645 self.root = valueOf(src) 646 } 647 648 if self.root.IsValid() { 649 self.fields = loadStructDbFields(self.root.Type()) 650 } 651 } 652 653 //nolint:unused 654 func (self *iter) reinit() { 655 self.index = 0 656 self.count = 0 657 } 658 659 func (self *iter) next() bool { 660 fil := self.filter 661 662 for self.index < len(self.fields) { 663 field := self.fields[self.index] 664 665 if fil != nil && !fil.AllowField(field) { 666 self.index++ 667 continue 668 } 669 670 self.field = field 671 self.value = self.root.FieldByIndex(field.Index) 672 self.count++ 673 self.index++ 674 return true 675 } 676 677 return false 678 } 679 680 func (self *iter) empty() bool { return self.count == 0 } 681 func (self *iter) first() bool { return self.count == 1 } 682 683 /* 684 Returns true if the iterator would visit at least one field/value, otherwise 685 returns false. Requires `.init`. 686 */ 687 func (self *iter) has() bool { 688 fil := self.filter 689 690 if fil == nil { 691 return len(self.fields) > 0 692 } 693 694 for _, field := range self.fields { 695 if fil.AllowField(field) { 696 return true 697 } 698 } 699 return false 700 } 701 702 func typeElem(typ r.Type) r.Type { 703 for typ != nil && (typ.Kind() == r.Ptr || typ.Kind() == r.Slice) { 704 typ = typ.Elem() 705 } 706 return typ 707 } 708 709 func valueDeref(val r.Value) r.Value { 710 for val.Kind() == r.Ptr { 711 if val.IsNil() { 712 return r.Value{} 713 } 714 val = val.Elem() 715 } 716 return val 717 } 718 719 func typeElemOf(typ any) r.Type { 720 return typeElem(r.TypeOf(typ)) 721 } 722 723 func typeOf(typ any) r.Type { 724 return typeDeref(r.TypeOf(typ)) 725 } 726 727 func valueOf(val any) r.Value { 728 return valueDeref(r.ValueOf(val)) 729 } 730 731 func kindOf(val any) r.Kind { 732 typ := typeOf(val) 733 if typ != nil { 734 return typ.Kind() 735 } 736 return r.Invalid 737 } 738 739 func isStructTypeEmpty(typ r.Type) bool { 740 typ = typeDeref(typ) 741 return typ == nil || typ.Kind() != r.Struct || typ.NumField() == 0 742 } 743 744 func reqGetter(val, method r.Type, name string) { 745 inputs := method.NumIn() 746 if inputs != 0 { 747 panic(ErrInternal{Err{ 748 `evaluating method`, 749 errf( 750 `can't evaluate %q of %v: expected 0 parameters, found %v parameters`, 751 name, val, inputs, 752 ), 753 }}) 754 } 755 756 outputs := method.NumOut() 757 if outputs != 1 { 758 panic(ErrInternal{Err{ 759 `evaluating method`, 760 errf( 761 `can't evaluate %q of %v: expected 1 return parameter, found %v return parameters`, 762 name, val, outputs, 763 ), 764 }}) 765 } 766 } 767 768 func reqStructType(while string, typ r.Type) { 769 if typ.Kind() != r.Struct { 770 panic(errExpectedStruct(while, typ.Name())) 771 } 772 } 773 774 func typeName(typ r.Type) string { 775 typ = typeDeref(typ) 776 if typ == nil { 777 return `nil` 778 } 779 return typ.Name() 780 } 781 782 func typeNameOf[A any](val A) string { return typeName(r.TypeOf(val)) } 783 784 func isNil(val any) bool { 785 return val == nil || isValueNil(r.ValueOf(val)) 786 } 787 788 func isValueNil(val r.Value) bool { 789 return !val.IsValid() || isNilable(val.Kind()) && val.IsNil() 790 } 791 792 func isNilable(kind r.Kind) bool { 793 switch kind { 794 case r.Chan, r.Func, r.Interface, r.Map, r.Ptr, r.Slice: 795 return true 796 default: 797 return false 798 } 799 } 800 801 func isPublic(pkgPath string) bool { return pkgPath == `` } 802 803 func typeDeref(typ r.Type) r.Type { 804 if typ == nil { 805 return nil 806 } 807 return typeDerefCache.Get(typ) 808 } 809 810 var typeDerefCache = cacheOf(func(typ r.Type) r.Type { 811 for typ != nil { 812 if typ.Kind() == r.Ptr { 813 typ = typ.Elem() 814 continue 815 } 816 817 if typ.Kind() == r.Struct && typ.NumField() > 0 { 818 field := typ.Field(0) 819 if field.Tag.Get(`role`) == `ref` { 820 typ = field.Type 821 continue 822 } 823 } 824 825 break 826 } 827 828 return typ 829 }) 830 831 /* 832 TODO: consider validating that the name doesn't contain double quotes. We might 833 return an error, or panic. 834 */ 835 func tagIdent(tag string) string { 836 index := strings.IndexRune(tag, ',') 837 if index >= 0 { 838 return tagIdent(tag[:index]) 839 } 840 if tag == "-" { 841 return "" 842 } 843 return tag 844 } 845 846 func structCols(typ r.Type) string { 847 reqStructType(`generating struct columns string from struct type`, typ) 848 849 var buf []byte 850 for ind, field := range loadStructDbFields(typ) { 851 if ind > 0 { 852 buf = append(buf, `, `...) 853 } 854 buf = Ident(FieldDbName(field)).AppendTo(buf) 855 } 856 return bytesToMutableString(buf) 857 } 858 859 func structColsDeep(typ r.Type) string { 860 reqStructType(`generating deep struct columns string from struct type`, typ) 861 862 var buf []byte 863 var path []string 864 865 for ind := range counter(typ.NumField()) { 866 appendFieldCols(&buf, &path, typ.Field(ind)) 867 } 868 return bytesToMutableString(buf) 869 } 870 871 func appendFieldCols(buf *[]byte, path *[]string, field r.StructField) { 872 if !isPublic(field.PkgPath) { 873 return 874 } 875 876 typ := typeDeref(field.Type) 877 tag, ok := field.Tag.Lookup(TagNameDb) 878 dbName := tagIdent(tag) 879 880 if dbName == `` { 881 if !ok { 882 if field.Anonymous && typ.Kind() == r.Struct { 883 for ind := range counter(typ.NumField()) { 884 appendFieldCols(buf, path, typ.Field(ind)) 885 } 886 } 887 } 888 return 889 } 890 891 defer resliceStrings(path, len(*path)) 892 *path = append(*path, dbName) 893 894 if isStructType(typ) { 895 for ind := range counter(typ.NumField()) { 896 appendFieldCols(buf, path, typ.Field(ind)) 897 } 898 return 899 } 900 901 text := *buf 902 903 if len(text) > 0 { 904 text = append(text, `, `...) 905 } 906 text = AliasedPath(*path).AppendTo(text) 907 908 *buf = text 909 } 910 911 func addJsonPathsToDbPaths( 912 buf map[string]structNestedDbField, jsonPath *[]string, dbPath *[]string, field r.StructField, 913 ) { 914 if !isPublic(field.PkgPath) { 915 return 916 } 917 918 typ := typeDeref(field.Type) 919 jsonName := FieldJsonName(field) 920 tag, ok := field.Tag.Lookup(TagNameDb) 921 dbName := tagIdent(tag) 922 923 if dbName == `` { 924 if !ok { 925 if field.Anonymous && typ.Kind() == r.Struct { 926 for ind := range counter(typ.NumField()) { 927 addJsonPathsToDbPaths(buf, jsonPath, dbPath, typ.Field(ind)) 928 } 929 } 930 } 931 return 932 } 933 934 defer resliceStrings(jsonPath, len(*jsonPath)) 935 *jsonPath = append(*jsonPath, jsonName) 936 937 defer resliceStrings(dbPath, len(*dbPath)) 938 *dbPath = append(*dbPath, dbName) 939 940 buf[strings.Join(*jsonPath, `.`)] = structNestedDbField{ 941 Field: field, 942 DbPath: copyStrings(*dbPath), 943 } 944 945 if isStructType(typ) { 946 for ind := range counter(typ.NumField()) { 947 addJsonPathsToDbPaths(buf, jsonPath, dbPath, typ.Field(ind)) 948 } 949 } 950 } 951 952 func trimWhitespaceAndComments(val Token) Token { 953 switch val.Type { 954 case TokenTypeWhitespace: 955 return Token{` `, TokenTypeWhitespace} 956 case TokenTypeCommentLine, TokenTypeCommentBlock: 957 return Token{} 958 default: 959 return val 960 } 961 } 962 963 func isJsonDict(val []byte) bool { return headByte(val) == '{' } 964 func isJsonList(val []byte) bool { return headByte(val) == '[' } 965 func isJsonString(val []byte) bool { return headByte(val) == '"' } 966 967 func headByte(val []byte) byte { 968 if len(val) > 0 { 969 return val[0] 970 } 971 return 0 972 } 973 974 func appendIntWith(text []byte, delim string, val int64) []byte { 975 if val == 0 { 976 return text 977 } 978 979 text = maybeAppendSpace(text) 980 text = append(text, delim...) 981 text = maybeAppendSpace(text) 982 text = strconv.AppendInt(text, val, 10) 983 return text 984 } 985 986 func appendPrefixSub( 987 text []byte, args []any, prefix string, val any, 988 ) ( 989 []byte, []any, 990 ) { 991 if val == nil { 992 return text, args 993 } 994 995 bui := Bui{text, args} 996 bui.Str(prefix) 997 bui.SubAny(val) 998 return bui.Get() 999 } 1000 1001 // Borrowed from the standard library. 1002 func noescape(src unsafe.Pointer) unsafe.Pointer { 1003 out := uintptr(src) 1004 // nolint:staticcheck 1005 return unsafe.Pointer(out ^ 0) 1006 } 1007 1008 type formatState []byte 1009 1010 var _ = fmt.Stringer(formatState(nil)) 1011 1012 func (self formatState) String() string { return bytesToMutableString(self) } 1013 1014 var _ = fmt.State((*formatState)(nil)) 1015 1016 func (self *formatState) Write(src []byte) (int, error) { 1017 *self = append(*self, src...) 1018 return len(src), nil 1019 } 1020 1021 func (self *formatState) Width() (int, bool) { return 0, false } 1022 func (self *formatState) Precision() (int, bool) { return 0, false } 1023 func (self *formatState) Flag(int) bool { return false }