@@ -128,6 +128,27 @@ func (v QueryValue) UniqueFields() []Field {
128128 return fields
129129}
130130
131+ // YDBUniqueFieldsWithComments returns unique fields for YDB struct generation with comments for interface{} fields
132+ func (v QueryValue ) YDBUniqueFieldsWithComments () []Field {
133+ seen := map [string ]struct {}{}
134+ fields := make ([]Field , 0 , len (v .Struct .Fields ))
135+
136+ for _ , field := range v .Struct .Fields {
137+ if _ , found := seen [field .Name ]; found {
138+ continue
139+ }
140+ seen [field .Name ] = struct {}{}
141+
142+ if strings .HasSuffix (field .Type , "interface{}" ) {
143+ field .Comment = "// sqlc couldn't resolve type, pass via params"
144+ }
145+
146+ fields = append (fields , field )
147+ }
148+
149+ return fields
150+ }
151+
131152func (v QueryValue ) Params () string {
132153 if v .isEmpty () {
133154 return ""
@@ -198,7 +219,7 @@ func (v QueryValue) HasSqlcSlices() bool {
198219func (v QueryValue ) Scan () string {
199220 var out []string
200221 if v .Struct == nil {
201- if strings .HasPrefix (v .Typ , "[]" ) && v .Typ != "[]byte" && ! v .SQLDriver .IsPGX () {
222+ if strings .HasPrefix (v .Typ , "[]" ) && v .Typ != "[]byte" && ! v .SQLDriver .IsPGX () && ! v . SQLDriver . IsYDBGoSDK () {
202223 out = append (out , "pq.Array(&" + v .Name + ")" )
203224 } else {
204225 out = append (out , "&" + v .Name )
@@ -209,7 +230,7 @@ func (v QueryValue) Scan() string {
209230 // append any embedded fields
210231 if len (f .EmbedFields ) > 0 {
211232 for _ , embed := range f .EmbedFields {
212- if strings .HasPrefix (embed .Type , "[]" ) && embed .Type != "[]byte" && ! v .SQLDriver .IsPGX () {
233+ if strings .HasPrefix (embed .Type , "[]" ) && embed .Type != "[]byte" && ! v .SQLDriver .IsPGX () && ! v . SQLDriver . IsYDBGoSDK () {
213234 out = append (out , "pq.Array(&" + v .Name + "." + f .Name + "." + embed .Name + ")" )
214235 } else {
215236 out = append (out , "&" + v .Name + "." + f .Name + "." + embed .Name )
@@ -218,7 +239,7 @@ func (v QueryValue) Scan() string {
218239 continue
219240 }
220241
221- if strings .HasPrefix (f .Type , "[]" ) && f .Type != "[]byte" && ! v .SQLDriver .IsPGX () {
242+ if strings .HasPrefix (f .Type , "[]" ) && f .Type != "[]byte" && ! v .SQLDriver .IsPGX () && ! v . SQLDriver . IsYDBGoSDK () {
222243 out = append (out , "pq.Array(&" + v .Name + "." + f .Name + ")" )
223244 } else {
224245 out = append (out , "&" + v .Name + "." + f .Name )
@@ -269,32 +290,6 @@ func addDollarPrefix(name string) string {
269290 return "$" + name
270291}
271292
272- // YDBParamMapEntries returns entries for a map[string]any literal for YDB parameters.
273- func (v QueryValue ) YDBParamMapEntries () string {
274- if v .isEmpty () {
275- return ""
276- }
277-
278- var parts []string
279- for _ , field := range v .getParameterFields () {
280- if field .Column != nil && field .Column .IsNamedParam {
281- name := field .Column .GetName ()
282- if name != "" {
283- key := fmt .Sprintf ("%q" , addDollarPrefix (name ))
284- variable := v .VariableForField (field )
285- parts = append (parts , key + ": " + escape (variable ))
286- }
287- }
288- }
289-
290- if len (parts ) == 0 {
291- return ""
292- }
293-
294- parts = append (parts , "" )
295- return "\n " + strings .Join (parts , ",\n " )
296- }
297-
298293// ydbBuilderMethodForColumnType maps a YDB column data type to a ParamsBuilder method name.
299294func ydbBuilderMethodForColumnType (dbType string ) string {
300295 baseType := extractBaseType (strings .ToLower (dbType ))
@@ -353,52 +348,89 @@ func ydbBuilderMethodForColumnType(dbType string) string {
353348 }
354349}
355350
356- // YDBParamsBuilder emits Go code that constructs YDB params using ParamsBuilder.
357- func (v QueryValue ) YDBParamsBuilder () string {
351+ // ydbIterateNamedParams iterates over named parameters and calls the provided function for each one.
352+ // The function receives the field and method name, and should return true to continue iteration.
353+ func (v QueryValue ) ydbIterateNamedParams (fn func (field Field , method string ) bool ) bool {
358354 if v .isEmpty () {
359- return ""
355+ return false
360356 }
361357
362- var lines []string
363-
364358 for _ , field := range v .getParameterFields () {
365- if field .Column != nil && field . Column . IsNamedParam {
359+ if field .Column != nil {
366360 name := field .Column .GetName ()
367361 if name == "" {
368362 continue
369363 }
370- paramName := fmt .Sprintf ("%q" , addDollarPrefix (name ))
371- variable := escape (v .VariableForField (field ))
372364
373365 var method string
374366 if field .Column != nil && field .Column .Type != nil {
375367 method = ydbBuilderMethodForColumnType (sdk .DataType (field .Column .Type ))
376368 }
377369
378- goType := field .Type
379- isPtr := strings .HasPrefix (goType , "*" )
380- if isPtr {
381- goType = strings .TrimPrefix (goType , "*" )
370+ if ! fn (field , method ) {
371+ return false
382372 }
373+ }
374+ }
375+ return true
376+ }
383377
384- if method == "" {
385- panic (fmt .Sprintf ("unknown YDB column type for param %s (goType=%s)" , name , goType ))
386- }
378+ // YDBHasComplexContainers returns true if there are complex container types that sqlc cannot handle automatically.
379+ func (v QueryValue ) YDBHasComplexContainers () bool {
380+ hasComplex := false
381+ v .ydbIterateNamedParams (func (field Field , method string ) bool {
382+ if method == "" {
383+ hasComplex = true
384+ return false
385+ }
386+ return true
387+ })
388+ return hasComplex
389+ }
387390
388- if isPtr {
389- lines = append (lines , fmt .Sprintf ("\t \t \t Param(%s).BeginOptional().%s(%s).EndOptional()." , paramName , method , variable ))
390- } else {
391- lines = append (lines , fmt .Sprintf ("\t \t \t Param(%s).%s(%s)." , paramName , method , variable ))
392- }
391+ // YDBParamsBuilder emits Go code that constructs YDB params using ParamsBuilder.
392+ func (v QueryValue ) YDBParamsBuilder () string {
393+ var lines []string
394+
395+ v .ydbIterateNamedParams (func (field Field , method string ) bool {
396+ if method == "" {
397+ return true
393398 }
394- }
395399
396- if len (lines ) == 0 {
397- return ""
398- }
400+ name := field .Column .GetName ()
401+ paramName := fmt .Sprintf ("%q" , addDollarPrefix (name ))
402+ variable := escape (v .VariableForField (field ))
403+
404+ goType := field .Type
405+ isPtr := strings .HasPrefix (goType , "*" )
406+ isArray := field .Column .IsArray || field .Column .IsSqlcSlice
407+
408+ if isArray {
409+ lines = append (lines , fmt .Sprintf ("\t var list = parameters.Param(%s).BeginList()" , paramName ))
410+ lines = append (lines , fmt .Sprintf ("\t for _, param := range %s {" , variable ))
411+ lines = append (lines , fmt .Sprintf ("\t \t list = list.Add().%s(param)" , method ))
412+ lines = append (lines , "\t }" )
413+ lines = append (lines , "\t parameters = list.EndList()" )
414+ } else if isPtr {
415+ lines = append (lines , fmt .Sprintf ("\t parameters = parameters.Param(%s).BeginOptional().%s(%s).EndOptional()" , paramName , method , variable ))
416+ } else {
417+ lines = append (lines , fmt .Sprintf ("\t parameters = parameters.Param(%s).%s(%s)" , paramName , method , variable ))
418+ }
419+
420+ return true
421+ })
399422
400423 params := strings .Join (lines , "\n " )
401- return fmt .Sprintf ("\n query.WithParameters(\n \t \t ydb.ParamsBuilder().\n %s\n \t \t \t Build(),\n \t \t ),\n " , params )
424+ return fmt .Sprintf ("\t parameters := ydb.ParamsBuilder()\n %s" , params )
425+ }
426+
427+ func (v QueryValue ) YDBHasParams () bool {
428+ hasParams := false
429+ v .ydbIterateNamedParams (func (field Field , method string ) bool {
430+ hasParams = true
431+ return false
432+ })
433+ return hasParams
402434}
403435
404436func (v QueryValue ) getParameterFields () []Field {
@@ -415,6 +447,53 @@ func (v QueryValue) getParameterFields() []Field {
415447 return v .Struct .Fields
416448}
417449
450+ // YDBPair returns the argument name and type for YDB query methods, filtering out interface{} parameters
451+ // that are handled by manualParams instead.
452+ func (v QueryValue ) YDBPair () string {
453+ if v .isEmpty () {
454+ return ""
455+ }
456+
457+ var out []string
458+ for _ , arg := range v .YDBPairs () {
459+ out = append (out , arg .Name + " " + arg .Type )
460+ }
461+ return strings .Join (out , "," )
462+ }
463+
464+ // YDBPairs returns the argument name and type for YDB query methods, filtering out interface{} parameters
465+ // that are handled by manualParams instead.
466+ func (v QueryValue ) YDBPairs () []Argument {
467+ if v .isEmpty () {
468+ return nil
469+ }
470+
471+ if ! v .EmitStruct () && v .IsStruct () {
472+ var out []Argument
473+ for _ , f := range v .Struct .Fields {
474+ if strings .HasSuffix (f .Type , "interface{}" ) {
475+ continue
476+ }
477+ out = append (out , Argument {
478+ Name : escape (toLowerCase (f .Name )),
479+ Type : f .Type ,
480+ })
481+ }
482+ return out
483+ }
484+
485+ if strings .HasSuffix (v .Typ , "interface{}" ) {
486+ return nil
487+ }
488+
489+ return []Argument {
490+ {
491+ Name : escape (v .Name ),
492+ Type : v .DefineType (),
493+ },
494+ }
495+ }
496+
418497// A struct used to generate methods and fields on the Queries struct
419498type Query struct {
420499 Cmd string
0 commit comments