Initial Development #1

Merged
danieljsummers merged 88 commits from v1-rc into main 2025-04-16 01:29:20 +00:00
6 changed files with 172 additions and 10 deletions
Showing only changes of commit 40f8bded81 - Show all commits

View File

@ -2,6 +2,7 @@ package solutions.bitbadger.documents.scala
import solutions.bitbadger.documents.{Configuration, Parameter} import solutions.bitbadger.documents.{Configuration, Parameter}
import java.io.PrintWriter
import java.sql.{Connection, ResultSet} import java.sql.{Connection, ResultSet}
import scala.reflect.ClassTag import scala.reflect.ClassTag
import scala.util.Using import scala.util.Using
@ -107,6 +108,60 @@ object Custom:
def jsonArray(query: String, mapFunc: ResultSet => String): String = def jsonArray(query: String, mapFunc: ResultSet => String): String =
jsonArray(query, Nil, mapFunc) jsonArray(query, Nil, mapFunc)
/**
* Execute a query that writes a JSON array of results to the given `PrintWriter`
*
* @param query The query to retrieve the results
* @param parameters Parameters to use for the query
* @param writer The writer to which the results should be written
* @param conn The connection over which the query should be executed
* @param mapFunc The mapping function to extract the JSON from the query
* @return A JSON array of results for the given query
* @throws DocumentException If parameters are invalid
*/
def writeJsonArray(query: String, parameters: Seq[Parameter[?]], writer: PrintWriter, conn: Connection,
mapFunc: ResultSet => String): Unit =
Using(Parameters.apply(conn, query, parameters)) { stmt => Results.writeJsonArray(writer, stmt, mapFunc) }
/**
* Execute a query that returns a JSON array of results
*
* @param query The query to retrieve the results
* @param writer The writer to which the results should be written
* @param conn The connection over which the query should be executed
* @param mapFunc The mapping function to extract the JSON from the query
* @return A JSON array of results for the given query
* @throws DocumentException If parameters are invalid
*/
def writeJsonArray(query: String, conn: Connection, writer: PrintWriter, mapFunc: ResultSet => String): Unit =
writeJsonArray(query, Nil, writer, conn, mapFunc)
/**
* Execute a query that returns a JSON array of results (creates connection)
*
* @param query The query to retrieve the results
* @param parameters Parameters to use for the query
* @param writer The writer to which the results should be written
* @param mapFunc The mapping function to extract the JSON from the query
* @return A JSON array of results for the given query
* @throws DocumentException If parameters are invalid
*/
def writeJsonArray(query: String, parameters: Seq[Parameter[?]], writer: PrintWriter,
mapFunc: ResultSet => String): Unit =
Using(Configuration.dbConn()) { conn => writeJsonArray(query, parameters, writer, conn, mapFunc) }
/**
* Execute a query that returns a JSON array of results (creates connection)
*
* @param query The query to retrieve the results
* @param writer The writer to which the results should be written
* @param mapFunc The mapping function to extract the JSON from the query
* @return A JSON array of results for the given query
* @throws DocumentException If parameters are invalid
*/
def writeJsonArray(query: String, writer: PrintWriter, mapFunc: ResultSet => String): Unit =
writeJsonArray(query, Nil, writer, mapFunc)
/** /**
* Execute a query that returns one or no results * Execute a query that returns one or no results
* *

View File

@ -3,6 +3,7 @@ package solutions.bitbadger.documents.scala
import solutions.bitbadger.documents.DocumentException import solutions.bitbadger.documents.DocumentException
import solutions.bitbadger.documents.java.Results as CoreResults import solutions.bitbadger.documents.java.Results as CoreResults
import java.io.PrintWriter
import java.sql.{PreparedStatement, ResultSet, SQLException} import java.sql.{PreparedStatement, ResultSet, SQLException}
import scala.collection.mutable.ListBuffer import scala.collection.mutable.ListBuffer
import scala.reflect.ClassTag import scala.reflect.ClassTag
@ -47,10 +48,9 @@ object Results:
try try
val buffer = ListBuffer[Doc]() val buffer = ListBuffer[Doc]()
Using(stmt.executeQuery()) { rs => Using(stmt.executeQuery()) { rs =>
while (rs.next()) { while rs.next() do
buffer.append(mapFunc(rs, tag)) buffer.append(mapFunc(rs, tag))
} }
}
buffer.toList buffer.toList
catch catch
case ex: SQLException => case ex: SQLException =>
@ -107,12 +107,37 @@ object Results:
try try
val results = StringBuilder("[") val results = StringBuilder("[")
Using(stmt.executeQuery()) { rs => Using(stmt.executeQuery()) { rs =>
while (rs.next()) { while rs.next() do
if (results.length > 2) results.append(",") if (results.length > 2) results.append(",")
results.append(mapFunc(rs)) results.append(mapFunc(rs))
} }
}
results.append("]").toString() results.append("]").toString()
catch catch
case ex: SQLException => case ex: SQLException => throw DocumentException("Error retrieving documents from query: ${ex.message}", ex)
throw DocumentException("Error retrieving documents from query: ${ex.message}", ex)
/**
* Write a JSON array of items for the results of the given command to the given `PrintWriter`, using the specified
* mapping function
*
* @param writer The writer for the results of the query
* @param stmt The prepared statement to execute
* @param mapFunc The mapping function from data reader to JSON text
* @return A string with a JSON array of documents from the query's result
* @throws DocumentException If there is a problem executing the query (unchecked)
*/
def writeJsonArray(writer: PrintWriter, stmt: PreparedStatement, mapFunc: ResultSet => String): Unit =
try
writer.write("[")
Using(stmt.executeQuery()) { rs =>
var isFirst = true
while rs.next() do
if isFirst then
isFirst = false
else
writer.write(",")
writer.write(mapFunc(rs))
}
writer.write("]")
catch
case ex: SQLException => throw DocumentException("Error writing documents from query: ${ex.message}", ex)

View File

@ -3,6 +3,7 @@ package solutions.bitbadger.documents.scala.extensions
import solutions.bitbadger.documents.{DocumentIndex, Field, FieldMatch, Parameter} import solutions.bitbadger.documents.{DocumentIndex, Field, FieldMatch, Parameter}
import solutions.bitbadger.documents.scala.* import solutions.bitbadger.documents.scala.*
import java.io.PrintWriter
import java.sql.{Connection, ResultSet} import java.sql.{Connection, ResultSet}
import scala.reflect.ClassTag import scala.reflect.ClassTag
@ -58,6 +59,32 @@ extension (conn: Connection)
def customJsonArray(query: String, mapFunc: ResultSet => String): String = def customJsonArray(query: String, mapFunc: ResultSet => String): String =
Custom.jsonArray(query, mapFunc) Custom.jsonArray(query, mapFunc)
/**
* Execute a query that writes a JSON array of results to the given `PrintWriter`
*
* @param query The query to retrieve the results
* @param parameters Parameters to use for the query
* @param writer The writer to which the results should be written
* @param mapFunc The mapping function to extract the JSON from the query
* @return A JSON array of results for the given query
* @throws DocumentException If parameters are invalid
*/
def writeCustomJsonArray(query: String, parameters: Seq[Parameter[?]], writer: PrintWriter,
mapFunc: ResultSet => String): Unit =
Custom.writeJsonArray(query, parameters, writer, conn, mapFunc)
/**
* Execute a query that writes a JSON array of results to the given `PrintWriter`
*
* @param query The query to retrieve the results
* @param writer The writer to which the results should be written
* @param mapFunc The mapping function to extract the JSON from the query
* @return A JSON array of results for the given query
* @throws DocumentException If parameters are invalid
*/
def writeCustomJsonArray(query: String, writer: PrintWriter, mapFunc: ResultSet => String): Unit =
Custom.writeJsonArray(query, writer, mapFunc)
/** /**
* Execute a query that returns one or no results * Execute a query that returns one or no results
* *

View File

@ -7,6 +7,7 @@ import solutions.bitbadger.documents.scala.extensions.*
import solutions.bitbadger.documents.scala.tests.TEST_TABLE import solutions.bitbadger.documents.scala.tests.TEST_TABLE
import solutions.bitbadger.documents.{Configuration, Field, Parameter, ParameterType} import solutions.bitbadger.documents.{Configuration, Field, Parameter, ParameterType}
import java.io.{PrintWriter, StringWriter}
import scala.jdk.CollectionConverters.* import scala.jdk.CollectionConverters.*
object CustomFunctions: object CustomFunctions:
@ -29,19 +30,43 @@ object CustomFunctions:
def jsonArraySingle(db: ThrowawayDatabase): Unit = def jsonArraySingle(db: ThrowawayDatabase): Unit =
db.conn.insert(TEST_TABLE, ArrayDocument("one", "2" :: "3" :: Nil)) db.conn.insert(TEST_TABLE, ArrayDocument("one", "2" :: "3" :: Nil))
assertEquals(JsonFunctions.maybeJsonB("[{\"id\":\"one\",\"values\":[\"2\",\"3\"]}]"), assertEquals(JsonFunctions.maybeJsonB("""[{"id":"one","values":["2","3"]}]"""),
db.conn.customJsonArray(FindQuery.all(TEST_TABLE), Nil, Results.jsonFromData), db.conn.customJsonArray(FindQuery.all(TEST_TABLE), Nil, Results.jsonFromData),
"A single document list was not represented correctly") "A single document list was not represented correctly")
def jsonArrayMany(db: ThrowawayDatabase): Unit = def jsonArrayMany(db: ThrowawayDatabase): Unit =
ArrayDocument.testDocuments.foreach { doc => db.conn.insert(TEST_TABLE, doc) } ArrayDocument.testDocuments.foreach { doc => db.conn.insert(TEST_TABLE, doc) }
assertEquals(JsonFunctions.maybeJsonB("[{\"id\":\"first\",\"values\":[\"a\",\"b\",\"c\"]}," assertEquals(JsonFunctions.maybeJsonB("""[{"id":"first","values":["a","b","c"]},"""
+ "{\"id\":\"second\",\"values\":[\"c\",\"d\",\"e\"]}," + """{"id":"second","values":["c","d","e"]},{"id":"third","values":["x","y","z"]}]"""),
+ "{\"id\":\"third\",\"values\":[\"x\",\"y\",\"z\"]}]"),
db.conn.customJsonArray(FindQuery.all(TEST_TABLE) + QueryUtils.orderBy((Field.named("id") :: Nil).asJava), Nil, db.conn.customJsonArray(FindQuery.all(TEST_TABLE) + QueryUtils.orderBy((Field.named("id") :: Nil).asJava), Nil,
Results.jsonFromData), Results.jsonFromData),
"A multiple document list was not represented correctly") "A multiple document list was not represented correctly")
def writeJsonArrayEmpty(db: ThrowawayDatabase): Unit =
assertEquals(0L, db.conn.countAll(TEST_TABLE), "The test table should be empty")
val output = StringWriter()
val writer = PrintWriter(output)
db.conn.writeCustomJsonArray(FindQuery.all(TEST_TABLE), Nil, writer, Results.jsonFromData)
assertEquals("[]", output.toString, "An empty list was not represented correctly")
def writeJsonArraySingle(db: ThrowawayDatabase): Unit =
db.conn.insert(TEST_TABLE, ArrayDocument("one", "2" :: "3" :: Nil))
val output = StringWriter()
val writer = PrintWriter(output)
db.conn.writeCustomJsonArray(FindQuery.all(TEST_TABLE), Nil, writer, Results.jsonFromData)
assertEquals(JsonFunctions.maybeJsonB("""[{"id":"one","values":["2","3"]}]"""), output.toString,
"A single document list was not represented correctly")
def writeJsonArrayMany(db: ThrowawayDatabase): Unit =
ArrayDocument.testDocuments.foreach { doc => db.conn.insert(TEST_TABLE, doc) }
val output = StringWriter()
val writer = PrintWriter(output)
db.conn.writeCustomJsonArray(FindQuery.all(TEST_TABLE) + QueryUtils.orderBy((Field.named("id") :: Nil).asJava), Nil,
writer, Results.jsonFromData)
assertEquals(JsonFunctions.maybeJsonB("""[{"id":"first","values":["a","b","c"]},"""
+ """{"id":"second","values":["c","d","e"]},{"id":"third","values":["x","y","z"]}]"""),
output.toString, "A multiple document list was not represented correctly")
def singleNone(db: ThrowawayDatabase): Unit = def singleNone(db: ThrowawayDatabase): Unit =
assertTrue(db.conn.customSingle[JsonDocument](FindQuery.all(TEST_TABLE), Results.fromData).isEmpty, assertTrue(db.conn.customSingle[JsonDocument](FindQuery.all(TEST_TABLE), Results.fromData).isEmpty,
"There should not have been a document returned") "There should not have been a document returned")

View File

@ -32,6 +32,21 @@ class PostgreSQLCustomIT:
def jsonArrayMany(): Unit = def jsonArrayMany(): Unit =
Using(PgDB()) { db => CustomFunctions.jsonArrayMany(db) } Using(PgDB()) { db => CustomFunctions.jsonArrayMany(db) }
@Test
@DisplayName("writeJsonArray succeeds with empty array")
def writeJsonArrayEmpty(): Unit =
Using(PgDB()) { db => CustomFunctions.writeJsonArrayEmpty(db) }
@Test
@DisplayName("writeJsonArray succeeds with a single-item array")
def writeJsonArraySingle(): Unit =
Using(PgDB()) { db => CustomFunctions.writeJsonArraySingle(db) }
@Test
@DisplayName("writeJsonArray succeeds with a multi-item array")
def writeJsonArrayMany(): Unit =
Using(PgDB()) { db => CustomFunctions.writeJsonArrayMany(db) }
@Test @Test
@DisplayName("single succeeds when document not found") @DisplayName("single succeeds when document not found")
def singleNone(): Unit = def singleNone(): Unit =

View File

@ -32,6 +32,21 @@ class SQLiteCustomIT:
def jsonArrayMany(): Unit = def jsonArrayMany(): Unit =
Using(SQLiteDB()) { db => CustomFunctions.jsonArrayMany(db) } Using(SQLiteDB()) { db => CustomFunctions.jsonArrayMany(db) }
@Test
@DisplayName("writeJsonArray succeeds with empty array")
def writeJsonArrayEmpty(): Unit =
Using(SQLiteDB()) { db => CustomFunctions.writeJsonArrayEmpty(db) }
@Test
@DisplayName("writeJsonArray succeeds with a single-item array")
def writeJsonArraySingle(): Unit =
Using(SQLiteDB()) { db => CustomFunctions.writeJsonArraySingle(db) }
@Test
@DisplayName("writeJsonArray succeeds with a multi-item array")
def writeJsonArrayMany(): Unit =
Using(SQLiteDB()) { db => CustomFunctions.writeJsonArrayMany(db) }
@Test @Test
@DisplayName("single succeeds when document not found") @DisplayName("single succeeds when document not found")
def singleNone(): Unit = def singleNone(): Unit =