File: lex.go

package info (click to toggle)
incus 6.0.5-6
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 25,788 kB
  • sloc: sh: 16,313; ansic: 3,121; python: 457; makefile: 337; ruby: 51; sql: 50; lisp: 6
file content (141 lines) | stat: -rw-r--r-- 3,824 bytes parent folder | download | duplicates (7)
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()
}