diff --git a/src/core/src/test/java/solutions/bitbadger/documents/core/tests/java/integration/JsonDocument.java b/src/core/src/test/java/solutions/bitbadger/documents/core/tests/java/integration/JsonDocument.java index cb85902..0745d92 100644 --- a/src/core/src/test/java/solutions/bitbadger/documents/core/tests/java/integration/JsonDocument.java +++ b/src/core/src/test/java/solutions/bitbadger/documents/core/tests/java/integration/JsonDocument.java @@ -87,4 +87,21 @@ public class JsonDocument { public static void load(ThrowawayDatabase db) { load(db, TEST_TABLE); } + + /** Document ID one as a JSON string */ + public static String one = "{\"id\":\"one\",\"value\":\"FIRST!\",\"numValue\":0,\"sub\":null}"; + + /** Document ID two as a JSON string */ + public static String two = "{\"id\":\"two\",\"value\":\"another\",\"numValue\":10," + + "\"sub\":{\"foo\":\"green\",\"bar\":\"blue\"}}"; + + /** Document ID three as a JSON string */ + public static String three = "{\"id\":\"three\",\"value\":\"\",\"numValue\":4,\"sub\":null}"; + + /** Document ID four as a JSON string */ + public static String four = "{\"id\":\"four\",\"value\":\"purple\",\"numValue\":17," + + "\"sub\":{\"foo\":\"green\",\"bar\":\"red\"}}"; + + /** Document ID five as a JSON string */ + public static String five = "{\"id\":\"five\",\"value\":\"purple\",\"numValue\":18,\"sub\":null}"; } diff --git a/src/core/src/test/java/solutions/bitbadger/documents/core/tests/java/integration/JsonFunctions.java b/src/core/src/test/java/solutions/bitbadger/documents/core/tests/java/integration/JsonFunctions.java index 0d440d2..646e386 100644 --- a/src/core/src/test/java/solutions/bitbadger/documents/core/tests/java/integration/JsonFunctions.java +++ b/src/core/src/test/java/solutions/bitbadger/documents/core/tests/java/integration/JsonFunctions.java @@ -1,10 +1,25 @@ package solutions.bitbadger.documents.core.tests.java.integration; -import solutions.bitbadger.documents.Configuration; -import solutions.bitbadger.documents.Dialect; -import solutions.bitbadger.documents.DocumentException; +import solutions.bitbadger.documents.*; +import solutions.bitbadger.documents.core.tests.integration.ThrowawayDatabase; -public class JsonFunctions { +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; +import static solutions.bitbadger.documents.core.tests.TypesKt.TEST_TABLE; +import static solutions.bitbadger.documents.java.extensions.ConnExt.*; + +/** + * 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. + */ +final public class JsonFunctions { /** * PostgreSQL, when returning JSONB as a string, has spaces after commas and colons delineating fields and values. @@ -14,9 +29,396 @@ public class JsonFunctions { * @return The actual expected JSON based on the database being tested */ public static String maybeJsonB(String json) throws DocumentException { - if (Configuration.dialect() == Dialect.SQLITE) { - return json; + return switch (Configuration.dialect()) { + case SQLITE -> json; + case 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 static String docId(String id) throws DocumentException { + return maybeJsonB(String.format("{\"id\":\"%s\"", id)); + } + + public static void allDefault(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + final String json = jsonAll(db.getConn(), TEST_TABLE); + assertTrue(json.startsWith("["), "JSON should start with '[' ($json)"); + switch (Configuration.dialect()) { + case SQLITE: + assertTrue(json.contains(JsonDocument.one), + String.format("Document 'one' not found in JSON (%s)", json)); + assertTrue(json.contains(JsonDocument.two), + String.format("Document 'two' not found in JSON (%s)", json)); + assertTrue(json.contains(JsonDocument.three), + String.format("Document 'three' not found in JSON (%s)", json)); + assertTrue(json.contains(JsonDocument.four), + String.format("Document 'four' not found in JSON (%s)", json)); + assertTrue(json.contains(JsonDocument.five), + String.format("Document 'five' not found in JSON (%s)", json)); + break; + case POSTGRESQL: + assertTrue(json.contains(docId("one")), String.format("Document 'one' not found in JSON (%s)", json)); + assertTrue(json.contains(docId("two")), String.format("Document 'two' not found in JSON (%s)", json)); + assertTrue(json.contains(docId("three")), + String.format("Document 'three' not found in JSON (%s)", json)); + assertTrue(json.contains(docId("four")), String.format("Document 'four' not found in JSON (%s)", json)); + assertTrue(json.contains(docId("five")), String.format("Document 'five' not found in JSON (%s)", json)); + break; } - return json.replace("\":\"", "\": \"").replace("\",\"", "\", \"").replace("\":[", "\": ["); + assertTrue(json.endsWith("]"), "JSON should end with ']' ($json)"); + } + + public static void allEmpty(ThrowawayDatabase db) throws DocumentException { + assertEquals("[]", jsonAll(db.getConn(), TEST_TABLE), "There should have been no documents returned"); + } + + public static void byIdString(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + final String json = jsonById(db.getConn(), TEST_TABLE, "two"); + switch (Configuration.dialect()) { + case SQLITE: + assertEquals(JsonDocument.two, json, "An incorrect document was returned"); + break; + case POSTGRESQL: + assertTrue(json.contains(docId("two")), String.format("An incorrect document was returned (%s)", json)); + break; + } + } + + public static void byIdNumber(ThrowawayDatabase db) throws DocumentException { + Configuration.idField = "key"; + try { + insert(db.getConn(), TEST_TABLE, new NumIdDocument(18, "howdy")); + assertEquals(maybeJsonB("{\"key\":18,\"text\":\"howdy\"}"), jsonById(db.getConn(), TEST_TABLE, 18), + "The document should have been found by numeric ID"); + } finally { + Configuration.idField = "id"; + } + } + + public static void byIdNotFound(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + assertEquals("{}", jsonById(db.getConn(), TEST_TABLE, "x"), "There should have been no document returned"); + } + + public static void byFieldsMatch(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + final String json = jsonByFields(db.getConn(), TEST_TABLE, + List.of(Field.any("value", List.of("blue", "purple")), Field.exists("sub")), FieldMatch.ALL); + switch (Configuration.dialect()) { + case SQLITE: + assertEquals(String.format("[%s]", JsonDocument.four), json, "The incorrect document was returned"); + break; + case POSTGRESQL: + assertTrue(json.startsWith("["), String.format("JSON should start with '[' (%s)", json)); + assertTrue(json.contains(docId("four")), + String.format("The incorrect document was returned (%s)", json)); + assertTrue(json.endsWith("]"), String.format("JSON should end with ']' (%s)", json)); + break; + } + } + + public static void byFieldsMatchOrdered(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + final String json = jsonByFields(db.getConn(), TEST_TABLE, List.of(Field.equal("value", "purple")), null, + List.of(Field.named("id"))); + switch (Configuration.dialect()) { + case SQLITE: + assertEquals(String.format("[%s,%s]", JsonDocument.five, JsonDocument.four), json, + "The documents were not ordered correctly"); + break; + case POSTGRESQL: + final int fiveIdx = json.indexOf(docId("five")); + final int fourIdx = json.indexOf(docId("four")); + assertTrue(json.startsWith("["), String.format("JSON should start with '[' (%s)", json)); + assertTrue(fiveIdx >= 0, String.format("Document 'five' not found (%s)", json)); + assertTrue(fourIdx >= 0, String.format("Document 'four' not found (%s)", json)); + assertTrue(fiveIdx < fourIdx, + String.format("Document 'five' should have been before 'four' (%s)", json)); + assertTrue(json.endsWith("]"), String.format("JSON should end with ']' (%s)", json)); + break; + } + } + + public static void byFieldsMatchNumIn(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + final String json = jsonByFields(db.getConn(), TEST_TABLE, List.of(Field.any("numValue", List.of(2, 4, 6, 8)))); + switch (Configuration.dialect()) { + case SQLITE: + assertEquals(String.format("[%s]", JsonDocument.three), json, "The incorrect document was returned"); + break; + case POSTGRESQL: + assertTrue(json.startsWith("["), String.format("JSON should start with '[' (%s)", json)); + assertTrue(json.contains(docId("three")), + String.format("The incorrect document was returned (%s)", json)); + assertTrue(json.endsWith("]"), String.format("JSON should end with ']' (%s)", json)); + break; + } + } + + public static void byFieldsNoMatch(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + assertEquals("[]", jsonByFields(db.getConn(), TEST_TABLE, List.of(Field.greater("numValue", 100))), + "There should have been no documents returned"); + } + + public static void byFieldsMatchInArray(ThrowawayDatabase db) throws DocumentException { + for (ArrayDocument doc : ArrayDocument.testDocuments) { insert(db.getConn(), TEST_TABLE, doc); } + final String json = jsonByFields(db.getConn(), TEST_TABLE, List.of(Field.inArray("values", TEST_TABLE, + List.of("c")))); + assertTrue(json.startsWith("["), String.format("JSON should start with '[' (%s)", json)); + assertTrue(json.contains(docId("first")), String.format("The 'first' document was not found (%s)", json)); + assertTrue(json.contains(docId("second")), String.format("The 'second' document was not found (%s)", json)); + assertTrue(json.endsWith("]"), String.format("JSON should end with ']' (%s)", json)); + } + + public static void byFieldsNoMatchInArray(ThrowawayDatabase db) throws DocumentException { + for (ArrayDocument doc : ArrayDocument.testDocuments) { insert(db.getConn(), TEST_TABLE, doc); } + assertEquals("[]", + jsonByFields(db.getConn(), TEST_TABLE, List.of(Field.inArray("values", TEST_TABLE, List.of("j")))), + "There should have been no documents returned"); + } + + public static void byContainsMatch(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + final String json = jsonByContains(db.getConn(), TEST_TABLE, Map.of("value", "purple")); + assertTrue(json.startsWith("["), String.format("JSON should start with '[' (%s)", json)); + switch (Configuration.dialect()) { + case SQLITE: + assertTrue(json.contains(JsonDocument.four), String.format("Document 'four' not found (%s)", json)); + assertTrue(json.contains(JsonDocument.five), String.format("Document 'five' not found (%s)", json)); + break; + case POSTGRESQL: + assertTrue(json.contains(docId("four")), String.format("Document 'four' not found (%s)", json)); + assertTrue(json.contains(docId("five")), String.format("Document 'five' not found (%s)", json)); + break; + } + assertTrue(json.endsWith("]"), String.format("JSON should end with ']' (%s)", json)); + } + + public static void byContainsMatchOrdered(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + final String json = jsonByContains(db.getConn(), TEST_TABLE, Map.of("sub", Map.of("foo", "green")), + List.of(Field.named("value"))); + switch (Configuration.dialect()) { + case SQLITE: + assertEquals(String.format("[%s,%s]", JsonDocument.two, JsonDocument.four), json, + "The documents were not ordered correctly"); + break; + case POSTGRESQL: + final int twoIdx = json.indexOf(docId("two")); + final int fourIdx = json.indexOf(docId("four")); + assertTrue(json.startsWith("["), String.format("JSON should start with '[' (%s)", json)); + assertTrue(twoIdx >= 0, String.format("Document 'two' not found (%s)", json)); + assertTrue(fourIdx >= 0, String.format("Document 'four' not found (%s)", json)); + assertTrue(twoIdx < fourIdx, String.format("Document 'two' should have been before 'four' (%s)", json)); + assertTrue(json.endsWith("]"), String.format("JSON should end with ']' (%s)", json)); + break; + } + } + + public static void byContainsNoMatch(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + assertEquals("[]", jsonByContains(db.getConn(), TEST_TABLE, Map.of("value", "indigo")), + "There should have been no documents returned"); + } + + public static void byJsonPathMatch(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + final String json = jsonByJsonPath(db.getConn(), TEST_TABLE, "$.numValue ? (@ > 10)"); + assertTrue(json.startsWith("["), String.format("JSON should start with '[' (%s)", json)); + switch (Configuration.dialect()) { + case SQLITE: + assertTrue(json.contains(JsonDocument.four), String.format("Document 'four' not found (%s)", json)); + assertTrue(json.contains(JsonDocument.five), String.format("Document 'five' not found (%s)", json)); + break; + case POSTGRESQL: + assertTrue(json.contains(docId("four")), String.format("Document 'four' not found (%s)", json)); + assertTrue(json.contains(docId("five")), String.format("Document 'five' not found (%s)", json)); + break; + } + assertTrue(json.endsWith("]"), String.format("JSON should end with ']' (%s)", json)); + } + + public static void byJsonPathMatchOrdered(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + final String json = jsonByJsonPath(db.getConn(), TEST_TABLE, "$.numValue ? (@ > 10)", + List.of(Field.named("id"))); + switch (Configuration.dialect()) { + case SQLITE: + assertEquals(String.format("[%s,%s]", JsonDocument.five, JsonDocument.four), json, + "The documents were not ordered correctly"); + break; + case POSTGRESQL: + final int fiveIdx = json.indexOf(docId("five")); + final int fourIdx = json.indexOf(docId("four")); + assertTrue(json.startsWith("["), String.format("JSON should start with '[' (%s)", json)); + assertTrue(fiveIdx >= 0, String.format("Document 'five' not found (%s)", json)); + assertTrue(fourIdx >= 0, String.format("Document 'four' not found (%s)", json)); + assertTrue(fiveIdx < fourIdx, + String.format("Document 'five' should have been before 'four' (%s)", json)); + assertTrue(json.endsWith("]"), String.format("JSON should end with ']' (%s)", json)); + break; + } + } + + public static void byJsonPathNoMatch(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + assertEquals("[]", jsonByJsonPath(db.getConn(), TEST_TABLE, "$.numValue ? (@ > 100)"), + "There should have been no documents returned"); + } + + public static void firstByFieldsMatchOne(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + final String json = jsonFirstByFields(db.getConn(), TEST_TABLE, List.of(Field.equal("value", "another"))); + switch (Configuration.dialect()) { + case SQLITE: + assertEquals(JsonDocument.two, json, "The incorrect document was returned"); + break; + case POSTGRESQL: + assertTrue(json.contains(docId("two")), + String.format("The incorrect document was returned (%s)", json)); + break; + } + } + + public static void firstByFieldsMatchMany(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + final String json = jsonFirstByFields(db.getConn(), TEST_TABLE, List.of(Field.equal("sub.foo", "green"))); + switch (Configuration.dialect()) { + case SQLITE: + assertTrue(json.contains(JsonDocument.two) || json.contains(JsonDocument.four), + String.format("Expected document 'two' or 'four' (%s)", json)); + break; + case POSTGRESQL: + assertTrue(json.contains(docId("two")) || json.contains(docId("four")), + String.format("Expected document 'two' or 'four' (%s)", json)); + break; + } + } + + public static void firstByFieldsMatchOrdered(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + final String json = jsonFirstByFields(db.getConn(), TEST_TABLE, List.of(Field.equal("sub.foo", "green")), null, + List.of(Field.named("n:numValue DESC"))); + switch (Configuration.dialect()) { + case SQLITE: + assertEquals(JsonDocument.four, json, "An incorrect document was returned"); + break; + case POSTGRESQL: + assertTrue(json.contains(docId("four")), + String.format("An incorrect document was returned (%s)", json)); + break; + } + } + + public static void firstByFieldsNoMatch(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + assertEquals("{}", jsonFirstByFields(db.getConn(), TEST_TABLE, List.of(Field.equal("value", "absent"))), + "There should have been no document returned"); + } + + public static void firstByContainsMatchOne(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + final String json = jsonFirstByContains(db.getConn(), TEST_TABLE, Map.of("value", "FIRST!")); + switch (Configuration.dialect()) { + case SQLITE: + assertEquals(JsonDocument.one, json, "An incorrect document was returned"); + break; + case POSTGRESQL: + assertTrue(json.contains(docId("one")), String.format("An incorrect document was returned (%s)", json)); + break; + } + } + + public static void firstByContainsMatchMany(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + final String json = jsonFirstByContains(db.getConn(), TEST_TABLE, Map.of("value", "purple")); + switch (Configuration.dialect()) { + case SQLITE: + assertTrue(json.contains(JsonDocument.four) || json.contains(JsonDocument.five), + String.format("Expected document 'four' or 'five' (%s)", json)); + break; + case POSTGRESQL: + assertTrue(json.contains(docId("four")) || json.contains(docId("five")), + String.format("Expected document 'four' or 'five' (%s)", json)); + break; + } + } + + public static void firstByContainsMatchOrdered(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + final String json = jsonFirstByContains(db.getConn(), TEST_TABLE, Map.of("value", "purple"), + List.of(Field.named("sub.bar NULLS FIRST"))); + switch (Configuration.dialect()) { + case SQLITE: + assertEquals(JsonDocument.five, json, "An incorrect document was returned"); + break; + case POSTGRESQL: + assertTrue(json.contains(docId("five")), + String.format("An incorrect document was returned (%s)", json)); + break; + } + } + + public static void firstByContainsNoMatch(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + assertEquals("{}", jsonFirstByContains(db.getConn(), TEST_TABLE, Map.of("value", "indigo")), + "There should have been no document returned"); + } + + public static void firstByJsonPathMatchOne(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + final String json = jsonFirstByJsonPath(db.getConn(), TEST_TABLE, "$.numValue ? (@ == 10)"); + switch (Configuration.dialect()) { + case SQLITE: + assertEquals(JsonDocument.two, json, "An incorrect document was returned"); + break; + case POSTGRESQL: + assertTrue(json.contains(docId("two")), String.format("An incorrect document was returned (%s)", json)); + break; + } + } + + public static void firstByJsonPathMatchMany(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + final String json = jsonFirstByJsonPath(db.getConn(), TEST_TABLE, "$.numValue ? (@ > 10)"); + switch (Configuration.dialect()) { + case SQLITE: + assertTrue(json.contains(JsonDocument.four) || json.contains(JsonDocument.five), + String.format("Expected document 'four' or 'five' (%s)", json)); + break; + case POSTGRESQL: + assertTrue(json.contains(docId("four")) || json.contains(docId("five")), + String.format("Expected document 'four' or 'five' (%s)", json)); + break; + } + } + + public static void firstByJsonPathMatchOrdered(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + final String json = jsonFirstByJsonPath(db.getConn(), TEST_TABLE, "$.numValue ? (@ > 10)", + List.of(Field.named("id DESC"))); + switch (Configuration.dialect()) { + case SQLITE: + assertEquals(JsonDocument.four, json, "An incorrect document was returned"); + break; + case POSTGRESQL: + assertTrue(json.contains(docId("four")), + String.format("An incorrect document was returned (%s)", json)); + break; + } + } + + public static void firstByJsonPathNoMatch(ThrowawayDatabase db) throws DocumentException { + JsonDocument.load(db); + assertEquals("{}", jsonFirstByJsonPath(db.getConn(), TEST_TABLE, "$.numValue ? (@ > 100)"), + "There should have been no document returned"); } } diff --git a/src/core/src/test/java/solutions/bitbadger/documents/core/tests/java/integration/NumIdDocument.java b/src/core/src/test/java/solutions/bitbadger/documents/core/tests/java/integration/NumIdDocument.java index f980c09..3d4ea66 100644 --- a/src/core/src/test/java/solutions/bitbadger/documents/core/tests/java/integration/NumIdDocument.java +++ b/src/core/src/test/java/solutions/bitbadger/documents/core/tests/java/integration/NumIdDocument.java @@ -3,7 +3,7 @@ package solutions.bitbadger.documents.core.tests.java.integration; public class NumIdDocument { private int key; - private String value; + private String text; public int getKey() { return key; @@ -13,17 +13,17 @@ public class NumIdDocument { this.key = key; } - public String getValue() { - return value; + public String getText() { + return text; } - public void setValue(String value) { - this.value = value; + public void setText(String text) { + this.text = text; } - public NumIdDocument(int key, String value) { + public NumIdDocument(int key, String text) { this.key = key; - this.value = value; + this.text = text; } public NumIdDocument() { diff --git a/src/core/src/test/java/solutions/bitbadger/documents/core/tests/java/integration/PostgreSQLJsonIT.java b/src/core/src/test/java/solutions/bitbadger/documents/core/tests/java/integration/PostgreSQLJsonIT.java new file mode 100644 index 0000000..c8129a5 --- /dev/null +++ b/src/core/src/test/java/solutions/bitbadger/documents/core/tests/java/integration/PostgreSQLJsonIT.java @@ -0,0 +1,245 @@ +package solutions.bitbadger.documents.core.tests.java.integration; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import solutions.bitbadger.documents.DocumentException; +import solutions.bitbadger.documents.core.tests.integration.PgDB; + +/** + * PostgreSQL integration tests for the `Json` object / `json*` connection extension functions + */ +@DisplayName("Core | Java | PostgreSQL: Json") +final public class PostgreSQLJsonIT { + + @Test + @DisplayName("all retrieves all documents") + public void allDefault() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.allDefault(db); + } + } + + @Test + @DisplayName("all succeeds with an empty table") + public void allEmpty() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.allEmpty(db); + } + } + + @Test + @DisplayName("byId retrieves a document via a string ID") + public void byIdString() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.byIdString(db); + } + } + + @Test + @DisplayName("byId retrieves a document via a numeric ID") + public void byIdNumber() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.byIdNumber(db); + } + } + + @Test + @DisplayName("byId returns null when a matching ID is not found") + public void byIdNotFound() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.byIdNotFound(db); + } + } + + @Test + @DisplayName("byFields retrieves matching documents") + public void byFieldsMatch() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.byFieldsMatch(db); + } + } + + @Test + @DisplayName("byFields retrieves ordered matching documents") + public void byFieldsMatchOrdered() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.byFieldsMatchOrdered(db); + } + } + + @Test + @DisplayName("byFields retrieves matching documents with a numeric IN clause") + public void byFieldsMatchNumIn() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.byFieldsMatchNumIn(db); + } + } + + @Test + @DisplayName("byFields succeeds when no documents match") + public void byFieldsNoMatch() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.byFieldsNoMatch(db); + } + } + + @Test + @DisplayName("byFields retrieves matching documents with an IN_ARRAY comparison") + public void byFieldsMatchInArray() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.byFieldsMatchInArray(db); + } + } + + @Test + @DisplayName("byFields succeeds when no documents match an IN_ARRAY comparison") + public void byFieldsNoMatchInArray() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.byFieldsNoMatchInArray(db); + } + } + + @Test + @DisplayName("byContains retrieves matching documents") + public void byContainsMatch() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.byContainsMatch(db); + } + } + + @Test + @DisplayName("byContains retrieves ordered matching documents") + public void byContainsMatchOrdered() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.byContainsMatchOrdered(db); + } + } + + @Test + @DisplayName("byContains succeeds when no documents match") + public void byContainsNoMatch() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.byContainsNoMatch(db); + } + } + + @Test + @DisplayName("byJsonPath retrieves matching documents") + public void byJsonPathMatch() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.byJsonPathMatch(db); + } + } + + @Test + @DisplayName("byJsonPath retrieves ordered matching documents") + public void byJsonPathMatchOrdered() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.byJsonPathMatchOrdered(db); + } + } + + @Test + @DisplayName("byJsonPath succeeds when no documents match") + public void byJsonPathNoMatch() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.byJsonPathNoMatch(db); + } + } + + @Test + @DisplayName("firstByFields retrieves a matching document") + public void firstByFieldsMatchOne() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.firstByFieldsMatchOne(db); + } + } + + @Test + @DisplayName("firstByFields retrieves a matching document among many") + public void firstByFieldsMatchMany() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.firstByFieldsMatchMany(db); + } + } + + @Test + @DisplayName("firstByFields retrieves a matching document among many (ordered)") + public void firstByFieldsMatchOrdered() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.firstByFieldsMatchOrdered(db); + } + } + + @Test + @DisplayName("firstByFields returns null when no document matches") + public void firstByFieldsNoMatch() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.firstByFieldsNoMatch(db); + } + } + + @Test + @DisplayName("firstByContains retrieves a matching document") + public void firstByContainsMatchOne() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.firstByContainsMatchOne(db); + } + } + + @Test + @DisplayName("firstByContains retrieves a matching document among many") + public void firstByContainsMatchMany() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.firstByContainsMatchMany(db); + } + } + + @Test + @DisplayName("firstByContains retrieves a matching document among many (ordered)") + public void firstByContainsMatchOrdered() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.firstByContainsMatchOrdered(db); + } + } + + @Test + @DisplayName("firstByContains returns null when no document matches") + public void firstByContainsNoMatch() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.firstByContainsNoMatch(db); + } + } + + @Test + @DisplayName("firstByJsonPath retrieves a matching document") + public void firstByJsonPathMatchOne() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.firstByJsonPathMatchOne(db); + } + } + + @Test + @DisplayName("firstByJsonPath retrieves a matching document among many") + public void firstByJsonPathMatchMany() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.firstByJsonPathMatchMany(db); + } + } + + @Test + @DisplayName("firstByJsonPath retrieves a matching document among many (ordered)") + public void firstByJsonPathMatchOrdered() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.firstByJsonPathMatchOrdered(db); + } + } + + @Test + @DisplayName("firstByJsonPath returns null when no document matches") + public void firstByJsonPathNoMatch() throws DocumentException { + try (PgDB db = new PgDB()) { + JsonFunctions.firstByJsonPathNoMatch(db); + } + } +} diff --git a/src/core/src/test/java/solutions/bitbadger/documents/core/tests/java/integration/SQLiteJsonIT.java b/src/core/src/test/java/solutions/bitbadger/documents/core/tests/java/integration/SQLiteJsonIT.java new file mode 100644 index 0000000..1b3d447 --- /dev/null +++ b/src/core/src/test/java/solutions/bitbadger/documents/core/tests/java/integration/SQLiteJsonIT.java @@ -0,0 +1,167 @@ +package solutions.bitbadger.documents.core.tests.java.integration; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import solutions.bitbadger.documents.DocumentException; +import solutions.bitbadger.documents.core.tests.integration.SQLiteDB; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * SQLite integration tests for the `Json` object / `json*` connection extension functions + */ +@DisplayName("Core | Java | SQLite: Json") +final public class SQLiteJsonIT { + + @Test + @DisplayName("all retrieves all documents") + public void allDefault() throws DocumentException { + try (SQLiteDB db = new SQLiteDB()) { + JsonFunctions.allDefault(db); + } + } + + @Test + @DisplayName("all succeeds with an empty table") + public void allEmpty() throws DocumentException { + try (SQLiteDB db = new SQLiteDB()) { + JsonFunctions.allEmpty(db); + } + } + + @Test + @DisplayName("byId retrieves a document via a string ID") + public void byIdString() throws DocumentException { + try (SQLiteDB db = new SQLiteDB()) { + JsonFunctions.byIdString(db); + } + } + + @Test + @DisplayName("byId retrieves a document via a numeric ID") + public void byIdNumber() throws DocumentException { + try (SQLiteDB db = new SQLiteDB()) { + JsonFunctions.byIdNumber(db); + } + } + + @Test + @DisplayName("byId returns null when a matching ID is not found") + public void byIdNotFound() throws DocumentException { + try (SQLiteDB db = new SQLiteDB()) { + JsonFunctions.byIdNotFound(db); + } + } + + @Test + @DisplayName("byFields retrieves matching documents") + public void byFieldsMatch() throws DocumentException { + try (SQLiteDB db = new SQLiteDB()) { + JsonFunctions.byFieldsMatch(db); + } + } + + @Test + @DisplayName("byFields retrieves ordered matching documents") + public void byFieldsMatchOrdered() throws DocumentException { + try (SQLiteDB db = new SQLiteDB()) { + JsonFunctions.byFieldsMatchOrdered(db); + } + } + + @Test + @DisplayName("byFields retrieves matching documents with a numeric IN clause") + public void byFieldsMatchNumIn() throws DocumentException { + try (SQLiteDB db = new SQLiteDB()) { + JsonFunctions.byFieldsMatchNumIn(db); + } + } + + @Test + @DisplayName("byFields succeeds when no documents match") + public void byFieldsNoMatch() throws DocumentException { + try (SQLiteDB db = new SQLiteDB()) { + JsonFunctions.byFieldsNoMatch(db); + } + } + + @Test + @DisplayName("byFields retrieves matching documents with an IN_ARRAY comparison") + public void byFieldsMatchInArray() throws DocumentException { + try (SQLiteDB db = new SQLiteDB()) { + JsonFunctions.byFieldsMatchInArray(db); + } + } + + @Test + @DisplayName("byFields succeeds when no documents match an IN_ARRAY comparison") + public void byFieldsNoMatchInArray() throws DocumentException { + try (SQLiteDB db = new SQLiteDB()) { + JsonFunctions.byFieldsNoMatchInArray(db); + } + } + + @Test + @DisplayName("byContains fails") + public void byContainsFails() { + try (SQLiteDB db = new SQLiteDB()) { + assertThrows(DocumentException.class, () -> JsonFunctions.byContainsMatch(db)); + } + } + + @Test + @DisplayName("byJsonPath fails") + public void byJsonPathFails() { + try (SQLiteDB db = new SQLiteDB()) { + assertThrows(DocumentException.class, () -> JsonFunctions.byJsonPathMatch(db)); + } + } + + @Test + @DisplayName("firstByFields retrieves a matching document") + public void firstByFieldsMatchOne() throws DocumentException { + try (SQLiteDB db = new SQLiteDB()) { + JsonFunctions.firstByFieldsMatchOne(db); + } + } + + @Test + @DisplayName("firstByFields retrieves a matching document among many") + public void firstByFieldsMatchMany() throws DocumentException { + try (SQLiteDB db = new SQLiteDB()) { + JsonFunctions.firstByFieldsMatchMany(db); + } + } + + @Test + @DisplayName("firstByFields retrieves a matching document among many (ordered)") + public void firstByFieldsMatchOrdered() throws DocumentException { + try (SQLiteDB db = new SQLiteDB()) { + JsonFunctions.firstByFieldsMatchOrdered(db); + } + } + + @Test + @DisplayName("firstByFields returns null when no document matches") + public void firstByFieldsNoMatch() throws DocumentException { + try (SQLiteDB db = new SQLiteDB()) { + JsonFunctions.firstByFieldsNoMatch(db); + } + } + + @Test + @DisplayName("firstByContains fails") + public void firstByContainsFails() { + try (SQLiteDB db = new SQLiteDB()) { + assertThrows(DocumentException.class, () -> JsonFunctions.firstByContainsMatchOne(db)); + } + } + + @Test + @DisplayName("firstByJsonPath fails") + public void firstByJsonPathFails() { + try (SQLiteDB db = new SQLiteDB()) { + assertThrows(DocumentException.class, () -> JsonFunctions.firstByJsonPathMatchOne(db)); + } + } +} diff --git a/src/core/src/test/kotlin/integration/JsonFunctions.kt b/src/core/src/test/kotlin/integration/JsonFunctions.kt index 77de5b8..94b23d4 100644 --- a/src/core/src/test/kotlin/integration/JsonFunctions.kt +++ b/src/core/src/test/kotlin/integration/JsonFunctions.kt @@ -58,11 +58,11 @@ object JsonFunctions { assertTrue(json.contains(JsonDocument.five), "Document 'five' not found in JSON ($json)") } Dialect.POSTGRESQL -> { - assertTrue(json.indexOf(docId("one")) >= 0, "Document 'one' not found in JSON ($json)") - assertTrue(json.indexOf(docId("two")) >= 0, "Document 'two' not found in JSON ($json)") - assertTrue(json.indexOf(docId("three")) >= 0, "Document 'three' not found in JSON ($json)") - assertTrue(json.indexOf(docId("four")) >= 0, "Document 'four' not found in JSON ($json)") - assertTrue(json.indexOf(docId("five")) >= 0, "Document 'five' not found in JSON ($json)") + assertTrue(json.contains(docId("one")), "Document 'one' not found in JSON ($json)") + assertTrue(json.contains(docId("two")), "Document 'two' not found in JSON ($json)") + assertTrue(json.contains(docId("three")), "Document 'three' not found in JSON ($json)") + assertTrue(json.contains(docId("four")), "Document 'four' not found in JSON ($json)") + assertTrue(json.contains(docId("five")), "Document 'five' not found in JSON ($json)") } } assertTrue(json.endsWith("]"), "JSON should end with ']' ($json)") @@ -76,10 +76,7 @@ object JsonFunctions { val json = db.conn.jsonById(TEST_TABLE, "two") when (Configuration.dialect()) { Dialect.SQLITE -> assertEquals(JsonDocument.two, json, "An incorrect document was returned") - Dialect.POSTGRESQL -> assertTrue( - json.indexOf(docId("two")) >= 0, - "An incorrect document was returned ($json)" - ) + Dialect.POSTGRESQL -> assertTrue(json.contains(docId("two")), "An incorrect document was returned ($json)") } }