Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,41 @@ jobs:
arrange:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.16'
- run: go get github.com/jdeflander/goarrange
working-directory: ${{ runner.temp }}
go-version-file: go.mod
- run: go install github.com/jdeflander/goarrange@v1.0.0
- run: test -z "$(goarrange run -r -d)"

lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: golangci/golangci-lint-action@v2
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
version: v1.39
go-version-file: go.mod
- uses: golangci/golangci-lint-action@v9
with:
version: v2.11.3
install-mode: goinstall
args: -E misspell,godot,whitespace

test:
strategy:
matrix:
go-version: [ 1.15.x, 1.16.x ]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
go-version-file: go.mod
- run: go test -v ./...

tidy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.16'
go-version-file: go.mod
- run: go mod tidy
- run: git diff --quiet go.mod go.sum
48 changes: 31 additions & 17 deletions ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const (
type AttributeExpression struct {
AttributePath AttributePath
Operator CompareOperator
CompareValue interface{}
CompareValue any
}

func (e AttributeExpression) String() string {
Expand All @@ -54,12 +54,13 @@ func (e AttributeExpression) String() string {

func (*AttributeExpression) exprNode() {}

// AttributePath represents an attribute path. Both URIPrefix and SubAttr are
// optional values and can be nil.
// e.g. urn:ietf:params:scim:schemas:core:2.0:User:name.givenName
// ^ ^ ^
// URIPrefix | SubAttribute
// AttributeName
// AttributePath represents an attribute path with an optional URIPrefix and
// SubAttribute.
//
// Example: urn:ietf:params:scim:schemas:core:2.0:User:name.givenName
// - URIPrefix: urn:ietf:params:scim:schemas:core:2.0:User
// - AttributeName: name
// - SubAttribute: givenName
type AttributePath struct {
URIPrefix *string
AttributeName string
Expand Down Expand Up @@ -100,10 +101,10 @@ type CompareOperator string

// Expression is a type to assign to implemented expressions.
// Valid expressions are:
// - ValuePath
// - AttributeExpression
// - LogicalExpression
// - NotExpression
// - ValuePath
// - AttributeExpression
// - LogicalExpression
// - NotExpression
type Expression interface {
exprNode()
}
Expand All @@ -115,7 +116,19 @@ type LogicalExpression struct {
}

func (e LogicalExpression) String() string {
return fmt.Sprintf("%v %s %v", e.Left, e.Operator, e.Right)
left := fmt.Sprintf("%v", e.Left)
if e.Operator == AND {
if l, ok := e.Left.(*LogicalExpression); ok && l.Operator == OR {
left = fmt.Sprintf("(%v)", e.Left)
}
}
right := fmt.Sprintf("%v", e.Right)
if e.Operator == AND {
if r, ok := e.Right.(*LogicalExpression); ok && r.Operator == OR {
right = fmt.Sprintf("(%v)", e.Right)
}
}
return fmt.Sprintf("%s %s %s", left, e.Operator, right)
}

func (*LogicalExpression) exprNode() {}
Expand All @@ -134,12 +147,13 @@ func (e NotExpression) String() string {

func (*NotExpression) exprNode() {}

// Path describes the target of a PATCH operation. Path can have an optional
// Path describes the target of a PATCH operation with an optional
// ValueExpression and SubAttribute.
// e.g. members[value eq "2819c223-7f76-453a-919d-413861904646"].displayName
// ^ ^ ^
// | ValueExpression SubAttribute
// AttributePath
//
// Example: members[value eq "2819c223-..."].displayName
// - AttributePath: members
// - ValueExpression: value eq "2819c223-..."
// - SubAttribute: displayName
type Path struct {
AttributePath AttributePath
ValueExpression Expression
Expand Down
4 changes: 2 additions & 2 deletions attrexp.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func (p config) parseAttrExp(node *ast.Node) (AttributeExpression, error) {

var (
compareOp = CompareOperator(strings.ToLower(children[1].Value))
compareValue interface{}
compareValue any
)
switch node := children[2]; node.Type {
case typ.False:
Expand Down Expand Up @@ -96,7 +96,7 @@ func (p config) parseAttrExp(node *ast.Node) (AttributeExpression, error) {
}, nil
}

func (p config) parseNumber(node *ast.Node) (interface{}, error) {
func (p config) parseNumber(node *ast.Node) (any, error) {
var frac, exp bool
var nStr string
for _, node := range node.Children() {
Expand Down
2 changes: 1 addition & 1 deletion attrexp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func ExampleParseAttrExp_sw() {
func TestParseNumber(t *testing.T) {
for _, test := range []struct {
nStr string
expected interface{}
expected any
}{
{
nStr: "-5.1e-2",
Expand Down
51 changes: 51 additions & 0 deletions filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,54 @@ func TestParseFilter(t *testing.T) {
})
}
}

func TestParseFilter_precedence(t *testing.T) {
for _, tc := range []struct {
input string
want string
}{
{
input: "(a eq \"1\" or b eq \"2\") and c eq \"3\"",
want: "(a eq \"1\" or b eq \"2\") and c eq \"3\"",
},
{
input: "c eq \"3\" and (a eq \"1\" or b eq \"2\")",
want: "c eq \"3\" and (a eq \"1\" or b eq \"2\")",
},
{
input: "(a eq \"1\" or b eq \"2\") and (c eq \"3\" or d eq \"4\")",
want: "(a eq \"1\" or b eq \"2\") and (c eq \"3\" or d eq \"4\")",
},
{
input: "a eq \"1\" and (b eq \"2\" or c eq \"3\") and d eq \"4\"",
want: "a eq \"1\" and (b eq \"2\" or c eq \"3\") and d eq \"4\"",
},
{
input: "a eq \"1\" or b eq \"2\" and c eq \"3\"",
want: "a eq \"1\" or b eq \"2\" and c eq \"3\"",
},
{
input: "(a eq \"1\" and b eq \"2\") or c eq \"3\"",
want: "a eq \"1\" and b eq \"2\" or c eq \"3\"",
},
{
input: "(a eq \"1\")",
want: "a eq \"1\"",
},
{
input: "a eq \"1\" or (b eq \"2\" and c eq \"3\")",
want: "a eq \"1\" or b eq \"2\" and c eq \"3\"",
},
} {
t.Run(tc.input, func(t *testing.T) {
exp, err := ParseFilter([]byte(tc.input))
if err != nil {
t.Fatal(err)
}
got := fmt.Sprintf("%v", exp)
if got != tc.want {
t.Errorf("got %q, want %q", got, tc.want)
}
})
}
}
27 changes: 27 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 26 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
};

outputs = { self, nixpkgs }:
let
supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
in
{
devShells = forAllSystems (system:
let
pkgs = nixpkgs.legacyPackages.${system};
in
{
default = pkgs.mkShell {
packages = [
pkgs.go_1_26
pkgs.golangci-lint
];
};
}
);
};
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module github.com/scim2/filter-parser/v2

go 1.16
go 1.26

require github.com/di-wu/parser v0.2.2
73 changes: 0 additions & 73 deletions internal/spec/grammar.pegn

This file was deleted.

Loading