Initial Development #1

Merged
danieljsummers merged 88 commits from v1-rc into main 2025-04-16 01:29:20 +00:00
77 changed files with 670 additions and 679 deletions
Showing only changes of commit f1385b6d55 - Show all commits

View File

@ -106,6 +106,9 @@
<goals> <goals>
<goal>jar</goal> <goal>jar</goal>
</goals> </goals>
<configuration>
<sourcepath>${project.basedir}/src/main/kotlin</sourcepath>
</configuration>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>

View File

@ -62,12 +62,12 @@ object Count:
* Count documents using a JSON containment query (PostgreSQL only) * Count documents using a JSON containment query (PostgreSQL only)
* *
* @param tableName The name of the table in which documents should be counted * @param tableName The name of the table in which documents should be counted
* @param criteria The object for which JSON containment should be checked * @param criteria The object for which JSON containment should be checked
* @param conn The connection on which the count should be executed * @param conn The connection on which the count should be executed
* @return A count of the matching documents in the table * @return A count of the matching documents in the table
* @throws DocumentException If called on a SQLite connection * @throws DocumentException If called on a SQLite connection
*/ */
def byContains[TContains](tableName: String, criteria: TContains, conn: Connection): Long = def byContains[A](tableName: String, criteria: A, conn: Connection): Long =
CoreCount.byContains(tableName, criteria, conn) CoreCount.byContains(tableName, criteria, conn)
/** /**
@ -78,7 +78,7 @@ object Count:
* @return A count of the matching documents in the table * @return A count of the matching documents in the table
* @throws DocumentException If called on a SQLite connection * @throws DocumentException If called on a SQLite connection
*/ */
def byContains[TContains](tableName: String, criteria: TContains): Long = def byContains[A](tableName: String, criteria: A): Long =
CoreCount.byContains(tableName, criteria) CoreCount.byContains(tableName, criteria)
/** /**

View File

@ -18,9 +18,9 @@ object Custom:
* @return A list of results for the given query * @return A list of results for the given query
* @throws DocumentException If parameters are invalid * @throws DocumentException If parameters are invalid
*/ */
def list[TDoc](query: String, parameters: Seq[Parameter[?]], conn: Connection, def list[Doc](query: String, parameters: Seq[Parameter[?]], conn: Connection,
mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): List[TDoc] = mapFunc: (ResultSet, ClassTag[Doc]) => Doc)(using tag: ClassTag[Doc]): List[Doc] =
Using(Parameters.apply(conn, query, parameters)) { stmt => Results.toCustomList[TDoc](stmt, mapFunc) }.get Using(Parameters.apply(conn, query, parameters)) { stmt => Results.toCustomList[Doc](stmt, mapFunc) }.get
/** /**
* Execute a query that returns a list of results * Execute a query that returns a list of results
@ -31,8 +31,8 @@ object Custom:
* @return A list of results for the given query * @return A list of results for the given query
* @throws DocumentException If parameters are invalid * @throws DocumentException If parameters are invalid
*/ */
def list[TDoc](query: String, conn: Connection, def list[Doc](query: String, conn: Connection, mapFunc: (ResultSet, ClassTag[Doc]) => Doc)
mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): List[TDoc] = (using tag: ClassTag[Doc]): List[Doc] =
list(query, List(), conn, mapFunc) list(query, List(), conn, mapFunc)
/** /**
@ -44,9 +44,9 @@ object Custom:
* @return A list of results for the given query * @return A list of results for the given query
* @throws DocumentException If parameters are invalid * @throws DocumentException If parameters are invalid
*/ */
def list[TDoc](query: String, parameters: Seq[Parameter[?]], def list[Doc](query: String, parameters: Seq[Parameter[?]], mapFunc: (ResultSet, ClassTag[Doc]) => Doc)
mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): List[TDoc] = (using tag: ClassTag[Doc]): List[Doc] =
Using(Configuration.dbConn()) { conn => list[TDoc](query, parameters, conn, mapFunc) }.get Using(Configuration.dbConn()) { conn => list[Doc](query, parameters, conn, mapFunc) }.get
/** /**
* Execute a query that returns a list of results (creates connection) * Execute a query that returns a list of results (creates connection)
@ -56,8 +56,7 @@ object Custom:
* @return A list of results for the given query * @return A list of results for the given query
* @throws DocumentException If parameters are invalid * @throws DocumentException If parameters are invalid
*/ */
def list[TDoc](query: String, def list[Doc](query: String, mapFunc: (ResultSet, ClassTag[Doc]) => Doc)(using tag: ClassTag[Doc]): List[Doc] =
mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): List[TDoc] =
list(query, List(), mapFunc) list(query, List(), mapFunc)
/** /**
@ -70,9 +69,9 @@ object Custom:
* @return An `Option` value, with the document if one matches the query * @return An `Option` value, with the document if one matches the query
* @throws DocumentException If parameters are invalid * @throws DocumentException If parameters are invalid
*/ */
def single[TDoc](query: String, parameters: Seq[Parameter[?]], conn: Connection, def single[Doc](query: String, parameters: Seq[Parameter[?]], conn: Connection,
mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): Option[TDoc] = mapFunc: (ResultSet, ClassTag[Doc]) => Doc)(using tag: ClassTag[Doc]): Option[Doc] =
list[TDoc](s"$query LIMIT 1", parameters, conn, mapFunc).headOption list[Doc](s"$query LIMIT 1", parameters, conn, mapFunc).headOption
/** /**
* Execute a query that returns one or no results * Execute a query that returns one or no results
@ -83,9 +82,9 @@ object Custom:
* @return An `Option` value, with the document if one matches the query * @return An `Option` value, with the document if one matches the query
* @throws DocumentException If parameters are invalid * @throws DocumentException If parameters are invalid
*/ */
def single[TDoc](query: String, conn: Connection, def single[Doc](query: String, conn: Connection, mapFunc: (ResultSet, ClassTag[Doc]) => Doc)
mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): Option[TDoc] = (using tag: ClassTag[Doc]): Option[Doc] =
list[TDoc](s"$query LIMIT 1", List(), conn, mapFunc).headOption list[Doc](s"$query LIMIT 1", List(), conn, mapFunc).headOption
/** /**
* Execute a query that returns one or no results (creates connection) * Execute a query that returns one or no results (creates connection)
@ -96,9 +95,9 @@ object Custom:
* @return An `Option` value, with the document if one matches the query * @return An `Option` value, with the document if one matches the query
* @throws DocumentException If parameters are invalid * @throws DocumentException If parameters are invalid
*/ */
def single[TDoc](query: String, parameters: Seq[Parameter[?]], def single[Doc](query: String, parameters: Seq[Parameter[?]], mapFunc: (ResultSet, ClassTag[Doc]) => Doc)
mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): Option[TDoc] = (using tag: ClassTag[Doc]): Option[Doc] =
Using(Configuration.dbConn()) { conn => single[TDoc](query, parameters, conn, mapFunc) }.get Using(Configuration.dbConn()) { conn => single[Doc](query, parameters, conn, mapFunc) }.get
/** /**
* Execute a query that returns one or no results (creates connection) * Execute a query that returns one or no results (creates connection)
@ -108,9 +107,8 @@ object Custom:
* @return An `Option` value, with the document if one matches the query * @return An `Option` value, with the document if one matches the query
* @throws DocumentException If parameters are invalid * @throws DocumentException If parameters are invalid
*/ */
def single[TDoc](query: String, def single[Doc](query: String, mapFunc: (ResultSet, ClassTag[Doc]) => Doc)(using tag: ClassTag[Doc]): Option[Doc] =
mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): Option[TDoc] = single[Doc](query, List(), mapFunc)
single[TDoc](query, List(), mapFunc)
/** /**
* Execute a query that returns no results * Execute a query that returns no results
@ -162,8 +160,8 @@ object Custom:
* @return The scalar value from the query * @return The scalar value from the query
* @throws DocumentException If parameters are invalid * @throws DocumentException If parameters are invalid
*/ */
def scalar[T](query: String, parameters: Seq[Parameter[?]], conn: Connection, def scalar[A](query: String, parameters: Seq[Parameter[?]], conn: Connection, mapFunc: (ResultSet, ClassTag[A]) => A)
mapFunc: (ResultSet, ClassTag[T]) => T)(implicit tag: ClassTag[T]): T = (using tag: ClassTag[A]): A =
Using(Parameters.apply(conn, query, parameters)) { stmt => Using(Parameters.apply(conn, query, parameters)) { stmt =>
Using(stmt.executeQuery()) { rs => Using(stmt.executeQuery()) { rs =>
rs.next() rs.next()
@ -180,9 +178,8 @@ object Custom:
* @return The scalar value from the query * @return The scalar value from the query
* @throws DocumentException If parameters are invalid * @throws DocumentException If parameters are invalid
*/ */
def scalar[T](query: String, conn: Connection, def scalar[A](query: String, conn: Connection, mapFunc: (ResultSet, ClassTag[A]) => A)(using tag: ClassTag[A]): A =
mapFunc: (ResultSet, ClassTag[T]) => T)(implicit tag: ClassTag[T]): T = scalar[A](query, List(), conn, mapFunc)
scalar[T](query, List(), conn, mapFunc)
/** /**
* Execute a query that returns a scalar result (creates connection) * Execute a query that returns a scalar result (creates connection)
@ -193,9 +190,9 @@ object Custom:
* @return The scalar value from the query * @return The scalar value from the query
* @throws DocumentException If parameters are invalid * @throws DocumentException If parameters are invalid
*/ */
def scalar[T](query: String, parameters: Seq[Parameter[?]], def scalar[A](query: String, parameters: Seq[Parameter[?]], mapFunc: (ResultSet, ClassTag[A]) => A)
mapFunc: (ResultSet, ClassTag[T]) => T)(implicit tag: ClassTag[T]): T = (using tag: ClassTag[A]): A =
Using(Configuration.dbConn()) { conn => scalar[T](query, parameters, conn, mapFunc) }.get Using(Configuration.dbConn()) { conn => scalar[A](query, parameters, conn, mapFunc) }.get
/** /**
* Execute a query that returns a scalar result (creates connection) * Execute a query that returns a scalar result (creates connection)
@ -205,6 +202,5 @@ object Custom:
* @return The scalar value from the query * @return The scalar value from the query
* @throws DocumentException If parameters are invalid * @throws DocumentException If parameters are invalid
*/ */
def scalar[T](query: String, def scalar[A](query: String, mapFunc: (ResultSet, ClassTag[A]) => A)(using tag: ClassTag[A]): A =
mapFunc: (ResultSet, ClassTag[T]) => T)(implicit tag: ClassTag[T]): T = scalar[A](query, List(), mapFunc)
scalar[T](query, List(), mapFunc)

View File

@ -19,7 +19,7 @@ object Delete:
* @param conn The connection on which the deletion should be executed * @param conn The connection on which the deletion should be executed
* @throws DocumentException If no dialect has been configured * @throws DocumentException If no dialect has been configured
*/ */
def byId[TKey](tableName: String, docId: TKey, conn: Connection): Unit = def byId[Key](tableName: String, docId: Key, conn: Connection): Unit =
CoreDelete.byId(tableName, docId, conn) CoreDelete.byId(tableName, docId, conn)
/** /**
@ -29,7 +29,7 @@ object Delete:
* @param docId The ID of the document to be deleted * @param docId The ID of the document to be deleted
* @throws DocumentException If no connection string has been set * @throws DocumentException If no connection string has been set
*/ */
def byId[TKey](tableName: String, docId: TKey): Unit = def byId[Key](tableName: String, docId: Key): Unit =
CoreDelete.byId(tableName, docId) CoreDelete.byId(tableName, docId)
/** /**
@ -63,7 +63,7 @@ object Delete:
* @param conn The connection on which the deletion should be executed * @param conn The connection on which the deletion should be executed
* @throws DocumentException If called on a SQLite connection * @throws DocumentException If called on a SQLite connection
*/ */
def byContains[TContains](tableName: String, criteria: TContains, conn: Connection): Unit = def byContains[A](tableName: String, criteria: A, conn: Connection): Unit =
CoreDelete.byContains(tableName, criteria, conn) CoreDelete.byContains(tableName, criteria, conn)
/** /**
@ -73,7 +73,7 @@ object Delete:
* @param criteria The object for which JSON containment should be checked * @param criteria The object for which JSON containment should be checked
* @throws DocumentException If no connection string has been set, or if called on a SQLite connection * @throws DocumentException If no connection string has been set, or if called on a SQLite connection
*/ */
def byContains[TContains](tableName: String, criteria: TContains): Unit = def byContains[A](tableName: String, criteria: A): Unit =
CoreDelete.byContains(tableName, criteria) CoreDelete.byContains(tableName, criteria)
/** /**
@ -91,7 +91,7 @@ object Delete:
* Delete documents using a JSON Path match query (PostgreSQL only; creates connection) * Delete documents using a JSON Path match query (PostgreSQL only; creates connection)
* *
* @param tableName The name of the table from which documents should be deleted * @param tableName The name of the table from which documents should be deleted
* @param path The JSON path comparison to match * @param path The JSON path comparison to match
* @throws DocumentException If no connection string has been set, or if called on a SQLite connection * @throws DocumentException If no connection string has been set, or if called on a SQLite connection
*/ */
def byJsonPath(tableName: String, path: String): Unit = def byJsonPath(tableName: String, path: String): Unit =

View File

@ -14,7 +14,7 @@ object Document:
* @param conn The connection on which the query should be executed * @param conn The connection on which the query should be executed
* @throws DocumentException If IDs are misconfigured, or if the database command fails * @throws DocumentException If IDs are misconfigured, or if the database command fails
*/ */
def insert[TDoc](tableName: String, document: TDoc, conn: Connection): Unit = def insert[Doc](tableName: String, document: Doc, conn: Connection): Unit =
CoreDocument.insert(tableName, document, conn) CoreDocument.insert(tableName, document, conn)
/** /**
@ -24,49 +24,49 @@ object Document:
* @param document The document to be inserted * @param document The document to be inserted
* @throws DocumentException If IDs are misconfigured, or if the database command fails * @throws DocumentException If IDs are misconfigured, or if the database command fails
*/ */
def insert[TDoc](tableName: String, document: TDoc): Unit = def insert[Doc](tableName: String, document: Doc): Unit =
CoreDocument.insert(tableName, document) CoreDocument.insert(tableName, document)
/** /**
* Save a document, inserting it if it does not exist and updating it if it does (AKA "upsert") * Save a document, inserting it if it does not exist and updating it if it does (AKA "upsert")
* *
* @param tableName The table in which the document should be saved (may include schema) * @param tableName The table in which the document should be saved (may include schema)
* @param document The document to be saved * @param document The document to be saved
* @param conn The connection on which the query should be executed * @param conn The connection on which the query should be executed
* @throws DocumentException If the database command fails * @throws DocumentException If the database command fails
*/ */
def save[TDoc](tableName: String, document: TDoc, conn: Connection): Unit = def save[Doc](tableName: String, document: Doc, conn: Connection): Unit =
CoreDocument.save(tableName, document, conn) CoreDocument.save(tableName, document, conn)
/** /**
* Save a document, inserting it if it does not exist and updating it if it does (AKA "upsert"; creates connection) * Save a document, inserting it if it does not exist and updating it if it does (AKA "upsert"; creates connection)
* *
* @param tableName The table in which the document should be saved (may include schema) * @param tableName The table in which the document should be saved (may include schema)
* @param document The document to be saved * @param document The document to be saved
* @throws DocumentException If the database command fails * @throws DocumentException If the database command fails
*/ */
def save[TDoc](tableName: String, document: TDoc): Unit = def save[Doc](tableName: String, document: Doc): Unit =
CoreDocument.save(tableName, document) CoreDocument.save(tableName, document)
/** /**
* Update (replace) a document by its ID * Update (replace) a document by its ID
* *
* @param tableName The table in which the document should be replaced (may include schema) * @param tableName The table in which the document should be replaced (may include schema)
* @param docId The ID of the document to be replaced * @param docId The ID of the document to be replaced
* @param document The document to be replaced * @param document The document to be replaced
* @param conn The connection on which the query should be executed * @param conn The connection on which the query should be executed
* @throws DocumentException If no dialect has been configured, or if the database command fails * @throws DocumentException If no dialect has been configured, or if the database command fails
*/ */
def update[TKey, TDoc](tableName: String, docId: TKey, document: TDoc, conn: Connection): Unit = def update[Key, Doc](tableName: String, docId: Key, document: Doc, conn: Connection): Unit =
CoreDocument.update(tableName, docId, document, conn) CoreDocument.update(tableName, docId, document, conn)
/** /**
* Update (replace) a document by its ID (creates connection) * Update (replace) a document by its ID (creates connection)
* *
* @param tableName The table in which the document should be replaced (may include schema) * @param tableName The table in which the document should be replaced (may include schema)
* @param docId The ID of the document to be replaced * @param docId The ID of the document to be replaced
* @param document The document to be replaced * @param document The document to be replaced
* @throws DocumentException If no dialect has been configured, or if the database command fails * @throws DocumentException If no dialect has been configured, or if the database command fails
*/ */
def update[TKey, TDoc](tableName: String, docId: TKey, document: TDoc): Unit = def update[Key, Doc](tableName: String, docId: Key, document: Doc): Unit =
CoreDocument.update(tableName, docId, document) CoreDocument.update(tableName, docId, document)

View File

@ -20,7 +20,7 @@ object Exists:
* @return True if the document exists, false if not * @return True if the document exists, false if not
* @throws DocumentException If no dialect has been configured * @throws DocumentException If no dialect has been configured
*/ */
def byId[TKey](tableName: String, docId: TKey, conn: Connection): Boolean = def byId[Key](tableName: String, docId: Key, conn: Connection): Boolean =
CoreExists.byId(tableName, docId, conn) CoreExists.byId(tableName, docId, conn)
/** /**
@ -31,7 +31,7 @@ object Exists:
* @return True if the document exists, false if not * @return True if the document exists, false if not
* @throws DocumentException If no connection string has been set * @throws DocumentException If no connection string has been set
*/ */
def byId[TKey](tableName: String, docId: TKey): Boolean = def byId[Key](tableName: String, docId: Key): Boolean =
CoreExists.byId(tableName, docId) CoreExists.byId(tableName, docId)
/** /**
@ -68,7 +68,7 @@ object Exists:
* @return True if any matching documents exist, false if not * @return True if any matching documents exist, false if not
* @throws DocumentException If called on a SQLite connection * @throws DocumentException If called on a SQLite connection
*/ */
def byContains[TContains](tableName: String, criteria: TContains, conn: Connection): Boolean = def byContains[A](tableName: String, criteria: A, conn: Connection): Boolean =
CoreExists.byContains(tableName, criteria, conn) CoreExists.byContains(tableName, criteria, conn)
/** /**
@ -79,7 +79,7 @@ object Exists:
* @return True if any matching documents exist, false if not * @return True if any matching documents exist, false if not
* @throws DocumentException If no connection string has been set, or if called on a SQLite connection * @throws DocumentException If no connection string has been set, or if called on a SQLite connection
*/ */
def byContains[TContains](tableName: String, criteria: TContains): Boolean = def byContains[A](tableName: String, criteria: A): Boolean =
CoreExists.byContains(tableName, criteria) CoreExists.byContains(tableName, criteria)
/** /**
@ -98,7 +98,7 @@ object Exists:
* Determine document existence using a JSON Path match query (PostgreSQL only; creates connection) * Determine document existence using a JSON Path match query (PostgreSQL only; creates connection)
* *
* @param tableName The name of the table in which document existence should be checked * @param tableName The name of the table in which document existence should be checked
* @param path The JSON path comparison to match * @param path The JSON path comparison to match
* @return True if any matching documents exist, false if not * @return True if any matching documents exist, false if not
* @throws DocumentException If no connection string has been set, or if called on a SQLite connection * @throws DocumentException If no connection string has been set, or if called on a SQLite connection
*/ */

View File

@ -22,8 +22,8 @@ object Find:
* @return A list of documents from the given table * @return A list of documents from the given table
* @throws DocumentException If query execution fails * @throws DocumentException If query execution fails
*/ */
def all[TDoc](tableName: String, orderBy: Seq[Field[?]], conn: Connection)(implicit tag: ClassTag[TDoc]): List[TDoc] = def all[Doc](tableName: String, orderBy: Seq[Field[?]], conn: Connection)(using tag: ClassTag[Doc]): List[Doc] =
Custom.list[TDoc](FindQuery.all(tableName) + QueryUtils.orderBy(orderBy.asJava), conn, Results.fromData) Custom.list[Doc](FindQuery.all(tableName) + QueryUtils.orderBy(orderBy.asJava), conn, Results.fromData)
/** /**
* Retrieve all documents in the given table, ordering results by the optional given fields * Retrieve all documents in the given table, ordering results by the optional given fields
@ -33,43 +33,43 @@ object Find:
* @return A list of documents from the given table * @return A list of documents from the given table
* @throws DocumentException If query execution fails * @throws DocumentException If query execution fails
*/ */
def all[TDoc](tableName: String, conn: Connection)(implicit tag: ClassTag[TDoc]): List[TDoc] = def all[Doc](tableName: String, conn: Connection)(using tag: ClassTag[Doc]): List[Doc] =
all[TDoc](tableName, List(), conn) all[Doc](tableName, List(), conn)
/** /**
* Retrieve all documents in the given table (creates connection) * Retrieve all documents in the given table (creates connection)
* *
* @param tableName The table from which documents should be retrieved * @param tableName The table from which documents should be retrieved
* @param orderBy Fields by which the query should be ordered (optional, defaults to no ordering) * @param orderBy Fields by which the query should be ordered (optional, defaults to no ordering)
* @return A list of documents from the given table * @return A list of documents from the given table
* @throws DocumentException If no connection string has been set, or if query execution fails * @throws DocumentException If no connection string has been set, or if query execution fails
*/ */
def all[TDoc](tableName: String, orderBy: Seq[Field[?]] = List())(implicit tag: ClassTag[TDoc]): List[TDoc] = def all[Doc](tableName: String, orderBy: Seq[Field[?]] = List())(using tag: ClassTag[Doc]): List[Doc] =
Using(Configuration.dbConn()) { conn => all[TDoc](tableName, orderBy, conn) }.get Using(Configuration.dbConn()) { conn => all[Doc](tableName, orderBy, conn) }.get
/** /**
* Retrieve a document by its ID * Retrieve a document by its ID
* *
* @param tableName The table from which the document should be retrieved * @param tableName The table from which the document should be retrieved
* @param docId The ID of the document to retrieve * @param docId The ID of the document to retrieve
* @param conn The connection over which documents should be retrieved * @param conn The connection over which documents should be retrieved
* @return An `Option` with the document if it is found * @return An `Option` with the document if it is found
* @throws DocumentException If no dialect has been configured * @throws DocumentException If no dialect has been configured
*/ */
def byId[TKey, TDoc](tableName: String, docId: TKey, conn: Connection)(implicit tag: ClassTag[TDoc]): Option[TDoc] = def byId[Key, Doc](tableName: String, docId: Key, conn: Connection)(using tag: ClassTag[Doc]): Option[Doc] =
Custom.single[TDoc](FindQuery.byId(tableName, docId), Custom.single[Doc](FindQuery.byId(tableName, docId),
Parameters.addFields(Field.equal(Configuration.idField, docId, ":id") :: Nil).toSeq, conn, Results.fromData) Parameters.addFields(Field.equal(Configuration.idField, docId, ":id") :: Nil).toSeq, conn, Results.fromData)
/** /**
* Retrieve a document by its ID (creates connection * Retrieve a document by its ID (creates connection
* *
* @param tableName The table from which the document should be retrieved * @param tableName The table from which the document should be retrieved
* @param docId The ID of the document to retrieve * @param docId The ID of the document to retrieve
* @return An `Option` with the document if it is found * @return An `Option` with the document if it is found
* @throws DocumentException If no connection string has been set * @throws DocumentException If no connection string has been set
*/ */
def byId[TKey, TDoc](tableName: String, docId: TKey)(implicit tag: ClassTag[TDoc]): Option[TDoc] = def byId[Key, Doc](tableName: String, docId: Key)(using tag: ClassTag[Doc]): Option[Doc] =
Using(Configuration.dbConn()) { conn => byId[TKey, TDoc](tableName, docId, conn) }.get Using(Configuration.dbConn()) { conn => byId[Key, Doc](tableName, docId, conn) }.get
/** /**
* Retrieve documents using a field comparison, ordering results by the given fields * Retrieve documents using a field comparison, ordering results by the given fields
@ -82,10 +82,10 @@ object Find:
* @return A list of documents matching the field comparison * @return A list of documents matching the field comparison
* @throws DocumentException If no dialect has been configured, or if parameters are invalid * @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/ */
def byFields[TDoc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch], orderBy: Seq[Field[?]], def byFields[Doc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch], orderBy: Seq[Field[?]],
conn: Connection)(implicit tag: ClassTag[TDoc]): List[TDoc] = conn: Connection)(using tag: ClassTag[Doc]): List[Doc] =
val named = Parameters.nameFields(fields) val named = Parameters.nameFields(fields)
Custom.list[TDoc]( Custom.list[Doc](
FindQuery.byFields(tableName, named.asJava, howMatched.orNull) + QueryUtils.orderBy(orderBy.asJava), FindQuery.byFields(tableName, named.asJava, howMatched.orNull) + QueryUtils.orderBy(orderBy.asJava),
Parameters.addFields(named).toSeq, conn, Results.fromData) Parameters.addFields(named).toSeq, conn, Results.fromData)
@ -99,9 +99,9 @@ object Find:
* @return A list of documents matching the field comparison * @return A list of documents matching the field comparison
* @throws DocumentException If no dialect has been configured, or if parameters are invalid * @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/ */
def byFields[TDoc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch], conn: Connection) def byFields[Doc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch], conn: Connection)
(implicit tag: ClassTag[TDoc]): List[TDoc] = (using tag: ClassTag[Doc]): List[Doc] =
byFields[TDoc](tableName, fields, howMatched, List(), conn) byFields[Doc](tableName, fields, howMatched, List(), conn)
/** /**
* Retrieve documents using a field comparison, ordering results by the given fields * Retrieve documents using a field comparison, ordering results by the given fields
@ -113,9 +113,9 @@ object Find:
* @return A list of documents matching the field comparison * @return A list of documents matching the field comparison
* @throws DocumentException If no dialect has been configured, or if parameters are invalid * @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/ */
def byFields[TDoc](tableName: String, fields: Seq[Field[?]], orderBy: Seq[Field[?]], conn: Connection) def byFields[Doc](tableName: String, fields: Seq[Field[?]], orderBy: Seq[Field[?]], conn: Connection)
(implicit tag: ClassTag[TDoc]): List[TDoc] = (using tag: ClassTag[Doc]): List[Doc] =
byFields[TDoc](tableName, fields, None, orderBy, conn) byFields[Doc](tableName, fields, None, orderBy, conn)
/** /**
* Retrieve documents using a field comparison, ordering results by the given fields (creates connection) * Retrieve documents using a field comparison, ordering results by the given fields (creates connection)
@ -127,9 +127,9 @@ object Find:
* @return A list of documents matching the field comparison * @return A list of documents matching the field comparison
* @throws DocumentException If no connection string has been set, or if parameters are invalid * @throws DocumentException If no connection string has been set, or if parameters are invalid
*/ */
def byFields[TDoc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch] = None, def byFields[Doc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch] = None,
orderBy: Seq[Field[?]] = List())(implicit tag: ClassTag[TDoc]): List[TDoc] = orderBy: Seq[Field[?]] = List())(using tag: ClassTag[Doc]): List[Doc] =
Using(Configuration.dbConn()) { conn => byFields[TDoc](tableName, fields, howMatched, orderBy, conn) }.get Using(Configuration.dbConn()) { conn => byFields[Doc](tableName, fields, howMatched, orderBy, conn) }.get
/** /**
* Retrieve documents using a JSON containment query, ordering results by the given fields (PostgreSQL only) * Retrieve documents using a JSON containment query, ordering results by the given fields (PostgreSQL only)
@ -141,9 +141,9 @@ object Find:
* @return A list of documents matching the JSON containment query * @return A list of documents matching the JSON containment query
* @throws DocumentException If called on a SQLite connection * @throws DocumentException If called on a SQLite connection
*/ */
def byContains[TDoc, TContains](tableName: String, criteria: TContains, orderBy: Seq[Field[?]], def byContains[Doc, A](tableName: String, criteria: A, orderBy: Seq[Field[?]], conn: Connection)
conn: Connection)(implicit tag: ClassTag[TDoc]): List[TDoc] = (using tag: ClassTag[Doc]): List[Doc] =
Custom.list[TDoc](FindQuery.byContains(tableName) + QueryUtils.orderBy(orderBy.asJava), Custom.list[Doc](FindQuery.byContains(tableName) + QueryUtils.orderBy(orderBy.asJava),
Parameters.json(":criteria", criteria) :: Nil, conn, Results.fromData) Parameters.json(":criteria", criteria) :: Nil, conn, Results.fromData)
/** /**
@ -155,9 +155,8 @@ object Find:
* @return A list of documents matching the JSON containment query * @return A list of documents matching the JSON containment query
* @throws DocumentException If called on a SQLite connection * @throws DocumentException If called on a SQLite connection
*/ */
def byContains[TDoc, TContains](tableName: String, criteria: TContains, conn: Connection) def byContains[Doc, A](tableName: String, criteria: A, conn: Connection)(using tag: ClassTag[Doc]): List[Doc] =
(implicit tag: ClassTag[TDoc]): List[TDoc] = byContains[Doc, A](tableName, criteria, List(), conn)
byContains[TDoc, TContains](tableName, criteria, List(), conn)
/** /**
* Retrieve documents using a JSON containment query, ordering results by the given fields (PostgreSQL only; creates * Retrieve documents using a JSON containment query, ordering results by the given fields (PostgreSQL only; creates
@ -169,9 +168,9 @@ object Find:
* @return A list of documents matching the JSON containment query * @return A list of documents matching the JSON containment query
* @throws DocumentException If no connection string has been set, or if called on a SQLite connection * @throws DocumentException If no connection string has been set, or if called on a SQLite connection
*/ */
def byContains[TDoc, TContains](tableName: String, criteria: TContains, orderBy: Seq[Field[?]] = List()) def byContains[Doc, A](tableName: String, criteria: A, orderBy: Seq[Field[?]] = List())
(implicit tag: ClassTag[TDoc]): List[TDoc] = (using tag: ClassTag[Doc]): List[Doc] =
Using(Configuration.dbConn()) { conn => byContains[TDoc, TContains](tableName, criteria, orderBy, conn) }.get Using(Configuration.dbConn()) { conn => byContains[Doc, A](tableName, criteria, orderBy, conn) }.get
/** /**
* Retrieve documents using a JSON Path match query, ordering results by the given fields (PostgreSQL only) * Retrieve documents using a JSON Path match query, ordering results by the given fields (PostgreSQL only)
@ -183,9 +182,9 @@ object Find:
* @return A list of documents matching the JSON Path match query * @return A list of documents matching the JSON Path match query
* @throws DocumentException If called on a SQLite connection * @throws DocumentException If called on a SQLite connection
*/ */
def byJsonPath[TDoc](tableName: String, path: String, orderBy: Seq[Field[?]], conn: Connection) def byJsonPath[Doc](tableName: String, path: String, orderBy: Seq[Field[?]], conn: Connection)
(implicit tag: ClassTag[TDoc]): List[TDoc] = (using tag: ClassTag[Doc]): List[Doc] =
Custom.list[TDoc](FindQuery.byJsonPath(tableName) + QueryUtils.orderBy(orderBy.asJava), Custom.list[Doc](FindQuery.byJsonPath(tableName) + QueryUtils.orderBy(orderBy.asJava),
Parameter(":path", ParameterType.STRING, path) :: Nil, conn, Results.fromData) Parameter(":path", ParameterType.STRING, path) :: Nil, conn, Results.fromData)
/** /**
@ -197,8 +196,8 @@ object Find:
* @return A list of documents matching the JSON Path match query * @return A list of documents matching the JSON Path match query
* @throws DocumentException If called on a SQLite connection * @throws DocumentException If called on a SQLite connection
*/ */
def byJsonPath[TDoc](tableName: String, path: String, conn: Connection)(implicit tag: ClassTag[TDoc]): List[TDoc] = def byJsonPath[Doc](tableName: String, path: String, conn: Connection)(using tag: ClassTag[Doc]): List[Doc] =
byJsonPath[TDoc](tableName, path, List(), conn) byJsonPath[Doc](tableName, path, List(), conn)
/** /**
* Retrieve documents using a JSON Path match query, ordering results by the given fields (PostgreSQL only; creates * Retrieve documents using a JSON Path match query, ordering results by the given fields (PostgreSQL only; creates
@ -210,9 +209,9 @@ object Find:
* @return A list of documents matching the JSON Path match query * @return A list of documents matching the JSON Path match query
* @throws DocumentException If no connection string has been set, or if called on a SQLite connection * @throws DocumentException If no connection string has been set, or if called on a SQLite connection
*/ */
def byJsonPath[TDoc](tableName: String, path: String, orderBy: Seq[Field[?]] = List()) def byJsonPath[Doc](tableName: String, path: String, orderBy: Seq[Field[?]] = List())
(implicit tag: ClassTag[TDoc]): List[TDoc] = (using tag: ClassTag[Doc]): List[Doc] =
Using(Configuration.dbConn()) { conn => byJsonPath[TDoc](tableName, path, orderBy, conn) }.get Using(Configuration.dbConn()) { conn => byJsonPath[Doc](tableName, path, orderBy, conn) }.get
/** /**
* Retrieve the first document using a field comparison and ordering fields * Retrieve the first document using a field comparison and ordering fields
@ -225,10 +224,10 @@ object Find:
* @return An `Option` with the first document matching the field comparison if found * @return An `Option` with the first document matching the field comparison if found
* @throws DocumentException If no dialect has been configured, or if parameters are invalid * @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/ */
def firstByFields[TDoc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch], def firstByFields[Doc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch],
orderBy: Seq[Field[?]], conn: Connection)(implicit tag: ClassTag[TDoc]): Option[TDoc] = orderBy: Seq[Field[?]], conn: Connection)(using tag: ClassTag[Doc]): Option[Doc] =
val named = Parameters.nameFields(fields) val named = Parameters.nameFields(fields)
Custom.single[TDoc]( Custom.single[Doc](
FindQuery.byFields(tableName, named.asJava, howMatched.orNull) + QueryUtils.orderBy(orderBy.asJava), FindQuery.byFields(tableName, named.asJava, howMatched.orNull) + QueryUtils.orderBy(orderBy.asJava),
Parameters.addFields(named).toSeq, conn, Results.fromData) Parameters.addFields(named).toSeq, conn, Results.fromData)
@ -242,9 +241,9 @@ object Find:
* @return An `Option` with the first document matching the field comparison if found * @return An `Option` with the first document matching the field comparison if found
* @throws DocumentException If no dialect has been configured, or if parameters are invalid * @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/ */
def firstByFields[TDoc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch], conn: Connection) def firstByFields[Doc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch], conn: Connection)
(implicit tag: ClassTag[TDoc]): Option[TDoc] = (using tag: ClassTag[Doc]): Option[Doc] =
firstByFields[TDoc](tableName, fields, howMatched, List(), conn) firstByFields[Doc](tableName, fields, howMatched, List(), conn)
/** /**
* Retrieve the first document using a field comparison and ordering fields * Retrieve the first document using a field comparison and ordering fields
@ -256,9 +255,9 @@ object Find:
* @return An `Option` with the first document matching the field comparison if found * @return An `Option` with the first document matching the field comparison if found
* @throws DocumentException If no dialect has been configured, or if parameters are invalid * @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/ */
def firstByFields[TDoc](tableName: String, fields: Seq[Field[?]], orderBy: Seq[Field[?]], conn: Connection) def firstByFields[Doc](tableName: String, fields: Seq[Field[?]], orderBy: Seq[Field[?]], conn: Connection)
(implicit tag: ClassTag[TDoc]): Option[TDoc] = (using tag: ClassTag[Doc]): Option[Doc] =
firstByFields[TDoc](tableName, fields, None, orderBy, conn) firstByFields[Doc](tableName, fields, None, orderBy, conn)
/** /**
* Retrieve the first document using a field comparison * Retrieve the first document using a field comparison
@ -269,9 +268,9 @@ object Find:
* @return An `Option` with the first document matching the field comparison if found * @return An `Option` with the first document matching the field comparison if found
* @throws DocumentException If no dialect has been configured, or if parameters are invalid * @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/ */
def firstByFields[TDoc](tableName: String, fields: Seq[Field[?]], conn: Connection) def firstByFields[Doc](tableName: String, fields: Seq[Field[?]], conn: Connection)
(implicit tag: ClassTag[TDoc]): Option[TDoc] = (using tag: ClassTag[Doc]): Option[Doc] =
firstByFields[TDoc](tableName, fields, None, List(), conn) firstByFields[Doc](tableName, fields, None, List(), conn)
/** /**
* Retrieve the first document using a field comparison and optional ordering fields (creates connection) * Retrieve the first document using a field comparison and optional ordering fields (creates connection)
@ -283,9 +282,9 @@ object Find:
* @return An `Option` with the first document matching the field comparison if found * @return An `Option` with the first document matching the field comparison if found
* @throws DocumentException If no connection string has been set, or if parameters are invalid * @throws DocumentException If no connection string has been set, or if parameters are invalid
*/ */
def firstByFields[TDoc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch] = None, def firstByFields[Doc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch] = None,
orderBy: Seq[Field[?]] = List())(implicit tag: ClassTag[TDoc]): Option[TDoc] = orderBy: Seq[Field[?]] = List())(using tag: ClassTag[Doc]): Option[Doc] =
Using(Configuration.dbConn()) { conn => firstByFields[TDoc](tableName, fields, howMatched, orderBy, conn) }.get Using(Configuration.dbConn()) { conn => firstByFields[Doc](tableName, fields, howMatched, orderBy, conn) }.get
/** /**
* Retrieve the first document using a JSON containment query and ordering fields (PostgreSQL only) * Retrieve the first document using a JSON containment query and ordering fields (PostgreSQL only)
@ -297,9 +296,9 @@ object Find:
* @return An `Option` with the first document matching the JSON containment query if found * @return An `Option` with the first document matching the JSON containment query if found
* @throws DocumentException If called on a SQLite connection * @throws DocumentException If called on a SQLite connection
*/ */
def firstByContains[TDoc, TContains](tableName: String, criteria: TContains, orderBy: Seq[Field[?]], def firstByContains[Doc, A](tableName: String, criteria: A, orderBy: Seq[Field[?]], conn: Connection)
conn: Connection)(implicit tag: ClassTag[TDoc]): Option[TDoc] = (using tag: ClassTag[Doc]): Option[Doc] =
Custom.single[TDoc](FindQuery.byContains(tableName) + QueryUtils.orderBy(orderBy.asJava), Custom.single[Doc](FindQuery.byContains(tableName) + QueryUtils.orderBy(orderBy.asJava),
Parameters.json(":criteria", criteria) :: Nil, conn, Results.fromData) Parameters.json(":criteria", criteria) :: Nil, conn, Results.fromData)
/** /**
@ -311,9 +310,8 @@ object Find:
* @return An `Option` with the first document matching the JSON containment query if found * @return An `Option` with the first document matching the JSON containment query if found
* @throws DocumentException If called on a SQLite connection * @throws DocumentException If called on a SQLite connection
*/ */
def firstByContains[TDoc, TContains](tableName: String, criteria: TContains, conn: Connection) def firstByContains[Doc, A](tableName: String, criteria: A, conn: Connection)(using tag: ClassTag[Doc]): Option[Doc] =
(implicit tag: ClassTag[TDoc]): Option[TDoc] = firstByContains[Doc, A](tableName, criteria, List(), conn)
firstByContains[TDoc, TContains](tableName, criteria, List(), conn)
/** /**
* Retrieve the first document using a JSON containment query and optional ordering fields (PostgreSQL only; creates * Retrieve the first document using a JSON containment query and optional ordering fields (PostgreSQL only; creates
@ -325,23 +323,23 @@ object Find:
* @return An `Option` with the first document matching the JSON containment query if found * @return An `Option` with the first document matching the JSON containment query if found
* @throws DocumentException If no connection string has been set, or if called on a SQLite connection * @throws DocumentException If no connection string has been set, or if called on a SQLite connection
*/ */
def firstByContains[TDoc, TContains](tableName: String, criteria: TContains, orderBy: Seq[Field[?]] = List()) def firstByContains[Doc, A](tableName: String, criteria: A, orderBy: Seq[Field[?]] = List())
(implicit tag: ClassTag[TDoc]): Option[TDoc] = (using tag: ClassTag[Doc]): Option[Doc] =
Using(Configuration.dbConn()) { conn => firstByContains[TDoc, TContains](tableName, criteria, orderBy, conn) }.get Using(Configuration.dbConn()) { conn => firstByContains[Doc, A](tableName, criteria, orderBy, conn) }.get
/** /**
* Retrieve the first document using a JSON Path match query and ordering fields (PostgreSQL only) * Retrieve the first document using a JSON Path match query and ordering fields (PostgreSQL only)
* *
* @param tableName The table from which documents should be retrieved * @param tableName The table from which documents should be retrieved
* @param path The JSON path comparison to match * @param path The JSON path comparison to match
* @param orderBy Fields by which the query should be ordered (optional, defaults to no ordering) * @param orderBy Fields by which the query should be ordered (optional, defaults to no ordering)
* @param conn The connection over which documents should be retrieved * @param conn The connection over which documents should be retrieved
* @return An `Optional` item, with the first document matching the JSON Path match query if found * @return An `Optional` item, with the first document matching the JSON Path match query if found
* @throws DocumentException If called on a SQLite connection * @throws DocumentException If called on a SQLite connection
*/ */
def firstByJsonPath[TDoc](tableName: String, path: String, orderBy: Seq[Field[?]], conn: Connection) def firstByJsonPath[Doc](tableName: String, path: String, orderBy: Seq[Field[?]], conn: Connection)
(implicit tag: ClassTag[TDoc]): Option[TDoc] = (using tag: ClassTag[Doc]): Option[Doc] =
Custom.single[TDoc](FindQuery.byJsonPath(tableName) + QueryUtils.orderBy(orderBy.asJava), Custom.single[Doc](FindQuery.byJsonPath(tableName) + QueryUtils.orderBy(orderBy.asJava),
Parameter(":path", ParameterType.STRING, path) :: Nil, conn, Results.fromData) Parameter(":path", ParameterType.STRING, path) :: Nil, conn, Results.fromData)
/** /**
@ -353,20 +351,19 @@ object Find:
* @return An `Option` with the first document matching the JSON Path match query if found * @return An `Option` with the first document matching the JSON Path match query if found
* @throws DocumentException If called on a SQLite connection * @throws DocumentException If called on a SQLite connection
*/ */
def firstByJsonPath[TDoc](tableName: String, path: String, conn: Connection) def firstByJsonPath[Doc](tableName: String, path: String, conn: Connection)(using tag: ClassTag[Doc]): Option[Doc] =
(implicit tag: ClassTag[TDoc]): Option[TDoc] = firstByJsonPath[Doc](tableName, path, List(), conn)
firstByJsonPath[TDoc](tableName, path, List(), conn)
/** /**
* Retrieve the first document using a JSON Path match query and optional ordering fields (PostgreSQL only; creates * Retrieve the first document using a JSON Path match query and optional ordering fields (PostgreSQL only; creates
* connection) * connection)
* *
* @param tableName The table from which documents should be retrieved * @param tableName The table from which documents should be retrieved
* @param path The JSON path comparison to match * @param path The JSON path comparison to match
* @param orderBy Fields by which the query should be ordered (optional, defaults to no ordering) * @param orderBy Fields by which the query should be ordered (optional, defaults to no ordering)
* @return An `Optional` item, with the first document matching the JSON Path match query if found * @return An `Optional` item, with the first document matching the JSON Path match query if found
* @throws DocumentException If no connection string has been set, or if called on a SQLite connection * @throws DocumentException If no connection string has been set, or if called on a SQLite connection
*/ */
def firstByJsonPath[TDoc](tableName: String, path: String, orderBy: Seq[Field[?]] = List()) def firstByJsonPath[Doc](tableName: String, path: String, orderBy: Seq[Field[?]] = List())
(implicit tag: ClassTag[TDoc]): Option[TDoc] = (using tag: ClassTag[Doc]): Option[Doc] =
Using(Configuration.dbConn()) { conn => firstByJsonPath[TDoc](tableName, path, orderBy, conn) }.get Using(Configuration.dbConn()) { conn => firstByJsonPath[Doc](tableName, path, orderBy, conn) }.get

View File

@ -38,13 +38,13 @@ object Parameters:
* @param value The object to be encoded as JSON * @param value The object to be encoded as JSON
* @return A parameter with the value encoded * @return A parameter with the value encoded
*/ */
def json[T](name: String, value: T): Parameter[String] = def json[A](name: String, value: A): Parameter[String] =
CoreParameters.json(name, value) CoreParameters.json(name, value)
/** /**
* Add field parameters to the given set of parameters * Add field parameters to the given set of parameters
* *
* @param fields The fields being compared in the query * @param fields The fields being compared in the query
* @param existing Any existing parameters for the query (optional, defaults to empty collection) * @param existing Any existing parameters for the query (optional, defaults to empty collection)
* @return A collection of parameters for the query * @return A collection of parameters for the query
*/ */
@ -56,7 +56,7 @@ object Parameters:
/** /**
* Replace the parameter names in the query with question marks * Replace the parameter names in the query with question marks
* *
* @param query The query with named placeholders * @param query The query with named placeholders
* @param parameters The parameters for the query * @param parameters The parameters for the query
* @return The query, with name parameters changed to `?`s * @return The query, with name parameters changed to `?`s
*/ */
@ -66,8 +66,8 @@ object Parameters:
/** /**
* Apply the given parameters to the given query, returning a prepared statement * Apply the given parameters to the given query, returning a prepared statement
* *
* @param conn The active JDBC connection * @param conn The active JDBC connection
* @param query The query * @param query The query
* @param parameters The parameters for the query * @param parameters The parameters for the query
* @return A `PreparedStatement` with the parameter names replaced with `?` and parameter values bound * @return A `PreparedStatement` with the parameter names replaced with `?` and parameter values bound
* @throws DocumentException If parameter names are invalid or number value types are invalid * @throws DocumentException If parameter names are invalid or number value types are invalid
@ -78,7 +78,7 @@ object Parameters:
/** /**
* Create parameters for field names to be removed from a document * Create parameters for field names to be removed from a document
* *
* @param names The names of the fields to be removed * @param names The names of the fields to be removed
* @param parameterName The parameter name to use for the query * @param parameterName The parameter name to use for the query
* @return A list of parameters to use for building the query * @return A list of parameters to use for building the query
* @throws DocumentException If the dialect has not been set * @throws DocumentException If the dialect has not been set

View File

@ -20,7 +20,7 @@ object Patch:
* @param conn The connection on which the update should be executed * @param conn The connection on which the update should be executed
* @throws DocumentException If no dialect has been configured * @throws DocumentException If no dialect has been configured
*/ */
def byId[TKey, TPatch](tableName: String, docId: TKey, patch: TPatch, conn: Connection): Unit = def byId[Key, Patch](tableName: String, docId: Key, patch: Patch, conn: Connection): Unit =
CorePatch.byId(tableName, docId, patch, conn) CorePatch.byId(tableName, docId, patch, conn)
/** /**
@ -31,7 +31,7 @@ object Patch:
* @param patch The object whose properties should be replaced in the document * @param patch The object whose properties should be replaced in the document
* @throws DocumentException If no connection string has been set * @throws DocumentException If no connection string has been set
*/ */
def byId[TKey, TPatch](tableName: String, docId: TKey, patch: TPatch) = def byId[Key, Patch](tableName: String, docId: Key, patch: Patch): Unit =
CorePatch.byId(tableName, docId, patch) CorePatch.byId(tableName, docId, patch)
/** /**
@ -44,8 +44,8 @@ object Patch:
* @param conn The connection on which the update should be executed * @param conn The connection on which the update should be executed
* @throws DocumentException If no dialect has been configured, or if parameters are invalid * @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/ */
def byFields[TPatch](tableName: String, fields: Seq[Field[?]], patch: TPatch, howMatched: Option[FieldMatch], def byFields[Patch](tableName: String, fields: Seq[Field[?]], patch: Patch, howMatched: Option[FieldMatch],
conn: Connection): Unit = conn: Connection): Unit =
CorePatch.byFields(tableName, fields.asJava, patch, howMatched.orNull, conn) CorePatch.byFields(tableName, fields.asJava, patch, howMatched.orNull, conn)
/** /**
@ -57,7 +57,7 @@ object Patch:
* @param conn The connection on which the update should be executed * @param conn The connection on which the update should be executed
* @throws DocumentException If no dialect has been configured, or if parameters are invalid * @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/ */
def byFields[TPatch](tableName: String, fields: Seq[Field[?]], patch: TPatch, conn: Connection): Unit = def byFields[Patch](tableName: String, fields: Seq[Field[?]], patch: Patch, conn: Connection): Unit =
byFields(tableName, fields, patch, None, conn) byFields(tableName, fields, patch, None, conn)
/** /**
@ -69,8 +69,8 @@ object Patch:
* @param howMatched How the fields should be matched * @param howMatched How the fields should be matched
* @throws DocumentException If no connection string has been set, or if parameters are invalid * @throws DocumentException If no connection string has been set, or if parameters are invalid
*/ */
def byFields[TPatch](tableName: String, fields: Seq[Field[?]], patch: TPatch, def byFields[Patch](tableName: String, fields: Seq[Field[?]], patch: Patch,
howMatched: Option[FieldMatch] = None): Unit = howMatched: Option[FieldMatch] = None): Unit =
CorePatch.byFields(tableName, fields.asJava, patch, howMatched.orNull) CorePatch.byFields(tableName, fields.asJava, patch, howMatched.orNull)
/** /**
@ -82,7 +82,7 @@ object Patch:
* @param conn The connection on which the update should be executed * @param conn The connection on which the update should be executed
* @throws DocumentException If called on a SQLite connection * @throws DocumentException If called on a SQLite connection
*/ */
def byContains[TContains, TPatch](tableName: String, criteria: TContains, patch: TPatch, conn: Connection): Unit = def byContains[A, Patch](tableName: String, criteria: A, patch: Patch, conn: Connection): Unit =
CorePatch.byContains(tableName, criteria, patch, conn) CorePatch.byContains(tableName, criteria, patch, conn)
/** /**
@ -93,7 +93,7 @@ object Patch:
* @param patch The object whose properties should be replaced in the document * @param patch The object whose properties should be replaced in the document
* @throws DocumentException If no connection string has been set, or if called on a SQLite connection * @throws DocumentException If no connection string has been set, or if called on a SQLite connection
*/ */
def byContains[TContains, TPatch](tableName: String, criteria: TContains, patch: TPatch): Unit = def byContains[A, Patch](tableName: String, criteria: A, patch: Patch): Unit =
CorePatch.byContains(tableName, criteria, patch) CorePatch.byContains(tableName, criteria, patch)
/** /**
@ -105,7 +105,7 @@ object Patch:
* @param conn The connection on which the update should be executed * @param conn The connection on which the update should be executed
* @throws DocumentException If called on a SQLite connection * @throws DocumentException If called on a SQLite connection
*/ */
def byJsonPath[TPatch](tableName: String, path: String, patch: TPatch, conn: Connection): Unit = def byJsonPath[Patch](tableName: String, path: String, patch: Patch, conn: Connection): Unit =
CorePatch.byJsonPath(tableName, path, patch, conn) CorePatch.byJsonPath(tableName, path, patch, conn)
/** /**
@ -116,5 +116,5 @@ object Patch:
* @param patch The object whose properties should be replaced in the document * @param patch The object whose properties should be replaced in the document
* @throws DocumentException If no connection string has been set, or if called on a SQLite connection * @throws DocumentException If no connection string has been set, or if called on a SQLite connection
*/ */
def byJsonPath[TPatch](tableName: String, path: String, patch: TPatch): Unit = def byJsonPath[Patch](tableName: String, path: String, patch: Patch): Unit =
CorePatch.byJsonPath(tableName, path, patch) CorePatch.byJsonPath(tableName, path, patch)

View File

@ -20,7 +20,7 @@ object RemoveFields:
* @param conn The connection on which the update should be executed * @param conn The connection on which the update should be executed
* @throws DocumentException If no dialect has been configured * @throws DocumentException If no dialect has been configured
*/ */
def byId[TKey](tableName: String, docId: TKey, toRemove: Seq[String], conn: Connection): Unit = def byId[Key](tableName: String, docId: Key, toRemove: Seq[String], conn: Connection): Unit =
CoreRemoveFields.byId(tableName, docId, toRemove.asJava, conn) CoreRemoveFields.byId(tableName, docId, toRemove.asJava, conn)
/** /**
@ -31,7 +31,7 @@ object RemoveFields:
* @param toRemove The names of the fields to be removed * @param toRemove The names of the fields to be removed
* @throws DocumentException If no connection string has been set * @throws DocumentException If no connection string has been set
*/ */
def byId[TKey](tableName: String, docId: TKey, toRemove: Seq[String]): Unit = def byId[Key](tableName: String, docId: Key, toRemove: Seq[String]): Unit =
CoreRemoveFields.byId(tableName, docId, toRemove.asJava) CoreRemoveFields.byId(tableName, docId, toRemove.asJava)
/** /**
@ -82,7 +82,7 @@ object RemoveFields:
* @param conn The connection on which the update should be executed * @param conn The connection on which the update should be executed
* @throws DocumentException If called on a SQLite connection * @throws DocumentException If called on a SQLite connection
*/ */
def byContains[TContains](tableName: String, criteria: TContains, toRemove: Seq[String], conn: Connection): Unit = def byContains[A](tableName: String, criteria: A, toRemove: Seq[String], conn: Connection): Unit =
CoreRemoveFields.byContains(tableName, criteria, toRemove.asJava, conn) CoreRemoveFields.byContains(tableName, criteria, toRemove.asJava, conn)
/** /**
@ -93,7 +93,7 @@ object RemoveFields:
* @param toRemove The names of the fields to be removed * @param toRemove The names of the fields to be removed
* @throws DocumentException If no connection string has been set, or if called on a SQLite connection * @throws DocumentException If no connection string has been set, or if called on a SQLite connection
*/ */
def byContains[TContains](tableName: String, criteria: TContains, toRemove: Seq[String]): Unit = def byContains[A](tableName: String, criteria: A, toRemove: Seq[String]): Unit =
CoreRemoveFields.byContains(tableName, criteria, toRemove.asJava) CoreRemoveFields.byContains(tableName, criteria, toRemove.asJava)
/** /**

View File

@ -21,8 +21,8 @@ object Results:
* @param ignored The class tag (placeholder used for signature; implicit tag used for serialization) * @param ignored The class tag (placeholder used for signature; implicit tag used for serialization)
* @return The constructed domain item * @return The constructed domain item
*/ */
def fromDocument[TDoc](field: String, rs: ResultSet, ignored: ClassTag[TDoc])(implicit tag: ClassTag[TDoc]): TDoc = def fromDocument[Doc](field: String, rs: ResultSet, ignored: ClassTag[Doc])(using tag: ClassTag[Doc]): Doc =
CoreResults.fromDocument(field, rs, tag.runtimeClass.asInstanceOf[Class[TDoc]]) CoreResults.fromDocument(field, rs, tag.runtimeClass.asInstanceOf[Class[Doc]])
/** /**
* Create a domain item from a document * Create a domain item from a document
@ -31,21 +31,21 @@ object Results:
* @param ignored The class tag (placeholder used for signature; implicit tag used for serialization) * @param ignored The class tag (placeholder used for signature; implicit tag used for serialization)
* @return The constructed domain item * @return The constructed domain item
*/ */
def fromData[TDoc](rs: ResultSet, ignored: ClassTag[TDoc])(implicit tag: ClassTag[TDoc]): TDoc = def fromData[Doc](rs: ResultSet, ignored: ClassTag[Doc])(using tag: ClassTag[Doc]): Doc =
fromDocument[TDoc]("data", rs, tag) fromDocument[Doc]("data", rs, tag)
/** /**
* Create a list of items for the results of the given command, using the specified mapping function * Create a list of items for the results of the given command, using the specified mapping function
* *
* @param stmt The prepared statement to execute * @param stmt The prepared statement to execute
* @param mapFunc The mapping function from data reader to domain class instance * @param mapFunc The mapping function from data reader to domain class instance
* @return A list of items from the query's result * @return A list of items from the query's result
* @throws DocumentException If there is a problem executing the query (unchecked) * @throws DocumentException If there is a problem executing the query (unchecked)
*/ */
def toCustomList[TDoc](stmt: PreparedStatement, def toCustomList[Doc](stmt: PreparedStatement,mapFunc: (ResultSet, ClassTag[Doc]) => Doc)
mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): List[TDoc] = (using tag: ClassTag[Doc]): List[Doc] =
try try
val buffer = ListBuffer[TDoc]() val buffer = ListBuffer[Doc]()
Using(stmt.executeQuery()) { rs => Using(stmt.executeQuery()) { rs =>
while (rs.next()) { while (rs.next()) {
buffer.append(mapFunc(rs, tag)) buffer.append(mapFunc(rs, tag))

View File

@ -0,0 +1,497 @@
package solutions.bitbadger.documents.scala.extensions
import solutions.bitbadger.documents.{DocumentIndex, Field, FieldMatch, Parameter}
import solutions.bitbadger.documents.scala.*
import java.sql.{Connection, ResultSet}
import scala.reflect.ClassTag
extension (conn: Connection)
// ~~~ CUSTOM QUERIES ~~~
/**
* Execute a query that returns a list of results
*
* @param query The query to retrieve the results
* @param parameters Parameters to use for the query
* @param mapFunc The mapping function between the document and the domain item
* @return A list of results for the given query
* @throws DocumentException If parameters are invalid
*/
def customList[Doc](query: String, parameters: Seq[Parameter[?]], mapFunc: (ResultSet, ClassTag[Doc]) => Doc)
(using tag: ClassTag[Doc]): List[Doc] =
Custom.list[Doc](query, parameters, conn, mapFunc)
/**
* Execute a query that returns a list of results
*
* @param query The query to retrieve the results
* @param mapFunc The mapping function between the document and the domain item
* @return A list of results for the given query
* @throws DocumentException If parameters are invalid
*/
def customList[Doc](query: String, mapFunc: (ResultSet, ClassTag[Doc]) => Doc)
(using tag: ClassTag[Doc]): List[Doc] =
Custom.list[Doc](query, conn, mapFunc)
/**
* Execute a query that returns one or no results
*
* @param query The query to retrieve the results
* @param parameters Parameters to use for the query
* @param mapFunc The mapping function between the document and the domain item
* @return An optional document, filled if one matches the query
* @throws DocumentException If parameters are invalid
*/
def customSingle[Doc](query: String, parameters: Seq[Parameter[?]], mapFunc: (ResultSet, ClassTag[Doc]) => Doc)
(using tag: ClassTag[Doc]): Option[Doc] =
Custom.single[Doc](query, parameters, conn, mapFunc)
/**
* Execute a query that returns one or no results
*
* @param query The query to retrieve the results
* @param mapFunc The mapping function between the document and the domain item
* @return An optional document, filled if one matches the query
* @throws DocumentException If parameters are invalid
*/
def customSingle[Doc](query: String, mapFunc: (ResultSet, ClassTag[Doc]) => Doc)
(using tag: ClassTag[Doc]): Option[Doc] =
Custom.single[Doc](query, conn, mapFunc)
/**
* Execute a query that returns no results
*
* @param query The query to retrieve the results
* @param parameters Parameters to use for the query
* @throws DocumentException If parameters are invalid
*/
def customNonQuery(query: String, parameters: Seq[Parameter[?]] = List()): Unit =
Custom.nonQuery(query, parameters, conn)
/**
* Execute a query that returns a scalar result
*
* @param query The query to retrieve the result
* @param parameters Parameters to use for the query
* @param mapFunc The mapping function between the document and the domain item
* @return The scalar value from the query
* @throws DocumentException If parameters are invalid
*/
def customScalar[A](query: String, parameters: Seq[Parameter[?]], mapFunc: (ResultSet, ClassTag[A]) => A)
(using tag: ClassTag[A]): A =
Custom.scalar[A](query, parameters, conn, mapFunc)
/**
* Execute a query that returns a scalar result
*
* @param query The query to retrieve the result
* @param mapFunc The mapping function between the document and the domain item
* @return The scalar value from the query
* @throws DocumentException If parameters are invalid
*/
def customScalar[A](query: String, mapFunc: (ResultSet, ClassTag[A]) => A)(using tag: ClassTag[A]): A =
Custom.scalar[A](query, conn, mapFunc)
// ~~~ DEFINITION QUERIES ~~~
/**
* Create a document table if necessary
*
* @param tableName The table whose existence should be ensured (may include schema)
* @throws DocumentException If the dialect is not configured
*/
def ensureTable(tableName: String): Unit =
Definition.ensureTable(tableName, conn)
/**
* Create an index on field(s) within documents in the specified table if necessary
*
* @param tableName The table to be indexed (may include schema)
* @param indexName The name of the index to create
* @param fields One or more fields to be indexed<
* @throws DocumentException If any dependent process does
*/
def ensureFieldIndex(tableName: String, indexName: String, fields: Seq[String]): Unit =
Definition.ensureFieldIndex(tableName, indexName, fields, conn)
/**
* Create a document index on a table (PostgreSQL only)
*
* @param tableName The table to be indexed (may include schema)
* @param indexType The type of index to ensure
* @throws DocumentException If called on a SQLite connection
*/
def ensureDocumentIndex(tableName: String, indexType: DocumentIndex): Unit =
Definition.ensureDocumentIndex (tableName, indexType, conn)
// ~~~ DOCUMENT MANIPULATION QUERIES ~~~
/**
* Insert a new document
*
* @param tableName The table into which the document should be inserted (may include schema)
* @param document The document to be inserted
* @throws DocumentException If IDs are misconfigured, or if the database command fails
*/
def insert[Doc](tableName: String, document: Doc): Unit =
Document.insert(tableName, document, conn)
/**
* Save a document, inserting it if it does not exist and updating it if it does (AKA "upsert")
*
* @param tableName The table in which the document should be saved (may include schema)
* @param document The document to be saved
* @throws DocumentException If the database command fails
*/
def save[Doc](tableName: String, document: Doc): Unit =
Document.save(tableName, document, conn)
/**
* Update (replace) a document by its ID
*
* @param tableName The table in which the document should be replaced (may include schema)
* @param docId The ID of the document to be replaced
* @param document The document to be replaced
* @throws DocumentException If no dialect has been configured, or if the database command fails
*/
def update[Key, Doc](tableName: String, docId: Key, document: Doc): Unit =
Document.update(tableName, docId, document, conn)
// ~~~ DOCUMENT COUNT QUERIES ~~~
/**
* Count all documents in the table
*
* @param tableName The name of the table in which documents should be counted
* @return A count of the documents in the table
* @throws DocumentException If any dependent process does
*/
def countAll(tableName: String): Long =
Count.all(tableName, conn)
/**
* Count documents using a field comparison
*
* @param tableName The name of the table in which documents should be counted
* @param fields The fields which should be compared
* @param howMatched How the fields should be matched (optional, default `ALL`)
* @return A count of the matching documents in the table
* @throws DocumentException If the dialect has not been configured
*/
def countByFields(tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch] = None): Long =
Count.byFields(tableName, fields, howMatched, conn)
/**
* Count documents using a JSON containment query (PostgreSQL only)
*
* @param tableName The name of the table in which documents should be counted
* @param criteria The object for which JSON containment should be checked
* @return A count of the matching documents in the table
* @throws DocumentException If called on a SQLite connection
*/
def countByContains[A](tableName: String, criteria: A): Long =
Count.byContains(tableName, criteria, conn)
/**
* Count documents using a JSON Path match query (PostgreSQL only)
*
* @param tableName The name of the table in which documents should be counted
* @param path The JSON path comparison to match
* @return A count of the matching documents in the table
* @throws DocumentException If called on a SQLite connection
*/
def countByJsonPath(tableName: String, path: String): Long =
Count.byJsonPath(tableName, path, conn)
// ~~~ DOCUMENT EXISTENCE QUERIES ~~~
/**
* Determine a document's existence by its ID
*
* @param tableName The name of the table in which document existence should be checked
* @param docId The ID of the document to be checked
* @return True if the document exists, false if not
* @throws DocumentException If no dialect has been configured
*/
def existsById[Key](tableName: String, docId: Key): Boolean =
Exists.byId(tableName, docId, conn)
/**
* Determine document existence using a field comparison
*
* @param tableName The name of the table in which document existence should be checked
* @param fields The fields which should be compared
* @param howMatched How the fields should be matched
* @return True if any matching documents exist, false if not
* @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/
def existsByFields(tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch] = None): Boolean =
Exists.byFields(tableName, fields, howMatched, conn)
/**
* Determine document existence using a JSON containment query (PostgreSQL only)
*
* @param tableName The name of the table in which document existence should be checked
* @param criteria The object for which JSON containment should be checked
* @return True if any matching documents exist, false if not
* @throws DocumentException If called on a SQLite connection
*/
def existsByContains[A](tableName: String, criteria: A): Boolean =
Exists.byContains(tableName, criteria, conn)
/**
* Determine document existence using a JSON Path match query (PostgreSQL only)
*
* @param tableName The name of the table in which document existence should be checked
* @param path The JSON path comparison to match
* @return True if any matching documents exist, false if not
* @throws DocumentException If called on a SQLite connection
*/
def existsByJsonPath(tableName: String, path: String): Boolean =
Exists.byJsonPath(tableName, path, conn)
// ~~~ DOCUMENT RETRIEVAL QUERIES ~~~
/**
* Retrieve all documents in the given table, ordering results by the optional given fields
*
* @param tableName The table from which documents should be retrieved
* @param orderBy Fields by which the query should be ordered (optional, defaults to no ordering)
* @return A list of documents from the given table
* @throws DocumentException If query execution fails
*/
def findAll[Doc](tableName: String, orderBy: Seq[Field[?]] = List())(using tag: ClassTag[Doc]): List[Doc] =
Find.all[Doc](tableName, orderBy, conn)
/**
* Retrieve a document by its ID
*
* @param tableName The table from which the document should be retrieved
* @param docId The ID of the document to retrieve
* @return The document if it is found, `None` otherwise
* @throws DocumentException If no dialect has been configured
*/
def findById[Key, Doc](tableName: String, docId: Key)(using tag: ClassTag[Doc]): Option[Doc] =
Find.byId[Key, Doc](tableName, docId, conn)
/**
* Retrieve documents using a field comparison, ordering results by the optional given fields
*
* @param tableName The table from which the document should be retrieved
* @param fields The fields which should be compared
* @param howMatched How the fields should be matched
* @param orderBy Fields by which the query should be ordered (optional, defaults to no ordering)
* @return A list of documents matching the field comparison
* @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/
def findByFields[Doc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch] = None,
orderBy: Seq[Field[?]] = List())(using tag: ClassTag[Doc]): List[Doc] =
Find.byFields[Doc](tableName, fields, howMatched, orderBy, conn)
/**
* Retrieve documents using a JSON containment query, ordering results by the optional given fields (PostgreSQL
* only)
*
* @param tableName The name of the table in which document existence should be checked
* @param criteria The object for which JSON containment should be checked
* @param orderBy Fields by which the query should be ordered (optional, defaults to no ordering)
* @return A list of documents matching the JSON containment query
* @throws DocumentException If called on a SQLite connection
*/
def findByContains[Doc, A](tableName: String, criteria: A, orderBy: Seq[Field[?]] = List())
(using tag: ClassTag[Doc]): List[Doc] =
Find.byContains[Doc, A](tableName, criteria, orderBy, conn)
/**
* Retrieve documents using a JSON Path match query, ordering results by the optional given fields (PostgreSQL only)
*
* @param tableName The table from which documents should be retrieved
* @param path The JSON path comparison to match
* @param orderBy Fields by which the query should be ordered (optional, defaults to no ordering)
* @return A list of documents matching the JSON Path match query
* @throws DocumentException If called on a SQLite connection
*/
def findByJsonPath[Doc](tableName: String, path: String, orderBy: Seq[Field[?]] = List())
(using tag: ClassTag[Doc]): List[Doc] =
Find.byJsonPath[Doc](tableName, path, orderBy, conn)
/**
* Retrieve the first document using a field comparison and optional ordering fields
*
* @param tableName The table from which documents should be retrieved
* @param fields The fields which should be compared
* @param howMatched How the fields should be matched (optional, defaults to `FieldMatch.ALL`)
* @param orderBy Fields by which the query should be ordered (optional, defaults to no ordering)
* @return The first document matching the field comparison, or `None` if no matches are found
* @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/
def findFirstByFields[Doc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch] = None,
orderBy: Seq[Field[?]] = List())(using tag: ClassTag[Doc]): Option[Doc] =
Find.firstByFields[Doc](tableName, fields, howMatched, orderBy, conn)
/**
* Retrieve the first document using a JSON containment query and optional ordering fields (PostgreSQL only)
*
* @param tableName The table from which documents should be retrieved
* @param criteria The object for which JSON containment should be checked
* @param orderBy Fields by which the query should be ordered (optional, defaults to no ordering)
* @return The first document matching the JSON containment query, or `None` if no matches are found
* @throws DocumentException If called on a SQLite connection
*/
def findFirstByContains[Doc, A](tableName: String, criteria: A, orderBy: Seq[Field[?]] = List())
(using tag: ClassTag[Doc]): Option[Doc] =
Find.firstByContains[Doc, A](tableName, criteria, orderBy, conn)
/**
* Retrieve the first document using a JSON Path match query and optional ordering fields (PostgreSQL only)
*
* @param tableName The table from which documents should be retrieved
* @param path The JSON path comparison to match
* @param orderBy Fields by which the query should be ordered (optional, defaults to no ordering)
* @return The first document matching the JSON Path match query, or `None` if no matches are found
* @throws DocumentException If called on a SQLite connection
*/
def findFirstByJsonPath[Doc](tableName: String, path: String, orderBy: Seq[Field[?]] = List())
(using tag: ClassTag[Doc]): Option[Doc] =
Find.firstByJsonPath[Doc](tableName, path, orderBy, conn)
// ~~~ DOCUMENT PATCH (PARTIAL UPDATE) QUERIES ~~~
/**
* Patch a document by its ID
*
* @param tableName The name of the table in which a document should be patched
* @param docId The ID of the document to be patched
* @param patch The object whose properties should be replaced in the document
* @throws DocumentException If no dialect has been configured
*/
def patchById[Key, Patch](tableName: String, docId: Key, patch: Patch): Unit =
Patch.byId(tableName, docId, patch, conn)
/**
* Patch documents using a field comparison
*
* @param tableName The name of the table in which documents should be patched
* @param fields The fields which should be compared
* @param patch The object whose properties should be replaced in the document
* @param howMatched How the fields should be matched
* @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/
def patchByFields[Patch](tableName: String, fields: Seq[Field[?]], patch: Patch,
howMatched: Option[FieldMatch] = None): Unit =
Patch.byFields(tableName, fields, patch, howMatched, conn)
/**
* Patch documents using a JSON containment query (PostgreSQL only)
*
* @param tableName The name of the table in which documents should be patched
* @param criteria The object against which JSON containment should be checked
* @param patch The object whose properties should be replaced in the document
* @throws DocumentException If called on a SQLite connection
*/
def patchByContains[A, Patch](tableName: String, criteria: A, patch: Patch): Unit =
Patch.byContains(tableName, criteria, patch, conn)
/**
* Patch documents using a JSON Path match query (PostgreSQL only)
*
* @param tableName The name of the table in which documents should be patched
* @param path The JSON path comparison to match
* @param patch The object whose properties should be replaced in the document
* @throws DocumentException If called on a SQLite connection
*/
def patchByJsonPath[Patch](tableName: String, path: String, patch: Patch): Unit =
Patch.byJsonPath(tableName, path, patch, conn)
// ~~~ DOCUMENT FIELD REMOVAL QUERIES ~~~
/**
* Remove fields from a document by its ID
*
* @param tableName The name of the table in which the document's fields should be removed
* @param docId The ID of the document to have fields removed
* @param toRemove The names of the fields to be removed
* @throws DocumentException If no dialect has been configured
*/
def removeFieldsById[Key](tableName: String, docId: Key, toRemove: Seq[String]): Unit =
RemoveFields.byId(tableName, docId, toRemove, conn)
/**
* Remove fields from documents using a field comparison
*
* @param tableName The name of the table in which document fields should be removed
* @param fields The fields which should be compared
* @param toRemove The names of the fields to be removed
* @param howMatched How the fields should be matched
* @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/
def removeFieldsByFields(tableName: String, fields: Seq[Field[?]], toRemove: Seq[String],
howMatched: Option[FieldMatch] = None): Unit =
RemoveFields.byFields(tableName, fields, toRemove, howMatched, conn)
/**
* Remove fields from documents using a JSON containment query (PostgreSQL only)
*
* @param tableName The name of the table in which document fields should be removed
* @param criteria The object against which JSON containment should be checked
* @param toRemove The names of the fields to be removed
* @throws DocumentException If called on a SQLite connection
*/
def removeFieldsByContains[A](tableName: String, criteria: A, toRemove: Seq[String]): Unit =
RemoveFields.byContains(tableName, criteria, toRemove, conn)
/**
* Remove fields from documents using a JSON Path match query (PostgreSQL only)
*
* @param tableName The name of the table in which document fields should be removed
* @param path The JSON path comparison to match
* @param toRemove The names of the fields to be removed
* @throws DocumentException If called on a SQLite connection
*/
def removeFieldsByJsonPath(tableName: String, path: String, toRemove: Seq[String]): Unit =
RemoveFields.byJsonPath(tableName, path, toRemove, conn)
// ~~~ DOCUMENT DELETION QUERIES ~~~
/**
* Delete a document by its ID
*
* @param tableName The name of the table from which documents should be deleted
* @param docId The ID of the document to be deleted
* @throws DocumentException If no dialect has been configured
*/
def deleteById[Key](tableName: String, docId: Key): Unit =
Delete.byId(tableName, docId, conn)
/**
* Delete documents using a field comparison
*
* @param tableName The name of the table from which documents should be deleted
* @param fields The fields which should be compared
* @param howMatched How the fields should be matched
* @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/
def deleteByFields(tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch] = None): Unit =
Delete.byFields(tableName, fields, howMatched, conn)
/**
* Delete documents using a JSON containment query (PostgreSQL only)
*
* @param tableName The name of the table from which documents should be deleted
* @param criteria The object for which JSON containment should be checked
* @throws DocumentException If called on a SQLite connection
*/
def deleteByContains[A](tableName: String, criteria: A): Unit =
Delete.byContains(tableName, criteria, conn)
/**
* Delete documents using a JSON Path match query (PostgreSQL only)
*
* @param tableName The name of the table from which documents should be deleted
* @param path The JSON path comparison to match
* @throws DocumentException If called on a SQLite connection
*/
def deleteByJsonPath(tableName: String, path: String): Unit =
Delete.byJsonPath(tableName, path, conn)

View File

@ -1,499 +0,0 @@
package solutions.bitbadger.documents.scala
import solutions.bitbadger.documents.{DocumentIndex, Field, FieldMatch, Parameter}
import java.sql.{Connection, ResultSet}
import scala.reflect.ClassTag
package object extensions:
extension (conn: Connection)
// ~~~ CUSTOM QUERIES ~~~
/**
* Execute a query that returns a list of results
*
* @param query The query to retrieve the results
* @param parameters Parameters to use for the query
* @param mapFunc The mapping function between the document and the domain item
* @return A list of results for the given query
* @throws DocumentException If parameters are invalid
*/
def customList[TDoc](query: String, parameters: Seq[Parameter[?]],
mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): List[TDoc] =
Custom.list[TDoc](query, parameters, conn, mapFunc)
/**
* Execute a query that returns a list of results
*
* @param query The query to retrieve the results
* @param mapFunc The mapping function between the document and the domain item
* @return A list of results for the given query
* @throws DocumentException If parameters are invalid
*/
def customList[TDoc](query: String,
mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): List[TDoc] =
Custom.list[TDoc](query, conn, mapFunc)
/**
* Execute a query that returns one or no results
*
* @param query The query to retrieve the results
* @param parameters Parameters to use for the query
* @param mapFunc The mapping function between the document and the domain item
* @return An optional document, filled if one matches the query
* @throws DocumentException If parameters are invalid
*/
def customSingle[TDoc](query: String, parameters: Seq[Parameter[?]],
mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): Option[TDoc] =
Custom.single[TDoc](query, parameters, conn, mapFunc)
/**
* Execute a query that returns one or no results
*
* @param query The query to retrieve the results
* @param mapFunc The mapping function between the document and the domain item
* @return An optional document, filled if one matches the query
* @throws DocumentException If parameters are invalid
*/
def customSingle[TDoc](query: String,
mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): Option[TDoc] =
Custom.single[TDoc](query, conn, mapFunc)
/**
* Execute a query that returns no results
*
* @param query The query to retrieve the results
* @param parameters Parameters to use for the query
* @throws DocumentException If parameters are invalid
*/
def customNonQuery(query: String, parameters: Seq[Parameter[?]] = List()): Unit =
Custom.nonQuery(query, parameters, conn)
/**
* Execute a query that returns a scalar result
*
* @param query The query to retrieve the result
* @param parameters Parameters to use for the query
* @param mapFunc The mapping function between the document and the domain item
* @return The scalar value from the query
* @throws DocumentException If parameters are invalid
*/
def customScalar[T](query: String, parameters: Seq[Parameter[?]],
mapFunc: (ResultSet, ClassTag[T]) => T)(implicit tag: ClassTag[T]): T =
Custom.scalar[T](query, parameters, conn, mapFunc)
/**
* Execute a query that returns a scalar result
*
* @param query The query to retrieve the result
* @param mapFunc The mapping function between the document and the domain item
* @return The scalar value from the query
* @throws DocumentException If parameters are invalid
*/
def customScalar[T](query: String,
mapFunc: (ResultSet, ClassTag[T]) => T)(implicit tag: ClassTag[T]): T =
Custom.scalar[T](query, conn, mapFunc)
// ~~~ DEFINITION QUERIES ~~~
/**
* Create a document table if necessary
*
* @param tableName The table whose existence should be ensured (may include schema)
* @throws DocumentException If the dialect is not configured
*/
def ensureTable(tableName: String): Unit =
Definition.ensureTable(tableName, conn)
/**
* Create an index on field(s) within documents in the specified table if necessary
*
* @param tableName The table to be indexed (may include schema)
* @param indexName The name of the index to create
* @param fields One or more fields to be indexed<
* @throws DocumentException If any dependent process does
*/
def ensureFieldIndex(tableName: String, indexName: String, fields: Seq[String]): Unit =
Definition.ensureFieldIndex(tableName, indexName, fields, conn)
/**
* Create a document index on a table (PostgreSQL only)
*
* @param tableName The table to be indexed (may include schema)
* @param indexType The type of index to ensure
* @throws DocumentException If called on a SQLite connection
*/
def ensureDocumentIndex(tableName: String, indexType: DocumentIndex): Unit =
Definition.ensureDocumentIndex (tableName, indexType, conn)
// ~~~ DOCUMENT MANIPULATION QUERIES ~~~
/**
* Insert a new document
*
* @param tableName The table into which the document should be inserted (may include schema)
* @param document The document to be inserted
* @throws DocumentException If IDs are misconfigured, or if the database command fails
*/
def insert[TDoc](tableName: String, document: TDoc): Unit =
Document.insert(tableName, document, conn)
/**
* Save a document, inserting it if it does not exist and updating it if it does (AKA "upsert")
*
* @param tableName The table in which the document should be saved (may include schema)
* @param document The document to be saved
* @throws DocumentException If the database command fails
*/
def save[TDoc](tableName: String, document: TDoc): Unit =
Document.save(tableName, document, conn)
/**
* Update (replace) a document by its ID
*
* @param tableName The table in which the document should be replaced (may include schema)
* @param docId The ID of the document to be replaced
* @param document The document to be replaced
* @throws DocumentException If no dialect has been configured, or if the database command fails
*/
def update[TKey, TDoc](tableName: String, docId: TKey, document: TDoc): Unit =
Document.update(tableName, docId, document, conn)
// ~~~ DOCUMENT COUNT QUERIES ~~~
/**
* Count all documents in the table
*
* @param tableName The name of the table in which documents should be counted
* @return A count of the documents in the table
* @throws DocumentException If any dependent process does
*/
def countAll(tableName: String): Long =
Count.all(tableName, conn)
/**
* Count documents using a field comparison
*
* @param tableName The name of the table in which documents should be counted
* @param fields The fields which should be compared
* @param howMatched How the fields should be matched (optional, default `ALL`)
* @return A count of the matching documents in the table
* @throws DocumentException If the dialect has not been configured
*/
def countByFields(tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch] = None): Long =
Count.byFields(tableName, fields, howMatched, conn)
/**
* Count documents using a JSON containment query (PostgreSQL only)
*
* @param tableName The name of the table in which documents should be counted
* @param criteria The object for which JSON containment should be checked
* @return A count of the matching documents in the table
* @throws DocumentException If called on a SQLite connection
*/
def countByContains[TContains](tableName: String, criteria: TContains): Long =
Count.byContains(tableName, criteria, conn)
/**
* Count documents using a JSON Path match query (PostgreSQL only)
*
* @param tableName The name of the table in which documents should be counted
* @param path The JSON path comparison to match
* @return A count of the matching documents in the table
* @throws DocumentException If called on a SQLite connection
*/
def countByJsonPath(tableName: String, path: String): Long =
Count.byJsonPath(tableName, path, conn)
// ~~~ DOCUMENT EXISTENCE QUERIES ~~~
/**
* Determine a document's existence by its ID
*
* @param tableName The name of the table in which document existence should be checked
* @param docId The ID of the document to be checked
* @return True if the document exists, false if not
* @throws DocumentException If no dialect has been configured
*/
def existsById[TKey](tableName: String, docId: TKey): Boolean =
Exists.byId(tableName, docId, conn)
/**
* Determine document existence using a field comparison
*
* @param tableName The name of the table in which document existence should be checked
* @param fields The fields which should be compared
* @param howMatched How the fields should be matched
* @return True if any matching documents exist, false if not
* @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/
def existsByFields(tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch] = None): Boolean =
Exists.byFields(tableName, fields, howMatched, conn)
/**
* Determine document existence using a JSON containment query (PostgreSQL only)
*
* @param tableName The name of the table in which document existence should be checked
* @param criteria The object for which JSON containment should be checked
* @return True if any matching documents exist, false if not
* @throws DocumentException If called on a SQLite connection
*/
def existsByContains[TContains](tableName: String, criteria: TContains): Boolean =
Exists.byContains(tableName, criteria, conn)
/**
* Determine document existence using a JSON Path match query (PostgreSQL only)
*
* @param tableName The name of the table in which document existence should be checked
* @param path The JSON path comparison to match
* @return True if any matching documents exist, false if not
* @throws DocumentException If called on a SQLite connection
*/
def existsByJsonPath(tableName: String, path: String): Boolean =
Exists.byJsonPath(tableName, path, conn)
// ~~~ DOCUMENT RETRIEVAL QUERIES ~~~
/**
* Retrieve all documents in the given table, ordering results by the optional given fields
*
* @param tableName The table from which documents should be retrieved
* @param orderBy Fields by which the query should be ordered (optional, defaults to no ordering)
* @return A list of documents from the given table
* @throws DocumentException If query execution fails
*/
def findAll[TDoc](tableName: String, orderBy: Seq[Field[?]] = List())(implicit tag: ClassTag[TDoc]): List[TDoc] =
Find.all[TDoc](tableName, orderBy, conn)
/**
* Retrieve a document by its ID
*
* @param tableName The table from which the document should be retrieved
* @param docId The ID of the document to retrieve
* @return The document if it is found, `None` otherwise
* @throws DocumentException If no dialect has been configured
*/
def findById[TKey, TDoc](tableName: String, docId: TKey)(implicit tag: ClassTag[TDoc]): Option[TDoc] =
Find.byId[TKey, TDoc](tableName, docId, conn)
/**
* Retrieve documents using a field comparison, ordering results by the optional given fields
*
* @param tableName The table from which the document should be retrieved
* @param fields The fields which should be compared
* @param howMatched How the fields should be matched
* @param orderBy Fields by which the query should be ordered (optional, defaults to no ordering)
* @return A list of documents matching the field comparison
* @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/
def findByFields[TDoc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch] = None,
orderBy: Seq[Field[?]] = List())(implicit tag: ClassTag[TDoc]): List[TDoc] =
Find.byFields[TDoc](tableName, fields, howMatched, orderBy, conn)
/**
* Retrieve documents using a JSON containment query, ordering results by the optional given fields (PostgreSQL
* only)
*
* @param tableName The name of the table in which document existence should be checked
* @param criteria The object for which JSON containment should be checked
* @param orderBy Fields by which the query should be ordered (optional, defaults to no ordering)
* @return A list of documents matching the JSON containment query
* @throws DocumentException If called on a SQLite connection
*/
def findByContains[TDoc, TContains](tableName: String, criteria: TContains, orderBy: Seq[Field[?]] = List())
(implicit tag: ClassTag[TDoc]): List[TDoc] =
Find.byContains[TDoc, TContains](tableName, criteria, orderBy, conn)
/**
* Retrieve documents using a JSON Path match query, ordering results by the optional given fields (PostgreSQL only)
*
* @param tableName The table from which documents should be retrieved
* @param path The JSON path comparison to match
* @param orderBy Fields by which the query should be ordered (optional, defaults to no ordering)
* @return A list of documents matching the JSON Path match query
* @throws DocumentException If called on a SQLite connection
*/
def findByJsonPath[TDoc](tableName: String, path: String, orderBy: Seq[Field[?]] = List())
(implicit tag: ClassTag[TDoc]): List[TDoc] =
Find.byJsonPath[TDoc](tableName, path, orderBy, conn)
/**
* Retrieve the first document using a field comparison and optional ordering fields
*
* @param tableName The table from which documents should be retrieved
* @param fields The fields which should be compared
* @param howMatched How the fields should be matched (optional, defaults to `FieldMatch.ALL`)
* @param orderBy Fields by which the query should be ordered (optional, defaults to no ordering)
* @return The first document matching the field comparison, or `None` if no matches are found
* @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/
def findFirstByFields[TDoc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch] = None,
orderBy: Seq[Field[?]] = List())(implicit tag: ClassTag[TDoc]): Option[TDoc] =
Find.firstByFields[TDoc](tableName, fields, howMatched, orderBy, conn)
/**
* Retrieve the first document using a JSON containment query and optional ordering fields (PostgreSQL only)
*
* @param tableName The table from which documents should be retrieved
* @param criteria The object for which JSON containment should be checked
* @param orderBy Fields by which the query should be ordered (optional, defaults to no ordering)
* @return The first document matching the JSON containment query, or `None` if no matches are found
* @throws DocumentException If called on a SQLite connection
*/
def findFirstByContains[TDoc, TContains](tableName: String, criteria: TContains, orderBy: Seq[Field[?]] = List())
(implicit tag: ClassTag[TDoc]): Option[TDoc] =
Find.firstByContains[TDoc, TContains](tableName, criteria, orderBy, conn)
/**
* Retrieve the first document using a JSON Path match query and optional ordering fields (PostgreSQL only)
*
* @param tableName The table from which documents should be retrieved
* @param path The JSON path comparison to match
* @param orderBy Fields by which the query should be ordered (optional, defaults to no ordering)
* @return The first document matching the JSON Path match query, or `None` if no matches are found
* @throws DocumentException If called on a SQLite connection
*/
def findFirstByJsonPath[TDoc](tableName: String, path: String, orderBy: Seq[Field[?]] = List())
(implicit tag: ClassTag[TDoc]): Option[TDoc] =
Find.firstByJsonPath[TDoc](tableName, path, orderBy, conn)
// ~~~ DOCUMENT PATCH (PARTIAL UPDATE) QUERIES ~~~
/**
* Patch a document by its ID
*
* @param tableName The name of the table in which a document should be patched
* @param docId The ID of the document to be patched
* @param patch The object whose properties should be replaced in the document
* @throws DocumentException If no dialect has been configured
*/
def patchById[TKey, TPatch](tableName: String, docId: TKey, patch: TPatch): Unit =
Patch.byId(tableName, docId, patch, conn)
/**
* Patch documents using a field comparison
*
* @param tableName The name of the table in which documents should be patched
* @param fields The fields which should be compared
* @param patch The object whose properties should be replaced in the document
* @param howMatched How the fields should be matched
* @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/
def patchByFields[TPatch](tableName: String, fields: Seq[Field[?]], patch: TPatch,
howMatched: Option[FieldMatch] = None): Unit =
Patch.byFields(tableName, fields, patch, howMatched, conn)
/**
* Patch documents using a JSON containment query (PostgreSQL only)
*
* @param tableName The name of the table in which documents should be patched
* @param criteria The object against which JSON containment should be checked
* @param patch The object whose properties should be replaced in the document
* @throws DocumentException If called on a SQLite connection
*/
def patchByContains[TContains, TPatch](tableName: String, criteria: TContains, patch: TPatch): Unit =
Patch.byContains(tableName, criteria, patch, conn)
/**
* Patch documents using a JSON Path match query (PostgreSQL only)
*
* @param tableName The name of the table in which documents should be patched
* @param path The JSON path comparison to match
* @param patch The object whose properties should be replaced in the document
* @throws DocumentException If called on a SQLite connection
*/
def patchByJsonPath[TPatch](tableName: String, path: String, patch: TPatch): Unit =
Patch.byJsonPath(tableName, path, patch, conn)
// ~~~ DOCUMENT FIELD REMOVAL QUERIES ~~~
/**
* Remove fields from a document by its ID
*
* @param tableName The name of the table in which the document's fields should be removed
* @param docId The ID of the document to have fields removed
* @param toRemove The names of the fields to be removed
* @throws DocumentException If no dialect has been configured
*/
def removeFieldsById[TKey](tableName: String, docId: TKey, toRemove: Seq[String]): Unit =
RemoveFields.byId(tableName, docId, toRemove, conn)
/**
* Remove fields from documents using a field comparison
*
* @param tableName The name of the table in which document fields should be removed
* @param fields The fields which should be compared
* @param toRemove The names of the fields to be removed
* @param howMatched How the fields should be matched
* @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/
def removeFieldsByFields(tableName: String, fields: Seq[Field[?]], toRemove: Seq[String],
howMatched: Option[FieldMatch] = None): Unit =
RemoveFields.byFields(tableName, fields, toRemove, howMatched, conn)
/**
* Remove fields from documents using a JSON containment query (PostgreSQL only)
*
* @param tableName The name of the table in which document fields should be removed
* @param criteria The object against which JSON containment should be checked
* @param toRemove The names of the fields to be removed
* @throws DocumentException If called on a SQLite connection
*/
def removeFieldsByContains[TContains](tableName: String, criteria: TContains, toRemove: Seq[String]): Unit =
RemoveFields.byContains(tableName, criteria, toRemove, conn)
/**
* Remove fields from documents using a JSON Path match query (PostgreSQL only)
*
* @param tableName The name of the table in which document fields should be removed
* @param path The JSON path comparison to match
* @param toRemove The names of the fields to be removed
* @throws DocumentException If called on a SQLite connection
*/
def removeFieldsByJsonPath(tableName: String, path: String, toRemove: Seq[String]): Unit =
RemoveFields.byJsonPath(tableName, path, toRemove, conn)
// ~~~ DOCUMENT DELETION QUERIES ~~~
/**
* Delete a document by its ID
*
* @param tableName The name of the table from which documents should be deleted
* @param docId The ID of the document to be deleted
* @throws DocumentException If no dialect has been configured
*/
def deleteById[TKey](tableName: String, docId: TKey): Unit =
Delete.byId(tableName, docId, conn)
/**
* Delete documents using a field comparison
*
* @param tableName The name of the table from which documents should be deleted
* @param fields The fields which should be compared
* @param howMatched How the fields should be matched
* @throws DocumentException If no dialect has been configured, or if parameters are invalid
*/
def deleteByFields(tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch] = None): Unit =
Delete.byFields(tableName, fields, howMatched, conn)
/**
* Delete documents using a JSON containment query (PostgreSQL only)
*
* @param tableName The name of the table from which documents should be deleted
* @param criteria The object for which JSON containment should be checked
* @throws DocumentException If called on a SQLite connection
*/
def deleteByContains[TContains](tableName: String, criteria: TContains): Unit =
Delete.byContains(tableName, criteria, conn)
/**
* Delete documents using a JSON Path match query (PostgreSQL only)
*
* @param tableName The name of the table from which documents should be deleted
* @param path The JSON path comparison to match
* @throws DocumentException If called on a SQLite connection
*/
def deleteByJsonPath(tableName: String, path: String): Unit =
Delete.byJsonPath(tableName, path, conn)

View File

@ -7,11 +7,11 @@ import solutions.bitbadger.documents.Configuration
*/ */
object ForceDialect: object ForceDialect:
def postgres (): Unit = def postgres(): Unit =
Configuration.setConnectionString(":postgresql:") Configuration.setConnectionString(":postgresql:")
def sqlite (): Unit = def sqlite(): Unit =
Configuration.setConnectionString(":sqlite:") Configuration.setConnectionString(":sqlite:")
def none (): Unit = def none(): Unit =
Configuration.setConnectionString(null) Configuration.setConnectionString(null)

View File

@ -0,0 +1,3 @@
package solutions.bitbadger.documents.scala.tests
def TEST_TABLE = "test_table"

View File

@ -1,6 +0,0 @@
package solutions.bitbadger.documents.scala
package object tests {
def TEST_TABLE = "test_table"
}