Giter Club home page Giter Club logo

spring-filter's Introduction

Spring Filter

Spring Filter Logo

You need a way to dynamically filter entities without any effort? Just add me to your pom.xml. Your API will gain a full featured search functionality. You don't work with APIs? No problem, you may still not want to mess with SQL, JPA predicates, security, and all of that I guess.

Example (try it live)

/search?filter= average(ratings) > 4.5 and brand.name in ('audi', 'land rover') and (year > 2018 or km < 50000) and color : 'white' and accidents is empty

/* Entity used in the query above */
@Entity public class Car {
  @Id long id;
      int year;
      int km;
  @Enumerated Color color;
  @ManyToOne Brand brand;
  @OneToMany List<Accident> accidents;
  @ElementCollection List<Integer> ratings;
  // ...
}

๐Ÿš€ Yes we support booleans, dates, enums, functions, and even relations! Need something else? Tell us here.

Installation

<dependency>
    <groupId>com.turkraft</groupId>
    <artifactId>spring-filter</artifactId>
    <version>2.0.2</version>
</dependency>

Usages

a. Controller

Requires javax.persistence-api, spring-data-jpa, spring-web and spring-webmvc

@GetMapping(value = "/search")
public Page<Entity> search(@Filter Specification<Entity> spec, Pageable page) {
  return repo.findAll(spec, page);
}

The repository should implement JpaSpecificationExecutor in order to execute Spring's Specification, SimpleJpaRepository is a well known implementation. You can remove the Pageable argument and return a List if pagination is not needed.

b. Specification

Requires javax.persistence-api, spring-data-jpa, spring-web

Specification<Entity> spec = new FilterSpecification<Entity>(query);

c. Predicate

Requires javax.persistence-api

Predicate predicate = ExpressionGenerator.run(String query, Root<?> r, CriteriaQuery<?> q, CriteriaBuilder cb);

โš ๏ธ If you need to search over relations, you also require hibernate-core

d. Builder

/* Using static methods */
import static com.turkraft.springfilter.FilterBuilder.*;
Filter filter = like("name", "%jose%");
String query = filter.generate(); // name ~ '%jose%'
// filter = Filter.from(query);
// Predicate predicate = ExpressionGenerator.run(filter, Root<?> r, CriteriaQuery<?> cq, CriteriaBuilder cb);
// Specification<Entity> spec = new FilterSpecification<Entity>(filter);

Syntax

Fields

Field names should be directly given without any extra literals. Dots indicate nested fields. For example: category.updatedAt

Inputs

Numbers should be directly given. Booleans should also directly be given, valid values are true and false (case insensitive). Others such as strings, enums, dates, should be quoted. For example: status : 'active'

Operators

Literal (case insensitive) Description Example
and and's two expressions status : 'active' and createdAt > '1-1-2000'
or or's two expressions value ~ '%hello%' or name ~ '%world%'
not not's an expression not (id > 100 or category.order is null)

You may prioritize operators using parentheses, for example: x and (y or z)

Comparators

Literal (case insensitive) Description Example
~ checks if the left (string) expression is similar to the right (string) expression catalog.name ~ 'electronic%'
: checks if the left expression is equal to the right expression id : 5
! checks if the left expression is not equal to the right expression username ! 'torshid'
> checks if the left expression is greater than the right expression distance > 100
>: checks if the left expression is greater or equal to the right expression distance >: 100
< checks if the left expression is smaller than the right expression distance < 100
<: checks if the left expression is smaller or equal to the right expression distance <: 100
is null checks if an expression is null status is null
is not null checks if an expression is not null status is not null
is empty checks if the (collection) expression is empty children is empty
is not empty checks if the (collection) expression is not empty children is not empty
in checks if an expression is present in the right expressions status in ('initialized', 'active')

Note that the * character can also be used instead of % when using the ~ comparator. By default, this comparator is case insensitive, the behavior can be changed with FilterParameters.CASE_SENSITIVE_LIKE_OPERATOR.

Functions

A function is characterized by its name (case insensitive) followed by parentheses. For example: currentTime(). Some functions might also take arguments, arguments are seperated with commas. For example: min(ratings) > 3

Name Description Example
absolute returns the absolute absolute(x)
average returns the average average(ratings)
min returns the minimum min(ratings)
max returns the maximum max(ratings)
sum returns the sum sum(scores)
currentDate returns the current date currentDate()
currentTime returns the current time currentTime()
currentTimestamp returns the current time stamp currentTimestamp()
size returns the collection's size size(accidents)
length returns the string's length length(name)
trim returns the trimmed string trim(name)
upper returns the uppercased string upper(name)
lower returns the lowercased string lower(name)
concat returns the concatenation of given strings concat(firstName, ' ', lastName)

Subqueries

Name Description Example Explanation
exists returns the existence of a subquery result exists(employees.age > 60) returns true if at least one employee's age is greater than 60

Configuration

Date format

You are able to change the date format by setting the static formatters inside the FilterParameters class. You may see below the default patterns and how you can set them with properties:

Type Default Pattern Property Name
java.util.Date dd-MM-yyyy turkraft.springfilter.dateformatter.pattern
java.time.LocalDate dd-MM-yyyy turkraft.springfilter.localdateformatter.pattern
java.time.LocalDateTime dd-MM-yyyy'T'HH:mm:ss turkraft.springfilter.localdatetimeformatter.pattern
java.time.OffsetDateTime dd-MM-yyyy'T'HH:mm:ss.SSSXXX turkraft.springfilter.offsetdatetimeformatter.pattern
java.time.Instant dd-MM-yyyy'T'HH:mm:ss.SSSXXX Parses using DateTimeFormatter.ISO_INSTANT

MongoDB

MongoDB is also partially supported as an alternative to JPA. The query input is compiled to a Bson/Document filter. You can then use it as you wish with MongoTemplate or MongoOperations for example.

Requires spring-data-mongodb

Usage

@GetMapping(value = "/search")
public Page<Entity> search(@Filter(entityClass = Entity.class) Document doc, Pageable page) {
  // your repo may implement DocumentExecutor for easy usage
  return repo.findAll(doc, page); 
}
Bson bson = BsonGenerator.run(Filter.from(query), Entity.class);
Document doc = BsonUtils.getDocumentFromBson(bson);
Query query = BsonUtils.getQueryFromDocument(doc);
// ...

โš ๏ธ Functions are currently not supported with MongoDB, and the ~ operator actually uses the regex operator

Customization

If you need to customize the behavior of the filter, the way to go is to extend the FilterBaseVisitor class, by taking QueryGenerator or ExpressionGenerator as examples. In order to also modify the query syntax, you should start by cloning the repository and editing the Filter.g4 file.

Articles

Contributing

Ideas and pull requests are always welcome. Google's Java Style is used for formatting.

Contributors

Thanks to @marcopag90 and @glodepa for adding support to MongoDB.

License

Distributed under the MIT license.

spring-filter's People

Contributors

torshid avatar dependabot[bot] avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.