Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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

This file was deleted.

Comment thread
jansigi marked this conversation as resolved.
Outdated
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package ch.ergon.dope.resolvable.expression.type.function.token

import ch.ergon.dope.resolvable.Resolvable

data class ContainsTokenOptions(
val names: Boolean? = null,
Comment thread
jansigi marked this conversation as resolved.
Outdated
val case: TokenCases? = null,
Comment thread
jansigi marked this conversation as resolved.
Outdated
val specials: Boolean? = null,
Comment thread
pgruntz marked this conversation as resolved.
Outdated
val split: Boolean? = null,
val trim: Boolean? = null,
Comment thread
jansigi marked this conversation as resolved.
Outdated
) : Resolvable

fun containsTokenOptions(
Comment thread
jansigi marked this conversation as resolved.
Outdated
names: Boolean? = null,
case: TokenCases? = null,
specials: Boolean? = null,
split: Boolean? = null,
trim: Boolean? = null,
) = ContainsTokenOptions(names, case, specials, split, trim)
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package ch.ergon.dope.resolvable.expression.type.function.token

import ch.ergon.dope.resolvable.expression.operator.FunctionOperator
import ch.ergon.dope.resolvable.expression.type.TypeExpression
import ch.ergon.dope.resolvable.expression.type.toDopeType
import ch.ergon.dope.validtype.BooleanType
import ch.ergon.dope.validtype.StringType

data class ContainsTokenExpression(
val inputExpression: TypeExpression<StringType>,
val tokenExpression: TypeExpression<StringType>,
val options: ContainsTokenOptions? = null,
) : FunctionOperator<BooleanType>

fun TypeExpression<StringType>.containsToken(
tokenExpression: TypeExpression<StringType>,
options: ContainsTokenOptions? = null,
) = ContainsTokenExpression(this, tokenExpression, options)

fun TypeExpression<StringType>.containsToken(
Comment thread
jansigi marked this conversation as resolved.
token: String,
options: ContainsTokenOptions? = null,
) = containsToken(token.toDopeType(), options)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ch.ergon.dope.resolvable.expression.type.function.token

import ch.ergon.dope.resolvable.expression.operator.FunctionOperator
import ch.ergon.dope.resolvable.expression.type.TypeExpression
import ch.ergon.dope.resolvable.expression.type.toDopeType
import ch.ergon.dope.validtype.BooleanType
import ch.ergon.dope.validtype.StringType
import ch.ergon.dope.validtype.ValidType

data class ContainsTokenLikeExpression(
val inputObject: TypeExpression<out ValidType>,
val likeExpression: TypeExpression<StringType>,
val options: ContainsTokenOptions? = null,
) : FunctionOperator<BooleanType>

fun TypeExpression<out ValidType>.containsTokenLike(
likeExpression: TypeExpression<StringType>,
options: ContainsTokenOptions? = null,
) = ContainsTokenLikeExpression(this, likeExpression, options)

fun TypeExpression<out ValidType>.containsTokenLike(
Comment thread
jansigi marked this conversation as resolved.
likeExpression: String,
options: ContainsTokenOptions? = null,
) = containsTokenLike(likeExpression.toDopeType(), options)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ch.ergon.dope.resolvable.expression.type.function.token

import ch.ergon.dope.resolvable.expression.operator.FunctionOperator
import ch.ergon.dope.resolvable.expression.type.TypeExpression
import ch.ergon.dope.resolvable.expression.type.toDopeType
import ch.ergon.dope.validtype.BooleanType
import ch.ergon.dope.validtype.StringType
import ch.ergon.dope.validtype.ValidType

data class ContainsTokenRegexpExpression(
val inputObject: TypeExpression<out ValidType>,
val regexExpression: TypeExpression<StringType>,
val options: ContainsTokenOptions? = null,
) : FunctionOperator<BooleanType>

fun TypeExpression<out ValidType>.containsTokenRegexp(
regexExpression: TypeExpression<StringType>,
options: ContainsTokenOptions? = null,
) = ContainsTokenRegexpExpression(this, regexExpression, options)

fun TypeExpression<out ValidType>.containsTokenRegexp(
Comment thread
jansigi marked this conversation as resolved.
regexExpression: String,
options: ContainsTokenOptions? = null,
) = containsTokenRegexp(regexExpression.toDopeType(), options)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package ch.ergon.dope.resolvable.expression.type.function.string.factory
package ch.ergon.dope.resolvable.expression.type.function.token

import ch.ergon.dope.resolvable.Resolvable

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ch.ergon.dope.resolvable.expression.type.function.token

import ch.ergon.dope.resolvable.expression.operator.FunctionOperator
import ch.ergon.dope.resolvable.expression.type.TypeExpression
import ch.ergon.dope.resolvable.expression.type.toDopeType
import ch.ergon.dope.validtype.ArrayType
import ch.ergon.dope.validtype.StringType

data class TokensExpression(
val inString: TypeExpression<ArrayType<StringType>>,
val options: CustomTokenOptions? = null,
Comment thread
jansigi marked this conversation as resolved.
Outdated
) : FunctionOperator<ArrayType<StringType>>

fun TypeExpression<ArrayType<StringType>>.tokens(options: CustomTokenOptions? = null) = TokensExpression(this, options)
Comment thread
jansigi marked this conversation as resolved.
Outdated

fun List<String>.tokens(options: CustomTokenOptions? = null) = toDopeType().tokens(options)
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ object TestCouchbaseDatabase {
}

private fun ensureAuditCollections() = runBlocking {
cluster.waitUntilReady(MAX_TIMEOUT_IN_SECONDS.seconds)
cluster.waitUntilReady(MAX_TIMEOUT_IN_SECONDS.seconds)
cluster.query("CREATE SCOPE `$BUCKET`.`app` IF NOT EXISTS").execute()
cluster.query("CREATE COLLECTION `$BUCKET`.`app`.`order_audit` IF NOT EXISTS").execute()
Expand All @@ -74,11 +75,22 @@ object TestCouchbaseDatabase {
private fun ensureIndexes() = runBlocking {
cluster.waitUntilReady(MAX_TIMEOUT_IN_SECONDS.seconds)
cluster.query("CREATE PRIMARY INDEX IF NOT EXISTS ON `$BUCKET`").execute()
cluster.query("CREATE PRIMARY INDEX IF NOT EXISTS ON `$BUCKET`.`app`.`order_audit`").execute()
retryOnFailure { cluster.query("CREATE PRIMARY INDEX IF NOT EXISTS ON `$BUCKET`.`app`.`order_audit`").execute() }
cluster.query("CREATE INDEX IF NOT EXISTS `ix_order_employee` ON `$BUCKET`(`employee`) WHERE `type` = \"order\"").execute()
cluster.query("CREATE INDEX IF NOT EXISTS `ix_order_client` ON `$BUCKET`(`client`) WHERE `type` = \"order\"").execute()
}

private suspend fun <T> retryOnFailure(maxRetries: Int = MAX_RETRIES, delayMs: Long = 2000, action: suspend () -> T): T {
repeat(maxRetries - 1) {
try {
return action()
} catch (_: Exception) {
Thread.sleep(delayMs)
}
}
return action()
}

private fun initDatabase() {
val bucket = cluster.bucket(BUCKET)
val collection = bucket.defaultCollection()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ import ch.ergon.dope.resolvable.expression.rowscope.windowdefinition.WindowDefin
import ch.ergon.dope.resolvable.expression.rowscope.windowdefinition.WindowFrameClause
import ch.ergon.dope.resolvable.expression.type.CaseClass
import ch.ergon.dope.resolvable.expression.type.ObjectEntryPrimitive
import ch.ergon.dope.resolvable.expression.type.function.string.factory.CustomTokenOptions
import ch.ergon.dope.resolvable.expression.type.function.token.ContainsTokenOptions
import ch.ergon.dope.resolvable.expression.type.function.token.CustomTokenOptions
import ch.ergon.dope.resolver.QueryResolver

interface AbstractCouchbaseResolver : QueryResolver<CouchbaseDopeQuery> {
Expand Down Expand Up @@ -88,6 +89,8 @@ class CouchbaseResolver(

is Asterisk -> resolve(resolvable)

is ContainsTokenOptions -> resolve(resolvable)

is CustomTokenOptions -> resolve(resolvable)

is HashOrNestedLoopHint -> resolve(resolvable)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ch.ergon.dope.couchbase.util.formatFunctionQueryString
import ch.ergon.dope.merge
import ch.ergon.dope.orEmpty
import ch.ergon.dope.resolvable.expression.operator.FunctionOperator
import ch.ergon.dope.resolvable.expression.type.TypeExpression
import ch.ergon.dope.resolvable.expression.type.function.FunctionExpression
import ch.ergon.dope.resolvable.expression.type.function.conditional.DecodeExpression
import ch.ergon.dope.resolvable.expression.type.function.conditional.Nvl2Expression
Expand All @@ -15,9 +16,15 @@ import ch.ergon.dope.resolvable.expression.type.function.search.ISearchFunctionE
import ch.ergon.dope.resolvable.expression.type.function.search.SearchDependencyFunctionExpression
import ch.ergon.dope.resolvable.expression.type.function.search.SearchFunctionType
import ch.ergon.dope.resolvable.expression.type.function.string.MaskExpression
import ch.ergon.dope.resolvable.expression.type.function.string.TokensExpression
import ch.ergon.dope.resolvable.expression.type.function.token.ContainsTokenExpression
import ch.ergon.dope.resolvable.expression.type.function.token.ContainsTokenLikeExpression
import ch.ergon.dope.resolvable.expression.type.function.token.ContainsTokenOptions
import ch.ergon.dope.resolvable.expression.type.function.token.ContainsTokenRegexpExpression
import ch.ergon.dope.resolvable.expression.type.function.token.TokensExpression
import ch.ergon.dope.resolvable.expression.type.function.type.ToNumberExpression
import ch.ergon.dope.resolvable.expression.type.toDopeType
import ch.ergon.dope.validtype.StringType
import ch.ergon.dope.validtype.ValidType

interface FunctionOperatorResolver : AbstractCouchbaseResolver {
fun resolve(typeExpression: FunctionOperator<*>): CouchbaseDopeQuery = when (typeExpression) {
Expand Down Expand Up @@ -51,16 +58,37 @@ interface FunctionOperatorResolver : AbstractCouchbaseResolver {
}

is TokensExpression -> {
val inString = typeExpression.inStr.toDopeType().toDopeQuery(this)
val inStringDopeQuery = typeExpression.inString.toDopeQuery(this)
val optionsDopeQuery = typeExpression.options?.toDopeQuery(this).takeIf { !it?.queryString.isNullOrEmpty() }
val functionQueryString = formatFunctionQueryString(
"TOKENS",
inString.queryString,
inStringDopeQuery.queryString,
optionsDopeQuery?.queryString,
)
CouchbaseDopeQuery(functionQueryString, optionsDopeQuery?.parameters.orEmpty())
CouchbaseDopeQuery(functionQueryString, inStringDopeQuery.parameters.merge(optionsDopeQuery?.parameters))
}

is ContainsTokenExpression -> resolve(
"CONTAINS_TOKEN",
typeExpression.inputExpression,
typeExpression.tokenExpression,
typeExpression.options,
)

is ContainsTokenLikeExpression -> resolve(
"CONTAINS_TOKEN_LIKE",
typeExpression.inputObject,
typeExpression.likeExpression,
typeExpression.options,
)

is ContainsTokenRegexpExpression -> resolve(
"CONTAINS_TOKEN_REGEXP",
typeExpression.inputObject,
typeExpression.regexExpression,
typeExpression.options,
)

is MaskExpression -> {
val inputStringDopeQuery = typeExpression.inStr.toDopeQuery(this)
val optionsString =
Expand Down Expand Up @@ -160,4 +188,25 @@ interface FunctionOperatorResolver : AbstractCouchbaseResolver {

else -> throw UnsupportedOperationException("Not supported: $typeExpression")
}

private fun resolve(
symbol: String,
inputObject: TypeExpression<out ValidType>,
tokenExpression: TypeExpression<StringType>,
options: ContainsTokenOptions?,
): CouchbaseDopeQuery {
val inputObjectDopeQuery = inputObject.toDopeQuery(this)
val tokenExpressionDopeQuery = tokenExpression.toDopeQuery(this)
val optionsDopeQuery = options?.toDopeQuery(this).takeIf { !it?.queryString.isNullOrEmpty() }
val functionQueryString = formatFunctionQueryString(
symbol,
inputObjectDopeQuery.queryString,
tokenExpressionDopeQuery.queryString,
optionsDopeQuery?.queryString,
)
return CouchbaseDopeQuery(
functionQueryString,
inputObjectDopeQuery.parameters.merge(tokenExpressionDopeQuery.parameters, optionsDopeQuery?.parameters),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ import ch.ergon.dope.resolvable.expression.type.collection.SatisfiesExpression
import ch.ergon.dope.resolvable.expression.type.function.array.UnpackExpression
import ch.ergon.dope.resolvable.expression.type.function.date.DateComponentType
import ch.ergon.dope.resolvable.expression.type.function.date.DateUnitType
import ch.ergon.dope.resolvable.expression.type.function.string.factory.CustomTokenOptions
import ch.ergon.dope.resolvable.expression.type.function.token.ContainsTokenOptions
import ch.ergon.dope.resolvable.expression.type.function.token.CustomTokenOptions
import ch.ergon.dope.resolvable.expression.type.range.RangeIndexedLike
import ch.ergon.dope.resolvable.expression.type.range.RangeLike
import ch.ergon.dope.resolvable.expression.type.relational.BetweenExpression
Expand Down Expand Up @@ -380,4 +381,20 @@ interface TypeExpressionResolver : InfixOperatorResolver, FunctionOperatorResolv

return CouchbaseDopeQuery(queryString = queryString)
}

fun resolve(containsTokenOptions: ContainsTokenOptions): CouchbaseDopeQuery {
val options = listOfNotNull(
containsTokenOptions.names?.let { "names" to it },
containsTokenOptions.case?.let { "case" to "\"${it.queryString}\"" },
containsTokenOptions.specials?.let { "specials" to it },
containsTokenOptions.split?.let { "split" to it },
containsTokenOptions.trim?.let { "trim" to it },
)
val queryString = options
.joinToString(", ", "{", "}") { (key, value) -> "\"$key\": $value" }
.takeIf { options.isNotEmpty() }
.orEmpty()
Comment thread
jansigi marked this conversation as resolved.

return CouchbaseDopeQuery(queryString = queryString)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import ch.ergon.dope.resolvable.expression.type.arithmetic.add
import ch.ergon.dope.resolvable.expression.type.function.string.concat
import ch.ergon.dope.resolvable.expression.type.function.string.concat2
import ch.ergon.dope.resolvable.expression.type.function.string.contains
import ch.ergon.dope.resolvable.expression.type.function.string.factory.TokenCases
import ch.ergon.dope.resolvable.expression.type.function.string.factory.customTokenOptions
import ch.ergon.dope.resolvable.expression.type.function.string.initCap
import ch.ergon.dope.resolvable.expression.type.function.string.length
import ch.ergon.dope.resolvable.expression.type.function.string.lower
Expand All @@ -38,11 +36,13 @@ import ch.ergon.dope.resolvable.expression.type.function.string.substring
import ch.ergon.dope.resolvable.expression.type.function.string.substring1
import ch.ergon.dope.resolvable.expression.type.function.string.suffixes
import ch.ergon.dope.resolvable.expression.type.function.string.title
import ch.ergon.dope.resolvable.expression.type.function.string.tokens
import ch.ergon.dope.resolvable.expression.type.function.string.trim
import ch.ergon.dope.resolvable.expression.type.function.string.upper
import ch.ergon.dope.resolvable.expression.type.function.string.urlDecode
import ch.ergon.dope.resolvable.expression.type.function.string.urlEncode
import ch.ergon.dope.resolvable.expression.type.function.token.TokenCases
import ch.ergon.dope.resolvable.expression.type.function.token.customTokenOptions
import ch.ergon.dope.resolvable.expression.type.function.token.tokens
import ch.ergon.dope.resolvable.expression.type.get
import ch.ergon.dope.resolvable.expression.type.logic.and
import ch.ergon.dope.resolvable.expression.type.relational.isEqualTo
Expand Down Expand Up @@ -85,9 +85,7 @@ class StringFunctionsTest : ResolverDependentTest {

val actual: String = QueryBuilder
.select(
"abc".toDopeType().concat("def".toDopeType(), "ghi".toDopeType(), someStringField()).alias(
"concat",
),
"abc".toDopeType().concat("def".toDopeType(), "ghi".toDopeType(), someStringField()).alias("concat"),
).build(CouchbaseResolver()).queryString

assertEquals(unifyString(expected), actual)
Expand Down Expand Up @@ -142,9 +140,7 @@ class StringFunctionsTest : ResolverDependentTest {
fun `should Support Concat2 One Argument`() {
val expected = "CONCAT2(\"-\", \"a\") AS `c2`"

val actual: String = "-".concat2("a".toDopeType()).alias(
"c2",
).toDopeQuery(resolver).queryString
val actual: String = "-".concat2("a".toDopeType()).alias("c2").toDopeQuery(resolver).queryString

assertEquals(unifyString(expected), actual)
}
Expand Down

This file was deleted.

Loading
Loading