diff --git a/README.md b/README.md index 691d005..92cff93 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,15 @@ Any filter combination can be used here `filter.PAGINATION|filter.ORDER_BY` e.g. curl -X GET http://localhost:8080/users?page=1&limit=10&order_by=username&order_direction=asc&filter="name:John" ``` +## Supported filter operators +- : The equality operator `filter=username:John` matches only when the username is exactly `John` +- \> The greater than operator `filter=age>35` matches only when age is more than 35 +- \< The less than operator `filter=salary<80000` matches only when salary is less than 80,000 +- \>= The greater than or equals to operator `filter=items>=100` matches only when items is at least 100 +- \<= The less than or equals to operator `filter=score<=100000` matches when score is 100,000 or lower +- \!= The not equals to operator `state!=FAIL` matches when state has any value other than FAIL +- \~ The like operator `filter=lastName~illi` matches when lastName contains the substring `illi` + ## TODO list - [x] Write tests for the lib with CI integration - [x] Add support for case-insensitive search diff --git a/gin-gorm-filter.go b/gin-gorm-filter.go index 97a66cc..c9f1187 100644 --- a/gin-gorm-filter.go +++ b/gin-gorm-filter.go @@ -104,7 +104,7 @@ func filterField(field reflect.StructField, phrase string) clause.Expression { // re, err := regexp.Compile(fmt.Sprintf(`(?m)%v([:<>!=]{1,2})(\w{1,}).*`, paramName)) // for the current regex, the compound operators (such as >=) must come before the // single operators (such as <) or they will be incorrectly identified - re, err := regexp.Compile(fmt.Sprintf(`(?m)%v(:|!=|>=|<=|>|<)([^,]*).*`, paramName)) + re, err := regexp.Compile(fmt.Sprintf(`(?m)%v(:|!=|>=|<=|>|<|~)([^,]*).*`, paramName)) if err != nil { return nil } @@ -121,6 +121,8 @@ func filterField(field reflect.StructField, phrase string) clause.Expression { return clause.Gt{Column: columnName, Value: filterSubPhraseMatch[2]} case "<": return clause.Lt{Column: columnName, Value: filterSubPhraseMatch[2]} + case "~": + return clause.Like{Column: columnName, Value: filterSubPhraseMatch[2]} default: return clause.Eq{Column: columnName, Value: filterSubPhraseMatch[2]} } diff --git a/gin-gorm-filter_test.go b/gin-gorm-filter_test.go index afec7fc..1cefcc3 100644 --- a/gin-gorm-filter_test.go +++ b/gin-gorm-filter_test.go @@ -80,6 +80,23 @@ func (s *TestSuite) TestFiltersBasic() { s.NoError(err) } +// TestFiltersBasic is a test for basic filters functionality. +func (s *TestSuite) TestFiltersLike() { + var users []User + ctx := gin.Context{} + ctx.Request = &http.Request{ + URL: &url.URL{ + RawQuery: "filter=login~samp", + }, + } + + s.mock.ExpectQuery(`^SELECT \* FROM "users" WHERE "Username" LIKE \$1 ORDER BY "id" DESC LIMIT \$2$`). + WithArgs("samp", 10). + WillReturnRows(sqlmock.NewRows([]string{"id", "Username", "FullName", "Email", "Password"})) + err := s.db.Model(&User{}).Scopes(FilterByQuery(&ctx, ALL)).Find(&users).Error + s.NoError(err) +} + // Filtering for a field that is not filtered should not be performed func (s *TestSuite) TestFiltersNotFilterable() { var users []User