snapshot of https://github.com/sqlc-dev/sqlc.git (main, 2026-09-16; blobs > 131072B omitted)
Some checks failed
kotlin / test (push) Has been skipped
python / test (push) Has been skipped
typescript / test (push) Has been skipped
go / build darwin/amd64 (push) Has been cancelled
go / build linux/amd64 (push) Has been cancelled
go / build windows/amd64 (push) Has been cancelled
go / build darwin/arm64 (push) Has been cancelled
go / build linux/arm64 (push) Has been cancelled
go / build windows/arm64 (push) Has been cancelled
go / test (push) Has been cancelled
go / vuln_check (push) Has been cancelled
Some checks failed
kotlin / test (push) Has been skipped
python / test (push) Has been skipped
typescript / test (push) Has been skipped
go / build darwin/amd64 (push) Has been cancelled
go / build linux/amd64 (push) Has been cancelled
go / build windows/amd64 (push) Has been cancelled
go / build darwin/arm64 (push) Has been cancelled
go / build linux/arm64 (push) Has been cancelled
go / build windows/arm64 (push) Has been cancelled
go / test (push) Has been cancelled
go / vuln_check (push) Has been cancelled
This commit is contained in:
308
internal/codegen/golang/query.go
Normal file
308
internal/codegen/golang/query.go
Normal file
@@ -0,0 +1,308 @@
|
||||
package golang
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/sqlc-dev/sqlc/internal/codegen/golang/opts"
|
||||
"github.com/sqlc-dev/sqlc/internal/metadata"
|
||||
"github.com/sqlc-dev/sqlc/internal/plugin"
|
||||
)
|
||||
|
||||
type QueryValue struct {
|
||||
Emit bool
|
||||
EmitPointer bool
|
||||
Name string
|
||||
DBName string // The name of the field in the database. Only set if Struct==nil.
|
||||
Struct *Struct
|
||||
Typ string
|
||||
SQLDriver opts.SQLDriver
|
||||
|
||||
// ModelQualifier prefixes references to model types when the models file
|
||||
// lives in a different Go package (e.g. "model."). Empty otherwise.
|
||||
ModelQualifier string
|
||||
|
||||
// Column is kept so late in the generation process around to differentiate
|
||||
// between mysql slices and pg arrays
|
||||
Column *plugin.Column
|
||||
}
|
||||
|
||||
func (v QueryValue) EmitStruct() bool {
|
||||
return v.Emit
|
||||
}
|
||||
|
||||
func (v QueryValue) IsStruct() bool {
|
||||
return v.Struct != nil
|
||||
}
|
||||
|
||||
func (v QueryValue) IsPointer() bool {
|
||||
return v.EmitPointer && v.Struct != nil
|
||||
}
|
||||
|
||||
func (v QueryValue) isEmpty() bool {
|
||||
return v.Typ == "" && v.Name == "" && v.Struct == nil
|
||||
}
|
||||
|
||||
type Argument struct {
|
||||
Name string
|
||||
Type string
|
||||
}
|
||||
|
||||
func (v QueryValue) Pair() string {
|
||||
var out []string
|
||||
for _, arg := range v.Pairs() {
|
||||
out = append(out, arg.Name+" "+arg.Type)
|
||||
}
|
||||
return strings.Join(out, ",")
|
||||
}
|
||||
|
||||
// Return the argument name and type for query methods. Should only be used in
|
||||
// the context of method arguments.
|
||||
func (v QueryValue) Pairs() []Argument {
|
||||
if v.isEmpty() {
|
||||
return nil
|
||||
}
|
||||
if !v.EmitStruct() && v.IsStruct() {
|
||||
var out []Argument
|
||||
for _, f := range v.Struct.Fields {
|
||||
out = append(out, Argument{
|
||||
Name: escape(toLowerCase(f.Name)),
|
||||
Type: f.Type,
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
return []Argument{
|
||||
{
|
||||
Name: escape(v.Name),
|
||||
Type: v.DefineType(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (v QueryValue) SlicePair() string {
|
||||
if v.isEmpty() {
|
||||
return ""
|
||||
}
|
||||
return v.Name + " []" + v.DefineType()
|
||||
}
|
||||
|
||||
func (v QueryValue) Type() string {
|
||||
if v.Typ != "" {
|
||||
return v.Typ
|
||||
}
|
||||
if v.Struct != nil {
|
||||
// Model structs (table-derived) live in the models file. When that
|
||||
// file is generated into a different Go package, references from
|
||||
// query files must be qualified. Synthetic structs (Params/Row)
|
||||
// are defined in the same query file as their use, so they stay
|
||||
// bare.
|
||||
if v.Struct.IsModel && v.ModelQualifier != "" {
|
||||
return v.ModelQualifier + v.Struct.Name
|
||||
}
|
||||
return v.Struct.Name
|
||||
}
|
||||
panic("no type for QueryValue: " + v.Name)
|
||||
}
|
||||
|
||||
func (v *QueryValue) DefineType() string {
|
||||
t := v.Type()
|
||||
if v.IsPointer() {
|
||||
return "*" + t
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (v *QueryValue) ReturnName() string {
|
||||
if v.IsPointer() {
|
||||
return "&" + escape(v.Name)
|
||||
}
|
||||
return escape(v.Name)
|
||||
}
|
||||
|
||||
func (v QueryValue) UniqueFields() []Field {
|
||||
seen := map[string]struct{}{}
|
||||
fields := make([]Field, 0, len(v.Struct.Fields))
|
||||
|
||||
for _, field := range v.Struct.Fields {
|
||||
if _, found := seen[field.Name]; found {
|
||||
continue
|
||||
}
|
||||
seen[field.Name] = struct{}{}
|
||||
fields = append(fields, field)
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
func (v QueryValue) Params() string {
|
||||
if v.isEmpty() {
|
||||
return ""
|
||||
}
|
||||
var out []string
|
||||
if v.Struct == nil {
|
||||
if !v.Column.IsSqlcSlice && strings.HasPrefix(v.Typ, "[]") && v.Typ != "[]byte" && !v.SQLDriver.IsPGX() {
|
||||
out = append(out, "pq.Array("+escape(v.Name)+")")
|
||||
} else {
|
||||
out = append(out, escape(v.Name))
|
||||
}
|
||||
} else {
|
||||
for _, f := range v.Struct.Fields {
|
||||
if !f.HasSqlcSlice() && strings.HasPrefix(f.Type, "[]") && f.Type != "[]byte" && !v.SQLDriver.IsPGX() {
|
||||
out = append(out, "pq.Array("+escape(v.VariableForField(f))+")")
|
||||
} else {
|
||||
out = append(out, escape(v.VariableForField(f)))
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(out) <= 3 {
|
||||
return strings.Join(out, ",")
|
||||
}
|
||||
out = append(out, "")
|
||||
return "\n" + strings.Join(out, ",\n")
|
||||
}
|
||||
|
||||
func (v QueryValue) ColumnNames() []string {
|
||||
if v.Struct == nil {
|
||||
return []string{v.DBName}
|
||||
}
|
||||
names := make([]string, len(v.Struct.Fields))
|
||||
for i, f := range v.Struct.Fields {
|
||||
names[i] = f.DBName
|
||||
}
|
||||
return names
|
||||
}
|
||||
|
||||
func (v QueryValue) ColumnNamesAsGoSlice() string {
|
||||
if v.Struct == nil {
|
||||
return fmt.Sprintf("[]string{%q}", v.DBName)
|
||||
}
|
||||
escapedNames := make([]string, len(v.Struct.Fields))
|
||||
for i, f := range v.Struct.Fields {
|
||||
if f.Column != nil && f.Column.OriginalName != "" {
|
||||
escapedNames[i] = fmt.Sprintf("%q", f.Column.OriginalName)
|
||||
} else {
|
||||
escapedNames[i] = fmt.Sprintf("%q", f.DBName)
|
||||
}
|
||||
}
|
||||
return "[]string{" + strings.Join(escapedNames, ", ") + "}"
|
||||
}
|
||||
|
||||
// When true, we have to build the arguments to q.db.QueryContext in addition to
|
||||
// munging the SQL
|
||||
func (v QueryValue) HasSqlcSlices() bool {
|
||||
if v.Struct == nil {
|
||||
return v.Column != nil && v.Column.IsSqlcSlice
|
||||
}
|
||||
for _, v := range v.Struct.Fields {
|
||||
if v.Column.IsSqlcSlice {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (v QueryValue) Scan() string {
|
||||
var out []string
|
||||
if v.Struct == nil {
|
||||
if strings.HasPrefix(v.Typ, "[]") && v.Typ != "[]byte" && !v.SQLDriver.IsPGX() {
|
||||
out = append(out, "pq.Array(&"+v.Name+")")
|
||||
} else {
|
||||
out = append(out, "&"+v.Name)
|
||||
}
|
||||
} else {
|
||||
for _, f := range v.Struct.Fields {
|
||||
|
||||
// append any embedded fields
|
||||
if len(f.EmbedFields) > 0 {
|
||||
for _, embed := range f.EmbedFields {
|
||||
if strings.HasPrefix(embed.Type, "[]") && embed.Type != "[]byte" && !v.SQLDriver.IsPGX() {
|
||||
out = append(out, "pq.Array(&"+v.Name+"."+f.Name+"."+embed.Name+")")
|
||||
} else {
|
||||
out = append(out, "&"+v.Name+"."+f.Name+"."+embed.Name)
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(f.Type, "[]") && f.Type != "[]byte" && !v.SQLDriver.IsPGX() {
|
||||
out = append(out, "pq.Array(&"+v.Name+"."+f.Name+")")
|
||||
} else {
|
||||
out = append(out, "&"+v.Name+"."+f.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(out) <= 3 {
|
||||
return strings.Join(out, ",")
|
||||
}
|
||||
out = append(out, "")
|
||||
return "\n" + strings.Join(out, ",\n")
|
||||
}
|
||||
|
||||
// Deprecated: This method does not respect the Emit field set on the
|
||||
// QueryValue. It's used by the go-sql-driver-mysql/copyfromCopy.tmpl and should
|
||||
// not be used other places.
|
||||
func (v QueryValue) CopyFromMySQLFields() []Field {
|
||||
// fmt.Printf("%#v\n", v)
|
||||
if v.Struct != nil {
|
||||
return v.Struct.Fields
|
||||
}
|
||||
return []Field{
|
||||
{
|
||||
Name: v.Name,
|
||||
DBName: v.DBName,
|
||||
Type: v.Typ,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (v QueryValue) VariableForField(f Field) string {
|
||||
if !v.IsStruct() {
|
||||
return v.Name
|
||||
}
|
||||
if !v.EmitStruct() {
|
||||
return toLowerCase(f.Name)
|
||||
}
|
||||
return v.Name + "." + f.Name
|
||||
}
|
||||
|
||||
// A struct used to generate methods and fields on the Queries struct
|
||||
type Query struct {
|
||||
Cmd string
|
||||
Comments []string
|
||||
MethodName string
|
||||
FieldName string
|
||||
ConstantName string
|
||||
SQL string
|
||||
SourceName string
|
||||
Ret QueryValue
|
||||
Arg QueryValue
|
||||
// Used for :copyfrom
|
||||
Table *plugin.Identifier
|
||||
}
|
||||
|
||||
func (q Query) hasRetType() bool {
|
||||
scanned := q.Cmd == metadata.CmdOne || q.Cmd == metadata.CmdMany ||
|
||||
q.Cmd == metadata.CmdBatchMany || q.Cmd == metadata.CmdBatchOne
|
||||
return scanned && !q.Ret.isEmpty()
|
||||
}
|
||||
|
||||
func (q Query) TableIdentifierAsGoSlice() string {
|
||||
escapedNames := make([]string, 0, 3)
|
||||
for _, p := range []string{q.Table.Catalog, q.Table.Schema, q.Table.Name} {
|
||||
if p != "" {
|
||||
escapedNames = append(escapedNames, fmt.Sprintf("%q", p))
|
||||
}
|
||||
}
|
||||
return "[]string{" + strings.Join(escapedNames, ", ") + "}"
|
||||
}
|
||||
|
||||
func (q Query) TableIdentifierForMySQL() string {
|
||||
escapedNames := make([]string, 0, 3)
|
||||
for _, p := range []string{q.Table.Catalog, q.Table.Schema, q.Table.Name} {
|
||||
if p != "" {
|
||||
escapedNames = append(escapedNames, fmt.Sprintf("`%s`", p))
|
||||
}
|
||||
}
|
||||
return strings.Join(escapedNames, ".")
|
||||
}
|
||||
Reference in New Issue
Block a user