fix: add involves edge from task to agent:nomos at creation
Plus sync vendor directory for Docker build compatibility.
This commit is contained in:
410
vendor/github.com/jackc/pgx/v5/named_args.go
generated
vendored
Normal file
410
vendor/github.com/jackc/pgx/v5/named_args.go
generated
vendored
Normal file
@@ -0,0 +1,410 @@
|
||||
package pgx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// NamedArgs can be used as the first argument to a query method. It will replace every '@' named placeholder with a '$'
|
||||
// ordinal placeholder and construct the appropriate arguments.
|
||||
//
|
||||
// For example, the following two queries are equivalent:
|
||||
//
|
||||
// conn.Query(ctx, "select * from widgets where foo = @foo and bar = @bar", pgx.NamedArgs{"foo": 1, "bar": 2})
|
||||
// conn.Query(ctx, "select * from widgets where foo = $1 and bar = $2", 1, 2)
|
||||
//
|
||||
// Named placeholders are case sensitive and must start with a letter or underscore. Subsequent characters can be
|
||||
// letters, numbers, or underscores.
|
||||
|
||||
type NamedArgs map[string]any
|
||||
|
||||
// RewriteQuery implements the QueryRewriter interface.
|
||||
func (na NamedArgs) RewriteQuery(ctx context.Context, conn *Conn, sql string, args []any) (newSQL string, newArgs []any, err error) {
|
||||
return rewriteQuery(na, sql, false)
|
||||
}
|
||||
|
||||
// StrictNamedArgs can be used in the same way as NamedArgs, but provided arguments are also checked to include all
|
||||
// named arguments that the sql query uses, and no extra arguments.
|
||||
type StrictNamedArgs map[string]any
|
||||
|
||||
// RewriteQuery implements the QueryRewriter interface.
|
||||
func (sna StrictNamedArgs) RewriteQuery(ctx context.Context, conn *Conn, sql string, args []any) (newSQL string, newArgs []any, err error) {
|
||||
return rewriteQuery(sna, sql, true)
|
||||
}
|
||||
|
||||
type errorQueryRewriter struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (r errorQueryRewriter) RewriteQuery(ctx context.Context, conn *Conn, sql string, args []any) (newSQL string, newArgs []any, err error) {
|
||||
return "", nil, r.err
|
||||
}
|
||||
|
||||
// StructArgs converts exported fields of a struct into a QueryRewriter so it can
|
||||
// be used as the first argument to a query method (e.g. "where id=@id").
|
||||
//
|
||||
// Field names are taken from the `db` struct tag if present. Tag values may
|
||||
// include comma-separated options (e.g. `db:"id,omitempty"`). A `db:"-"` field is
|
||||
// ignored. If no `db` tag is present, the Go field name is used.
|
||||
//
|
||||
// sa may be a struct or a pointer to a struct.
|
||||
func StructArgs(sa any) QueryRewriter {
|
||||
args, err := structArgs(sa)
|
||||
if err != nil {
|
||||
return errorQueryRewriter{err: err}
|
||||
}
|
||||
return NamedArgs(args)
|
||||
}
|
||||
|
||||
// StrictStructArgs is like StructArgs but uses StrictNamedArgs rewriting
|
||||
// semantics (i.e. errors if the SQL query references missing arguments or if
|
||||
// extra arguments are provided).
|
||||
func StrictStructArgs(sa any) QueryRewriter {
|
||||
args, err := structArgs(sa)
|
||||
if err != nil {
|
||||
return errorQueryRewriter{err: err}
|
||||
}
|
||||
return StrictNamedArgs(args)
|
||||
}
|
||||
|
||||
func structArgs(sa any) (map[string]any, error) {
|
||||
if sa == nil {
|
||||
return nil, fmt.Errorf("StructArgs requires a struct or pointer to struct, got nil")
|
||||
}
|
||||
|
||||
v := reflect.ValueOf(sa)
|
||||
t := v.Type()
|
||||
|
||||
if t.Kind() == reflect.Pointer {
|
||||
if v.IsNil() {
|
||||
return nil, fmt.Errorf("StructArgs requires a non-nil pointer to struct")
|
||||
}
|
||||
v = v.Elem()
|
||||
t = v.Type()
|
||||
}
|
||||
|
||||
if t.Kind() != reflect.Struct {
|
||||
return nil, fmt.Errorf("StructArgs requires a struct or pointer to struct, got %s", t)
|
||||
}
|
||||
|
||||
out := make(map[string]any, t.NumField())
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
sf := t.Field(i)
|
||||
|
||||
// Ignore unexported fields.
|
||||
if sf.PkgPath != "" {
|
||||
continue
|
||||
}
|
||||
|
||||
key, ok, err := dbTagKey(sf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, exists := out[key]; exists {
|
||||
return nil, fmt.Errorf("duplicate StructArgs key %q", key)
|
||||
}
|
||||
|
||||
out[key] = v.Field(i).Interface()
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// dbTagKey derives the named-argument key for a struct field. Tag parsing matches
|
||||
// RowToStructByName* in rows.go (structTagKey, Lookup, comma options, db:"-").
|
||||
// Anonymous embedded structs are skipped without flattening (unlike row scanning).
|
||||
func dbTagKey(sf reflect.StructField) (key string, ok bool, err error) {
|
||||
if sf.Anonymous {
|
||||
ft := sf.Type
|
||||
if ft.Kind() == reflect.Pointer {
|
||||
ft = ft.Elem()
|
||||
}
|
||||
if ft.Kind() == reflect.Struct {
|
||||
return "", false, nil
|
||||
}
|
||||
}
|
||||
|
||||
dbTag, dbTagPresent := sf.Tag.Lookup(structTagKey)
|
||||
if dbTagPresent {
|
||||
dbTag, _, _ = strings.Cut(dbTag, ",")
|
||||
}
|
||||
if dbTag == "-" {
|
||||
return "", false, nil
|
||||
}
|
||||
if dbTagPresent {
|
||||
if dbTag == "" {
|
||||
return "", false, fmt.Errorf("field %s has empty `%s` tag", sf.Name, structTagKey)
|
||||
}
|
||||
return dbTag, true, nil
|
||||
}
|
||||
|
||||
return sf.Name, true, nil
|
||||
}
|
||||
|
||||
type namedArg string
|
||||
|
||||
type sqlLexer struct {
|
||||
src string
|
||||
start int
|
||||
pos int
|
||||
nested int // multiline comment nesting level.
|
||||
stateFn stateFn
|
||||
parts []any
|
||||
|
||||
nameToOrdinal map[namedArg]int
|
||||
}
|
||||
|
||||
type stateFn func(*sqlLexer) stateFn
|
||||
|
||||
func rewriteQuery(na map[string]any, sql string, isStrict bool) (newSQL string, newArgs []any, err error) {
|
||||
l := &sqlLexer{
|
||||
src: sql,
|
||||
stateFn: rawState,
|
||||
nameToOrdinal: make(map[namedArg]int, len(na)),
|
||||
}
|
||||
|
||||
for l.stateFn != nil {
|
||||
l.stateFn = l.stateFn(l)
|
||||
}
|
||||
|
||||
sb := strings.Builder{}
|
||||
for _, p := range l.parts {
|
||||
switch p := p.(type) {
|
||||
case string:
|
||||
sb.WriteString(p)
|
||||
case namedArg:
|
||||
sb.WriteRune('$')
|
||||
sb.WriteString(strconv.Itoa(l.nameToOrdinal[p]))
|
||||
}
|
||||
}
|
||||
|
||||
newArgs = make([]any, len(l.nameToOrdinal))
|
||||
for name, ordinal := range l.nameToOrdinal {
|
||||
var found bool
|
||||
newArgs[ordinal-1], found = na[string(name)]
|
||||
if isStrict && !found {
|
||||
return "", nil, fmt.Errorf("argument %s found in sql query but not present in StrictNamedArgs", name)
|
||||
}
|
||||
}
|
||||
|
||||
if isStrict {
|
||||
for name := range na {
|
||||
if _, found := l.nameToOrdinal[namedArg(name)]; !found {
|
||||
return "", nil, fmt.Errorf("argument %s of StrictNamedArgs not found in sql query", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb.String(), newArgs, nil
|
||||
}
|
||||
|
||||
func rawState(l *sqlLexer) stateFn {
|
||||
for {
|
||||
r, width := utf8.DecodeRuneInString(l.src[l.pos:])
|
||||
l.pos += width
|
||||
|
||||
switch r {
|
||||
case 'e', 'E':
|
||||
nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
|
||||
if nextRune == '\'' {
|
||||
l.pos += width
|
||||
return escapeStringState
|
||||
}
|
||||
case '\'':
|
||||
return singleQuoteState
|
||||
case '"':
|
||||
return doubleQuoteState
|
||||
case '@':
|
||||
nextRune, _ := utf8.DecodeRuneInString(l.src[l.pos:])
|
||||
if isLetter(nextRune) || nextRune == '_' {
|
||||
if l.pos-l.start > 0 {
|
||||
l.parts = append(l.parts, l.src[l.start:l.pos-width])
|
||||
}
|
||||
l.start = l.pos
|
||||
return namedArgState
|
||||
}
|
||||
case '-':
|
||||
nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
|
||||
if nextRune == '-' {
|
||||
l.pos += width
|
||||
return oneLineCommentState
|
||||
}
|
||||
case '/':
|
||||
nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
|
||||
if nextRune == '*' {
|
||||
l.pos += width
|
||||
return multilineCommentState
|
||||
}
|
||||
case utf8.RuneError:
|
||||
if l.pos-l.start > 0 {
|
||||
l.parts = append(l.parts, l.src[l.start:l.pos])
|
||||
l.start = l.pos
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isLetter(r rune) bool {
|
||||
return (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z')
|
||||
}
|
||||
|
||||
func namedArgState(l *sqlLexer) stateFn {
|
||||
for {
|
||||
r, width := utf8.DecodeRuneInString(l.src[l.pos:])
|
||||
l.pos += width
|
||||
|
||||
if r == utf8.RuneError {
|
||||
if l.pos-l.start > 0 {
|
||||
na := namedArg(l.src[l.start:l.pos])
|
||||
if _, found := l.nameToOrdinal[na]; !found {
|
||||
l.nameToOrdinal[na] = len(l.nameToOrdinal) + 1
|
||||
}
|
||||
l.parts = append(l.parts, na)
|
||||
l.start = l.pos
|
||||
}
|
||||
return nil
|
||||
} else if !(isLetter(r) || (r >= '0' && r <= '9') || r == '_') {
|
||||
l.pos -= width
|
||||
na := namedArg(l.src[l.start:l.pos])
|
||||
if _, found := l.nameToOrdinal[na]; !found {
|
||||
l.nameToOrdinal[na] = len(l.nameToOrdinal) + 1
|
||||
}
|
||||
l.parts = append(l.parts, na)
|
||||
l.start = l.pos
|
||||
return rawState
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func singleQuoteState(l *sqlLexer) stateFn {
|
||||
for {
|
||||
r, width := utf8.DecodeRuneInString(l.src[l.pos:])
|
||||
l.pos += width
|
||||
|
||||
switch r {
|
||||
case '\'':
|
||||
nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
|
||||
if nextRune != '\'' {
|
||||
return rawState
|
||||
}
|
||||
l.pos += width
|
||||
case utf8.RuneError:
|
||||
if l.pos-l.start > 0 {
|
||||
l.parts = append(l.parts, l.src[l.start:l.pos])
|
||||
l.start = l.pos
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func doubleQuoteState(l *sqlLexer) stateFn {
|
||||
for {
|
||||
r, width := utf8.DecodeRuneInString(l.src[l.pos:])
|
||||
l.pos += width
|
||||
|
||||
switch r {
|
||||
case '"':
|
||||
nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
|
||||
if nextRune != '"' {
|
||||
return rawState
|
||||
}
|
||||
l.pos += width
|
||||
case utf8.RuneError:
|
||||
if l.pos-l.start > 0 {
|
||||
l.parts = append(l.parts, l.src[l.start:l.pos])
|
||||
l.start = l.pos
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func escapeStringState(l *sqlLexer) stateFn {
|
||||
for {
|
||||
r, width := utf8.DecodeRuneInString(l.src[l.pos:])
|
||||
l.pos += width
|
||||
|
||||
switch r {
|
||||
case '\\':
|
||||
_, width = utf8.DecodeRuneInString(l.src[l.pos:])
|
||||
l.pos += width
|
||||
case '\'':
|
||||
nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
|
||||
if nextRune != '\'' {
|
||||
return rawState
|
||||
}
|
||||
l.pos += width
|
||||
case utf8.RuneError:
|
||||
if l.pos-l.start > 0 {
|
||||
l.parts = append(l.parts, l.src[l.start:l.pos])
|
||||
l.start = l.pos
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func oneLineCommentState(l *sqlLexer) stateFn {
|
||||
for {
|
||||
r, width := utf8.DecodeRuneInString(l.src[l.pos:])
|
||||
l.pos += width
|
||||
|
||||
switch r {
|
||||
case '\\':
|
||||
_, width = utf8.DecodeRuneInString(l.src[l.pos:])
|
||||
l.pos += width
|
||||
case '\n', '\r':
|
||||
return rawState
|
||||
case utf8.RuneError:
|
||||
if l.pos-l.start > 0 {
|
||||
l.parts = append(l.parts, l.src[l.start:l.pos])
|
||||
l.start = l.pos
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func multilineCommentState(l *sqlLexer) stateFn {
|
||||
for {
|
||||
r, width := utf8.DecodeRuneInString(l.src[l.pos:])
|
||||
l.pos += width
|
||||
|
||||
switch r {
|
||||
case '/':
|
||||
nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
|
||||
if nextRune == '*' {
|
||||
l.pos += width
|
||||
l.nested++
|
||||
}
|
||||
case '*':
|
||||
nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
|
||||
if nextRune != '/' {
|
||||
continue
|
||||
}
|
||||
|
||||
l.pos += width
|
||||
if l.nested == 0 {
|
||||
return rawState
|
||||
}
|
||||
l.nested--
|
||||
|
||||
case utf8.RuneError:
|
||||
if l.pos-l.start > 0 {
|
||||
l.parts = append(l.parts, l.src[l.start:l.pos])
|
||||
l.start = l.pos
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user