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 }