Currently, predicates/sorts/etc. can be re-used by calling {{.toPredicate()}}/{{toSort()}}/etc. on the terminal context in the DSL. The user gets a {{SearchPredicate}}/{{SearchSort}}/etc. instance that can be reused in multiple queries, even in different threads.
But, there are rough edges .
First, regarding the API, the name {{.toPredicate()}}/{{toSort()}}/etc. do not make it clear that you only need to call these methods if you need re-usable objects. In any other case, just passing the terminal DSL context to other methods of the DSL should work fine. On the other hand, if you're using the non-lambda syntax, you probably want to call these methods, even if you don't reuse the objects : the object need to be stored in variables, and having to write down the type of the DSL contexts in your code will be painful.
Second, regarding the implementation:
# {{SearchPredicate}}/{{SearchSort}}/etc. are not *actually* immutable. They internally store the builders that were used by the DSL, so if you keep a reference to the DSL contexts around, you should be able to change the builders, and thus the {{SearchPredicate}}/{{SearchSort}}/etc. Maybe we should somehow "freeze" the builders when we build the {{SearchPredicate}}/{{SearchSort}}/etc., so that trying to call a method on the DSL after that will trigger an exception? # When reusing a {{SearchPredicate}}/{{SearchSort}}/etc., we do not check that the search target is compatible with the one the objects were originally created for, beyond the usual technology check (Lucene/Elasticsearch). For example if you create a {{SearchPredicate}} while targeting the index {{book}}, then you re-use it while targeting the index {{user}}, something will eventually go wrong, but we won't detect it. Maybe we should? Ideally, when a {{SearchPredicate}}/{{SearchSort}}/etc. was created with a target A, and is reused in a target B, we should make sure that B is a subset of A. If we do that, worst case, the fields referenced in the predicate/sort/etc. do not exist, but if they do we are sure they are compatible. # The DSL contexts can also be reused. They shouldn't be, because they reference objects that are no longer useful once the predicate/sort/etc. is built and should be garbage-collected, but everything will work if you just store the DSL contexts somewhere and re-use them. Maybe we should prevent that somehow? |
|