Skip to content

add variance #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -60,29 +60,34 @@ fun <T> KProperty1<T, String?>.notLike(x: String): Specifications<T> = spec { no
fun <T> KProperty1<T, String?>.notLike(x: String, escapeChar: Char): Specifications<T> = spec { notLike(it, x, escapeChar) }

// And
infix fun <T> Specifications<T>.and(other: Specification<T>) = this.and(other)
inline fun <reified T> and(vararg specs: Specifications<T>?): Specifications<T> {
@Suppress("UNCHECKED_CAST")
infix fun <T> Specifications<T>.and(other: Specification<in T>) = this.and(other as Specification<T>)
inline fun <reified T> and(vararg specs: Specifications<in T>?): Specifications<T> {
return and(specs.toList())
}
inline fun <reified T> and(specs: Iterable<Specifications<T>?>): Specifications<T> {
inline fun <reified T> and(specs: Iterable<Specifications<in T>?>): Specifications<T> {
return combineSpecifications(specs, Specifications<T>::and)
}

// Or
infix fun <T> Specifications<T>.or(other: Specification<T>) = this.or(other)
inline fun <reified T> or(vararg specs: Specifications<T>?): Specifications<T> {
@Suppress("UNCHECKED_CAST")
infix fun <T> Specifications<T>.or(other: Specification<in T>) = this.or(other as Specification<T>)
inline fun <reified T> or(vararg specs: Specifications<in T>?): Specifications<T> {
return or(specs.toList())
}
inline fun <reified T> or(specs: Iterable<Specifications<T>?>): Specifications<T> {
inline fun <reified T> or(specs: Iterable<Specifications<in T>?>): Specifications<T> {
return combineSpecifications(specs, Specifications<T>::or)
}

// Not
operator fun <T> Specifications<T>.not() = Specifications.not(this)

// Combines Specifications with an operation
inline fun <reified T> combineSpecifications(specs: Iterable<Specification<T>?>, operation: Specifications<T>.(Specification<T>) -> Specifications<T>): Specifications<T> {
return specs.filterNotNull().fold(emptySpecification<T>()) { existing, new -> existing.operation(new) }
inline fun <reified T> combineSpecifications(specs: Iterable<Specification<in T>?>, operation: Specifications<T>.(Specification<T>) -> Specifications<T>): Specifications<T> {
return specs.filterNotNull().fold(emptySpecification()) { existing, new ->
@Suppress("UNCHECKED_CAST")
existing.operation(new as Specification<T>)
}
}

// Empty Specification
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,21 @@ import javax.persistence.OneToMany
@Repository
interface TvShowRepository : CrudRepository<TvShow, Int>, JpaSpecificationExecutor<TvShow>

interface HasName {
val name: String
}

@Entity
data class TvShow(
data class TvShow (
@Id
@GeneratedValue
val id: Int = 0,
val name: String = "",
override val name: String = "",
val synopsis: String = "",
val availableOnNetflix: Boolean = false,
val releaseDate: String? = null,
@OneToMany(cascade = kotlin.arrayOf(javax.persistence.CascadeType.ALL))
val starRatings: Set<StarRating> = emptySet())
val starRatings: Set<StarRating> = emptySet()): HasName

@Entity
data class StarRating(
Expand All @@ -36,8 +40,8 @@ data class StarRating(
// Note: these functions return null for a null input. This means that when included in
// and() or or() they will be ignored as if they weren't supplied.

fun hasName(name: String?): Specifications<TvShow>? = name?.let {
TvShow::name.equal(it)
fun hasName(name: String?): Specifications<HasName>? = name?.let {
HasName::name.equal(it)
}

fun availableOnNetflix(available: Boolean?): Specifications<TvShow>? = available?.let {
Expand Down