Flutter — handle Elasticsearch Queries with the Builder Pattern

courtesy: from Photo by Littlehampton Bricks from Pexels

Foreword…

If you ever work with Elasticsearch before, you know that a specific Query syntax (named QueryDSL) would be employed to instruct how Elasticsearch works for us. QueryDSL is a human readable format expressed in JSON, typically it is quite straightforward and easy to write out a query to handle search requests; however… if we are supposed to handle dynamic query conditions… then we would very soon fall into a mud of miserables where we need to take care of lots of String level modifications and make sure the query works.

The Challenge — hardcoded String Query

Based on the demo app, we send out a http GET request with a hardcoded String query to the target Elasticsearch cluster; the response returned is displayed on the TextField widget.

The if-then-else solution

Assume that our application now provided 2 dynamic options as follows:

  • filter data based on customer’s firstname
the new UI supporting week-of-day and firstname filtering
  • based on the variables’ values, we could create the corresponding query parts
  • finally assemble the query parts together and form the query for search.
  • cons: maintainability is the major downside of this solution, imagine maintaining some 10s of lines of code just to build a query

Introducing the Builder Pattern solution

Before we move on, let’s understand what is a builder pattern. According to wikipedia

  • a getter method for building the query part for a condition / field (e.g. buildSourcePartsOnly method)
  • _value — the field’s expected value for matching, compulsory
  • cons: some efforts on code design is required — intermediate level of programming skills. Creating more classes / code instead of bare if-then-else.

Why not the Factory Pattern???

Our final question would be why adopting the builder pattern and not the factory pattern. Again, we need to know what is the factory pattern, by wikipedia:

  • Another issue is what if… we would like to add back a missing criteria later on? Of course we could add back methods to handle such criteria updates — but then… it would kind of break the purpose in the 1st place, we are expecting a factory to build something that is already known or stable (usually all configurations are set during the factory method execution and the created instance provides only utility methods to handle operations instead of changing configurations)

closings

Great~ We have gone through a couple of things again :)

  • taming the Query in a pure String way — if-then-else approach, there is nothing wrong with if-then-else, just maintainability might be an issue when the codebase increases
  • builder pattern to the rescue, by breaking the query build logic into modules / components increase flexibility. Maintainability is less an issue at once plus logic changes are hidden from users / callers as long as the exposed methods remain intact
  • factory pattern?? A discussion on why factory pattern might not work in our situation. If we do have manageable and stable criteria for building the query, then it is possible to use a factory pattern too~

a java / golang / flutter developer, a big data scientist, a father :)