11package au.com.console.jpaspecificationdsl
22
33import org.springframework.data.jpa.domain.Specification
4- import org.springframework.data.jpa.domain.Specifications
54import javax.persistence.criteria.*
65import kotlin.reflect.KProperty1
76
@@ -11,25 +10,27 @@ fun <Z, T, R> From<Z, T>.join(prop: KProperty1<T, R?>): Join<T, R> = this.join<T
1110// Helper to enable get by Property
1211fun <R > Path <* >.get (prop : KProperty1 <* , R ?>): Path <R > = this .get<R >(prop.name)
1312
14- // Version of Specifications .where that makes the CriteriaBuilder implicit
15- fun <T > where (makePredicate : CriteriaBuilder .(Root <T >) -> Predicate ): Specifications <T > =
16- Specifications .where< T > { root, _, criteriaBuilder -> criteriaBuilder.makePredicate(root) }
13+ // Version of Specification .where that makes the CriteriaBuilder implicit
14+ fun <T > where (makePredicate : CriteriaBuilder .(Root <T >) -> Predicate ): Specification <T > =
15+ Specification { root, _, criteriaBuilder -> criteriaBuilder.makePredicate(root) }
1716
18- // helper function for defining Specifications that take a Path to a property and send it to a CriteriaBuilder
19- private fun <T , R > KProperty1 <T , R ?>.spec (makePredicate : CriteriaBuilder .(path: Path <R >) -> Predicate ): Specifications <T > =
20- this . let { property -> where { root -> makePredicate(root.get(property)) } }
17+ // helper function for defining Specification that take a Path to a property and send it to a CriteriaBuilder
18+ private fun <T , R > KProperty1 <T , R ?>.spec (makePredicate : CriteriaBuilder .(path: Path <R >) -> Predicate ): Specification <T > =
19+ let { property -> where { root -> makePredicate(root.get(property)) } }
2120
2221// Equality
23- fun <T , R > KProperty1 <T , R ?>.equal (x : R ): Specifications <T > = spec { equal(it, x) }
24- fun <T , R > KProperty1 <T , R ?>.notEqual (x : R ): Specifications <T > = spec { notEqual(it, x) }
22+ fun <T , R > KProperty1 <T , R ?>.equal (x : R ): Specification <T > = spec { equal(it, x) }
23+
24+ fun <T , R > KProperty1 <T , R ?>.notEqual (x : R ): Specification <T > = spec { notEqual(it, x) }
2525
2626// Ignores empty collection otherwise an empty 'in' predicate will be generated which will never match any results
27- fun <T , R : Any > KProperty1 <T , R ?>.`in` (values : Collection <R >): Specifications <T > = if (values.isNotEmpty()) spec { path ->
27+ fun <T , R : Any > KProperty1 <T , R ?>.`in` (values : Collection <R >): Specification <T > = if (values.isNotEmpty()) spec { path ->
2828 `in `(path).apply { values.forEach { this .value(it) } }
29- } else Specifications .where< T > (null )
29+ } else Specification .where(null )!!
3030
3131// Comparison
3232fun <T > KProperty1 <T , Number ?>.le (x : Number ) = spec { le(it, x) }
33+
3334fun <T > KProperty1 <T , Number ?>.lt (x : Number ) = spec { lt(it, x) }
3435fun <T > KProperty1 <T , Number ?>.ge (x : Number ) = spec { ge(it, x) }
3536fun <T > KProperty1 <T , Number ?>.gt (x : Number ) = spec { gt(it, x) }
@@ -41,49 +42,58 @@ fun <T, R : Comparable<R>> KProperty1<T, R?>.between(x: R, y: R) = spec { betwee
4142
4243// True/False
4344fun <T > KProperty1 <T , Boolean ?>.isTrue () = spec { isTrue(it) }
45+
4446fun <T > KProperty1 <T , Boolean ?>.isFalse () = spec { isFalse(it) }
4547
4648// Null / NotNull
4749fun <T , R > KProperty1 <T , R ?>.isNull () = spec { isNull(it) }
50+
4851fun <T , R > KProperty1 <T , R ?>.isNotNull () = spec { isNotNull(it) }
4952
5053// Collections
5154fun <T , R : Collection <* >> KProperty1 <T , R ?>.isEmpty () = spec { isEmpty(it) }
55+
5256fun <T , R : Collection <* >> KProperty1 <T , R ?>.isNotEmpty () = spec { isNotEmpty(it) }
5357fun <T , E , R : Collection <E >> KProperty1 <T , R ?>.isMember (elem : E ) = spec { isMember(elem, it) }
5458fun <T , E , R : Collection <E >> KProperty1 <T , R ?>.isNotMember (elem : E ) = spec { isNotMember(elem, it) }
5559
5660// Strings
57- fun <T > KProperty1 <T , String ?>.like (x : String ): Specifications <T > = spec { like(it, x) }
58- fun <T > KProperty1 <T , String ?>.like (x : String , escapeChar : Char ): Specifications <T > = spec { like(it, x, escapeChar) }
59- fun <T > KProperty1 <T , String ?>.notLike (x : String ): Specifications <T > = spec { notLike(it, x) }
60- fun <T > KProperty1 <T , String ?>.notLike (x : String , escapeChar : Char ): Specifications <T > = spec { notLike(it, x, escapeChar) }
61+ fun <T > KProperty1 <T , String ?>.like (x : String ): Specification <T > = spec { like(it, x) }
62+
63+ fun <T > KProperty1 <T , String ?>.like (x : String , escapeChar : Char ): Specification <T > = spec { like(it, x, escapeChar) }
64+ fun <T > KProperty1 <T , String ?>.notLike (x : String ): Specification <T > = spec { notLike(it, x) }
65+ fun <T > KProperty1 <T , String ?>.notLike (x : String , escapeChar : Char ): Specification <T > = spec { notLike(it, x, escapeChar) }
6166
6267// And
63- infix fun <T > Specifications<T>.and (other : Specification <T >): Specifications <T > = this .and (other)
64- inline fun <reified T > and (vararg specs : Specifications <T >? ): Specifications <T > {
68+ infix fun <T > Specification<T>.and (other : Specification <T >): Specification <T > = this .and (other)!!
69+
70+ inline fun <reified T > and (vararg specs : Specification <T >? ): Specification <T > {
6571 return and (specs.toList())
6672}
67- inline fun <reified T > and (specs : Iterable <Specifications <T >? >): Specifications <T > {
68- return combineSpecifications(specs, Specifications <T >::and )
73+
74+ inline fun <reified T > and (specs : Iterable <Specification <T >? >): Specification <T > {
75+ return combineSpecification(specs, Specification <T >::and )
6976}
7077
7178// Or
72- infix fun <T > Specifications<T>.or (other : Specification <T >) : Specifications <T > = this .or (other)
73- inline fun <reified T > or (vararg specs : Specifications <T >? ): Specifications <T > {
79+ infix fun <T > Specification<T>.or (other : Specification <T >): Specification <T > = this .or (other)!!
80+
81+ inline fun <reified T > or (vararg specs : Specification <T >? ): Specification <T > {
7482 return or (specs.toList())
7583}
76- inline fun <reified T > or (specs : Iterable <Specifications <T >? >): Specifications <T > {
77- return combineSpecifications(specs, Specifications <T >::or )
84+
85+ inline fun <reified T > or (specs : Iterable <Specification <T >? >): Specification <T > {
86+ return combineSpecification(specs, Specification <T >::or )
7887}
7988
8089// Not
81- operator fun <T > Specifications <T>.not (): Specifications <T > = Specifications .not (this )
90+ operator fun <T > Specification <T>.not (): Specification <T > = Specification .not (this )
8291
83- // Combines Specifications with an operation
84- inline fun <reified T > combineSpecifications (specs : Iterable <Specification <T >? >, operation : Specifications <T >.(Specification <T >) -> Specifications <T >): Specifications <T > {
92+ // Combines Specification with an operation
93+ inline fun <reified T > combineSpecification (specs : Iterable <Specification <T >? >,
94+ operation : Specification <T >.(Specification <T >) -> Specification <T >): Specification <T > {
8595 return specs.filterNotNull().fold(emptySpecification()) { existing, new -> existing.operation(new) }
8696}
8797
8898// Empty Specification
89- inline fun <reified T > emptySpecification (): Specifications <T > = Specifications .where< T > (null )
99+ inline fun <reified T > emptySpecification (): Specification <T > = Specification .where(null )!!
0 commit comments