Extract rql package
This commit is contained in:
commit
00c6309659
42
.golangci.yml
Normal file
42
.golangci.yml
Normal file
@ -0,0 +1,42 @@
|
||||
run:
|
||||
timeout: 5m
|
||||
|
||||
linters-settings:
|
||||
goconst:
|
||||
min-len: 2
|
||||
min-occurrences: 2
|
||||
misspell:
|
||||
locale: US
|
||||
lll:
|
||||
line-length: 140
|
||||
gocritic:
|
||||
enabled-tags:
|
||||
- performance
|
||||
- style
|
||||
- experimental
|
||||
disabled-checks:
|
||||
- paramTypeCombine
|
||||
- unnamedResult
|
||||
|
||||
linters:
|
||||
enable:
|
||||
- dupl
|
||||
- exportloopref
|
||||
- gochecknoinits
|
||||
- gocritic
|
||||
- gocyclo
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- misspell
|
||||
- nakedret
|
||||
- prealloc
|
||||
- revive
|
||||
- staticcheck
|
||||
- stylecheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unused
|
||||
fast: false
|
||||
disable-all: true
|
14
go.mod
Normal file
14
go.mod
Normal file
@ -0,0 +1,14 @@
|
||||
module go.pkg.cx/rql
|
||||
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/alecthomas/participle/v2 v2.1.1
|
||||
github.com/stretchr/testify v1.8.4
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
18
go.sum
Normal file
18
go.sum
Normal file
@ -0,0 +1,18 @@
|
||||
github.com/alecthomas/assert/v2 v2.3.0 h1:mAsH2wmvjsuvyBvAmCtm7zFsBlb8mIHx5ySLVdDZXL0=
|
||||
github.com/alecthomas/assert/v2 v2.3.0/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
|
||||
github.com/alecthomas/participle/v2 v2.1.1 h1:hrjKESvSqGHzRb4yW1ciisFJ4p3MGYih6icjJvbsmV8=
|
||||
github.com/alecthomas/participle/v2 v2.1.1/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c=
|
||||
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
|
||||
github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
42
parser.go
Normal file
42
parser.go
Normal file
@ -0,0 +1,42 @@
|
||||
package rql
|
||||
|
||||
import (
|
||||
"github.com/alecthomas/participle/v2"
|
||||
"github.com/alecthomas/participle/v2/lexer"
|
||||
)
|
||||
|
||||
var (
|
||||
rqlLexer = lexer.MustSimple([]lexer.SimpleRule{
|
||||
{Name: "whitespace", Pattern: `\s+`},
|
||||
{Name: "String", Pattern: `"[^"]*"`},
|
||||
{Name: "Ident", Pattern: `[a-zA-Z_][a-zA-Z_0-9]*`},
|
||||
{Name: "Punct", Pattern: `[-[!@#$%^&*()+_={};':",.<>?/]|]`},
|
||||
})
|
||||
|
||||
rqlParser = participle.MustBuild[Query](
|
||||
participle.Lexer(rqlLexer),
|
||||
participle.Unquote("String"),
|
||||
participle.UseLookahead(2),
|
||||
)
|
||||
)
|
||||
|
||||
func Parse(query string) (*Query, error) {
|
||||
return rqlParser.ParseString("", query)
|
||||
}
|
||||
|
||||
type Operator string
|
||||
|
||||
type Values struct {
|
||||
Single *string `parser:"@String"`
|
||||
List []string `parser:"| ( '[' @String (',' @String)* ']' )"`
|
||||
}
|
||||
|
||||
type Predicate struct {
|
||||
Key string `parser:"@Ident '.'"`
|
||||
Operator Operator `parser:"@('eq'|'lt'|'lte'|'gt'|'gte'|'like'|'in')"`
|
||||
Values Values `parser:"'=' @@"`
|
||||
}
|
||||
|
||||
type Query struct {
|
||||
Predicates []*Predicate `parser:"@@*"`
|
||||
}
|
87
parser_test.go
Normal file
87
parser_test.go
Normal file
@ -0,0 +1,87 @@
|
||||
package rql
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
one := "1"
|
||||
john := "John"
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
query string
|
||||
predicates []*Predicate
|
||||
errMessage string
|
||||
}{
|
||||
{
|
||||
name: "Valid Query",
|
||||
query: `id.eq="1"`,
|
||||
predicates: []*Predicate{{Key: "id", Operator: "eq", Values: Values{Single: &one}}},
|
||||
errMessage: "",
|
||||
},
|
||||
{
|
||||
name: "Multiple Predicates",
|
||||
query: `id.eq="1" name.eq="John"`,
|
||||
predicates: []*Predicate{{Key: "id", Operator: "eq", Values: Values{Single: &one}}, {Key: "name", Operator: "eq", Values: Values{Single: &john}}},
|
||||
errMessage: "",
|
||||
},
|
||||
{
|
||||
name: "List Values",
|
||||
query: `id.in=["1", "2", "3"]`,
|
||||
predicates: []*Predicate{
|
||||
{
|
||||
Key: "id",
|
||||
Operator: "in",
|
||||
Values: Values{
|
||||
List: []string{"1", "2", "3"},
|
||||
},
|
||||
},
|
||||
},
|
||||
errMessage: "",
|
||||
},
|
||||
{
|
||||
name: "Empty Query",
|
||||
query: "",
|
||||
predicates: nil,
|
||||
errMessage: "",
|
||||
},
|
||||
{
|
||||
name: "Whitespace in Query",
|
||||
query: ` id . eq = "1" `,
|
||||
predicates: []*Predicate{{Key: "id", Operator: "eq", Values: Values{Single: &one}}},
|
||||
errMessage: "",
|
||||
},
|
||||
{
|
||||
name: "Missing Key",
|
||||
query: `.eq="1"`,
|
||||
predicates: nil,
|
||||
errMessage: `unexpected token "."`,
|
||||
},
|
||||
{
|
||||
name: "Invalid Operator",
|
||||
query: `id.invalid="1"`,
|
||||
predicates: nil,
|
||||
errMessage: `unexpected token "invalid"`,
|
||||
},
|
||||
{
|
||||
name: "Invalid Query",
|
||||
query: "invalid_query",
|
||||
predicates: nil,
|
||||
errMessage: `unexpected token "<EOF>"`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
result, err := Parse(tc.query)
|
||||
|
||||
assert.Equal(t, tc.predicates, result.Predicates)
|
||||
if tc.errMessage != "" {
|
||||
assert.ErrorContains(t, err, tc.errMessage)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user