@@ -2,7 +2,7 @@ package sqlb
22
33import (
44 "fmt"
5- "reflect"
5+ r "reflect"
66 "strconv"
77 "strings"
88)
@@ -662,13 +662,11 @@ func (self Seq) Append(text []byte) []byte { return exprAppend(&self, text) }
662662func (self Seq ) String () string { return exprString (& self ) }
663663
664664func (self * Seq ) any (bui * Bui , val interface {}) {
665- rval := valueOf (val )
666-
667- switch rval .Kind () {
668- case reflect .Invalid :
665+ switch kindOf (val ) {
666+ case r .Invalid :
669667 self .appendEmpty (bui )
670- case reflect .Slice :
671- self .appendSlice (bui , rval )
668+ case r .Slice :
669+ self .appendSlice (bui , val )
672670 default :
673671 panic (errExpectedSlice (`building SQL expression` , val ))
674672 }
@@ -678,7 +676,9 @@ func (self *Seq) appendEmpty(bui *Bui) {
678676 bui .Str (self .Empty )
679677}
680678
681- func (self Seq ) appendSlice (bui * Bui , val reflect.Value ) {
679+ func (self Seq ) appendSlice (bui * Bui , src interface {}) {
680+ val := valueOf (src )
681+
682682 if val .Len () == 0 {
683683 self .appendEmpty (bui )
684684 return
@@ -833,17 +833,14 @@ func (self Cond) Append(text []byte) []byte { return exprAppend(&self, text) }
833833func (self Cond ) String () string { return exprString (& self ) }
834834
835835func (self * Cond ) any (bui * Bui , val interface {}) {
836- rval := valueOf (val )
837-
838- switch rval .Kind () {
839- case reflect .Invalid :
836+ switch kindOf (val ) {
837+ case r .Invalid :
840838 self .appendEmpty (bui )
841- case reflect .Struct :
842- self .appendStruct (bui , rval )
843- case reflect .Slice :
844- self .appendSlice (bui , rval )
839+ case r .Struct :
840+ self .appendStruct (bui , val )
841+ case r .Slice :
842+ self .appendSlice (bui , val )
845843 default :
846- // panic(errExpectedStructOrSlice(`building SQL expression`, val))
847844 bui .Any (val )
848845 }
849846}
@@ -853,30 +850,30 @@ func (self *Cond) appendEmpty(bui *Bui) {
853850}
854851
855852// TODO consider if we should support nested non-embedded structs.
856- func (self * Cond ) appendStruct (bui * Bui , val reflect.Value ) {
857- fields := loadStructDbFields (val .Type ())
858- if len (fields ) == 0 {
859- self .appendEmpty (bui )
860- return
861- }
853+ func (self * Cond ) appendStruct (bui * Bui , src interface {}) {
854+ iter := makeIter (src )
862855
863- for i , field := range fields {
864- if i > 0 {
856+ for iter . next () {
857+ if ! iter . first () {
865858 bui .Str (self .Delim )
866859 }
867860
868- lhs := Ident (field . DbName )
869- rhs := Eq {nil , val . FieldByIndex ( field . Index ) .Interface ()}
861+ lhs := Ident (FieldDbName ( iter . field ) )
862+ rhs := Eq {nil , iter . value .Interface ()}
870863
871864 // Equivalent to using `Eq` for the full expression, but avoids an
872865 // allocation caused by converting `Ident` to `Expr`. As a bonus, this also
873866 // avoids unnecessary parens around the ident.
874867 bui .Set (lhs .AppendExpr (bui .Get ()))
875868 bui .Set (rhs .AppendRhs (bui .Get ()))
876869 }
870+
871+ if iter .empty () {
872+ self .appendEmpty (bui )
873+ }
877874}
878875
879- func (self * Cond ) appendSlice (bui * Bui , val reflect. Value ) {
876+ func (self * Cond ) appendSlice (bui * Bui , val interface {} ) {
880877 (* Seq )(self ).appendSlice (bui , val )
881878}
882879
@@ -886,6 +883,10 @@ any type, and is used as a type carrier; its actual value is ignored. If the
886883inner value is a struct or struct slice, the resulting expression is a list of
887884column names corresponding to its fields, using a "db" tag. Otherwise the
888885expression is `*`.
886+
887+ Unlike many other struct-scanning expressions, this doesn't support filtering
888+ via `Sparse`. It operates at the level of a struct type, not an individual
889+ struct value.
889890*/
890891type Cols [1 ]interface {}
891892
@@ -902,7 +903,7 @@ func (self Cols) Append(text []byte) []byte {
902903
903904// Implement the `fmt.Stringer` interface for debug purposes.
904905func (self Cols ) String () string {
905- return TypeCols (reflect .TypeOf (self [0 ]))
906+ return TypeCols (r .TypeOf (self [0 ]))
906907}
907908
908909/*
@@ -914,6 +915,10 @@ expression is `*`.
914915
915916Unlike `Cols`, this has special support for nested structs and nested column
916917paths. See the examples.
918+
919+ Unlike many other struct-scanning expressions, this doesn't support filtering
920+ via `Sparse`. It operates at the level of a struct type, not an individual
921+ struct value.
917922*/
918923type ColsDeep [1 ]interface {}
919924
@@ -930,7 +935,7 @@ func (self ColsDeep) Append(text []byte) []byte {
930935
931936// Implement the `fmt.Stringer` interface for debug purposes.
932937func (self ColsDeep ) String () string {
933- return TypeColsDeep (reflect .TypeOf (self [0 ]))
938+ return TypeColsDeep (r .TypeOf (self [0 ]))
934939}
935940
936941/*
@@ -939,21 +944,24 @@ struct. Field/column names are ignored. Values may be arbitrary sub-expressions
939944or arguments. The value passed to `StructValues` may be nil, which is
940945equivalent to an empty struct. It may also be an arbitrarily-nested struct
941946pointer, which is automatically dereferenced.
947+
948+ Supports filtering. If the inner value implements `Sparse`, then not all fields
949+ are considered to be "present", which is useful for PATCH semantics. See the
950+ docs on `Sparse` and `Part`.
942951*/
943952type StructValues [1 ]interface {}
944953
945954// Implement the `Expr` interface, making this a sub-expression.
946955func (self StructValues ) AppendExpr (text []byte , args []interface {}) ([]byte , []interface {}) {
947956 bui := Bui {text , args }
957+ iter := makeIter (self [0 ])
948958
949- val := valueOf (self [0 ])
950- if val .IsValid () {
951- for i , field := range loadStructDbFields (val .Type ()) {
952- if i > 0 {
953- bui .Str (`,` )
954- }
955- bui .SubAny (val .FieldByIndex (field .Index ).Interface ())
959+ // TODO consider panicking when empty.
960+ for iter .next () {
961+ if ! iter .first () {
962+ bui .Str (`,` )
956963 }
964+ bui .SubAny (iter .value .Interface ())
957965 }
958966
959967 return bui .Get ()
@@ -971,21 +979,36 @@ Represents a names-and-values clause suitable for insertion. The inner value
971979must be nil or a struct. Nil or empty struct generates a "default values"
972980clause. Otherwise the resulting expression has SQL column names and values
973981generated by scanning the input struct. See the examples.
982+
983+ Supports filtering. If the inner value implements `Sparse`, then not all fields
984+ are considered to be "present", which is useful for PATCH semantics. See the
985+ docs on `Sparse` and `Part`.
974986*/
975987type StructInsert [1 ]interface {}
976988
977989// Implement the `Expr` interface, making this a sub-expression.
978990func (self StructInsert ) AppendExpr (text []byte , args []interface {}) ([]byte , []interface {}) {
979991 bui := Bui {text , args }
992+ iter := makeIter (self [0 ])
993+
994+ for iter .next () {
995+ if iter .first () {
996+ bui .Str (`(` )
997+ bui .Str (TypeCols (iter .root .Type ()))
998+ bui .Str (`)` )
999+ bui .Str (`values (` )
1000+ } else {
1001+ bui .Str (`,` )
1002+ }
1003+ bui .SubAny (iter .value .Interface ())
1004+ }
9801005
981- if self [ 0 ] == nil || isStructEmpty ( self [ 0 ] ) {
1006+ if iter . empty ( ) {
9821007 bui .Str (`default values` )
983- return bui .Get ()
1008+ } else {
1009+ bui .Str (`)` )
9841010 }
9851011
986- bui .Set (Parens {Cols (self )}.AppendExpr (bui .Get ()))
987- bui .Str (`values` )
988- bui .Set (Parens {StructValues (self )}.AppendExpr (bui .Get ()))
9891012 return bui .Get ()
9901013}
9911014
@@ -1001,24 +1024,30 @@ Represents an SQL assignment clause suitable for "update set" operations. The
10011024inner value must be a struct. The resulting expression consists of
10021025comma-separated assignments with column names and values derived from the
10031026provided struct. See the example.
1027+
1028+ Supports filtering. If the inner value implements `Sparse`, then not all fields
1029+ are considered to be "present", which is useful for PATCH semantics. See the
1030+ docs on `Sparse` and `Part`.
10041031*/
10051032type StructAssign [1 ]interface {}
10061033
10071034// Implement the `Expr` interface, making this a sub-expression.
10081035func (self StructAssign ) AppendExpr (text []byte , args []interface {}) ([]byte , []interface {}) {
10091036 bui := Bui {text , args }
1037+ iter := makeIter (self [0 ])
10101038
1011- val := valueOf (self [0 ])
1012- if val .IsValid () {
1013- for i , field := range loadStructDbFields (val .Type ()) {
1014- if i > 0 {
1015- bui .Str (`,` )
1016- }
1017- bui .Set (Assign {
1018- Ident (field .DbName ),
1019- val .FieldByIndex (field .Index ).Interface (),
1020- }.AppendExpr (bui .Get ()))
1039+ for iter .next () {
1040+ if ! iter .first () {
1041+ bui .Str (`,` )
10211042 }
1043+ bui .Set (Assign {
1044+ Ident (FieldDbName (iter .field )),
1045+ iter .value .Interface (),
1046+ }.AppendExpr (bui .Get ()))
1047+ }
1048+
1049+ if iter .empty () {
1050+ panic (errEmptyAssign )
10221051 }
10231052
10241053 return bui .Get ()
0 commit comments