Custom Search Queries with SpringBot

This article will walkthrough how to add custom queries via your serverside project.


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 Zoo 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, whereas the first array represents AND and each nested array represents OR.

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/com/springbot/zoo/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 Zoo project.

Create Custom Search Queries

Each animal has a keeper. Let’s add a custom query to search the animals by the keeper’s firstname and lastname.

Create Custom Query Keyword

  1. Open AnimalService under serverside/src/main/java/zoo/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 "keeperName":
        
     // Use Not equal when where has not equal operation 
     if (condition.getOperation().equals(QueryOperation.notEqual)) {
         predicate = entity.keeper.lastName.containsIgnoreCase(condition.getValue()).not()
                 .and(entity.keeper.firstName.containsIgnoreCase(condition.getValue()).not());
        
     // Otherwise search with contain
     } else {
         predicate = entity.keeper.lastName.containsIgnoreCase(condition.getValue())
                 .or(entity.keeper.firstName.containsIgnoreCase(condition.getValue()));
     }
        
     break;
    

Here we are using QueryDSL to generate conditions for finding animals whose keeper's firstname or lastname contains a certain word and finding animals whose keeper's firstname and lastname both do 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 animal.model.ts located at clientside/src/app/models/animal.
  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:

    'keeperName'
    

Your file should now look like:

static searchFields: string[] = [
    // % protected region % [Add any additional searchable field names here] on begin
    'keeperName'
    // % 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/animal-crud
  2. After logging in, you can now see the page for the animal.
  3. Create multiple animals, and set the keeper of one of them.
    Now, use the search box.
    Image

If you search keeper, the client-side will fetch all animals whose keeper’s lastname or first name contains keeper.

4. Testing with GraphQL Requests

Testing the graphql in Altair

You also test the new searching function with a GraphQL request. The easiest way to do that in SpringBot is by elevating Altair.

  1. Login into http://localhost:4200 to get the Authorization header from the request.
  2. Add the following content to the Query section:

    query GetWithQuery($pageIndex: Int, $pageSize: Int, $orderBy: [OrderBy!], $where: [[Where!]!]) {
    animals: animals(pageIndex: $pageIndex, pageSize: $pageSize, orderBy: $orderBy, where: $where) {
     ...AnimalProperties
     enclosure {
       id
       name
       __typename
     }
     keeper {
       id
       email
       __typename
     }
     __typename
    }
    totalCount: countAnimals(where: $where),
    }
    fragment AnimalProperties on Animal {
    ...AnimalBaseProperties
    name
    feedingTime
    diet
    lastVetCheck
    vetCheckStatus
    __typename
    }
    fragment AnimalBaseProperties on Animal {
    id
    created
    modified
    __typename
    }
    
  3. Add the following content to the Variables section:

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

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

  1. Run the request and you will receive a response with filtered animals from the server side.

Image

Solution

Video

Next Steps

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

Last updated: 09 July 2020


Start modelling your app today.