Skip to content

Commit

Permalink
refactor: EXPOSED-88 Remove kotlinx-serialization dep from exposed-co…
Browse files Browse the repository at this point in the history
…re (JetBrains#1793)

Create new module exposed-json with api folder.

Migrate JSON/JSONB column type classes, function classes, and extension functions.

Migrate all testing data/functions and test suites.

Make postgresql driver compileOnly (and update valueFromDB() in column type
classes).

Remove all kotlinx-serialization and postgresql driver dependencies from
exposed-core and exposed-tests modules.

Add testDependency on new module to all 3 datetime modules.

Rename public API extension functions by removing 'json' prefix. Function names
in exposed-core module vendor FunctionProvider have not been renamed to properly
emphasize that theyare related to the new module.
  • Loading branch information
bog-walk authored and saral committed Oct 3, 2023
1 parent f07546a commit 3a947a3
Show file tree
Hide file tree
Showing 25 changed files with 504 additions and 419 deletions.
61 changes: 0 additions & 61 deletions exposed-core/api/exposed-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -926,9 +926,6 @@ public abstract interface class org/jetbrains/exposed/sql/ISqlExpressionBuilder
public abstract fun isNotDistinctFromEntityID (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/IsNotDistinctFromOp;
public abstract fun isNotNull (Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/IsNotNullOp;
public abstract fun isNull (Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/IsNullOp;
public abstract fun jsonContains (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Object;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/JsonContains;
public abstract fun jsonContains (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/JsonContains;
public abstract fun jsonExists (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;[Ljava/lang/String;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/JsonExists;
public abstract fun lag (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/Lag;
public abstract fun lastValue (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/LastValue;
public abstract fun lead (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/Lead;
Expand Down Expand Up @@ -1034,12 +1031,6 @@ public final class org/jetbrains/exposed/sql/ISqlExpressionBuilder$DefaultImpls
public static fun isNotDistinctFromEntityID (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/IsNotDistinctFromOp;
public static fun isNotNull (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/IsNotNullOp;
public static fun isNull (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/IsNullOp;
public static fun jsonContains (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Object;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/JsonContains;
public static fun jsonContains (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/JsonContains;
public static synthetic fun jsonContains$default (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Object;Ljava/lang/String;ILjava/lang/Object;)Lorg/jetbrains/exposed/sql/JsonContains;
public static synthetic fun jsonContains$default (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;Ljava/lang/String;ILjava/lang/Object;)Lorg/jetbrains/exposed/sql/JsonContains;
public static fun jsonExists (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;[Ljava/lang/String;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/JsonExists;
public static synthetic fun jsonExists$default (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;[Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lorg/jetbrains/exposed/sql/JsonExists;
public static fun lag (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/Lag;
public static synthetic fun lag$default (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;ILjava/lang/Object;)Lorg/jetbrains/exposed/sql/Lag;
public static fun lastValue (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/LastValue;
Expand Down Expand Up @@ -1207,50 +1198,6 @@ public final class org/jetbrains/exposed/sql/JoinType : java/lang/Enum {
public static fun values ()[Lorg/jetbrains/exposed/sql/JoinType;
}

public final class org/jetbrains/exposed/sql/JsonBColumnType : org/jetbrains/exposed/sql/JsonColumnType {
public fun <init> (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
public fun sqlType ()Ljava/lang/String;
}

public class org/jetbrains/exposed/sql/JsonColumnType : org/jetbrains/exposed/sql/ColumnType {
public fun <init> (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
public final fun getDeserialize ()Lkotlin/jvm/functions/Function1;
public final fun getSerialize ()Lkotlin/jvm/functions/Function1;
public fun nonNullValueToString (Ljava/lang/Object;)Ljava/lang/String;
public synthetic fun notNullValueToDB (Ljava/lang/Object;)Ljava/lang/Object;
public fun notNullValueToDB (Ljava/lang/Object;)Ljava/lang/String;
public fun setParameter (Lorg/jetbrains/exposed/sql/statements/api/PreparedStatementApi;ILjava/lang/Object;)V
public fun sqlType ()Ljava/lang/String;
public fun valueFromDB (Ljava/lang/Object;)Ljava/lang/Object;
}

public final class org/jetbrains/exposed/sql/JsonContains : org/jetbrains/exposed/sql/Op, org/jetbrains/exposed/sql/ComplexExpression, org/jetbrains/exposed/sql/Op$OpBoolean {
public fun <init> (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/Expression;Ljava/lang/String;Lorg/jetbrains/exposed/sql/IColumnType;)V
public final fun getCandidate ()Lorg/jetbrains/exposed/sql/Expression;
public final fun getJsonType ()Lorg/jetbrains/exposed/sql/IColumnType;
public final fun getPath ()Ljava/lang/String;
public final fun getTarget ()Lorg/jetbrains/exposed/sql/Expression;
public fun toQueryBuilder (Lorg/jetbrains/exposed/sql/QueryBuilder;)V
}

public final class org/jetbrains/exposed/sql/JsonExists : org/jetbrains/exposed/sql/Op, org/jetbrains/exposed/sql/ComplexExpression, org/jetbrains/exposed/sql/Op$OpBoolean {
public fun <init> (Lorg/jetbrains/exposed/sql/Expression;[Ljava/lang/String;Ljava/lang/String;Lorg/jetbrains/exposed/sql/IColumnType;)V
public final fun getExpression ()Lorg/jetbrains/exposed/sql/Expression;
public final fun getJsonType ()Lorg/jetbrains/exposed/sql/IColumnType;
public final fun getOptional ()Ljava/lang/String;
public final fun getPath ()[Ljava/lang/String;
public fun toQueryBuilder (Lorg/jetbrains/exposed/sql/QueryBuilder;)V
}

public final class org/jetbrains/exposed/sql/JsonExtract : org/jetbrains/exposed/sql/Function {
public fun <init> (Lorg/jetbrains/exposed/sql/Expression;[Ljava/lang/String;ZLorg/jetbrains/exposed/sql/IColumnType;Lorg/jetbrains/exposed/sql/IColumnType;)V
public final fun getExpression ()Lorg/jetbrains/exposed/sql/Expression;
public final fun getJsonType ()Lorg/jetbrains/exposed/sql/IColumnType;
public final fun getPath ()[Ljava/lang/String;
public final fun getToScalar ()Z
public fun toQueryBuilder (Lorg/jetbrains/exposed/sql/QueryBuilder;)V
}

public final class org/jetbrains/exposed/sql/Key {
public fun <init> ()V
}
Expand Down Expand Up @@ -2015,9 +1962,6 @@ public final class org/jetbrains/exposed/sql/SqlExpressionBuilder : org/jetbrain
public fun isNotDistinctFromEntityID (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/IsNotDistinctFromOp;
public fun isNotNull (Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/IsNotNullOp;
public fun isNull (Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/IsNullOp;
public fun jsonContains (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Object;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/JsonContains;
public fun jsonContains (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/JsonContains;
public fun jsonExists (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;[Ljava/lang/String;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/JsonExists;
public fun lag (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/Lag;
public fun lastValue (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/LastValue;
public fun lead (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/Lead;
Expand Down Expand Up @@ -2122,9 +2066,6 @@ public class org/jetbrains/exposed/sql/SqlExpressionBuilderClass : org/jetbrains
public fun isNotDistinctFromEntityID (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/IsNotDistinctFromOp;
public fun isNotNull (Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/IsNotNullOp;
public fun isNull (Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/IsNullOp;
public fun jsonContains (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Object;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/JsonContains;
public fun jsonContains (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/JsonContains;
public fun jsonExists (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;[Ljava/lang/String;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/JsonExists;
public fun lag (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/Lag;
public fun lastValue (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/LastValue;
public fun lead (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/Lead;
Expand Down Expand Up @@ -2305,8 +2246,6 @@ public class org/jetbrains/exposed/sql/Table : org/jetbrains/exposed/sql/ColumnS
public fun innerJoin (Lorg/jetbrains/exposed/sql/ColumnSet;)Lorg/jetbrains/exposed/sql/Join;
public final fun integer (Ljava/lang/String;)Lorg/jetbrains/exposed/sql/Column;
public fun join (Lorg/jetbrains/exposed/sql/ColumnSet;Lorg/jetbrains/exposed/sql/JoinType;Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/Expression;Lkotlin/jvm/functions/Function1;)Lorg/jetbrains/exposed/sql/Join;
public final fun json (Ljava/lang/String;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lorg/jetbrains/exposed/sql/Column;
public final fun jsonb (Ljava/lang/String;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lorg/jetbrains/exposed/sql/Column;
public final fun largeText (Ljava/lang/String;Ljava/lang/String;Z)Lorg/jetbrains/exposed/sql/Column;
public static synthetic fun largeText$default (Lorg/jetbrains/exposed/sql/Table;Ljava/lang/String;Ljava/lang/String;ZILjava/lang/Object;)Lorg/jetbrains/exposed/sql/Column;
public fun leftJoin (Lorg/jetbrains/exposed/sql/ColumnSet;)Lorg/jetbrains/exposed/sql/Join;
Expand Down
3 changes: 0 additions & 3 deletions exposed-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import org.jetbrains.exposed.gradle.Versions

plugins {
kotlin("jvm") apply true
kotlin("plugin.serialization") apply true
}

repositories {
Expand All @@ -13,7 +12,5 @@ dependencies {
api(kotlin("stdlib"))
api(kotlin("reflect"))
api("org.jetbrains.kotlinx", "kotlinx-coroutines-core", Versions.kotlinCoroutines)
api("org.jetbrains.kotlinx", "kotlinx-serialization-json", Versions.kotlinxSerialization)
api("org.postgresql", "postgresql", Versions.postgre)
api("org.slf4j", "slf4j-api", "1.7.25")
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import org.jetbrains.exposed.sql.statements.DefaultValueMarker
import org.jetbrains.exposed.sql.statements.api.ExposedBlob
import org.jetbrains.exposed.sql.statements.api.PreparedStatementApi
import org.jetbrains.exposed.sql.vendors.*
import org.postgresql.util.PGobject
import java.io.InputStream
import java.math.BigDecimal
import java.math.MathContext
Expand Down Expand Up @@ -926,67 +925,6 @@ class CustomEnumerationColumnType<T : Enum<T>>(
override fun nonNullValueToString(value: Any): String = super.nonNullValueToString(notNullValueToDB(value))
}

// JSON columns

/**
* Column for storing JSON data, either in non-binary text format or the vendor's default JSON type format.
*/
open class JsonColumnType<T : Any>(
/** Returns the function that encodes an object of type [T] to a JSON String. */
val serialize: (T) -> String,
/** Returns the function that decodes a JSON String to an object of type [T]. */
val deserialize: (String) -> T
) : ColumnType() {
override fun sqlType(): String = currentDialect.dataTypeProvider.jsonType()

override fun valueFromDB(value: Any): Any {
return when (value) {
is String -> deserialize(value)
is PGobject -> deserialize(value.value!!)
is ByteArray -> deserialize(value.decodeToString())
else -> value
}
}

@Suppress("UNCHECKED_CAST")
override fun notNullValueToDB(value: Any) = serialize(value as T)

override fun nonNullValueToString(value: Any): String {
return when (currentDialect) {
is H2Dialect -> "JSON '${notNullValueToDB(value)}'"
else -> super.nonNullValueToString(value)
}
}

override fun setParameter(stmt: PreparedStatementApi, index: Int, value: Any?) {
val parameterValue = when (currentDialect) {
is PostgreSQLDialect -> PGobject().apply {
type = sqlType()
this.value = value as String?
}
is H2Dialect -> (value as String).encodeToByteArray()
else -> value
}
super.setParameter(stmt, index, parameterValue)
}
}

/**
* Column for storing JSON data in binary format.
*
* @param serialize Function that encodes an object of type [T] to a JSON String
* @param deserialize Function that decodes a JSON String to an object of type [T]
*/
class JsonBColumnType<T : Any>(
serialize: (T) -> String,
deserialize: (String) -> T
) : JsonColumnType<T>(serialize, deserialize) {
override fun sqlType(): String = when (currentDialect) {
is H2Dialect -> H2DataTypeProvider.jsonBType()
else -> currentDialect.dataTypeProvider.jsonBType()
}
}

// Date/Time columns

/**
Expand Down
21 changes: 0 additions & 21 deletions exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Function.kt
Original file line number Diff line number Diff line change
Expand Up @@ -335,27 +335,6 @@ class VarSamp<T>(
}
}

// JSON Functions

/**
* Represents an SQL function that returns extracted data from a JSON object at the specified [path],
* either as a JSON representation or as a scalar value.
*/
class JsonExtract<T>(
/** Returns the expression from which to extract JSON subcomponents matched by [path]. */
val expression: Expression<*>,
/** Returns array of Strings representing JSON path/keys that match fields to be extracted. */
vararg val path: String,
/** Returns whether the extracted result should be a scalar or text value; if `false`, result will be a JSON object. */
val toScalar: Boolean,
/** Returns the column type of [expression] to check, if casting to JSONB is required. */
val jsonType: IColumnType,
columnType: IColumnType
) : Function<T>(columnType) {
override fun toQueryBuilder(queryBuilder: QueryBuilder) =
currentDialect.functionProvider.jsonExtract(expression, path = path, toScalar, jsonType, queryBuilder)
}

// Sequence Manipulation Functions

/**
Expand Down
36 changes: 0 additions & 36 deletions exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Op.kt
Original file line number Diff line number Diff line change
Expand Up @@ -548,42 +548,6 @@ class RegexpOp<T : String?>(
}
}

// JSON Conditions

/**
* Represents an SQL operator that checks whether a [candidate] expression is contained within a JSON [target].
*/
class JsonContains(
/** Returns the JSON expression being searched. */
val target: Expression<*>,
/** Returns the expression being searched for in [target]. */
val candidate: Expression<*>,
/** Returns an optional String representing JSON path/keys that match specific fields to search for [candidate]. */
val path: String?,
/** Returns the column type of [target] to check, if casting to JSONB is required. */
val jsonType: IColumnType
) : Op<Boolean>(), ComplexExpression, Op.OpBoolean {
override fun toQueryBuilder(queryBuilder: QueryBuilder) =
currentDialect.functionProvider.jsonContains(target, candidate, path, jsonType, queryBuilder)
}

/**
* Represents an SQL operator that checks whether data exists within a JSON [expression] at the specified [path].
*/
class JsonExists(
/** Returns the JSON expression being checked. */
val expression: Expression<*>,
/** Returns the array of Strings representing JSON path/keys that match fields to check for existing data. */
vararg val path: String,
/** Returns an optional String representing any vendor-specific clause or argument. */
val optional: String?,
/** Returns the column type of [expression] to check, if casting to JSONB is required. */
val jsonType: IColumnType
) : Op<Boolean>(), ComplexExpression, Op.OpBoolean {
override fun toQueryBuilder(queryBuilder: QueryBuilder) =
currentDialect.functionProvider.jsonExists(expression, path = path, optional, jsonType, queryBuilder)
}

// Subquery Expressions

/**
Expand Down
Loading

0 comments on commit 3a947a3

Please sign in to comment.