dev.krud.crudframework.jpa.dao.JpaDaoImpl.kt Maven / Gradle / Ivy
package dev.krud.crudframework.jpa.dao
import dev.krud.crudframework.crud.handler.CrudDao
import dev.krud.crudframework.model.BaseCrudEntity
import dev.krud.crudframework.modelfilter.DynamicModelFilter
import dev.krud.crudframework.modelfilter.FilterField
import dev.krud.crudframework.modelfilter.enums.FilterFieldOperation
import java.io.Serializable
import jakarta.persistence.EntityManager
import jakarta.persistence.PersistenceContext
import jakarta.persistence.TypedQuery
import jakarta.persistence.criteria.CriteriaBuilder
import jakarta.persistence.criteria.CriteriaQuery
import jakarta.persistence.criteria.Expression
import jakarta.persistence.criteria.From
import jakarta.persistence.criteria.Order
import jakarta.persistence.criteria.Path
import jakarta.persistence.criteria.Predicate
import jakarta.persistence.criteria.Root
class JpaDaoImpl : CrudDao {
@PersistenceContext
private lateinit var entityManager: EntityManager
override fun , E : DynamicModelFilter> index(
filter: E,
clazz: Class
): MutableList {
val cb = entityManager.criteriaBuilder
val cq = cb.buildQueryFromFilter(filter, clazz)
val query = entityManager.createQuery(cq)
setLimits(filter, query)
return query.resultList as MutableList
}
override fun , E : DynamicModelFilter> indexCount(
filter: E,
clazz: Class
): Long {
val cb = entityManager.criteriaBuilder
val cq = cb.buildQueryFromFilter(filter, clazz) as CriteriaQuery>
cq.select(
cb.count(
cq.roots.first().get("id")
)
)
return entityManager.createQuery(cq).singleResult as Long
}
override fun > hardDeleteById(id: ID, clazz: Class?) {
val entity = entityManager.find(clazz, id)
entityManager.remove(entity)
}
override fun > saveOrUpdate(entity: Entity): Entity {
val merged = entityManager.merge(entity)
entityManager.flush()
entityManager.refresh(merged)
return merged
}
override fun ?> saveOrUpdate(entities: MutableList): MutableList {
val mergedEntities = entities.map { entityManager.merge(it) }.toMutableList()
entityManager.flush()
return mergedEntities.onEach { entityManager.refresh(it) }
}
private fun CriteriaBuilder.buildQueryFromFilter(filter: DynamicModelFilter, clazz: Class<*>): CriteriaQuery<*> {
val cq = createQuery()
val root = cq.from(clazz)
val predicates = filter.filterFields
.map { processFilterField(it, root) }
.toTypedArray()
if (predicates.isNotEmpty()) {
cq.where(*predicates)
}
if (filter.orders.isNotEmpty()) {
cq.orderBy(getOrders(filter, root))
}
return cq
}
private fun setLimits(filter: DynamicModelFilter, query: TypedQuery<*>) {
filter.start?.let {
query.firstResult = it.toInt()
}
filter.limit?.let {
query.maxResults = it.toInt()
}
}
private fun CriteriaBuilder.getOrders(
filter: DynamicModelFilter,
root: Root<*>
): List {
return filter.orders.mapNotNull {
val by = it.by ?: return@mapNotNull null
if (it.descending) {
desc(root.getExpressionByFieldName(by))
} else {
asc(root.getExpressionByFieldName(by))
}
}
}
private fun CriteriaBuilder.processFilterField(filterField: FilterField, root: Root<*>): Predicate {
val predicate: Predicate = when (filterField.operation) {
FilterFieldOperation.Equal -> {
equal(root.getExpressionByFieldName(filterField.fieldName), filterField.value1())
}
FilterFieldOperation.NotEqual -> {
notEqual(root.getExpressionByFieldName(filterField.fieldName), filterField.value1())
}
FilterFieldOperation.In -> {
`in`(root.getExpressionByFieldName(filterField.fieldName)).value(filterField.values.toList())
}
FilterFieldOperation.NotIn -> {
not(`in`(root.getExpressionByFieldName(filterField.fieldName)).value(filterField.values.toList()))
}
FilterFieldOperation.GreaterThan -> {
greaterThan(
root.getExpressionByFieldName(filterField.fieldName) as Expression>,
filterField.value1() as Comparable
)
}
FilterFieldOperation.GreaterEqual -> {
greaterThanOrEqualTo(
root.getExpressionByFieldName(filterField.fieldName) as Expression>,
filterField.value1() as Comparable
)
}
FilterFieldOperation.LowerThan -> {
lessThan(
root.getExpressionByFieldName(filterField.fieldName) as Expression>,
filterField.value1() as Comparable
)
}
FilterFieldOperation.LowerEqual -> {
lessThanOrEqualTo(
root.getExpressionByFieldName(filterField.fieldName) as Expression>,
filterField.value1() as Comparable
)
}
FilterFieldOperation.Between -> {
between(
root.getExpressionByFieldName(filterField.fieldName) as Expression>,
filterField.value1() as Comparable,
filterField.value2() as Comparable
)
}
FilterFieldOperation.Contains -> {
like(root.getExpressionByFieldName(filterField.fieldName) as Path, "%${filterField.value1()}%")
}
FilterFieldOperation.IsNull -> {
isNull(root.getExpressionByFieldName(filterField.fieldName))
}
FilterFieldOperation.IsNotNull -> {
isNotNull(root.getExpressionByFieldName(filterField.fieldName))
}
FilterFieldOperation.IsEmpty -> {
this.isEmpty(root.getExpressionByFieldName(filterField.fieldName) as Path>)
}
FilterFieldOperation.IsNotEmpty -> {
this.isNotEmpty(root.getExpressionByFieldName(filterField.fieldName) as Path>)
}
FilterFieldOperation.And -> {
and(*filterField.children.map { processFilterField(it, root) }.toTypedArray())
}
FilterFieldOperation.Or -> {
or(*filterField.children.map { processFilterField(it, root) }.toTypedArray())
}
FilterFieldOperation.Not -> {
not(processFilterField(filterField.children.first(), root))
}
FilterFieldOperation.Noop -> {
equal(literal(true), literal(false))
}
else -> error("Unknown operation: ${filterField.operation}")
}
return predicate
}
private fun From<*, *>.getExpressionByFieldName(fieldName: String): Expression<*> {
if (!fieldName.contains(".")) {
return this.get(fieldName)
}
var expression = this
val parts = fieldName.replace("/",".").split(".")
if(parts.size > 1) {
for (i in 0 .. parts.size - 2) {
expression = expression.joins.find { it.attribute.name == parts[i] } ?: expression.join(parts[i])
}
}
return expression.getExpressionByFieldName(parts[parts.size - 1])
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy