Files
sqlite3/util/sql3util/arg.go

181 lines
3.2 KiB
Go
Raw Normal View History

2024-10-22 23:32:57 +01:00
package sql3util
2024-01-03 00:54:30 +00:00
2025-12-04 15:27:16 +00:00
import (
"strings"
"time"
)
2024-01-03 00:54:30 +00:00
// NamedArg splits an named arg into a key and value,
// around an equals sign.
// Spaces are trimmed around both key and value.
func NamedArg(arg string) (key, val string) {
key, val, _ = strings.Cut(arg, "=")
key = strings.TrimSpace(key)
val = strings.TrimSpace(val)
return
}
// Unquote unquotes a string.
2024-10-24 00:22:20 +01:00
//
// https://sqlite.org/lang_keywords.html
2024-01-03 00:54:30 +00:00
func Unquote(val string) string {
if len(val) < 2 {
return val
}
2024-10-22 23:32:57 +01:00
fst := val[0]
lst := val[len(val)-1]
rst := val[1 : len(val)-1]
if fst == '[' && lst == ']' {
return rst
}
if fst != lst {
2024-01-03 00:54:30 +00:00
return val
}
var old, new string
2024-10-22 23:32:57 +01:00
switch fst {
2024-01-03 00:54:30 +00:00
default:
return val
2024-09-22 12:09:23 +01:00
case '`':
old, new = "``", "`"
2024-10-22 23:32:57 +01:00
case '"':
old, new = `""`, `"`
2024-01-03 00:54:30 +00:00
case '\'':
old, new = `''`, `'`
}
2024-10-22 23:32:57 +01:00
return strings.ReplaceAll(rst, old, new)
}
2024-10-24 00:22:20 +01:00
// ParseBool parses a boolean.
//
// https://sqlite.org/pragma.html#syntax
2024-10-22 23:32:57 +01:00
func ParseBool(s string) (b, ok bool) {
if len(s) == 0 {
return false, false
}
if s[0] == '0' {
return false, true
}
if '1' <= s[0] && s[0] <= '9' {
return true, true
}
switch strings.ToLower(s) {
case "true", "yes", "on":
return true, true
case "false", "no", "off":
return false, true
}
return false, false
2024-01-03 00:54:30 +00:00
}
2025-12-04 15:27:16 +00:00
// ParseTimeShift parses a time shift modifier,
// also the output of timediff.
//
// https://sqlite.org/lang_datefunc.html
func ParseTimeShift(s string) (years, months, days int, duration time.Duration, ok bool) {
// Sign part: ±
neg := strings.HasPrefix(s, "-")
sign := neg || strings.HasPrefix(s, "+")
if sign {
s = s[1:]
}
if ok = len(s) >= 5; !ok {
return // !ok
}
defer func() {
if neg {
years = -years
months = -months
days = -days
duration = -duration
}
}()
// Date part: YYYY-MM-DD
if s[4] == '-' {
if ok = sign && len(s) >= 10 && s[7] == '-'; !ok {
return // !ok
}
2025-12-10 16:15:19 +00:00
if years, ok = parseInt(s[0:4], 0); !ok {
2025-12-04 15:27:16 +00:00
return // !ok
}
2025-12-10 16:15:19 +00:00
if months, ok = parseInt(s[5:7], 12); !ok {
2025-12-04 15:27:16 +00:00
return // !ok
}
2025-12-10 16:15:19 +00:00
if days, ok = parseInt(s[8:10], 31); !ok {
2025-12-04 15:27:16 +00:00
return // !ok
}
if len(s) == 10 {
return
}
if ok = s[10] == ' '; !ok {
return // !ok
}
s = s[11:]
}
// Time part: HH:MM
if ok = len(s) >= 5 && s[2] == ':'; !ok {
return // !ok
}
var hours, minutes int
2025-12-10 16:15:19 +00:00
if hours, ok = parseInt(s[0:2], 24); !ok {
2025-12-04 15:27:16 +00:00
return
}
2025-12-10 16:15:19 +00:00
if minutes, ok = parseInt(s[3:5], 60); !ok {
2025-12-04 15:27:16 +00:00
return
}
duration = time.Duration(hours)*time.Hour + time.Duration(minutes)*time.Minute
if len(s) == 5 {
return
}
if ok = len(s) >= 8 && s[5] == ':'; !ok {
return // !ok
}
// Seconds part: HH:MM:SS
var seconds int
2025-12-10 16:15:19 +00:00
if seconds, ok = parseInt(s[6:8], 60); !ok {
2025-12-04 15:27:16 +00:00
return
}
duration += time.Duration(seconds) * time.Second
if len(s) == 8 {
return
}
if ok = len(s) >= 10 && s[8] == '.'; !ok {
return // !ok
}
s = s[9:]
// Nanosecond part: HH:MM:SS.SSS
var nanos int
2025-12-10 16:15:19 +00:00
if nanos, ok = parseInt(s[0:min(9, len(s))], 0); !ok {
2025-12-04 15:27:16 +00:00
return
}
for i := len(s); i < 9; i++ {
nanos *= 10
}
duration += time.Duration(nanos)
// Subnanosecond part.
if len(s) > 9 {
2025-12-10 16:15:19 +00:00
_, ok = parseInt(s[9:], 0)
2025-12-04 15:27:16 +00:00
}
return
}
2025-12-10 16:15:19 +00:00
func parseInt(s string, max int) (i int, _ bool) {
2025-12-04 15:27:16 +00:00
for _, r := range []byte(s) {
r -= '0'
if r > 9 {
return
}
i = i*10 + int(r)
}
2025-12-10 16:15:19 +00:00
return i, max == 0 || i < max
2025-12-04 15:27:16 +00:00
}