From 6bd7f7a8d5a462f0b4abec728a9b5f14e80cf754 Mon Sep 17 00:00:00 2001 From: Massimo Siani Date: Wed, 10 Jan 2024 16:26:43 +0100 Subject: [PATCH 1/3] Add merge completion case --- .../src/main/scala/data/Completion.scala | 1 + .../scala/net/message/CommandComplete.scala | 2 ++ .../shared/src/test/scala/CommandTest.scala | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+) diff --git a/modules/core/shared/src/main/scala/data/Completion.scala b/modules/core/shared/src/main/scala/data/Completion.scala index 70fdbf51..44e6f849 100644 --- a/modules/core/shared/src/main/scala/data/Completion.scala +++ b/modules/core/shared/src/main/scala/data/Completion.scala @@ -64,6 +64,7 @@ object Completion { case object Grant extends Completion case object Revoke extends Completion case object AlterIndex extends Completion + case class Merge(count: Int) extends Completion // more ... /** diff --git a/modules/core/shared/src/main/scala/net/message/CommandComplete.scala b/modules/core/shared/src/main/scala/net/message/CommandComplete.scala index 7bdcaaad..d759399a 100644 --- a/modules/core/shared/src/main/scala/net/message/CommandComplete.scala +++ b/modules/core/shared/src/main/scala/net/message/CommandComplete.scala @@ -41,6 +41,7 @@ object CommandComplete { val Update: Regex = """UPDATE (\d+)""".r val Insert: Regex = """INSERT (\d+ \d+)""".r val Copy: Regex = """COPY (\d+)""".r + val Merge: Regex = """MERGE (\d+)""".r } //TODO: maybe make lazy val @@ -102,6 +103,7 @@ object CommandComplete { case "GRANT" => apply(Completion.Grant) case "REVOKE" => apply(Completion.Revoke) case "ALTER INDEX" => apply(Completion.AlterIndex) + case Patterns.Merge(s) => apply(Completion.Merge(s.toInt)) // more .. fill in as we hit them case s => apply(Completion.Unknown(s)) diff --git a/modules/tests/shared/src/test/scala/CommandTest.scala b/modules/tests/shared/src/test/scala/CommandTest.scala index 96458e14..bfcd029d 100644 --- a/modules/tests/shared/src/test/scala/CommandTest.scala +++ b/modules/tests/shared/src/test/scala/CommandTest.scala @@ -94,6 +94,13 @@ class CommandTest extends SkunkTest { WHERE id = $int4 """.command + val mergeCity: Command[Int] = + sql""" + MERGE INTO city + USING (VALUES ($int4)) t(city_id) ON t.city_id = city.id + WHEN MATCHED THEN DELETE + """.command + val createTable: Command[Void] = sql""" CREATE TABLE IF NOT EXISTS earth ( @@ -524,6 +531,18 @@ class CommandTest extends SkunkTest { } yield "ok" } + sessionTest("merge a record") { s => + for { + c <- s.prepare(insertCity).flatMap(_.execute(Garin)) + _ <- assert("completion", c == Completion.Insert(1)) + c <- s.prepare(mergeCity).flatMap(_.execute(Garin.id)) + _ <- assert("merge", c == Completion.Merge(1)) + c <- s.prepare(selectCity).flatMap(_.option(Garin.id)) + _ <- assert("read", c == None) + _ <- s.assertHealthy + } yield "ok" + } + sessionTest("pipe") { s => for { _ <- s.execute(sql"delete from city where name like 'Pipe%'".command) From b90205f1d74010f951f7a18e978e0a845c69f66e Mon Sep 17 00:00:00 2001 From: Massimo Siani Date: Thu, 11 Jan 2024 23:50:23 +0100 Subject: [PATCH 2/3] avoid failure testing merge if not supported --- bin/local | 2 +- modules/tests/shared/src/test/scala/CommandTest.scala | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/bin/local b/bin/local index d36bb84d..3e5f2800 100755 --- a/bin/local +++ b/bin/local @@ -28,4 +28,4 @@ esac export SERVER_KEY=$(cat world/server.key) export SERVER_CERT=$(cat world/server.crt) -docker-compose $CMD $EXTRA_FLAGS +docker compose $CMD $EXTRA_FLAGS diff --git a/modules/tests/shared/src/test/scala/CommandTest.scala b/modules/tests/shared/src/test/scala/CommandTest.scala index bfcd029d..79b8fce4 100644 --- a/modules/tests/shared/src/test/scala/CommandTest.scala +++ b/modules/tests/shared/src/test/scala/CommandTest.scala @@ -532,15 +532,19 @@ class CommandTest extends SkunkTest { } sessionTest("merge a record") { s => - for { + (for { c <- s.prepare(insertCity).flatMap(_.execute(Garin)) _ <- assert("completion", c == Completion.Insert(1)) c <- s.prepare(mergeCity).flatMap(_.execute(Garin.id)) _ <- assert("merge", c == Completion.Merge(1)) c <- s.prepare(selectCity).flatMap(_.option(Garin.id)) _ <- assert("read", c == None) + _ <- s.execute(deleteCity)(Garin.id) _ <- s.assertHealthy - } yield "ok" + } yield "ok") + .recoverWith { + case SqlState.SyntaxError(ex) if ex.message.startsWith("""Syntax error at or near "MERGE"""") => s.execute(deleteCity)(Garin.id).as("ok") + } } sessionTest("pipe") { s => From 6d943be0f26e09d3ed3dc867f93680b5d77cbce3 Mon Sep 17 00:00:00 2001 From: Massimo Siani Date: Fri, 12 Jan 2024 09:36:32 +0100 Subject: [PATCH 3/3] the merge test should only run if the pg version is 15 or greater --- .../shared/src/test/scala/CommandTest.scala | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/modules/tests/shared/src/test/scala/CommandTest.scala b/modules/tests/shared/src/test/scala/CommandTest.scala index 79b8fce4..3e7b5f47 100644 --- a/modules/tests/shared/src/test/scala/CommandTest.scala +++ b/modules/tests/shared/src/test/scala/CommandTest.scala @@ -532,18 +532,22 @@ class CommandTest extends SkunkTest { } sessionTest("merge a record") { s => - (for { - c <- s.prepare(insertCity).flatMap(_.execute(Garin)) - _ <- assert("completion", c == Completion.Insert(1)) - c <- s.prepare(mergeCity).flatMap(_.execute(Garin.id)) - _ <- assert("merge", c == Completion.Merge(1)) - c <- s.prepare(selectCity).flatMap(_.option(Garin.id)) - _ <- assert("read", c == None) - _ <- s.execute(deleteCity)(Garin.id) - _ <- s.assertHealthy - } yield "ok") - .recoverWith { - case SqlState.SyntaxError(ex) if ex.message.startsWith("""Syntax error at or near "MERGE"""") => s.execute(deleteCity)(Garin.id).as("ok") + s.unique(sql"SHOW server_version".query(skunk.codec.all.text)) + .flatMap { version => + val majorVersion = version.substring(0, 2).toInt + if (majorVersion >= 15) { + for { + c <- s.prepare(insertCity).flatMap(_.execute(Garin)) + _ <- assert("completion", c == Completion.Insert(1)) + c <- s.prepare(mergeCity).flatMap(_.execute(Garin.id)) + _ <- assert("merge", c == Completion.Merge(1)) + c <- s.prepare(selectCity).flatMap(_.option(Garin.id)) + _ <- assert("read", c == None) + _ <- s.execute(deleteCity)(Garin.id) + _ <- s.assertHealthy + } yield "ok" + } + else IO.pure("skip") } }