Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -310,26 +310,12 @@ open class PgSession(
}
}

private var isTransactionStored = false
private fun saveTransactionIntoDb(create: Boolean = false) {
// FIXME instead of create/update we can use upsert when ready
if (isTransactionStored && create) {
return
} else if (isTransactionStored) {
val updateTxReq = WriteRequest()
val updateTx = Write()
updateTxReq.add(updateTx)
updateTx.updateFeature(null, VIRT_TRANSACTIONS, transaction())
// FIXME uncomment when counts and update ready
// PgWriter(this, updateTxReq).execute()
} else {
val writeTxReq = WriteRequest()
val writeTx = Write()
writeTxReq.add(writeTx)
writeTx.createFeature(null, VIRT_TRANSACTIONS, transaction())
PgWriter(this, writeTxReq, InstantWriteExecutor(this)).execute()
isTransactionStored = true
}
private fun saveTransactionIntoDb() {
val writeTxReq = WriteRequest()
val writeTx = Write()
writeTxReq.add(writeTx)
writeTx.upsertFeature(null, VIRT_TRANSACTIONS, transaction())
PgWriter(this, writeTxReq, InstantWriteExecutor(this)).execute()
}

/**
Expand Down Expand Up @@ -363,7 +349,7 @@ open class PgSession(
val tx = transaction
if (tx != null) {
try {
saveTransactionIntoDb(true)
saveTransactionIntoDb()
} catch (e: Throwable) {
throw NakshaException(EXCEPTION, "Failed to save transaction", cause = e)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ class PgWriter(

// If everything was done perfectly, fine.
val tupleNumberByteArray = TupleNumberByteArray(storage, tupleNumbers.toByteArray())
session.transaction().featuresModified += tupleNumbers.size
return SuccessResponse(
PgResultSet(
storage,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
package naksha.psql

import naksha.geo.PointCoord
import naksha.geo.SpGeometry
import naksha.model.Naksha.NakshaCompanion.VIRT_COLLECTIONS
import naksha.model.request.ReadCollections
import naksha.model.request.ReadFeatures
import naksha.model.request.RequestQuery
import naksha.model.request.query.*
import naksha.model.request.query.StringOp.QStringOpCompanion.EQUALS
import naksha.model.request.query.TupleColumn.TupleColumn_C.ID
import naksha.model.request.query.TupleColumn.TupleColumn_C.UID
import naksha.psql.base.PgTestBase
import naksha.psql.executors.query.PgQueryBuilder
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue

@Suppress("UNCHECKED_CAST")
class PgQueryBuilderTest : PgTestBase() {

private val session = storage.newReadSession() as PgSession

@Test
fun testReadNoConditions() {
// given
val req = ReadFeatures().apply { collectionIds += "foo" }

// when

val query = PgQueryBuilder(session, req).build()

// then
assertEquals(0, query.argValues.size)
assertEquals(
"""
SELECT gzip(bytea_agg(tuple_number)) AS rs FROM (SELECT tuple_number FROM (
(SELECT tuple_number, id FROM foo)
) ORDER BY id, tuple_number) LIMIT 1000000;
""".trimIndent(), query.sql.trimIndent()
)
}

@Test
fun testReadMultipleCollections() {
// given
val req = ReadFeatures().apply {
collectionIds += "foo1"
collectionIds += "foo2"
}

// when
val query = PgQueryBuilder(session, req).build()

// then
assertEquals(0, query.argValues.size)
assertEquals(
"""
SELECT gzip(bytea_agg(tuple_number)) AS rs FROM (SELECT tuple_number FROM (
(SELECT tuple_number, id FROM foo1) UNION ALL
(SELECT tuple_number, id FROM foo2)
) ORDER BY id, tuple_number) LIMIT 1000000;
""".trimIndent(), query.sql.trimIndent()
)
}

@Test
fun testReadById() {
// given
val req = ReadFeatures().apply {
collectionIds += "foo"
featureIds += "f1"
}

// when
val query = PgQueryBuilder(session, req).build()

// then
assertEquals(1, query.argValues.size)
assertEquals("f1", (query.argValues[0] as Array<String>)[0])
assertEquals(
"""(SELECT tuple_number, id FROM foo WHERE id = ANY($1))""",
removeLimitWrapper(query.sql)
)
}

@Test
fun testReadWithOr() {
// given
val req = ReadFeatures().apply {
collectionIds += "foo"
featureIds += "f1"
featureIds += "f2"
}

// when
val query = PgQueryBuilder(session, req).build()

// then
assertEquals(1, query.argValues.size)
assertTrue(arrayOf("f1", "f2") contentEquals (query.argValues[0] as Array<String>))
assertEquals(
"""(SELECT tuple_number, id FROM foo WHERE id = ANY($1))""",
removeLimitWrapper(query.sql)
)
}

// TODO FIXME uncomment me once property read is ready (CASL-473).
// @Test
fun testReadWithAnd() {
// given
val req = ReadFeatures().apply {
collectionIds += "foo"
query = RequestQuery().apply {
properties = POr(
PQuery(Property(ID), EQUALS, "f1"),
PAnd(
PQuery(Property(ID), EQUALS, "f2"),
PQuery(Property(UID), DoubleOp.LT, 2.0)
)
)
}
}

// when
val query = PgQueryBuilder(session, req).build()

// then
assertEquals(0, query.argValues.size)
assertEquals(
"""((SELECT tuple_number, id FROM foo WHERE (id=$1 OR (id=$2 AND uid<$3)))""",
removeLimitWrapper(query.sql)
)
}

@Test
fun testReadHistory() {
// given
val req = ReadFeatures().apply {
collectionIds += "foo"
queryHistory = true
}

// when
val query = PgQueryBuilder(session, req).build()


// then
assertEquals(
"""
(SELECT tuple_number, id FROM foo) UNION ALL
(SELECT tuple_number, id FROM "foo${'$'}hst")
""".trimIndent(), removeLimitWrapper(query.sql)
)
}

@Test
fun testReadWithHistoryAndDel() {
// given
val req = ReadFeatures().apply {
collectionIds += "foo"
featureIds += "f1"
queryHistory = true
queryDeleted = true
}

// when
val query = PgQueryBuilder(session, req).build()


// then
assertEquals(
"""
(SELECT tuple_number, id FROM foo WHERE id = ANY(${'$'}1)) UNION ALL
(SELECT tuple_number, id FROM "foo${'$'}del" WHERE id = ANY($1)) UNION ALL
(SELECT tuple_number, id FROM "foo${'$'}hst" WHERE id = ANY($1))
""".trimIndent(), removeLimitWrapper(query.sql)
)
}


@Test
fun testReadBySpatial() {
// given
val req = ReadFeatures().apply {
collectionIds += "foo"
query = RequestQuery().apply {
spatial = SpIntersects(SpGeometry(PointCoord(1.0, 1.0, 1.0)))
}
}

// when
val query = PgQueryBuilder(session, req).build()

// then
assertEquals(
"""(SELECT tuple_number, id FROM foo WHERE (ST_Intersects(naksha_geometry(geo, flags), naksha_geometry($1, 0))))""",
removeLimitWrapper(query.sql)
)
}

@Test
fun testReadBySpatialWithBuffer() {
// given
val geometryTransformation = SpBuffer(22.2, geography = true)
val req = ReadFeatures().apply {
collectionIds += "foo"
query = RequestQuery().apply {
spatial = SpIntersects(SpGeometry(PointCoord(1.0, 1.0, 1.0)), geometryTransformation)
}
}

// when
val query = PgQueryBuilder(session, req).build()

// then
assertEquals(
"""(SELECT tuple_number, id FROM foo WHERE (ST_Intersects(naksha_geometry(geo, flags), ST_Buffer(naksha_geometry($1, 0)::geography, $2))))""",
removeLimitWrapper(query.sql)
)
}

@Test
fun testReadAllCollections() {
// given
val req = ReadCollections()

// when
val query = PgQueryBuilder(session, req).build()

// then
assertEquals(0, query.argValues.size)
assertEquals(
"""(SELECT tuple_number, id FROM "$VIRT_COLLECTIONS")""",
removeLimitWrapper(query.sql)
)
}

@Test
fun testTagsQuery() {
// given
val req = ReadFeatures().apply {
collectionIds += "foo"
query = RequestQuery().apply {
tags = TagExists("stg")
}
}

// when
val query = PgQueryBuilder(session, req).build()

// then
assertEquals(1, query.argValues.size)
assertEquals(
"""(SELECT tuple_number, id FROM foo WHERE (naksha_tags(tags, flags) ?? $1))""",
removeLimitWrapper(query.sql)
)
}


private fun removeLimitWrapper(sql: String) =
sql.replace("SELECT gzip(bytea_agg(tuple_number)) AS rs FROM (SELECT tuple_number FROM (\n", "")
.replace("\n) ORDER BY id, tuple_number) LIMIT 1000000;", "")
.trimIndent()
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
package naksha.psql

import kotlinx.datetime.Clock.System.now
import kotlinx.datetime.TimeZone.Companion.currentSystemDefault
import kotlinx.datetime.toLocalDateTime
import naksha.model.Naksha
import naksha.model.NakshaCache
import naksha.model.objects.NakshaCollection
import naksha.model.objects.NakshaFeature
import naksha.model.objects.Transaction
import naksha.model.request.ReadFeatures
import naksha.model.request.SuccessResponse
import naksha.model.request.Write
import naksha.model.request.WriteRequest
import naksha.psql.base.PgTestBase
import naksha.psql.util.ProxyFeatureGenerator.generateRandomFeature
import kotlin.test.AfterTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlin.test.assertTrue

class TransactionsTest : PgTestBase(NakshaCollection("transaction_test")) {

Expand Down Expand Up @@ -43,4 +41,51 @@ class TransactionsTest : PgTestBase(NakshaCollection("transaction_test")) {
// then
assertEquals(savedFeatureVersion, readResponse.tuples[0]?.tuple?.meta?.version)
}

@Test
fun updateTrasactionInfoOnMultipleWrites() {
// given
val feature1 = NakshaFeature("f2")
val writeRequest1 = WriteRequest().apply { add(Write().createFeature(map = null, collection!!.id, feature1)) }

val feature2 = NakshaFeature("f3")
val writeRequest2 = WriteRequest().apply { add(Write().createFeature(map = null, collection!!.id, feature2)) }

val writeSession = env.storage.newWriteSession(null)

// when
assertIs<SuccessResponse>(writeSession.execute(writeRequest1))

// then
assertEquals(1, writeSession.transaction().featuresModified)

// when
val value = writeSession.execute(writeRequest2)
assertIs<SuccessResponse>(value)

// then
assertEquals(2, writeSession.transaction().featuresModified)
}

@Test
fun shouldBeAbleToTagTransaction() {
// given
val feature = NakshaFeature("f40")
val writeRequest = WriteRequest().apply { add(Write().createFeature(map = null, collection!!.id, feature)) }

val writeSession = env.storage.newWriteSession(null)

// when
writeSession.transaction().properties.xyz.addTag("sth", false)
assertIs<SuccessResponse>(writeSession.execute(writeRequest))
val transactionId = writeSession.transaction().id
writeSession.commit()

// then
val readRequest = ReadFeatures(Naksha.VIRT_TRANSACTIONS).apply {
featureIds += transactionId
}
val readResponse = storage.newReadSession().execute(readRequest) as SuccessResponse
assertTrue(readResponse.features[0]!!.properties.xyz.tags!!.contains("sth"))
}
}
Loading
Loading