-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
implement postgres timestamptz, int[], text[], jsonb columns
- Loading branch information
Juan Liska
authored and
Juan Liska
committed
Nov 4, 2018
1 parent
c287546
commit b2caebc
Showing
13 changed files
with
235 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package org.jetbrains.squash.definition | ||
|
||
data class Json(val json: String?) |
54 changes: 48 additions & 6 deletions
54
squash-postgres/src/org/jetbrains/squash/dialects/postgres/PgDataConversion.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,63 @@ | ||
package org.jetbrains.squash.dialects.postgres | ||
|
||
import org.jetbrains.squash.drivers.* | ||
import org.jetbrains.squash.definition.Json | ||
import org.jetbrains.squash.drivers.JDBCDataConversion | ||
import org.jetbrains.squash.drivers.JDBCResponseColumn | ||
import org.postgresql.util.PGobject | ||
import java.sql.Connection | ||
import java.sql.ResultSet | ||
import java.time.OffsetDateTime | ||
import kotlin.reflect.KClass | ||
|
||
class PgDataConversion : JDBCDataConversion() { | ||
override fun convertValueToDatabase(value: Any?): Any? { | ||
return when (value) { | ||
value is OffsetDateTime -> value | ||
else -> super.convertValueToDatabase(value) | ||
override fun convertValueToDatabase(value: Any?, connection: Connection): Any? { | ||
return when { | ||
value is OffsetDateTime -> { value } | ||
Array<Int>::class.isInstance(value) -> { | ||
val typedArray = value as Array<Int> | ||
connection.createArrayOf("int4", typedArray) | ||
} | ||
Array<String>::class.isInstance(value) -> { | ||
val typedArray = value as Array<String> | ||
connection.createArrayOf("text", typedArray) | ||
} | ||
Json::class.isInstance(value) -> { | ||
val json = value as Json | ||
PGobject().apply { | ||
this.type = "json" | ||
this.value = json.json | ||
} | ||
} | ||
else -> super.convertValueToDatabase(value, connection) | ||
} | ||
} | ||
|
||
override fun convertValueFromDatabase(value: Any?, type: KClass<*>): Any? { | ||
return when (value) { | ||
value is OffsetDateTime -> value | ||
type == java.time.OffsetDateTime::class && value is java.time.OffsetDateTime -> { value } | ||
type == kotlin.Array<Int>::class && value is java.sql.Array -> { | ||
val array = value as java.sql.Array | ||
array.array as Array<Int> | ||
} | ||
type == kotlin.Array<String>::class && value is java.sql.Array -> { | ||
val array = value as java.sql.Array | ||
array.array as Array<String> | ||
} | ||
type == Json::class && value is Json -> { | ||
val json = value as Json | ||
json.json | ||
} | ||
else -> super.convertValueFromDatabase(value, type) | ||
} | ||
} | ||
|
||
override fun fetch(resultSet: ResultSet, dbColumnIndex: Int, column: JDBCResponseColumn): Any? { | ||
return when (column.databaseType) { | ||
"_int4" -> resultSet.getArray(dbColumnIndex)?.array as Array<Int>? | ||
"_text" -> resultSet.getArray(dbColumnIndex)?.array as Array<String>? | ||
"timestamptz" -> resultSet.getObject(dbColumnIndex, OffsetDateTime::class.java) | ||
"json" -> Json(resultSet.getString(dbColumnIndex)) | ||
else -> super.fetch(resultSet, dbColumnIndex, column) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 4 additions & 0 deletions
4
squash-postgres/src/org/jetbrains/squash/expressions/PgExpression.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package org.jetbrains.squash.expressions | ||
|
||
class ArrayInExpression<out V>(val value: Expression<V>, val values: Collection<V>) : Expression<Boolean> | ||
class ArrayOverlapExpression<out V>(val value: Expression<V>, val values: Collection<V>) : Expression<Boolean> |
4 changes: 4 additions & 0 deletions
4
squash-postgres/src/org/jetbrains/squash/expressions/PgExpressionBuilder.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package org.jetbrains.squash.expressions | ||
|
||
infix fun <V> Expression<V>.contains(values: Collection<V>): ArrayInExpression<V> = ArrayInExpression(this, values) | ||
infix fun <V> Expression<V>.containsAny(values: Collection<V>): ArrayOverlapExpression<V> = ArrayOverlapExpression(this, values) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 14 additions & 0 deletions
14
squash-postgres/test/org/jetbrains/squash/dialects/postgres/tests/PgDialectColumnTypes.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package org.jetbrains.squash.dialects.postgres.tests | ||
|
||
import org.jetbrains.squash.definition.* | ||
|
||
object PgDialectColumnTypes : TableDefinition() { | ||
val id = integer("id").autoIncrement().primaryKey() | ||
val offsetdatetime = offsetDatetime("offsetdatetime") | ||
val notnullIntarray = intArray("intarray") | ||
val nullableIntarray = intArray("nullable_intarray").nullable() | ||
val notnullTextarray = textArray("textarray") | ||
val nullableTextarray = textArray("nullable_textarray").nullable() | ||
val notnullJsonb = jsonb("notnull_jsonb") | ||
val nullableJsonb = jsonb("nullable_jsonb").nullable() | ||
} |
89 changes: 89 additions & 0 deletions
89
...h-postgres/test/org/jetbrains/squash/dialects/postgres/tests/PgDialectColumnTypesTests.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package org.jetbrains.squash.dialects.postgres.tests | ||
|
||
import org.jetbrains.squash.connection.Transaction | ||
import org.jetbrains.squash.definition.IntColumnType | ||
import org.jetbrains.squash.definition.Json | ||
import org.jetbrains.squash.expressions.contains | ||
import org.jetbrains.squash.expressions.containsAny | ||
import org.jetbrains.squash.query.from | ||
import org.jetbrains.squash.query.where | ||
import org.jetbrains.squash.results.ResultRow | ||
import org.jetbrains.squash.results.get | ||
import org.jetbrains.squash.statements.insertInto | ||
import org.jetbrains.squash.statements.values | ||
import org.jetbrains.squash.tests.DatabaseTests | ||
import java.time.OffsetDateTime | ||
import java.time.ZoneOffset | ||
import java.util.* | ||
import kotlin.test.Test | ||
import kotlin.test.assertEquals | ||
import kotlin.test.assertNull | ||
import kotlin.test.assertTrue | ||
|
||
class PgDialectColumnTypesTests: DatabaseTests by PgDatabaseTests() { | ||
private val dialectColumnsTableSQL: String get() = "CREATE TABLE IF NOT EXISTS PgDialectColumnTypes (" + | ||
"id ${getIdColumnType(IntColumnType)}, " + | ||
"offsetdatetime TIMESTAMP WITH TIME ZONE NOT NULL, " + | ||
"intarray INT[] NOT NULL, " + | ||
"nullable_intarray INT[] NULL, " + | ||
"textarray TEXT[] NOT NULL, " + | ||
"nullable_textarray TEXT[] NULL, " + | ||
"notnull_jsonb JSONB NOT NULL, " + | ||
"nullable_jsonb JSONB NULL, " + | ||
"CONSTRAINT PK_PgDialectColumnTypes PRIMARY KEY (id))" | ||
|
||
@Test fun sql() { | ||
withTransaction { | ||
connection.dialect.definition.tableSQL(PgDialectColumnTypes).assertSQL { dialectColumnsTableSQL } | ||
} | ||
} | ||
|
||
@Test fun insert() { | ||
withTables(PgDialectColumnTypes) { | ||
insertData() | ||
} | ||
} | ||
|
||
private val offsetDate = OffsetDateTime.of(1976, 11, 24, 12, 1, 1, 0, ZoneOffset.ofHours(-6)) | ||
private val arrayOfInt = arrayOf(1, 2, 3, 4) | ||
private val arrayOfString = arrayOf("see", "spot", "run") | ||
private val jsonb = Json("{}") | ||
|
||
@Test fun query() { | ||
withTables(PgDialectColumnTypes) { | ||
insertData() | ||
|
||
fun checkRow(row: ResultRow) { | ||
assertEquals(OffsetDateTime::class.java, row[PgDialectColumnTypes.offsetdatetime].javaClass) | ||
assertEquals(offsetDate.toEpochSecond(), row[PgDialectColumnTypes.offsetdatetime].toEpochSecond()) | ||
|
||
assertEquals(Array<Int>::class.java, row[PgDialectColumnTypes.notnullIntarray].javaClass) | ||
assertTrue { Arrays.equals(arrayOfInt, row[PgDialectColumnTypes.notnullIntarray]) } | ||
|
||
assertEquals(Array<String>::class.java, row[PgDialectColumnTypes.notnullTextarray].javaClass) | ||
assertTrue { Arrays.equals(arrayOfString, row[PgDialectColumnTypes.notnullTextarray]) } | ||
} | ||
|
||
val containsRow = from(PgDialectColumnTypes).where { PgDialectColumnTypes.notnullIntarray contains arrayOfInt.take(2) }.execute().single() | ||
checkRow(containsRow) | ||
|
||
val containsAnyRow = from(PgDialectColumnTypes).where { PgDialectColumnTypes.notnullTextarray containsAny listOf(arrayOfString.first(), "other")}.execute().single() | ||
checkRow(containsAnyRow) | ||
|
||
val noRow = from(PgDialectColumnTypes).where { PgDialectColumnTypes.notnullIntarray contains listOf(9) }.execute().singleOrNull() | ||
assertNull(noRow) | ||
} | ||
} | ||
|
||
private fun Transaction.insertData() { | ||
insertInto(PgDialectColumnTypes).values { | ||
it[offsetdatetime] = offsetDate | ||
it[notnullIntarray] = arrayOfInt | ||
it[nullableIntarray] = null | ||
it[notnullTextarray] = arrayOfString | ||
it[nullableTextarray] = arrayOfString | ||
it[notnullJsonb] = jsonb | ||
it[nullableJsonb] = null | ||
}.execute() | ||
} | ||
} |