You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Renamed ExampleSpecification to ExampleMatcher and introduced a matching() factory method, dropping the dedicated override mechanism for types for now. Updated documentation accordingly.
Used Lombok for constructor creation, field defaults, toString() as well as equals(…) and hashCode() implementations.
Tweaked imports in unit tests. Renamed methods to express expected behavior.
Original pull request: #153.
Copy file name to clipboardExpand all lines: src/main/asciidoc/query-by-example.adoc
+32-80
Original file line number
Diff line number
Diff line change
@@ -12,8 +12,8 @@ Query by Example (QBE) is a user-friendly querying technique with a simple inter
12
12
The Query by Example API consists of three parts:
13
13
14
14
* Probe: That is the actual example of a domain object with populated fields.
15
-
* `ExampleSpec`: The `ExampleSpec` carries details on how to match particular fields. It can be reused across multiple Examples. `ExampleSpec` comes in two flavors: <<query.by.example.examplespec,untyped>> and <<query.by.example.examplespec.typed,typed>>.
16
-
* `Example`: An Example consists of the probe and the ExampleSpec. It is used to create the query. An `Example` takes a probe (usually the domain object or a subtype of it) and the `ExampleSpec`.
15
+
* `ExampleMatcher`: The `ExampleMatcher` carries details on how to match particular fields. It can be reused across multiple Examples.
16
+
* `Example`: An `Example` consists of the probe and the `ExampleMatcher`. It is used to create the query.
17
17
18
18
Query by Example is suited for several use-cases but also comes with limitations:
19
19
@@ -48,14 +48,13 @@ public class Person {
48
48
----
49
49
====
50
50
51
-
This is a simple domain object. You can use it to create an `Example`. By default, fields having `null` values are ignored, and strings are matched using the store specific defaults. Examples can be built by either using the `of` factory method or by using <<query.by.example.examplespec,`ExampleSpec`>>. `Example` is immutable.
51
+
This is a simple domain object. You can use it to create an `Example`. By default, fields having `null` values are ignored, and strings are matched using the store specific defaults. Examples can be built by either using the `of` factory method or by using <<query.by.example.matcher,`ExampleMatcher`>>. `Example` is immutable.
52
52
53
53
.Simple Example
54
54
====
55
55
[source,java]
56
56
----
57
57
Person person = new Person(); <1>
58
-
59
58
person.setFirstname("Dave"); <2>
60
59
61
60
Example<Person> example = Example.of(person); <3>
@@ -65,19 +64,17 @@ Example<Person> example = Example.of(person); <3>
65
64
<3> Create the `Example`
66
65
====
67
66
68
-
NOTE: Property names of the sample object must correlate with the property names of the queried domain object.
69
-
70
-
Examples can be executed ideally with Repositories. To do so, let your repository extend from `QueryByExampleExecutor`, here's an excerpt from the `QueryByExampleExecutor` interface:
67
+
Examples are ideally be executed with repositories. To do so, let your repository interface extend `QueryByExampleExecutor<T>`. Here's an excerpt from the `QueryByExampleExecutor` interface:
@@ -86,50 +83,44 @@ public interface QueryByExampleExecutor<T> {
86
83
87
84
You can read more about <<query.by.example.execution, Query by Example Execution>> below.
88
85
89
-
[[query.by.example.examplespec]]
90
-
=== Example Spec
86
+
[[query.by.example.matcher]]
87
+
=== Example matchers
91
88
92
-
Examples are not limited to default settings. You can specify own defaults for string matching, null handling and property-specific settings using the `ExampleSpec`. `ExampleSpec` comes in two flavors: untyped and typed. By default `Example.of(Person.class)` uses an untyped `ExampleSpec`. Using untyped `ExampleSpec` will use the Repository entity information to determine the type to query and has no control over inheritance queries. Also, untyped `ExampleSpec` will use the probe type when using with a Template to determine the type to query. Read more about <<query.by.example.examplespec.typed,typed `ExampleSpec`>> below.
89
+
Examples are not limited to default settings. You can specify own defaults for string matching, null handling and property-specific settings using the `ExampleMatcher`. `ExampleMatcher` comes in two flavors: untyped and typed. By default `Example.of(Person.class)` uses an untyped `ExampleMatcher`. Using untyped `ExampleMatcher` will use the Repository entity information to determine the type to query and has no control over inheritance queries. Also, untyped `ExampleMatcher` will use the probe type when using with a Template to determine the type to query. Read more about <<query.by.example.matcher.typed,typed `ExampleMatcher`>> below.
Example<Person> example = Example.of(person, exampleSpec); <7>
103
+
Example<Person> example = Example.of(person, matcher); <7>
111
104
112
105
----
113
106
<1> Create a new instance of the domain object.
114
107
<2> Set properties.
115
-
<3> Create an untyped `ExampleSpec`. The `ExampleSpec` is usable at this stage.
116
-
<4> Construct a new `ExampleSpec` to ignore the property path `lastname`.
117
-
<5> Construct a new `ExampleSpec` to ignore the property path `lastname` and to include null values.
118
-
<6> Construct a new `ExampleSpec` to ignore the property path `lastname`, to include null values, and use perform suffix string matching.
119
-
<7> Create a new `Example` based on the domain object and the configured `ExampleSpec`.
108
+
<3> Create an `ExampleMatcher` which is usable at this stage even without further configuration.
109
+
<4> Construct a new `ExampleMatcher` to ignore the property path `lastname`.
110
+
<5> Construct a new `ExampleMatcher` to ignore the property path `lastname` and to include null values.
111
+
<6> Construct a new `ExampleMatcher` to ignore the property path `lastname`, to include null values, and use perform suffix string matching.
112
+
<7> Create a new `Example` based on the domain object and the configured `ExampleMatcher`.
120
113
====
121
114
122
-
`ExampleSpec` is immutable. Calls to `with…(…)` return a copy of `ExampleSpec` with the specific setting applied. Intermediate objects can be safely reused. An `ExampleSpec` can be used to create ad-hoc example specs or to be reused across the application as a specification for `Example`. You can use `ExampleSpec` as a template to configure a default behavior for your example spec. You also can derive from it a more specific `ExampleSpec` where you need to customize it.
123
-
124
115
You can specify behavior for individual properties (e.g. "firstname" and "lastname", "address.city" for nested properties). You can tune it with matching options and case sensitivity.
Queries created by `Example` use a merged view of the configuration. Default matching settings can be set at `ExampleSpec` level while individual settings can be applied to particular property paths. Settings that are set on `ExampleSpec` are inherited by property path settings unless they are defined explicitly. Settings on a property patch have higher precedence than default settings.
141
+
Queries created by `Example` use a merged view of the configuration. Default matching settings can be set at `ExampleMatcher` level while individual settings can be applied to particular property paths. Settings that are set on `ExampleMatcher` are inherited by property path settings unless they are defined explicitly. Settings on a property patch have higher precedence than default settings.
151
142
152
143
[cols="1,2", options="header"]
153
-
.Scope of `ExampleSpec` settings
144
+
.Scope of `ExampleMatcher` settings
154
145
|===
155
146
| Setting
156
147
| Scope
157
148
158
149
| Null-handling
159
-
| `ExampleSpec`
150
+
| `ExampleMatcher`
160
151
161
152
| String matching
162
-
| `ExampleSpec` and property path
153
+
| `ExampleMatcher` and property path
163
154
164
155
| Ignoring properties
165
156
| Property path
166
157
167
158
| Case sensitivity
168
-
| `ExampleSpec` and property path
159
+
| `ExampleMatcher` and property path
169
160
170
161
| Value transformation
171
162
| Property path
172
163
173
164
|===
174
165
175
-
[[query.by.example.examplespec.typed]]
176
-
==== Typed Example Spec
177
-
You have now seen the usage of untyped `ExampleSpec`. The second flavor of `ExampleSpec` is typed which adds more control over the result type. When executing an `Example` containing a typed `ExampleSpec` the type of the `ExampleSpec` is used as domain type. Control over the domain type is useful in particular when querying along the inheritance hierarchy or the repository contains multiple types within one table/collection/keyspace.
0 commit comments