Skip to content

Commit

Permalink
feat(filter): Implement wild card searching for issue #95
Browse files Browse the repository at this point in the history
- Add search filter for wildcard-like searching
- Add compose makefile targets

Signed-off-by: Michal Krzyz <[email protected]>
  • Loading branch information
michalkrzyz committed Aug 8, 2024
1 parent 20b2ccd commit 01b61cd
Show file tree
Hide file tree
Showing 27 changed files with 238 additions and 69 deletions.
28 changes: 22 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ VERSION ?= $(shell git log -1 --pretty=format:"%H")
OS := $(shell go env GOOS)
ARCH := $(shell go env GOARCH)

.PHONY: all test doc gqlgen test-all test-e2e test-app test-db
.PHONY: all test doc gqlgen test-all test-e2e test-app test-db fmt compose-prepare compose-up compose-down compose-restart compose-build

# Source the .env file to use the env vars with make
-include .env
Expand Down Expand Up @@ -55,16 +55,32 @@ mockery:
mockery

test-all:
ginkgo -r
go run github.com/onsi/ginkgo/v2/ginkgo -r

test-e2e:
ginkgo internal/e2e
go run github.com/onsi/ginkgo/v2/ginkgo -r internal/e2e

test-app:
ginkgo internal/app
go run github.com/onsi/ginkgo/v2/ginkgo -r internal/app

test-db:
ginkgo internal/database/mariadb
go run github.com/onsi/ginkgo/v2/ginkgo -r internal/database/mariadb

fmt:
go fmt ./...
go fmt ./...

DOCKER_COMPOSE := docker-compose -f docker-compose.yaml
DOCKER_COMPOSE_SERVICES := heureka-app heureka-db
compose-prepare:
sed 's/^SEED_MODE=false/SEED_MODE=true/g' .test.env > .env

compose-up:
$(DOCKER_COMPOSE) up -d $(DOCKER_COMPOSE_SERVICES)

compose-down:
$(DOCKER_COMPOSE) down $(DOCKER_COMPOSE_SERVICES)

compose-restart: compose-down compose-up

compose-build:
$(DOCKER_COMPOSE) build $(DOCKER_COMPOSE_SERVICES)
1 change: 1 addition & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ services:

heureka-app:
build: .
container_name: heureka-app
profiles:
- heureka
environment:
Expand Down
2 changes: 2 additions & 0 deletions internal/api/graphql/graph/baseResolver/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ func IssueBaseResolver(app app.Heureka, ctx context.Context, filter *model.Issue
PrimaryName: filter.PrimaryName,
Type: lo.Map(filter.IssueType, func(item *model.IssueTypes, _ int) *string { return pointer.String(item.String()) }),

Search: filter.Search,

IssueMatchStatus: nil, //@todo Implement
IssueMatchDiscoveryDate: nil, //@todo Implement
IssueMatchTargetRemediationDate: nil, //@todo Implement
Expand Down
12 changes: 8 additions & 4 deletions internal/api/graphql/graph/generated.go

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

4 changes: 1 addition & 3 deletions internal/api/graphql/graph/model/models_gen.go

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

3 changes: 0 additions & 3 deletions internal/api/graphql/graph/resolver/activity.go

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

3 changes: 0 additions & 3 deletions internal/api/graphql/graph/resolver/component.go

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

3 changes: 0 additions & 3 deletions internal/api/graphql/graph/resolver/component_instance.go

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

3 changes: 0 additions & 3 deletions internal/api/graphql/graph/resolver/component_version.go

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

3 changes: 0 additions & 3 deletions internal/api/graphql/graph/resolver/evidence.go

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

3 changes: 0 additions & 3 deletions internal/api/graphql/graph/resolver/issue.go

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

3 changes: 0 additions & 3 deletions internal/api/graphql/graph/resolver/issue_match.go

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

3 changes: 0 additions & 3 deletions internal/api/graphql/graph/resolver/issue_match_change.go

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

3 changes: 0 additions & 3 deletions internal/api/graphql/graph/resolver/issue_repository.go

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

3 changes: 0 additions & 3 deletions internal/api/graphql/graph/resolver/issue_variant.go

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

3 changes: 0 additions & 3 deletions internal/api/graphql/graph/resolver/mutation.go

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

3 changes: 0 additions & 3 deletions internal/api/graphql/graph/resolver/query.go

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

3 changes: 0 additions & 3 deletions internal/api/graphql/graph/resolver/service.go

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

3 changes: 0 additions & 3 deletions internal/api/graphql/graph/resolver/support_group.go

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

3 changes: 0 additions & 3 deletions internal/api/graphql/graph/resolver/user.go

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

4 changes: 3 additions & 1 deletion internal/api/graphql/graph/schema/issue.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ input IssueFilter {

componentVersionId: [String],

search: [String],

# leave away for MVP
# cveDescription: [String]
# fromAdvisory: ID,
Expand All @@ -69,4 +71,4 @@ enum IssueTypes {
Vulnerability,
PolicyViolation,
SecurityEvent
}
}
8 changes: 7 additions & 1 deletion internal/database/mariadb/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,14 @@ func buildFilterQuery[T any](filter []T, expr string, op string) string {
}

func buildQueryParameters[T any](params []interface{}, filter []T) []interface{} {
return buildQueryParametersCount(params, filter, 1)
}

func buildQueryParametersCount[T any](params []interface{}, filter []T, count int) []interface{} {
for _, item := range filter {
params = append(params, item)
for i := 0; i < count; i++ {
params = append(params, item)
}
}
return params
}
Expand Down
9 changes: 8 additions & 1 deletion internal/database/mariadb/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ import (
"github.wdf.sap.corp/cc/heureka/internal/entity"
)

const (
wildCardFilterQuery = "IV.issuevariant_secondary_name LIKE Concat('%',?,'%') OR I.issue_primary_name LIKE Concat('%',?,'%')"
wildCardFilterParamCount = 2
)

func (s *SqlDatabase) getIssueFilterString(filter *entity.IssueFilter) string {
var fl []string
fl = append(fl, buildFilterQuery(filter.ServiceName, "S.service_name = ?", OP_OR))
Expand All @@ -23,6 +28,7 @@ func (s *SqlDatabase) getIssueFilterString(filter *entity.IssueFilter) string {
fl = append(fl, buildFilterQuery(filter.IssueVariantId, "IV.issuevariant_id = ?", OP_OR))
fl = append(fl, buildFilterQuery(filter.Type, "I.issue_type = ?", OP_OR))
fl = append(fl, buildFilterQuery(filter.PrimaryName, "I.issue_primary_name = ?", OP_OR))
fl = append(fl, buildFilterQuery(filter.Search, wildCardFilterQuery, OP_OR))
fl = append(fl, "I.issue_deleted_at IS NULL")

return combineFilterQueries(fl, OP_AND)
Expand Down Expand Up @@ -55,7 +61,7 @@ func (s *SqlDatabase) getIssueJoins(filter *entity.IssueFilter, withAggregations
`)
}

if len(filter.IssueVariantId) > 0 {
if len(filter.IssueVariantId) > 0 || len(filter.Search) > 0 {
joins = fmt.Sprintf("%s\n%s", joins, `
LEFT JOIN IssueVariant IV ON I.issue_id = IV.issuevariant_issue_id
`)
Expand Down Expand Up @@ -164,6 +170,7 @@ func (s *SqlDatabase) buildIssueStatement(baseQuery string, filter *entity.Issue
filterParameters = buildQueryParameters(filterParameters, filter.IssueVariantId)
filterParameters = buildQueryParameters(filterParameters, filter.Type)
filterParameters = buildQueryParameters(filterParameters, filter.PrimaryName)
filterParameters = buildQueryParametersCount(filterParameters, filter.Search, wildCardFilterParamCount)
if withCursor {
filterParameters = append(filterParameters, cursor.Value)
filterParameters = append(filterParameters, cursor.Limit)
Expand Down
65 changes: 65 additions & 0 deletions internal/database/mariadb/issue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,71 @@ var _ = Describe("Issue", Label("database", "Issue"), func() {
Expect(entry.Type).To(BeEquivalentTo(issueType))
}
})
It("can filter issue PrimaryName using wild card search", func() {
row := seedCollection.IssueRows[rand.Intn(len(seedCollection.IssueRows))]

const charactersToRemoveFromBeginning = 2
const charactersToRemoveFromEnd = 2
const minimalCharactersToKeep = 5

start := charactersToRemoveFromBeginning
end := len(row.PrimaryName.String) - charactersToRemoveFromEnd

Expect(start+minimalCharactersToKeep < end).To(BeTrue())

searchStr := row.PrimaryName.String[start:end]
filter := &entity.IssueFilter{Search: []*string{&searchStr}}

entries, err := db.GetIssues(filter)

issueIds := []int64{}
for _, entry := range entries {
issueIds = append(issueIds, entry.Id)
}

By("throwing no error", func() {
Expect(err).To(BeNil())
})

By("at least single value was discarded (filtered)", func() {
Expect(len(seedCollection.IssueRows) > len(issueIds)).To(BeTrue())
})

By("returning the expected elements", func() {
Expect(issueIds).To(ContainElement(row.Id.Int64))
})
})
It("can filter issue variant SecondaryName using wild card search", func() {
// select an issueVariant
issueVariantRow := seedCollection.IssueVariantRows[rand.Intn(len(seedCollection.IssueVariantRows))]

const charactersToRemoveFromBeginning = 2
const charactersToRemoveFromEnd = 2
const minimalCharactersToKeep = 5

start := charactersToRemoveFromBeginning
end := len(issueVariantRow.SecondaryName.String) - charactersToRemoveFromEnd

Expect(start+minimalCharactersToKeep < end).To(BeTrue())

searchStr := issueVariantRow.SecondaryName.String[start:end]
filter := &entity.IssueFilter{Search: []*string{&searchStr}}

entries, err := db.GetIssues(filter)

issueIds := []int64{}
for _, entry := range entries {
issueIds = append(issueIds, entry.Id)
}

By("throwing no error", func() {
Expect(err).To(BeNil())
})

By("returning the expected elements", func() {
Expect(issueIds).To(ContainElement(issueVariantRow.IssueId.Int64))
})
})
})
Context("and using pagination", func() {
DescribeTable("can correctly paginate", func(pageSize int) {
Expand Down
1 change: 1 addition & 0 deletions internal/entity/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ type IssueFilter struct {
IssueMatchId []*int64 `json:"issue_match_id"`
ComponentVersionId []*int64 `json:"component_version_id"`
IssueVariantId []*int64 `json:"issue_variant_id"`
Search []*string `json:"search"`
IssueMatchStatus []*string `json:"issue_match_status"`
IssueMatchDiscoveryDate *TimeFilter `json:"issue_match_discovery_date"`
IssueMatchTargetRemediationDate *TimeFilter `json:"issue_match_target_remediation_date"`
Expand Down
5 changes: 1 addition & 4 deletions internal/mocks/mock_Database.go

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

Loading

0 comments on commit 01b61cd

Please sign in to comment.