1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
package db
import (
"fmt"
"strings"
"github.com/lxc/incus/v6/cmd/generate-database/lex"
"github.com/lxc/incus/v6/shared/util"
)
// Return the table name for the given database entity.
func entityTable(entity string, override string) string {
if override != "" {
return override
}
entityParts := strings.Split(lex.SnakeCase(entity), "_")
tableParts := make([]string, len(entityParts))
for i, part := range entityParts {
if strings.HasSuffix(part, "ty") || strings.HasSuffix(part, "ly") {
tableParts[i] = part
} else {
tableParts[i] = lex.Plural(part)
}
}
return strings.Join(tableParts, "_")
}
// Return the name of the Filter struct for the given database entity.
func entityFilter(entity string) string {
return fmt.Sprintf("%sFilter", lex.PascalCase(entity))
}
// Return the name of the global variable holding the registration code for
// the given kind of statement aganst the given entity.
func stmtCodeVar(entity string, kind string, filters ...string) string {
prefix := lex.CamelCase(entity)
name := fmt.Sprintf("%s%s", prefix, lex.PascalCase(kind))
if len(filters) > 0 {
name += "By"
name += strings.Join(filters, "And")
}
return name
}
// operation returns the kind of operation being performed, without filter fields.
func operation(kind string) string {
return strings.Split(kind, "-by-")[0]
}
// activeFilters returns the filters mentioned in the command name.
func activeFilters(kind string) []string {
startIndex := strings.Index(kind, "-by-") + len("-by-")
return strings.Split(kind[startIndex:], "-and-")
}
// Return an expression evaluating if a filter should be used (based on active
// criteria).
func activeCriteria(filter []string, ignoredFilter []string) string {
expr := ""
for i, name := range filter {
if i > 0 {
expr += " && "
}
expr += fmt.Sprintf("filter.%s != nil", name)
}
for _, name := range ignoredFilter {
if len(expr) > 0 {
expr += " && "
}
expr += fmt.Sprintf("filter.%s == nil", name)
}
return expr
}
// Return the code for a "dest" function, to be passed as parameter to
// selectObjects in order to scan a single row.
func destFunc(slice string, entity string, importType string, fields []*Field) string {
var builder strings.Builder
writeLine := func(line string) { builder.WriteString(fmt.Sprintf("%s\n", line)) }
writeLine(`func(scan func(dest ...any) error) error {`)
varName := lex.Minuscule(string(entity[0]))
writeLine(fmt.Sprintf("%s := %s{}", varName, importType))
checkErr := func() {
writeLine("if err != nil {\nreturn err\n}")
writeLine("")
}
unmarshal := func(declVarName string, field *Field) {
unmarshalFunc := "unmarshal"
if field.Config.Get("marshal") == "json" {
unmarshalFunc = "unmarshalJSON"
}
writeLine(fmt.Sprintf("err = %s(%s, &%s.%s)", unmarshalFunc, declVarName, varName, field.Name))
checkErr()
}
args := make([]string, len(fields))
declVars := make(map[string]*Field, len(fields))
declVarNames := make([]string, 0, len(fields))
for i, field := range fields {
var arg string
if util.IsNeitherFalseNorEmpty(field.Config.Get("marshal")) {
declVarName := fmt.Sprintf("%sStr", lex.Minuscule(field.Name))
declVarNames = append(declVarNames, declVarName)
declVars[declVarName] = field
arg = fmt.Sprintf("&%s", declVarName)
} else {
arg = fmt.Sprintf("&%s.%s", varName, field.Name)
}
args[i] = arg
}
for _, declVarName := range declVarNames {
writeLine(fmt.Sprintf("var %s string", declVarName))
}
writeLine(fmt.Sprintf("err := scan(%s)", strings.Join(args, ", ")))
checkErr()
for _, declVarName := range declVarNames {
unmarshal(declVarName, declVars[declVarName])
}
writeLine(fmt.Sprintf("%s = append(%s, %s)\n", slice, slice, varName))
writeLine("return nil")
writeLine("}")
return builder.String()
}
|