Skip to content

Commit

Permalink
Merge pull request #538 from waahhh/feature/add-string-functions-subs…
Browse files Browse the repository at this point in the history
…tring

Add String functions(substring)
  • Loading branch information
shouwn authored Nov 25, 2023
2 parents c5945bd + be8a15c commit 3ddf4cc
Show file tree
Hide file tree
Showing 8 changed files with 354 additions and 0 deletions.
54 changes: 54 additions & 0 deletions dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/Jpql.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1090,6 +1090,60 @@ open class Jpql : JpqlDsl {
return Expressions.type(path.toPath())
}

/**
* Creates an expression that represents a substring of the specified length from the start position of the string.
* If the length is not specified, it is returned from the start position of the string to the end of the string.
* The first position of a string is 1.
*/
@SinceJdsl("3.2.0")
fun substring(
value: String,
start: Int,
length: Int? = null,
): Expression<String> {
return Expressions.substring(
Expressions.value(value),
Expressions.value(start),
length?.let { Expressions.value(length) },
)
}

/**
* Creates an expression that represents a substring of the specified length from the start position of the string.
* If the length is not specified, it is returned from the start position of the string to the end of the string.
* The first position of a string is 1.
*/
@SinceJdsl("3.2.0")
fun substring(
value: Expressionable<String>,
start: Int,
length: Int? = null,
): Expression<String> {
return Expressions.substring(
value.toExpression(),
Expressions.value(start),
length?.let { Expressions.value(length) },
)
}

/**
* Creates an expression that represents a substring of the specified length from the start position of the string.
* If the length is not specified, it is returned from the start position of the string to the end of the string.
* The first position of a string is 1.
*/
@SinceJdsl("3.2.0")
fun substring(
value: Expressionable<String>,
start: Expressionable<Int>,
length: Expressionable<Int>? = null,
): Expression<String> {
return Expressions.substring(
value.toExpression(),
start.toExpression(),
length?.toExpression(),
)
}

/**
* Creates an expression that represents a string with the whitespaces all trimmed
* from the both sides of the string.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package com.linecorp.kotlinjdsl.dsl.jpql.expression

import com.linecorp.kotlinjdsl.dsl.jpql.queryPart
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
import org.assertj.core.api.WithAssertions
import org.junit.jupiter.api.Test

class SubstringDslTest : WithAssertions {
private val string1 = "string1"
private val int1 = 1
private val int2 = 2

private val stringExpression1 = Expressions.value("string1")
private val intExpression1 = Expressions.value(1)
private val intExpression2 = Expressions.value(2)

@Test
fun `substring() with a string and an int`() {
// when
val expression = queryPart {
substring(string1, int1)
}.toExpression()

val actual: Expression<String> = expression // for type check

// then
val expected = Expressions.substring(
value = Expressions.value(string1),
start = Expressions.value(int1),
)

assertThat(actual).isEqualTo(expected)
}

@Test
fun `substring() with a string and ints`() {
// when
val expression = queryPart {
substring(string1, int1, int2)
}.toExpression()

val actual: Expression<String> = expression // for type check

// then
val expected = Expressions.substring(
value = Expressions.value(string1),
start = Expressions.value(int1),
length = Expressions.value(int2),
)

assertThat(actual).isEqualTo(expected)
}

@Test
fun `substring() with a string expression and an int`() {
// when
val expression = queryPart {
substring(stringExpression1, int1)
}.toExpression()

val actual: Expression<String> = expression // for type check

// then
val expected = Expressions.substring(
value = stringExpression1,
start = Expressions.value(int1),
)

assertThat(actual).isEqualTo(expected)
}

@Test
fun `substring() with a string expression and ints`() {
// when
val expression = queryPart {
substring(stringExpression1, int1, int2)
}.toExpression()

val actual: Expression<String> = expression // for type check

// then
val expected = Expressions.substring(
value = stringExpression1,
start = Expressions.value(int1),
length = Expressions.value(int2),
)

assertThat(actual).isEqualTo(expected)
}

@Test
fun `substring() with a string expression and an int expression`() {
// when
val expression = queryPart {
substring(stringExpression1, intExpression1)
}.toExpression()

val actual: Expression<String> = expression // for type check

// then
val expected = Expressions.substring(
value = stringExpression1,
start = intExpression1,
)

assertThat(actual).isEqualTo(expected)
}

@Test
fun `substring() with a string expression and int expressions`() {
// when
val expression = queryPart {
substring(stringExpression1, intExpression1, intExpression2)
}.toExpression()

val actual: Expression<String> = expression // for type check

// then
val expected = Expressions.substring(
value = stringExpression1,
start = intExpression1,
length = intExpression2,
)

assertThat(actual).isEqualTo(expected)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlParam
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlPathType
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlPlus
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSubquery
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSubstring
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSum
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTimes
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTrim
Expand Down Expand Up @@ -420,6 +421,20 @@ object Expressions {
return JpqlPathType(path)
}

/**
* Creates an expression that represents a substring of the specified length from the start position of the string.
* If the length is not specified, it is returned from the start position of the string to the end of the string.
* The first position of a string is 1.
*/
@SinceJdsl("3.2.0")
fun substring(
value: Expression<String>,
start: Expression<Int>,
length: Expression<Int>? = null,
): Expression<String> {
return JpqlSubstring(value, start, length)
}

/**
* Creates an expression that represents a string with the specified characters all trimmed
* from the both sides of the string.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl

import com.linecorp.kotlinjdsl.Internal
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression

@Internal
data class JpqlSubstring internal constructor(
val value: Expression<String>,
val start: Expression<Int>,
val length: Expression<Int>?,
) : Expression<String>
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlParam
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlPathType
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlPlus
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSubquery
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSubstring
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSum
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTimes
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlTrim
Expand Down Expand Up @@ -605,6 +606,25 @@ class ExpressionsTest : WithAssertions {
assertThat(actual).isEqualTo(expected)
}

@Test
fun substring() {
// when
val actual = Expressions.substring(
stringExpression1,
intExpression1,
intExpression2,
)

// then
val expected = JpqlSubstring(
stringExpression1,
intExpression1,
intExpression2,
)

assertThat(actual).isEqualTo(expected)
}

@Test
fun trim() {
// when
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlPredicateParenthe
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlSelectQuerySerializer
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlSortSerializer
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlSubquerySerializer
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlSubstringSerializer
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlSumSerializer
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlTimesSerializer
import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlTrimBothSerializer
Expand Down Expand Up @@ -334,6 +335,7 @@ private class DefaultModule : JpqlRenderModule {
JpqlSelectQuerySerializer(),
JpqlSortSerializer(),
JpqlSubquerySerializer(),
JpqlSubstringSerializer(),
JpqlSumSerializer(),
JpqlTimesSerializer(),
JpqlTrimBothSerializer(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.linecorp.kotlinjdsl.render.jpql.serializer.impl

import com.linecorp.kotlinjdsl.Internal
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSubstring
import com.linecorp.kotlinjdsl.render.RenderContext
import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlRenderSerializer
import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlSerializer
import com.linecorp.kotlinjdsl.render.jpql.writer.JpqlWriter
import kotlin.reflect.KClass

@Internal
class JpqlSubstringSerializer : JpqlSerializer<JpqlSubstring> {
override fun handledType(): KClass<JpqlSubstring> {
return JpqlSubstring::class
}

override fun serialize(part: JpqlSubstring, writer: JpqlWriter, context: RenderContext) {
val delegate = context.getValue(JpqlRenderSerializer)

writer.write("SUBSTRING")

writer.writeParentheses {
delegate.serialize(part.value, writer, context)

writer.write(",")
writer.write(" ")

delegate.serialize(part.start, writer, context)

part.length?.let {
writer.write(",")
writer.write(" ")

delegate.serialize(it, writer, context)
}
}
}
}
Loading

0 comments on commit 3ddf4cc

Please sign in to comment.