diff --git a/src/scala/src/test/scala/integration/JsonDocument.scala b/src/scala/src/test/scala/integration/JsonDocument.scala index 899409d..b5ef2e7 100644 --- a/src/scala/src/test/scala/integration/JsonDocument.scala +++ b/src/scala/src/test/scala/integration/JsonDocument.scala @@ -17,3 +17,18 @@ object JsonDocument: def load(db: ThrowawayDatabase, tableName: String = TEST_TABLE): Unit = testDocuments.foreach { it => db.conn.insert(tableName, it) } + + /** Document ID `one` as a JSON string */ + val one = """{"id":"one","value":"FIRST!","numValue":0,"sub":null}""" + + /** Document ID `two` as a JSON string */ + val two = """{"id":"two","value":"another","numValue":10,"sub":{"foo":"green","bar":"blue"}}""" + + /** Document ID `three` as a JSON string */ + val three = """{"id":"three","value":"","numValue":4,"sub":null}""" + + /** Document ID `four` as a JSON string */ + val four = """{"id":"four","value":"purple","numValue":17,"sub":{"foo":"green","bar":"red"}}""" + + /** Document ID `five` as a JSON string */ + val five = """{"id":"five","value":"purple","numValue":18,"sub":null}""" diff --git a/src/scala/src/test/scala/integration/JsonFunctions.scala b/src/scala/src/test/scala/integration/JsonFunctions.scala index a8cfc97..938b064 100644 --- a/src/scala/src/test/scala/integration/JsonFunctions.scala +++ b/src/scala/src/test/scala/integration/JsonFunctions.scala @@ -1,7 +1,21 @@ package solutions.bitbadger.documents.scala.tests.integration -import solutions.bitbadger.documents.{Configuration, Dialect} +import org.junit.jupiter.api.Assertions.* +import solutions.bitbadger.documents.{Configuration, Dialect, Field, FieldMatch} +import solutions.bitbadger.documents.scala.extensions.* +import solutions.bitbadger.documents.scala.tests.TEST_TABLE +import scala.jdk.CollectionConverters.* + +/** + * Tests for the JSON-returning functions + * + * NOTE: PostgreSQL JSONB columns do not preserve the original JSON with which a document was stored. These tests are + * the most complex within the library, as they have split testing based on the backing data store. The PostgreSQL tests + * check IDs (and, in the case of ordered queries, which ones occur before which others) vs. the entire JSON string. + * Meanwhile, SQLite stores JSON as text, and will return exactly the JSON it was given when it was originally written. + * These tests can ensure the expected round-trip of the entire JSON string. + */ object JsonFunctions: /** @@ -14,4 +28,273 @@ object JsonFunctions: def maybeJsonB(json: String): String = Configuration.dialect() match case Dialect.SQLITE => json - case Dialect.POSTGRESQL => json.replace("\":\"", "\": \"").replace("\",\"", "\", \"").replace("\":[", "\": [") + case Dialect.POSTGRESQL => json.replace("\":", "\": ").replace(",\"", ", \"") + + /** + * Create a snippet of JSON to find a document ID + * + * @param id The ID of the document + * @return A connection-aware ID to check for presence and positioning + */ + private def docId(id: String): String = + maybeJsonB(s"""{"id":"$id"""") + + def allDefault(db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + val json = db.conn.jsonAll(TEST_TABLE) + assertTrue(json.startsWith("["), s"JSON should start with '[' ($json)") + Configuration.dialect() match + case Dialect.SQLITE => + assertTrue(json.contains(JsonDocument.one), s"Document 'one' not found in JSON ($json)") + assertTrue(json.contains(JsonDocument.two), s"Document 'two' not found in JSON ($json)") + assertTrue(json.contains(JsonDocument.three), s"Document 'three' not found in JSON ($json)") + assertTrue(json.contains(JsonDocument.four), s"Document 'four' not found in JSON ($json)") + assertTrue(json.contains(JsonDocument.five), s"Document 'five' not found in JSON ($json)") + + case Dialect.POSTGRESQL => + assertTrue(json.contains(docId("one")), s"Document 'one' not found in JSON ($json)") + assertTrue(json.contains(docId("two")), s"Document 'two' not found in JSON ($json)") + assertTrue(json.contains(docId("three")), s"Document 'three' not found in JSON ($json)") + assertTrue(json.contains(docId("four")), s"Document 'four' not found in JSON ($json)") + assertTrue(json.contains(docId("five")), s"Document 'five' not found in JSON ($json)") + assertTrue(json.endsWith("]"), s"JSON should end with ']' ($json)") + + def allEmpty(db: ThrowawayDatabase): Unit = + assertEquals("[]", db.conn.jsonAll(TEST_TABLE), "There should have been no documents returned") + + def byIdString (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + val json = db.conn.jsonById(TEST_TABLE, "two") + Configuration.dialect() match + case Dialect.SQLITE => assertEquals(JsonDocument.two, json, "An incorrect document was returned") + case Dialect.POSTGRESQL => assertTrue(json.contains(docId("two")), s"An incorrect document was returned ($json)") + + def byIdNumber (db: ThrowawayDatabase): Unit = + Configuration.idField = "key" + try { + db.conn.insert(TEST_TABLE, NumIdDocument(18, "howdy")) + assertEquals(maybeJsonB("""{"key":18,"text":"howdy"}"""), db.conn.jsonById(TEST_TABLE, 18), + "The document should have been found by numeric ID") + } finally { + Configuration.idField = "id" + } + + def byIdNotFound (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + assertEquals("{}", db.conn.jsonById(TEST_TABLE, "x"), "There should have been no document returned") + + def byFieldsMatch (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + val json = db.conn.jsonByFields(TEST_TABLE, + Field.any("value", ("blue" :: "purple" :: Nil).asJava) :: Field.exists("sub") :: Nil, Some(FieldMatch.ALL)) + Configuration.dialect() match + case Dialect.SQLITE => + assertEquals(s"[${JsonDocument.four}]", json, "The incorrect document was returned") + case Dialect.POSTGRESQL => + assertTrue(json.startsWith("["), s"JSON should start with '[' ($json)") + assertTrue(json.contains(docId("four")), s"The incorrect document was returned ($json)") + assertTrue(json.endsWith("]"), s"JSON should end with ']' ($json)") + + def byFieldsMatchOrdered (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + val json = db.conn.jsonByFields(TEST_TABLE, Field.equal("value", "purple") :: Nil, None, Field.named("id") :: Nil) + Configuration.dialect() match + case Dialect.SQLITE => + assertEquals(s"[${JsonDocument.five},${JsonDocument.four}]", json, "The documents were not ordered correctly") + case Dialect.POSTGRESQL => + val fiveIdx = json.indexOf(docId("five")) + val fourIdx = json.indexOf(docId("four")) + assertTrue(json.startsWith("["), s"JSON should start with '[' ($json)") + assertTrue(fiveIdx >= 0, s"Document 'five' not found ($json)") + assertTrue(fourIdx >= 0, s"Document 'four' not found ($json)") + assertTrue(fiveIdx < fourIdx, s"Document 'five' should have been before 'four' ($json)") + assertTrue(json.endsWith("]"), s"JSON should end with ']' ($json)") + + def byFieldsMatchNumIn (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + val json = db.conn.jsonByFields(TEST_TABLE, Field.any("numValue", (2 :: 4 :: 6 :: 8 :: Nil).asJava) :: Nil) + Configuration.dialect() match + case Dialect.SQLITE => + assertEquals(s"[${JsonDocument.three}]", json, "The incorrect document was returned") + case Dialect.POSTGRESQL => + assertTrue(json.startsWith("["), s"JSON should start with '[' ($json)") + assertTrue(json.contains(docId("three")), s"The incorrect document was returned ($json)") + assertTrue(json.endsWith("]"), s"JSON should end with ']' ($json)") + + def byFieldsNoMatch (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + assertEquals("[]", db.conn.jsonByFields(TEST_TABLE, Field.greater("numValue", 100) :: Nil), + "There should have been no documents returned") + + def byFieldsMatchInArray (db: ThrowawayDatabase): Unit = + ArrayDocument.testDocuments.foreach { doc => db.conn.insert(TEST_TABLE, doc) } + val json = db.conn.jsonByFields(TEST_TABLE, Field.inArray("values", TEST_TABLE, ("c" :: Nil).asJava) :: Nil) + assertTrue(json.startsWith("["), s"JSON should start with '[' ($json)") + assertTrue(json.contains(docId("first")), s"The 'first' document was not found ($json)") + assertTrue(json.contains(docId("second")), s"The 'second' document was not found ($json)") + assertTrue(json.endsWith("]"), s"JSON should end with ']' ($json)") + + def byFieldsNoMatchInArray (db: ThrowawayDatabase): Unit = + ArrayDocument.testDocuments.foreach { doc => db.conn.insert(TEST_TABLE, doc) } + assertEquals("[]", + db.conn.jsonByFields(TEST_TABLE, Field.inArray("values", TEST_TABLE, ("j" :: Nil).asJava) :: Nil), + "There should have been no documents returned") + + def byContainsMatch (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + val json = db.conn.jsonByContains(TEST_TABLE, Map.Map1("value", "purple")) + assertTrue(json.startsWith("["), s"JSON should start with '[' ($json)") + Configuration.dialect() match + case Dialect.SQLITE => + assertTrue(json.contains(JsonDocument.four), s"Document 'four' not found ($json)") + assertTrue(json.contains(JsonDocument.five), s"Document 'five' not found ($json)") + case Dialect.POSTGRESQL => + assertTrue(json.contains(docId("four")), s"Document 'four' not found ($json)") + assertTrue(json.contains(docId("five")), s"Document 'five' not found ($json)") + assertTrue(json.endsWith("]"), s"JSON should end with ']' ($json)") + + def byContainsMatchOrdered (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + val json = db.conn.jsonByContains(TEST_TABLE, Map.Map1("sub", Map.Map1("foo", "green")), + Field.named("value") :: Nil) + Configuration.dialect() match + case Dialect.SQLITE => + assertEquals(s"[${JsonDocument.two},${JsonDocument.four}]", json, "The documents were not ordered correctly") + case Dialect.POSTGRESQL => + val twoIdx = json.indexOf(docId("two")) + val fourIdx = json.indexOf(docId("four")) + assertTrue(json.startsWith("["), s"JSON should start with '[' ($json)") + assertTrue(twoIdx >= 0, s"Document 'two' not found ($json)") + assertTrue(fourIdx >= 0, s"Document 'four' not found ($json)") + assertTrue(twoIdx < fourIdx, s"Document 'two' should have been before 'four' ($json)") + assertTrue(json.endsWith("]"), s"JSON should end with ']' ($json)") + + def byContainsNoMatch (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + assertEquals("[]", db.conn.jsonByContains(TEST_TABLE, Map.Map1("value", "indigo")), + "There should have been no documents returned") + + def byJsonPathMatch (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + val json = db.conn.jsonByJsonPath(TEST_TABLE, "$.numValue ? (@ > 10)") + assertTrue(json.startsWith("["), s"JSON should start with '[' ($json)") + Configuration.dialect() match + case Dialect.SQLITE => + assertTrue(json.contains(JsonDocument.four), s"Document 'four' not found ($json)") + assertTrue(json.contains(JsonDocument.five), s"Document 'five' not found ($json)") + case Dialect.POSTGRESQL => + assertTrue(json.contains(docId("four")), s"Document 'four' not found ($json)") + assertTrue(json.contains(docId("five")), s"Document 'five' not found ($json)") + assertTrue(json.endsWith("]"), s"JSON should end with ']' ($json)") + + def byJsonPathMatchOrdered (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + val json = db.conn.jsonByJsonPath(TEST_TABLE, "$.numValue ? (@ > 10)", Field.named("id") :: Nil) + Configuration.dialect() match + case Dialect.SQLITE => + assertEquals(s"[${JsonDocument.five},${JsonDocument.four}]", json, "The documents were not ordered correctly") + case Dialect.POSTGRESQL => + val fiveIdx = json.indexOf(docId("five")) + val fourIdx = json.indexOf(docId("four")) + assertTrue(json.startsWith("["), s"JSON should start with '[' ($json)") + assertTrue(fiveIdx >= 0, s"Document 'five' not found ($json)") + assertTrue(fourIdx >= 0, s"Document 'four' not found ($json)") + assertTrue(fiveIdx < fourIdx, s"Document 'five' should have been before 'four' ($json)") + assertTrue(json.endsWith("]"), s"JSON should end with ']' ($json)") + + def byJsonPathNoMatch (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + assertEquals("[]", db.conn.jsonByJsonPath(TEST_TABLE, "$.numValue ? (@ > 100)"), + "There should have been no documents returned") + + def firstByFieldsMatchOne (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + val json = db.conn.jsonFirstByFields(TEST_TABLE, Field.equal("value", "another") :: Nil) + Configuration.dialect() match + case Dialect.SQLITE => assertEquals(JsonDocument.two, json, "The incorrect document was returned") + case Dialect.POSTGRESQL => assertTrue(json.contains(docId("two")), s"The incorrect document was returned ($json)") + + def firstByFieldsMatchMany (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + val json = db.conn.jsonFirstByFields(TEST_TABLE, Field.equal("sub.foo", "green") :: Nil) + Configuration.dialect() match + case Dialect.SQLITE => + assertTrue(json.contains(JsonDocument.two) || json.contains(JsonDocument.four), + s"Expected document 'two' or 'four' ($json)") + case Dialect.POSTGRESQL => + assertTrue(json.contains(docId("two")) || json.contains(docId("four")), + s"Expected document 'two' or 'four' ($json)") + + def firstByFieldsMatchOrdered (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + val json = db.conn.jsonFirstByFields(TEST_TABLE, Field.equal("sub.foo", "green") :: Nil, None, + Field.named("n:numValue DESC") :: Nil) + Configuration.dialect() match + case Dialect.SQLITE => assertEquals(JsonDocument.four, json, "An incorrect document was returned") + case Dialect.POSTGRESQL => assertTrue(json.contains(docId("four")), s"An incorrect document was returned ($json)") + + def firstByFieldsNoMatch (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + assertEquals("{}", db.conn.jsonFirstByFields(TEST_TABLE, Field.equal("value", "absent") :: Nil), + "There should have been no document returned") + + def firstByContainsMatchOne (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + val json = db.conn.jsonFirstByContains(TEST_TABLE, Map.Map1("value", "FIRST!")) + Configuration.dialect() match + case Dialect.SQLITE => assertEquals(JsonDocument.one, json, "An incorrect document was returned") + case Dialect.POSTGRESQL => assertTrue(json.contains(docId("one")), s"An incorrect document was returned ($json)") + + def firstByContainsMatchMany (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + val json = db.conn.jsonFirstByContains(TEST_TABLE, Map.Map1("value", "purple")) + Configuration.dialect() match + case Dialect.SQLITE => + assertTrue(json.contains(JsonDocument.four) || json.contains(JsonDocument.five), + s"Expected document 'four' or 'five' ($json)") + case Dialect.POSTGRESQL => + assertTrue(json.contains(docId("four")) || json.contains(docId("five")), + s"Expected document 'four' or 'five' ($json)") + + def firstByContainsMatchOrdered (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + val json = db.conn.jsonFirstByContains(TEST_TABLE, Map.Map1("value", "purple"), + Field.named("sub.bar NULLS FIRST") :: Nil) + Configuration.dialect() match + case Dialect.SQLITE => assertEquals(JsonDocument.five, json, "An incorrect document was returned") + case Dialect.POSTGRESQL => assertTrue(json.contains(docId("five")), s"An incorrect document was returned ($json)") + + def firstByContainsNoMatch (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + assertEquals("{}", db.conn.jsonFirstByContains(TEST_TABLE, Map.Map1("value", "indigo")), + "There should have been no document returned") + + def firstByJsonPathMatchOne (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + val json = db.conn.jsonFirstByJsonPath(TEST_TABLE, "$.numValue ? (@ == 10)") + Configuration.dialect() match + case Dialect.SQLITE => assertEquals(JsonDocument.two, json, "An incorrect document was returned") + case Dialect.POSTGRESQL => assertTrue(json.contains(docId("two")), s"An incorrect document was returned ($json)") + + def firstByJsonPathMatchMany (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + val json = db.conn.jsonFirstByJsonPath(TEST_TABLE, "$.numValue ? (@ > 10)") + Configuration.dialect() match + case Dialect.SQLITE => + assertTrue(json.contains(JsonDocument.four) || json.contains(JsonDocument.five), + s"Expected document 'four' or 'five' ($json)") + case Dialect.POSTGRESQL => + assertTrue(json.contains(docId("four")) || json.contains(docId("five")), + s"Expected document 'four' or 'five' ($json)") + + def firstByJsonPathMatchOrdered (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + val json = db.conn.jsonFirstByJsonPath(TEST_TABLE, "$.numValue ? (@ > 10)", Field.named("id DESC") :: Nil) + Configuration.dialect() match + case Dialect.SQLITE => assertEquals(JsonDocument.four, json, "An incorrect document was returned") + case Dialect.POSTGRESQL => assertTrue(json.contains(docId("four")), s"An incorrect document was returned ($json)") + + def firstByJsonPathNoMatch (db: ThrowawayDatabase): Unit = + JsonDocument.load(db) + assertEquals("{}", db.conn.jsonFirstByJsonPath(TEST_TABLE, "$.numValue ? (@ > 100)"), + "There should have been no document returned") diff --git a/src/scala/src/test/scala/integration/PostgreSQLFindIT.scala b/src/scala/src/test/scala/integration/PostgreSQLFindIT.scala index 7074ada..e7f85be 100644 --- a/src/scala/src/test/scala/integration/PostgreSQLFindIT.scala +++ b/src/scala/src/test/scala/integration/PostgreSQLFindIT.scala @@ -169,4 +169,3 @@ class PostgreSQLFindIT: @DisplayName("firstByJsonPath returns null when no document matches") def firstByJsonPathNoMatch(): Unit = Using(PgDB()) { db => FindFunctions.firstByJsonPathNoMatch(db) } - diff --git a/src/scala/src/test/scala/integration/PostgreSQLJsonIT.scala b/src/scala/src/test/scala/integration/PostgreSQLJsonIT.scala new file mode 100644 index 0000000..cc7f04c --- /dev/null +++ b/src/scala/src/test/scala/integration/PostgreSQLJsonIT.scala @@ -0,0 +1,156 @@ +package solutions.bitbadger.documents.scala.tests.integration + +import org.junit.jupiter.api.{DisplayName, Test} + +import scala.util.Using + +/** + * PostgreSQL integration tests for the `Json` object / `json*` connection extension functions + */ +@DisplayName("Scala | PostgreSQL: Json") +class PostgreSQLJsonIT: + + @Test + @DisplayName("all retrieves all documents") + def allDefault(): Unit = + Using(PgDB()) { db => JsonFunctions.allDefault(db) } + + @Test + @DisplayName("all succeeds with an empty table") + def allEmpty(): Unit = + Using(PgDB()) { db => JsonFunctions.allEmpty(db) } + + @Test + @DisplayName("byId retrieves a document via a string ID") + def byIdString(): Unit = + Using(PgDB()) { db => JsonFunctions.byIdString(db) } + + @Test + @DisplayName("byId retrieves a document via a numeric ID") + def byIdNumber(): Unit = + Using(PgDB()) { db => JsonFunctions.byIdNumber(db) } + + @Test + @DisplayName("byId returns null when a matching ID is not found") + def byIdNotFound(): Unit = + Using(PgDB()) { db => JsonFunctions.byIdNotFound(db) } + + @Test + @DisplayName("byFields retrieves matching documents") + def byFieldsMatch(): Unit = + Using(PgDB()) { db => JsonFunctions.byFieldsMatch(db) } + + @Test + @DisplayName("byFields retrieves ordered matching documents") + def byFieldsMatchOrdered(): Unit = + Using(PgDB()) { db => JsonFunctions.byFieldsMatchOrdered(db) } + + @Test + @DisplayName("byFields retrieves matching documents with a numeric IN clause") + def byFieldsMatchNumIn(): Unit = + Using(PgDB()) { db => JsonFunctions.byFieldsMatchNumIn(db) } + + @Test + @DisplayName("byFields succeeds when no documents match") + def byFieldsNoMatch(): Unit = + Using(PgDB()) { db => JsonFunctions.byFieldsNoMatch(db) } + + @Test + @DisplayName("byFields retrieves matching documents with an IN_ARRAY comparison") + def byFieldsMatchInArray(): Unit = + Using(PgDB()) { db => JsonFunctions.byFieldsMatchInArray(db) } + + @Test + @DisplayName("byFields succeeds when no documents match an IN_ARRAY comparison") + def byFieldsNoMatchInArray(): Unit = + Using(PgDB()) { db => JsonFunctions.byFieldsNoMatchInArray(db) } + + @Test + @DisplayName("byContains retrieves matching documents") + def byContainsMatch(): Unit = + Using(PgDB()) { db => JsonFunctions.byContainsMatch(db) } + + @Test + @DisplayName("byContains retrieves ordered matching documents") + def byContainsMatchOrdered(): Unit = + Using(PgDB()) { db => JsonFunctions.byContainsMatchOrdered(db) } + + @Test + @DisplayName("byContains succeeds when no documents match") + def byContainsNoMatch(): Unit = + Using(PgDB()) { db => JsonFunctions.byContainsNoMatch(db) } + + @Test + @DisplayName("byJsonPath retrieves matching documents") + def byJsonPathMatch(): Unit = + Using(PgDB()) { db => JsonFunctions.byJsonPathMatch(db) } + + @Test + @DisplayName("byJsonPath retrieves ordered matching documents") + def byJsonPathMatchOrdered(): Unit = + Using(PgDB()) { db => JsonFunctions.byJsonPathMatchOrdered(db) } + + @Test + @DisplayName("byJsonPath succeeds when no documents match") + def byJsonPathNoMatch(): Unit = + Using(PgDB()) { db => JsonFunctions.byJsonPathNoMatch(db) } + + @Test + @DisplayName("firstByFields retrieves a matching document") + def firstByFieldsMatchOne(): Unit = + Using(PgDB()) { db => JsonFunctions.firstByFieldsMatchOne(db) } + + @Test + @DisplayName("firstByFields retrieves a matching document among many") + def firstByFieldsMatchMany(): Unit = + Using(PgDB()) { db => JsonFunctions.firstByFieldsMatchMany(db) } + + @Test + @DisplayName("firstByFields retrieves a matching document among many (ordered)") + def firstByFieldsMatchOrdered(): Unit = + Using(PgDB()) { db => JsonFunctions.firstByFieldsMatchOrdered(db) } + + @Test + @DisplayName("firstByFields returns null when no document matches") + def firstByFieldsNoMatch(): Unit = + Using(PgDB()) { db => JsonFunctions.firstByFieldsNoMatch(db) } + + @Test + @DisplayName("firstByContains retrieves a matching document") + def firstByContainsMatchOne(): Unit = + Using(PgDB()) { db => JsonFunctions.firstByContainsMatchOne(db) } + + @Test + @DisplayName("firstByContains retrieves a matching document among many") + def firstByContainsMatchMany(): Unit = + Using(PgDB()) { db => JsonFunctions.firstByContainsMatchMany(db) } + + @Test + @DisplayName("firstByContains retrieves a matching document among many (ordered)") + def firstByContainsMatchOrdered(): Unit = + Using(PgDB()) { db => JsonFunctions.firstByContainsMatchOrdered(db) } + + @Test + @DisplayName("firstByContains returns null when no document matches") + def firstByContainsNoMatch(): Unit = + Using(PgDB()) { db => JsonFunctions.firstByContainsNoMatch(db) } + + @Test + @DisplayName("firstByJsonPath retrieves a matching document") + def firstByJsonPathMatchOne(): Unit = + Using(PgDB()) { db => JsonFunctions.firstByJsonPathMatchOne(db) } + + @Test + @DisplayName("firstByJsonPath retrieves a matching document among many") + def firstByJsonPathMatchMany(): Unit = + Using(PgDB()) { db => JsonFunctions.firstByJsonPathMatchMany(db) } + + @Test + @DisplayName("firstByJsonPath retrieves a matching document among many (ordered)") + def firstByJsonPathMatchOrdered(): Unit = + Using(PgDB()) { db => JsonFunctions.firstByJsonPathMatchOrdered(db) } + + @Test + @DisplayName("firstByJsonPath returns null when no document matches") + def firstByJsonPathNoMatch(): Unit = + Using(PgDB()) { db => JsonFunctions.firstByJsonPathNoMatch(db) } diff --git a/src/scala/src/test/scala/integration/SQLiteJsonIT.scala b/src/scala/src/test/scala/integration/SQLiteJsonIT.scala new file mode 100644 index 0000000..b58a35e --- /dev/null +++ b/src/scala/src/test/scala/integration/SQLiteJsonIT.scala @@ -0,0 +1,112 @@ +package solutions.bitbadger.documents.scala.tests.integration + +import org.junit.jupiter.api.Assertions.assertThrows +import org.junit.jupiter.api.{DisplayName, Test} +import solutions.bitbadger.documents.DocumentException + +import scala.util.Using + +/** + * SQLite integration tests for the `Json` object / `json*` connection extension functions + */ +@DisplayName("Scala | SQLite: Json") +class SQLiteJsonIT: + + @Test + @DisplayName("all retrieves all documents") + def allDefault(): Unit = + Using(SQLiteDB()) { db => JsonFunctions.allDefault(db) } + + @Test + @DisplayName("all succeeds with an empty table") + def allEmpty(): Unit = + Using(SQLiteDB()) { db => JsonFunctions.allEmpty(db) } + + @Test + @DisplayName("byId retrieves a document via a string ID") + def byIdString(): Unit = + Using(SQLiteDB()) { db => JsonFunctions.byIdString(db) } + + @Test + @DisplayName("byId retrieves a document via a numeric ID") + def byIdNumber(): Unit = + Using(SQLiteDB()) { db => JsonFunctions.byIdNumber(db) } + + @Test + @DisplayName("byId returns null when a matching ID is not found") + def byIdNotFound(): Unit = + Using(SQLiteDB()) { db => JsonFunctions.byIdNotFound(db) } + + @Test + @DisplayName("byFields retrieves matching documents") + def byFieldsMatch(): Unit = + Using(SQLiteDB()) { db => JsonFunctions.byFieldsMatch(db) } + + @Test + @DisplayName("byFields retrieves ordered matching documents") + def byFieldsMatchOrdered(): Unit = + Using(SQLiteDB()) { db => JsonFunctions.byFieldsMatchOrdered(db) } + + @Test + @DisplayName("byFields retrieves matching documents with a numeric IN clause") + def byFieldsMatchNumIn(): Unit = + Using(SQLiteDB()) { db => JsonFunctions.byFieldsMatchNumIn(db) } + + @Test + @DisplayName("byFields succeeds when no documents match") + def byFieldsNoMatch(): Unit = + Using(SQLiteDB()) { db => JsonFunctions.byFieldsNoMatch(db) } + + @Test + @DisplayName("byFields retrieves matching documents with an IN_ARRAY comparison") + def byFieldsMatchInArray(): Unit = + Using(SQLiteDB()) { db => JsonFunctions.byFieldsMatchInArray(db) } + + @Test + @DisplayName("byFields succeeds when no documents match an IN_ARRAY comparison") + def byFieldsNoMatchInArray(): Unit = + Using(SQLiteDB()) { db => JsonFunctions.byFieldsNoMatchInArray(db) } + + @Test + @DisplayName("byContains fails") + def byContainsFails(): Unit = + Using(SQLiteDB()) { db => assertThrows(classOf[DocumentException], () => JsonFunctions.byContainsMatch(db)) } + + @Test + @DisplayName("byJsonPath fails") + def byJsonPathFails(): Unit = + Using(SQLiteDB()) { db => assertThrows(classOf[DocumentException], () => JsonFunctions.byJsonPathMatch(db)) } + + @Test + @DisplayName("firstByFields retrieves a matching document") + def firstByFieldsMatchOne(): Unit = + Using(SQLiteDB()) { db => JsonFunctions.firstByFieldsMatchOne(db) } + + @Test + @DisplayName("firstByFields retrieves a matching document among many") + def firstByFieldsMatchMany(): Unit = + Using(SQLiteDB()) { db => JsonFunctions.firstByFieldsMatchMany(db) } + + @Test + @DisplayName("firstByFields retrieves a matching document among many (ordered)") + def firstByFieldsMatchOrdered(): Unit = + Using(SQLiteDB()) { db => JsonFunctions.firstByFieldsMatchOrdered(db) } + + @Test + @DisplayName("firstByFields returns null when no document matches") + def firstByFieldsNoMatch(): Unit = + Using(SQLiteDB()) { db => JsonFunctions.firstByFieldsNoMatch(db) } + + @Test + @DisplayName("firstByContains fails") + def firstByContainsFails(): Unit = + Using(SQLiteDB()) { db => + assertThrows(classOf[DocumentException], () => JsonFunctions.firstByContainsMatchOne(db)) + } + + @Test + @DisplayName("firstByJsonPath fails") + def firstByJsonPathFails(): Unit = + Using(SQLiteDB()) { db => + assertThrows(classOf[DocumentException], () => JsonFunctions.firstByJsonPathMatchOne(db)) + }