github.com/mitranim/sqlb@v0.7.2/sqlb_array.go (about)

     1  package sqlb
     2  
     3  import "database/sql/driver"
     4  
     5  /*
     6  Intermediary tool for implementing SQL array encoding. Has the same behavior as
     7  `CommaAppender`, but the text output is always enclosed in `{}`.
     8  */
     9  type ArrayAppender[A AppenderTo] []A
    10  
    11  /*
    12  Implement `fmt.Stringer`. Same as `CommaAppender.String`, but the output is
    13  always enclosed in `{}`.
    14  */
    15  func (self ArrayAppender[_]) String() string { return AppenderString(&self) }
    16  
    17  /*
    18  Implement `AppenderTo`. Same as `CommaAppender.AppendTo`, but the output is always
    19  enclosed in `{}`.
    20  */
    21  func (self ArrayAppender[A]) AppendTo(buf []byte) []byte {
    22  	buf = append(buf, `{`...)
    23  	buf = CommaAppender[A](self).AppendTo(buf)
    24  	buf = append(buf, `}`...)
    25  	return buf
    26  }
    27  
    28  func (self ArrayAppender[_]) Get() any { return self.String() }
    29  
    30  func (self ArrayAppender[_]) Value() (driver.Value, error) { return self.Get(), nil }
    31  
    32  /*
    33  Intermediary tool for implementing SQL array encoding. Combines multiple
    34  arbitrary text encoders. On demand (on a call to `.AppendTo` or `.String`),
    35  combines their text representations, separating them with a comma, while
    36  skipping any empty representations. The output will never contain a dangling
    37  leading comma, double comma, or leading trailing comma, unless they were
    38  explicitly generated by the inner encoders. Compare `SliceCommaAppender`
    39  which takes an arbitrary slice.
    40  */
    41  type CommaAppender[A AppenderTo] []A
    42  
    43  // Implement `fmt.Stringer` by calling `.AppendTo`.
    44  func (self CommaAppender[_]) String() string { return AppenderString(&self) }
    45  
    46  /*
    47  Implement `AppenderTo`. Appends comma-separated text representations of the inner
    48  encoders to the output buffer, skipping any empty representations.
    49  */
    50  func (self CommaAppender[_]) AppendTo(buf []byte) []byte {
    51  	var found bool
    52  
    53  	for _, val := range self {
    54  		if (found && TryAppendWith(&buf, `,`, val)) || TryAppendWith(&buf, ``, val) {
    55  			found = true
    56  		}
    57  	}
    58  
    59  	return buf
    60  }
    61  
    62  /*
    63  Intermediary tool for implementing SQL array encoding. The inner value must be
    64  either nil, a slice/array, or a pointer to a slice/array, where each element
    65  must implement `AppenderTo`. When `.AppendTo` or `.String` is called, this combines
    66  the text representations of the elements, separating them with a comma, while
    67  skipping any empty representations. The output will never contain a dangling
    68  leading comma, double comma, or leading trailing comma, unless they were
    69  explicitly generated by the inner encoders. Compare `CommaAppender` which
    70  itself is a slice.
    71  */
    72  type SliceCommaAppender [1]any
    73  
    74  // Implement `fmt.Stringer` by calling `.AppendTo`.
    75  func (self SliceCommaAppender) String() string { return AppenderString(&self) }
    76  
    77  /*
    78  Implement `AppenderTo`. Appends comma-separated text representations of the inner
    79  encoders to the output buffer, skipping any empty representations.
    80  */
    81  func (self SliceCommaAppender) AppendTo(buf []byte) []byte {
    82  	if self[0] == nil {
    83  		return buf
    84  	}
    85  
    86  	val, _ := self[0].(AppenderTo)
    87  	if val != nil {
    88  		return val.AppendTo(buf)
    89  	}
    90  
    91  	src := valueOf(self[0])
    92  	if !src.IsValid() {
    93  		return buf
    94  	}
    95  
    96  	var found bool
    97  	for ind := range counter(src.Len()) {
    98  		elem := src.Index(ind)
    99  		if !elem.IsValid() {
   100  			continue
   101  		}
   102  
   103  		iface := elem.Interface()
   104  		if iface == nil {
   105  			continue
   106  		}
   107  
   108  		val := iface.(AppenderTo)
   109  		if (found && TryAppendWith(&buf, `,`, val)) || TryAppendWith(&buf, ``, val) {
   110  			found = true
   111  		}
   112  	}
   113  
   114  	return buf
   115  }