Skip to content

Commit 7d6f397

Browse files
committed
feat: support temporal field types
1 parent f1193df commit 7d6f397

12 files changed

Lines changed: 155 additions & 28 deletions

File tree

src/main/kotlin/team/yi/rsql/querydsl/QuerydslRsql.kt

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import com.querydsl.core.types.*
44
import com.querydsl.core.types.dsl.*
55
import com.querydsl.jpa.impl.*
66
import cz.jirutka.rsql.parser.RSQLParser
7-
import team.yi.rsql.querydsl.exception.*
7+
import team.yi.rsql.querydsl.exception.RsqlException
88
import team.yi.rsql.querydsl.handler.SortFieldTypeHandler
99
import team.yi.rsql.querydsl.util.*
1010

@@ -173,16 +173,30 @@ class QuerydslRsql<E> private constructor(builder: Builder<E>) {
173173
this.orderSpecifiers = builder.orderSpecifiers
174174
}
175175

176-
fun select(select: String?): BuildBuilder<E> = BuildBuilder(this).apply { this.selectString = select }
177-
fun select(vararg expression: Expression<*>?): BuildBuilder<E> = BuildBuilder(this).apply { this.selectExpressions = expression.filterNotNull().distinct() }
176+
fun select(select: String?): BuildBuilder<E> = BuildBuilder(this).apply {
177+
this.selectString = select
178+
}
179+
180+
fun select(vararg expression: Expression<*>?): BuildBuilder<E> = BuildBuilder(this).apply {
181+
this.selectExpressions = expression.filterNotNull().distinct()
182+
}
178183

179-
fun from(entityName: String?): BuildBuilder<E> = BuildBuilder(this).apply { this.entityName = entityName }
180-
fun from(entityClass: Class<E>?): BuildBuilder<E> = BuildBuilder(this).apply { this.entityClass = entityClass }
184+
fun from(entityName: String?): BuildBuilder<E> = BuildBuilder(this).apply {
185+
this.entityName = entityName
186+
}
181187

182-
fun where(where: String?): BuildBuilder<E> = BuildBuilder(this).apply { this.where = where }
188+
fun from(entityClass: Class<E>?): BuildBuilder<E> = BuildBuilder(this).apply {
189+
this.entityClass = entityClass
190+
}
191+
192+
fun where(where: String?): BuildBuilder<E> = BuildBuilder(this).apply {
193+
this.where = where
194+
}
183195

184196
class BuildBuilder<E>(builder: Builder<E>) : Builder<E>(builder) {
185-
fun globalPredicate(globalPredicate: BooleanExpression?): BuildBuilder<E> = this.apply { super.globalPredicate = globalPredicate }
197+
fun globalPredicate(globalPredicate: BooleanExpression?): BuildBuilder<E> = this.apply {
198+
super.globalPredicate = globalPredicate
199+
}
186200

187201
fun build(): QuerydslRsql<E> {
188202
return try {
@@ -213,8 +227,13 @@ class QuerydslRsql<E> private constructor(builder: Builder<E>) {
213227
}
214228

215229
fun sort(sort: String?): BuildBuilder<E> = this.apply { super.sort = sort }
216-
fun sort(vararg expression: OrderSpecifier<*>?): BuildBuilder<E> = this.apply { super.orderSpecifiers = expression.filterNotNull().distinct() }
217-
fun sort(orderSpecifiers: List<OrderSpecifier<*>>?): BuildBuilder<E> = this.apply { super.orderSpecifiers = orderSpecifiers }
230+
fun sort(vararg expression: OrderSpecifier<*>?): BuildBuilder<E> = this.apply {
231+
super.orderSpecifiers = expression.filterNotNull().distinct()
232+
}
233+
234+
fun sort(orderSpecifiers: List<OrderSpecifier<*>>?): BuildBuilder<E> = this.apply {
235+
super.orderSpecifiers = orderSpecifiers
236+
}
218237
}
219238
}
220239

src/main/kotlin/team/yi/rsql/querydsl/RsqlConfig.kt

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,19 +61,33 @@ class RsqlConfig private constructor(builder: Builder) {
6161
internal val nodeInterceptors = mutableListOf<RsqlNodeInterceptor>()
6262
internal var dateFormat: String? = null
6363

64-
fun operator(vararg operator: RsqlOperator): Builder = this.apply { this.operators += operator }
64+
fun operator(vararg operator: RsqlOperator): Builder = this.apply {
65+
this.operators += operator
66+
}
6567

66-
fun fieldTypeHandler(vararg typeHandler: Class<out FieldTypeHandler>): Builder = this.apply { this.fieldTypeHandlers += typeHandler }
68+
fun fieldTypeHandler(vararg typeHandler: Class<out FieldTypeHandler>): Builder = this.apply {
69+
this.fieldTypeHandlers += typeHandler
70+
}
6771

68-
fun sortFieldTypeHandler(vararg typeHandler: Class<out SortFieldTypeHandler>): Builder = this.apply { this.sortFieldTypeHandlers += typeHandler }
72+
fun sortFieldTypeHandler(vararg typeHandler: Class<out SortFieldTypeHandler>): Builder = this.apply {
73+
this.sortFieldTypeHandlers += typeHandler
74+
}
6975

70-
fun nodeInterceptors(nodeInterceptors: List<RsqlNodeInterceptor>?): Builder = this.apply { nodeInterceptors?.let { this.nodeInterceptors.addAll(nodeInterceptors) } }
76+
fun nodeInterceptors(nodeInterceptors: List<RsqlNodeInterceptor>?): Builder = this.apply {
77+
nodeInterceptors?.let { this.nodeInterceptors.addAll(nodeInterceptors) }
78+
}
7179

72-
fun nodeInterceptor(block: () -> RsqlNodeInterceptor?): Builder = this.apply { block()?.let { this.nodeInterceptor(it) } }
80+
fun nodeInterceptor(block: () -> RsqlNodeInterceptor?): Builder = this.apply {
81+
block()?.let { this.nodeInterceptor(it) }
82+
}
7383

74-
fun nodeInterceptor(nodeInterceptor: RsqlNodeInterceptor?): Builder = this.apply { nodeInterceptor?.let { this.nodeInterceptors.add(nodeInterceptor) } }
84+
fun nodeInterceptor(nodeInterceptor: RsqlNodeInterceptor?): Builder = this.apply {
85+
nodeInterceptor?.let { this.nodeInterceptors.add(nodeInterceptor) }
86+
}
7587

76-
fun dateFormat(dateFormat: String?): Builder = this.apply { this.dateFormat = dateFormat }
88+
fun dateFormat(dateFormat: String?): Builder = this.apply {
89+
this.dateFormat = dateFormat
90+
}
7791

7892
fun build(): RsqlConfig {
7993
return try {

src/main/kotlin/team/yi/rsql/querydsl/RsqlConstants.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ object RsqlConstants {
1010
StringFieldTypeHandler::class.java,
1111
CharacterFieldTypeHandler::class.java,
1212
DateTimeFieldTypeHandler::class.java,
13+
TemporalAccessorFieldTypeHandler::class.java,
1314
BooleanFieldTypeHandler::class.java,
1415
ListFieldTypeHandler::class.java,
1516
SetFieldTypeHandler::class.java,

src/main/kotlin/team/yi/rsql/querydsl/handler/BooleanFieldTypeHandler.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class BooleanFieldTypeHandler(
3434
}
3535
}
3636

37-
override fun toComparable(value: String?): Comparable<Boolean>? {
37+
override fun toComparable(value: String?, fm: FieldMetadata?): Comparable<Boolean>? {
3838
return value?.toBoolean()
3939
}
4040

src/main/kotlin/team/yi/rsql/querydsl/handler/ComparableFieldTypeHandler.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ abstract class ComparableFieldTypeHandler<E : Comparable<E>>(
2222
if (values.isEmpty()) return null
2323

2424
return values.map {
25-
val value = toComparable(it) ?: return null
25+
val value = toComparable(it, fm) ?: return null
2626

2727
Expressions.asComparable(value)
2828
}.toList()
2929
}
3030

31-
protected abstract fun toComparable(value: String?): Comparable<E>?
31+
protected abstract fun toComparable(value: String?, fm: FieldMetadata?): Comparable<E>?
3232

3333
override fun getExpression(path: Expression<*>?, values: Collection<Expression<out Any?>?>?, fm: FieldMetadata?): BooleanExpression? {
3434
val left = path as ComparableExpression<E>

src/main/kotlin/team/yi/rsql/querydsl/handler/DateTimeFieldTypeHandler.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ class DateTimeFieldTypeHandler<E : Comparable<E>>(
2626
if (values.isEmpty()) return null
2727

2828
return values.map {
29-
val value = toComparable(it) ?: return null
29+
val value = toComparable(it, fm) ?: return null
3030

3131
Expressions.asDateTime(value)
3232
}.toList()
3333
}
3434

35-
override fun toComparable(value: String?): Comparable<E>? {
35+
override fun toComparable(value: String?, fm: FieldMetadata?): Comparable<E>? {
3636
if (value.isNullOrBlank()) return null
3737

3838
val dateFormat = rsqlConfig.dateFormat

src/main/kotlin/team/yi/rsql/querydsl/handler/EnumFieldTypeHandler.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,13 @@ class EnumFieldTypeHandler<E : Enum<E>>(
3333
if (values.isEmpty()) return null
3434

3535
return values
36-
.map { if (it.isNullOrBlank()) null else Expressions.asEnum(java.lang.Enum.valueOf(fieldMetadata.clazz as Class<E>, it)) }
36+
.map {
37+
if (it.isNullOrBlank()) {
38+
null
39+
} else {
40+
Expressions.asEnum(java.lang.Enum.valueOf(fieldMetadata.clazz as Class<E>, it))
41+
}
42+
}
3743
.toList()
3844
}
3945
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package team.yi.rsql.querydsl.handler
2+
3+
import com.querydsl.core.types.*
4+
import com.querydsl.core.types.dsl.Expressions
5+
import cz.jirutka.rsql.parser.ast.ComparisonNode
6+
import team.yi.rsql.querydsl.*
7+
import team.yi.rsql.querydsl.operator.RsqlOperator
8+
import java.time.*
9+
import java.time.temporal.TemporalAccessor
10+
11+
@Suppress("UNCHECKED_CAST")
12+
class TemporalAccessorFieldTypeHandler<E : Comparable<E>>(
13+
override val node: ComparisonNode,
14+
override val operator: RsqlOperator,
15+
override val fieldMetadata: FieldMetadata,
16+
override val rsqlConfig: RsqlConfig,
17+
) : TemporalFieldTypeHandler<E>(node, operator, fieldMetadata, rsqlConfig) {
18+
override fun supports(type: Class<*>?): Boolean {
19+
return if (type == null) {
20+
false
21+
} else {
22+
TemporalAccessor::class.java.isAssignableFrom(type)
23+
}
24+
}
25+
26+
override fun getPath(parentPath: Expression<*>?): Expression<*>? {
27+
return Expressions.dateTimePath(
28+
fieldMetadata.clazz as Class<out Comparable<*>?>,
29+
parentPath as Path<*>?,
30+
fieldMetadata.fieldSelector
31+
)
32+
}
33+
34+
override fun getValue(values: List<String?>, rootPath: Path<*>, fm: FieldMetadata?): Collection<Expression<out Any?>?>? {
35+
if (values.isEmpty()) return null
36+
37+
return values.map {
38+
val value = toComparable(it, fm) ?: return null
39+
40+
Expressions.asDateTime(value)
41+
}.toList()
42+
}
43+
44+
@Suppress("CyclomaticComplexMethod")
45+
override fun toComparable(value: String?, fm: FieldMetadata?): Comparable<E>? {
46+
if (value.isNullOrBlank()) return null
47+
48+
val fieldType = fm?.clazz ?: return null
49+
50+
return runCatching {
51+
when (fieldType) {
52+
LocalDate::class.java -> LocalDate.parse(value)
53+
LocalDateTime::class.java -> LocalDateTime.parse(value)
54+
LocalTime::class.java -> LocalTime.parse(value)
55+
OffsetDateTime::class.java -> OffsetDateTime.parse(value)
56+
OffsetTime::class.java -> OffsetTime.parse(value)
57+
ZonedDateTime::class.java -> ZonedDateTime.parse(value)
58+
Duration::class.java -> Duration.parse(value)
59+
Period::class.java -> Period.parse(value)
60+
Instant::class.java -> Instant.parse(value)
61+
MonthDay::class.java -> MonthDay.parse(value)
62+
Year::class.java -> Year.parse(value)
63+
YearMonth::class.java -> YearMonth.parse(value)
64+
Month::class.java -> Month.valueOf(value)
65+
DayOfWeek::class.java -> DayOfWeek.valueOf(value)
66+
else -> null
67+
} as? Comparable<E>?
68+
}.getOrNull()
69+
}
70+
}

src/main/kotlin/team/yi/rsql/querydsl/handler/TemporalFieldTypeHandler.kt

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import com.querydsl.core.types.dsl.*
55
import cz.jirutka.rsql.parser.ast.ComparisonNode
66
import team.yi.rsql.querydsl.*
77
import team.yi.rsql.querydsl.operator.*
8-
import java.sql.Time
9-
import java.sql.Timestamp
108
import java.util.*
119

1210
@Suppress("UNCHECKED_CAST")
@@ -20,10 +18,7 @@ abstract class TemporalFieldTypeHandler<E : Comparable<E>>(
2018
return if (type == null) {
2119
false
2220
} else {
23-
Date::class.java.isAssignableFrom(type) ||
24-
java.sql.Date::class.java.isAssignableFrom(type) ||
25-
Time::class.java.isAssignableFrom(type) ||
26-
Timestamp::class.java.isAssignableFrom(type)
21+
Date::class.java.isAssignableFrom(type)
2722
}
2823
}
2924

src/test/kotlin/team/yi/rsql/querydsl/model/Car.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package team.yi.rsql.querydsl.model
22

33
import jakarta.persistence.*
4+
import java.time.LocalDateTime
45
import java.util.*
56

67
@Suppress("unused", "SpellCheckingInspection")
@@ -22,6 +23,9 @@ class Car {
2223
@Column
2324
var mfgdt: Date? = null
2425

26+
@Column(name = "created_at")
27+
var createdAt: LocalDateTime? = null
28+
2529
@OneToOne(fetch = FetchType.LAZY)
2630
var engine: Engine? = null
2731

0 commit comments

Comments
 (0)