More custom-api additions/tweaks

* Remove need to convert to int for math stuff
* Add `now` and `duration` functions
This commit is contained in:
Svilen Markov 2025-03-28 23:34:49 +00:00
parent bd020c93f5
commit dd74c173a5
2 changed files with 63 additions and 12 deletions

View File

@ -226,10 +226,10 @@ JSON response:
} }
``` ```
Calculations can be performed, however all numbers must be converted to floats first if they are not already: Calculations can be performed on either ints or floats. If both numbers are ints, an int will be returned, otherwise a float will be returned. If you try to divide by zero, 0 will be returned. If you provide non-numeric values, `NaN` will be returned.
```html ```html
<div>{{ sub (.JSON.Int "price" | toFloat) (.JSON.Int "discount" | toFloat) }}</div> <div>{{ sub (.JSON.Int "price") (.JSON.Int "discount") }}</div>
``` ```
Output: Output:
@ -325,6 +325,8 @@ The following helper functions provided by Glance are available:
- `toFloat(i int) float`: Converts an integer to a float. - `toFloat(i int) float`: Converts an integer to a float.
- `toInt(f float) int`: Converts a float to an integer. - `toInt(f float) int`: Converts a float to an integer.
- `toRelativeTime(t time.Time) template.HTMLAttr`: Converts Time to a relative time such as 2h, 1d, etc which dynamically updates. **NOTE:** the value of this function should be used as an attribute in an HTML tag, e.g. `<span {{ toRelativeTime .Time }}></span>`. - `toRelativeTime(t time.Time) template.HTMLAttr`: Converts Time to a relative time such as 2h, 1d, etc which dynamically updates. **NOTE:** the value of this function should be used as an attribute in an HTML tag, e.g. `<span {{ toRelativeTime .Time }}></span>`.
- `now() time.Time`: Returns the current time.
- `duration(str string) time.Duration`: Parses a string such as `1h`, `1d`, `5h30m`, etc into a `time.Duration`.
- `parseTime(layout string, s string) time.Time`: Parses a string into time.Time. The layout must be provided in Go's [date format](https://pkg.go.dev/time#pkg-constants). You can alternatively use these values instead of the literal format: "unix", "RFC3339", "RFC3339Nano", "DateTime", "DateOnly". - `parseTime(layout string, s string) time.Time`: Parses a string into time.Time. The layout must be provided in Go's [date format](https://pkg.go.dev/time#pkg-constants). You can alternatively use these values instead of the literal format: "unix", "RFC3339", "RFC3339Nano", "DateTime", "DateOnly".
- `parseRelativeTime(layout string, s string) time.Time`: A shorthand for `{{ .String "date" | parseTime "rfc3339" | toRelativeTime }}`. - `parseRelativeTime(layout string, s string) time.Time`: A shorthand for `{{ .String "date" | parseTime "rfc3339" | toRelativeTime }}`.
- `add(a, b float) float`: Adds two numbers. - `add(a, b float) float`: Adds two numbers.

View File

@ -342,6 +342,23 @@ func (r *decoratedGJSONResult) Bool(key string) bool {
return r.Get(key).Bool() return r.Get(key).Bool()
} }
func customAPIDoMathOp[T int | float64](a, b T, op string) T {
switch op {
case "add":
return a + b
case "sub":
return a - b
case "mul":
return a * b
case "div":
if b == 0 {
return 0
}
return a / b
}
return 0
}
var customAPITemplateFuncs = func() template.FuncMap { var customAPITemplateFuncs = func() template.FuncMap {
var regexpCacheMu sync.Mutex var regexpCacheMu sync.Mutex
var regexpCache = make(map[string]*regexp.Regexp) var regexpCache = make(map[string]*regexp.Regexp)
@ -359,6 +376,31 @@ var customAPITemplateFuncs = func() template.FuncMap {
return regex return regex
} }
doMathOpWithAny := func(a, b any, op string) any {
switch at := a.(type) {
case int:
switch bt := b.(type) {
case int:
return customAPIDoMathOp(at, bt, op)
case float64:
return customAPIDoMathOp(float64(at), bt, op)
default:
return math.NaN()
}
case float64:
switch bt := b.(type) {
case int:
return customAPIDoMathOp(at, float64(bt), op)
case float64:
return customAPIDoMathOp(at, bt, op)
default:
return math.NaN()
}
default:
return math.NaN()
}
}
funcs := template.FuncMap{ funcs := template.FuncMap{
"toFloat": func(a int) float64 { "toFloat": func(a int) float64 {
return float64(a) return float64(a)
@ -366,21 +408,28 @@ var customAPITemplateFuncs = func() template.FuncMap {
"toInt": func(a float64) int { "toInt": func(a float64) int {
return int(a) return int(a)
}, },
"add": func(a, b float64) float64 { "add": func(a, b any) any {
return a + b return doMathOpWithAny(a, b, "add")
}, },
"sub": func(a, b float64) float64 { "sub": func(a, b any) any {
return a - b return doMathOpWithAny(a, b, "sub")
}, },
"mul": func(a, b float64) float64 { "mul": func(a, b any) any {
return a * b return doMathOpWithAny(a, b, "mul")
}, },
"div": func(a, b float64) float64 { "div": func(a, b any) any {
if b == 0 { return doMathOpWithAny(a, b, "div")
return math.NaN() },
"now": func() time.Time {
return time.Now()
},
"duration": func(str string) time.Duration {
d, err := time.ParseDuration(str)
if err != nil {
return 0
} }
return a / b return d
}, },
"parseTime": customAPIFuncParseTime, "parseTime": customAPIFuncParseTime,
"toRelativeTime": dynamicRelativeTimeAttrs, "toRelativeTime": dynamicRelativeTimeAttrs,