Developer Docs

Custom Search Queries with SpringBot

This article will walkthrough how to add custom queries via your serverside project. This enables the client-side to automatically use the custom query parameters as part of the search keywords within the CRUD tile. For this project, we will be using the Codebots LMS Project. You can follow along with the project by downloading the latest version from the public git page.

Introduction of Query Parameters in SpringBot

SpringBot has built-in query parameters to support dynamic queries, which is useful when queries are modified often and used in different contexts. When using SpringBot, query parameters are formatted in a 2D-array, where the items in each array represent OR, and the arrays together represent AND.

For example:

[
    [a, b, c],
    [d, e]
]

would be parsed as (a OR b OR c) AND (d OR e).

This query construction allows for complex queries without any extra work required.

By default, this feature can be turned on via the Searchable property of your attributes in the Entity Diagram.

While the default functionality is powerful, there may be occasions where you want to add query logic and keywords specific to your application domain.

In SpringBot, the dynamic queries are implemented with QueryDSL.

At its core, whenever a query parameter is sent to the server, every nested condition will be transformed into an instance of the Where class. This can be located at serverside/src/main/java/lmsspring/graphql/utils/Where.java. This class is the data structure used to pass this information around the applicaiton for later usage.

Now let’s add a new custom query inside our Codebots LMS project.

Create Custom Search Queries

Each course has a corresponding course category. Lets add a custom query to search the courses by the course category names.

Create Custom Query Keyword

  1. Open CourseService under serverside/src/main/java/lmsspring/services.
  2. Locate the fuction protected Predicate processCondition(Where condition). This function changes the searching parameters into Predicate in QueryDSL to Where conditions. The 2D array will then be parsed to a Predicate, which is used by the QueryDSLExecutor at the Repository layer.
  3. Find the protected region Add any additional cases for the custom query parameters here and turn it on by replacing off begin to on begin. Insert the following code:

     case "name":
    
         // Use Not equal when where has not equal operation 
         if (condition.getOperation().equals(QueryOperation.notEqual)) {
             predicate = entity.courseCategory.name.containsIgnoreCase(condition.getValue()).not();
    
         // Otherwise search with contain
         } else {
             predicate = 
             entity.courseCategory.name.containsIgnoreCase(condition.getValue());
             }
    
         break;
    

Here we are using QueryDSL to generate conditions for courses whose coures category's name contains a certain word and courses whose coures category's name does not contain a certain word. The code creates the predicates based on the keyword, operation, and value.

Add new search keyword to the client

Now we need to add the new keyword in the client-side.

  1. Open course.model.ts located at clientside/src/app/models/course.
  2. Locate the protected region Add any additional searchable field names here and turn it on by replacing off begin with on begin. Insert the following code:

     'courseCategory'
    
  3. Your file should now look like:

     static searchFields: string[] = [
         // % protected region % [Add any additional searchable field names here] on begin
         'courseCategory'
         // % protected region % [Add any additional searchable field names here] end
     ];
    

Validate the Result

  1. Restart the client-side and server-side, and go to the URL http://localhost:4200/course-crud
  2. After logging in, you can now see the page for the course.
  3. Create multiple courses, and set the category of one of them.
    Now, use the search box.

If you search category, the client-side will fetch all courses with a course category name containing category.

Testing with GraphQL Requests

Testing with graphiQL

You also test the new searching function with a GraphQL request.

  1. Navigate to http://localhost:8080/graphiql
  2. Paste the following content to the Query section:

     query GetWithQuery($pageIndex: Int, $pageSize: Int, $orderBy: [OrderBy!], $where: [[Where!]!]) {
       courses: courses(pageIndex: $pageIndex, pageSize: $pageSize, orderBy: $orderBy, where: $where) {
         ...CourseProperties
         courseCatgory {
           name
           colour
           summary
           __typename
         }
         __typename
       }
       totalCount: countCourses(where: $where),
     }
     fragment CourseProperties on Course {
       ...CourseBaseProperties
       name
       summary
       coverImage
       difficulty
       __typename
     }
     fragment CourseBaseProperties on Course {
       id
       created
       modified
       __typename
     }
    
  3. Add the following content to the Variables section:

     {
     "pageIndex":0,
     "pageSize":10,
     "orderBy":[
        {
           "path":"created",
           "descending":true
        }
     ],
     "where":[
        [
           {
              "path":"courseCategoryName",
              "operation":"contains",
              "value":"category"
           }
        ]
     ]
     }
    

    If you change the operation from contains to notEqual you will get the opposite results. "operation":"notEqual"

  4. Run the request and you will receive a response with filtered courses from the server side.

Solution

Have a look at the custom-search-query branch to see the code solution.

Next Steps

See Custom Search Predicates with SpringBot and QueryDSL for more detail on creating custom search predicates.

On this page