From f1385b6d55c418bbd2ec1dd130bd929f865ed96f Mon Sep 17 00:00:00 2001
From: "Daniel J. Summers" <daniel@bitbadger.solutions>
Date: Tue, 25 Mar 2025 16:57:24 -0400
Subject: [PATCH] Flatten Scala source trees

---
 src/core/pom.xml                              |   3 +
 .../documents/scala => }/Count.scala          |   8 +-
 .../documents/scala => }/Custom.scala         |  62 +--
 .../documents/scala => }/Definition.scala     |   0
 .../documents/scala => }/Delete.scala         |  10 +-
 .../documents/scala => }/Document.scala       |  28 +-
 .../documents/scala => }/Exists.scala         |  10 +-
 .../bitbadger/documents/scala => }/Find.scala | 159 +++---
 .../documents/scala => }/Parameters.scala     |  12 +-
 .../documents/scala => }/Patch.scala          |  22 +-
 .../documents/scala => }/RemoveFields.scala   |   8 +-
 .../documents/scala => }/Results.scala        |  16 +-
 .../src/main/scala/extensions/package.scala   | 497 +++++++++++++++++
 .../documents/scala/extensions/package.scala  | 499 ------------------
 .../scala/tests => }/AutoIdTest.scala         |   0
 .../scala/tests => }/ByteIdClass.scala        |   0
 .../scala/tests => }/ConfigurationTest.scala  |   0
 .../scala/tests => }/CountQueryTest.scala     |   0
 .../tests => }/DefinitionQueryTest.scala      |   0
 .../scala/tests => }/DeleteQueryTest.scala    |   0
 .../scala/tests => }/DialectTest.scala        |   0
 .../scala/tests => }/DocumentIndexTest.scala  |   0
 .../scala/tests => }/DocumentQueryTest.scala  |   0
 .../scala/tests => }/ExistsQueryTest.scala    |   0
 .../scala/tests => }/FieldMatchTest.scala     |   0
 .../scala/tests => }/FieldTest.scala          |   0
 .../scala/tests => }/FindQueryTest.scala      |   0
 .../scala/tests => }/ForceDialect.scala       |   6 +-
 .../scala/tests => }/IntIdClass.scala         |   0
 .../scala/tests => }/LongIdClass.scala        |   0
 .../documents/scala/tests => }/OpTest.scala   |   0
 .../scala/tests => }/ParameterNameTest.scala  |   0
 .../scala/tests => }/ParameterTest.scala      |   0
 .../scala/tests => }/ParametersTest.scala     |   0
 .../scala/tests => }/PatchQueryTest.scala     |   0
 .../scala/tests => }/QueryUtilsTest.scala     |   0
 .../tests => }/RemoveFieldsQueryTest.scala    |   0
 .../scala/tests => }/ShortIdClass.scala       |   0
 .../scala/tests => }/StringIdClass.scala      |   0
 .../scala/tests => }/WhereTest.scala          |   0
 .../integration/ArrayDocument.scala           |   0
 .../integration/CountFunctions.scala          |   0
 .../integration/CustomFunctions.scala         |   0
 .../integration/DefinitionFunctions.scala     |   0
 .../integration/DeleteFunctions.scala         |   0
 .../integration/DocumentFunctions.scala       |   0
 .../integration/ExistsFunctions.scala         |   0
 .../integration/FindFunctions.scala           |   0
 .../JacksonDocumentSerializer.scala           |   0
 .../tests => }/integration/JsonDocument.scala |   0
 .../integration/NumIdDocument.scala           |   0
 .../integration/PatchFunctions.scala          |   0
 .../scala/tests => }/integration/PgDB.scala   |   0
 .../integration/PostgreSQLCountIT.scala       |   0
 .../integration/PostgreSQLCustomIT.scala      |   0
 .../integration/PostgreSQLDefinitionIT.scala  |   0
 .../integration/PostgreSQLDeleteIT.scala      |   0
 .../integration/PostgreSQLDocumentIT.scala    |   0
 .../integration/PostgreSQLExistsIT.scala      |   0
 .../integration/PostgreSQLFindIT.scala        |   0
 .../integration/PostgreSQLPatchIT.scala       |   0
 .../PostgreSQLRemoveFieldsIT.scala            |   0
 .../integration/RemoveFieldsFunctions.scala   |   0
 .../integration/SQLiteCountIT.scala           |   0
 .../integration/SQLiteCustomIT.scala          |   0
 .../tests => }/integration/SQLiteDB.scala     |   0
 .../integration/SQLiteDefinitionIT.scala      |   0
 .../integration/SQLiteDeleteIT.scala          |   0
 .../integration/SQLiteDocumentIT.scala        |   0
 .../integration/SQLiteExistsIT.scala          |   0
 .../tests => }/integration/SQLiteFindIT.scala |   0
 .../integration/SQLitePatchIT.scala           |   0
 .../integration/SQLiteRemoveFieldsIT.scala    |   0
 .../tests => }/integration/SubDocument.scala  |   0
 .../integration/ThrowawayDatabase.scala       |   0
 src/scala/src/test/scala/package.scala        |   3 +
 .../documents/scala/tests/package.scala       |   6 -
 77 files changed, 670 insertions(+), 679 deletions(-)
 rename src/scala/src/main/scala/{solutions/bitbadger/documents/scala => }/Count.scala (92%)
 rename src/scala/src/main/scala/{solutions/bitbadger/documents/scala => }/Custom.scala (73%)
 rename src/scala/src/main/scala/{solutions/bitbadger/documents/scala => }/Definition.scala (100%)
 rename src/scala/src/main/scala/{solutions/bitbadger/documents/scala => }/Delete.scala (91%)
 rename src/scala/src/main/scala/{solutions/bitbadger/documents/scala => }/Document.scala (71%)
 rename src/scala/src/main/scala/{solutions/bitbadger/documents/scala => }/Exists.scala (92%)
 rename src/scala/src/main/scala/{solutions/bitbadger/documents/scala => }/Find.scala (67%)
 rename src/scala/src/main/scala/{solutions/bitbadger/documents/scala => }/Parameters.scala (90%)
 rename src/scala/src/main/scala/{solutions/bitbadger/documents/scala => }/Patch.scala (83%)
 rename src/scala/src/main/scala/{solutions/bitbadger/documents/scala => }/RemoveFields.scala (93%)
 rename src/scala/src/main/scala/{solutions/bitbadger/documents/scala => }/Results.scala (82%)
 create mode 100644 src/scala/src/main/scala/extensions/package.scala
 delete mode 100644 src/scala/src/main/scala/solutions/bitbadger/documents/scala/extensions/package.scala
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/AutoIdTest.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/ByteIdClass.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/ConfigurationTest.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/CountQueryTest.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/DefinitionQueryTest.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/DeleteQueryTest.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/DialectTest.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/DocumentIndexTest.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/DocumentQueryTest.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/ExistsQueryTest.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/FieldMatchTest.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/FieldTest.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/FindQueryTest.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/ForceDialect.scala (83%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/IntIdClass.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/LongIdClass.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/OpTest.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/ParameterNameTest.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/ParameterTest.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/ParametersTest.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/PatchQueryTest.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/QueryUtilsTest.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/RemoveFieldsQueryTest.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/ShortIdClass.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/StringIdClass.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/WhereTest.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/ArrayDocument.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/CountFunctions.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/CustomFunctions.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/DefinitionFunctions.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/DeleteFunctions.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/DocumentFunctions.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/ExistsFunctions.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/FindFunctions.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/JacksonDocumentSerializer.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/JsonDocument.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/NumIdDocument.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/PatchFunctions.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/PgDB.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/PostgreSQLCountIT.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/PostgreSQLCustomIT.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/PostgreSQLDefinitionIT.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/PostgreSQLDeleteIT.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/PostgreSQLDocumentIT.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/PostgreSQLExistsIT.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/PostgreSQLFindIT.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/PostgreSQLPatchIT.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/PostgreSQLRemoveFieldsIT.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/RemoveFieldsFunctions.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/SQLiteCountIT.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/SQLiteCustomIT.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/SQLiteDB.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/SQLiteDefinitionIT.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/SQLiteDeleteIT.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/SQLiteDocumentIT.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/SQLiteExistsIT.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/SQLiteFindIT.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/SQLitePatchIT.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/SQLiteRemoveFieldsIT.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/SubDocument.scala (100%)
 rename src/scala/src/test/scala/{solutions/bitbadger/documents/scala/tests => }/integration/ThrowawayDatabase.scala (100%)
 create mode 100644 src/scala/src/test/scala/package.scala
 delete mode 100644 src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/package.scala

diff --git a/src/core/pom.xml b/src/core/pom.xml
index 2da4e57..d54de26 100644
--- a/src/core/pom.xml
+++ b/src/core/pom.xml
@@ -106,6 +106,9 @@
                         <goals>
                             <goal>jar</goal>
                         </goals>
+                        <configuration>
+                            <sourcepath>${project.basedir}/src/main/kotlin</sourcepath>
+                        </configuration>
                     </execution>
                 </executions>
             </plugin>
diff --git a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/Count.scala b/src/scala/src/main/scala/Count.scala
similarity index 92%
rename from src/scala/src/main/scala/solutions/bitbadger/documents/scala/Count.scala
rename to src/scala/src/main/scala/Count.scala
index a2a1d3c..df5a319 100644
--- a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/Count.scala
+++ b/src/scala/src/main/scala/Count.scala
@@ -62,12 +62,12 @@ object Count:
    * 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
-   * @param conn The connection on which the count should be executed
+   * @param criteria  The object for which JSON containment should be checked
+   * @param conn      The connection on which the count should be executed
    * @return A count of the matching documents in the table
    * @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)
 
   /**
@@ -78,7 +78,7 @@ object Count:
    * @return A count of the matching documents in the table
    * @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)
 
   /**
diff --git a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/Custom.scala b/src/scala/src/main/scala/Custom.scala
similarity index 73%
rename from src/scala/src/main/scala/solutions/bitbadger/documents/scala/Custom.scala
rename to src/scala/src/main/scala/Custom.scala
index b59bee2..d946b33 100644
--- a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/Custom.scala
+++ b/src/scala/src/main/scala/Custom.scala
@@ -18,9 +18,9 @@ object Custom:
    * @return A list of results for the given query
    * @throws DocumentException If parameters are invalid
    */
-  def list[TDoc](query: String, parameters: Seq[Parameter[?]], conn: Connection,
-                 mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): List[TDoc] =
-    Using(Parameters.apply(conn, query, parameters)) { stmt => Results.toCustomList[TDoc](stmt, mapFunc) }.get
+  def list[Doc](query: String, parameters: Seq[Parameter[?]], conn: Connection,
+                mapFunc: (ResultSet, ClassTag[Doc]) => Doc)(using tag: ClassTag[Doc]): List[Doc] =
+    Using(Parameters.apply(conn, query, parameters)) { stmt => Results.toCustomList[Doc](stmt, mapFunc) }.get
 
   /**
    * Execute a query that returns a list of results
@@ -31,8 +31,8 @@ object Custom:
    * @return A list of results for the given query
    * @throws DocumentException If parameters are invalid
    */
-  def list[TDoc](query: String, conn: Connection,
-                 mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): List[TDoc] =
+  def list[Doc](query: String, conn: Connection, mapFunc: (ResultSet, ClassTag[Doc]) => Doc)
+               (using tag: ClassTag[Doc]): List[Doc] =
     list(query, List(), conn, mapFunc)
 
   /**
@@ -44,9 +44,9 @@ object Custom:
    * @return A list of results for the given query
    * @throws DocumentException If parameters are invalid
    */
-  def list[TDoc](query: String, parameters: Seq[Parameter[?]],
-                 mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): List[TDoc] =
-    Using(Configuration.dbConn()) { conn => list[TDoc](query, parameters, conn, mapFunc) }.get
+  def list[Doc](query: String, parameters: Seq[Parameter[?]], mapFunc: (ResultSet, ClassTag[Doc]) => Doc)
+               (using tag: ClassTag[Doc]): List[Doc] =
+    Using(Configuration.dbConn()) { conn => list[Doc](query, parameters, conn, mapFunc) }.get
 
   /**
    * 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
    * @throws DocumentException If parameters are invalid
    */
-  def list[TDoc](query: String,
-                 mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): List[TDoc] =
+  def list[Doc](query: String, mapFunc: (ResultSet, ClassTag[Doc]) => Doc)(using tag: ClassTag[Doc]): List[Doc] =
     list(query, List(), mapFunc)
 
   /**
@@ -70,9 +69,9 @@ object Custom:
    * @return An `Option` value, with the document if one matches the query
    * @throws DocumentException If parameters are invalid
    */
-  def single[TDoc](query: String, parameters: Seq[Parameter[?]], conn: Connection,
-                   mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): Option[TDoc] =
-    list[TDoc](s"$query LIMIT 1", parameters, conn, mapFunc).headOption
+  def single[Doc](query: String, parameters: Seq[Parameter[?]], conn: Connection,
+                  mapFunc: (ResultSet, ClassTag[Doc]) => Doc)(using tag: ClassTag[Doc]): Option[Doc] =
+    list[Doc](s"$query LIMIT 1", parameters, conn, mapFunc).headOption
 
   /**
    * 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
    * @throws DocumentException If parameters are invalid
    */
-  def single[TDoc](query: String, conn: Connection,
-                   mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): Option[TDoc] =
-    list[TDoc](s"$query LIMIT 1", List(), conn, mapFunc).headOption
+  def single[Doc](query: String, conn: Connection, mapFunc: (ResultSet, ClassTag[Doc]) => Doc)
+                 (using tag: ClassTag[Doc]): Option[Doc] =
+    list[Doc](s"$query LIMIT 1", List(), conn, mapFunc).headOption
 
   /**
    * 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
    * @throws DocumentException If parameters are invalid
    */
-  def single[TDoc](query: String, parameters: Seq[Parameter[?]],
-                   mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): Option[TDoc] =
-    Using(Configuration.dbConn()) { conn => single[TDoc](query, parameters, conn, mapFunc) }.get
+  def single[Doc](query: String, parameters: Seq[Parameter[?]], mapFunc: (ResultSet, ClassTag[Doc]) => Doc)
+                 (using tag: ClassTag[Doc]): Option[Doc] =
+    Using(Configuration.dbConn()) { conn => single[Doc](query, parameters, conn, mapFunc) }.get
 
   /**
    * 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
    * @throws DocumentException If parameters are invalid
    */
-  def single[TDoc](query: String,
-                   mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): Option[TDoc] =
-    single[TDoc](query, List(), mapFunc)
+  def single[Doc](query: String, mapFunc: (ResultSet, ClassTag[Doc]) => Doc)(using tag: ClassTag[Doc]): Option[Doc] =
+    single[Doc](query, List(), mapFunc)
 
   /**
    * Execute a query that returns no results
@@ -162,8 +160,8 @@ object Custom:
    * @return The scalar value from the query
    * @throws DocumentException If parameters are invalid
    */
-  def scalar[T](query: String, parameters: Seq[Parameter[?]], conn: Connection,
-                mapFunc: (ResultSet, ClassTag[T]) => T)(implicit tag: ClassTag[T]): T =
+  def scalar[A](query: String, parameters: Seq[Parameter[?]], conn: Connection, mapFunc: (ResultSet, ClassTag[A]) => A)
+               (using tag: ClassTag[A]): A =
     Using(Parameters.apply(conn, query, parameters)) { stmt =>
       Using(stmt.executeQuery()) { rs =>
         rs.next()
@@ -180,9 +178,8 @@ object Custom:
    * @return The scalar value from the query
    * @throws DocumentException If parameters are invalid
    */
-  def scalar[T](query: String, conn: Connection,
-                mapFunc: (ResultSet, ClassTag[T]) => T)(implicit tag: ClassTag[T]): T =
-    scalar[T](query, List(), conn, mapFunc)
+  def scalar[A](query: String, conn: Connection, mapFunc: (ResultSet, ClassTag[A]) => A)(using tag: ClassTag[A]): A =
+    scalar[A](query, List(), conn, mapFunc)
 
   /**
    * Execute a query that returns a scalar result (creates connection)
@@ -193,9 +190,9 @@ object Custom:
    * @return The scalar value from the query
    * @throws DocumentException If parameters are invalid
    */
-  def scalar[T](query: String, parameters: Seq[Parameter[?]],
-                mapFunc: (ResultSet, ClassTag[T]) => T)(implicit tag: ClassTag[T]): T =
-    Using(Configuration.dbConn()) { conn => scalar[T](query, parameters, conn, mapFunc) }.get
+  def scalar[A](query: String, parameters: Seq[Parameter[?]], mapFunc: (ResultSet, ClassTag[A]) => A)
+               (using tag: ClassTag[A]): A =
+    Using(Configuration.dbConn()) { conn => scalar[A](query, parameters, conn, mapFunc) }.get
 
   /**
    * Execute a query that returns a scalar result (creates connection)
@@ -205,6 +202,5 @@ object Custom:
    * @return The scalar value from the query
    * @throws DocumentException If parameters are invalid
    */
-  def scalar[T](query: String,
-                mapFunc: (ResultSet, ClassTag[T]) => T)(implicit tag: ClassTag[T]): T =
-    scalar[T](query, List(), mapFunc)
+  def scalar[A](query: String, mapFunc: (ResultSet, ClassTag[A]) => A)(using tag: ClassTag[A]): A =
+    scalar[A](query, List(), mapFunc)
diff --git a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/Definition.scala b/src/scala/src/main/scala/Definition.scala
similarity index 100%
rename from src/scala/src/main/scala/solutions/bitbadger/documents/scala/Definition.scala
rename to src/scala/src/main/scala/Definition.scala
diff --git a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/Delete.scala b/src/scala/src/main/scala/Delete.scala
similarity index 91%
rename from src/scala/src/main/scala/solutions/bitbadger/documents/scala/Delete.scala
rename to src/scala/src/main/scala/Delete.scala
index 19729af..bd67103 100644
--- a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/Delete.scala
+++ b/src/scala/src/main/scala/Delete.scala
@@ -19,7 +19,7 @@ object Delete:
    * @param conn      The connection on which the deletion should be executed
    * @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)
 
   /**
@@ -29,7 +29,7 @@ object Delete:
   * @param docId     The ID of the document to be deleted
   * @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)
 
   /**
@@ -63,7 +63,7 @@ object Delete:
    * @param conn      The connection on which the deletion should be executed
    * @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)
 
   /**
@@ -73,7 +73,7 @@ object Delete:
    * @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
    */
-  def byContains[TContains](tableName: String, criteria: TContains): Unit =
+  def byContains[A](tableName: String, criteria: A): Unit =
     CoreDelete.byContains(tableName, criteria)
 
   /**
@@ -91,7 +91,7 @@ object Delete:
   * 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 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
   */
   def byJsonPath(tableName: String, path: String): Unit =
diff --git a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/Document.scala b/src/scala/src/main/scala/Document.scala
similarity index 71%
rename from src/scala/src/main/scala/solutions/bitbadger/documents/scala/Document.scala
rename to src/scala/src/main/scala/Document.scala
index ca23662..cab75fe 100644
--- a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/Document.scala
+++ b/src/scala/src/main/scala/Document.scala
@@ -14,7 +14,7 @@ object Document:
    * @param conn      The connection on which the query should be executed
    * @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)
 
   /**
@@ -24,49 +24,49 @@ object Document:
    * @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 =
+  def insert[Doc](tableName: String, document: Doc): Unit =
     CoreDocument.insert(tableName, document)
 
   /**
    * 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
-   * @param conn The connection on which the query should be executed
+   * @param document  The document to be saved
+   * @param conn      The connection on which the query should be executed
    * @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)
 
   /**
    * 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 document The document to be saved
+   * @param document  The document to be saved
    * @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)
 
   /**
    * 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
-   * @param conn The connection on which the query should be executed
+   * @param docId     The ID of the document to be replaced
+   * @param document  The document to be replaced
+   * @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
    */
-  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)
 
   /**
    * Update (replace) a document by its ID (creates connection)
    *
    * @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
+   * @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 =
+  def update[Key, Doc](tableName: String, docId: Key, document: Doc): Unit =
     CoreDocument.update(tableName, docId, document)
diff --git a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/Exists.scala b/src/scala/src/main/scala/Exists.scala
similarity index 92%
rename from src/scala/src/main/scala/solutions/bitbadger/documents/scala/Exists.scala
rename to src/scala/src/main/scala/Exists.scala
index 90883f0..ef1c4fb 100644
--- a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/Exists.scala
+++ b/src/scala/src/main/scala/Exists.scala
@@ -20,7 +20,7 @@ object Exists:
    * @return True if the document exists, false if not
    * @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)
 
   /**
@@ -31,7 +31,7 @@ object Exists:
    * @return True if the document exists, false if not
    * @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)
 
   /**
@@ -68,7 +68,7 @@ object Exists:
    * @return True if any matching documents exist, false if not
    * @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)
 
   /**
@@ -79,7 +79,7 @@ object Exists:
    * @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
    */
-  def byContains[TContains](tableName: String, criteria: TContains): Boolean =
+  def byContains[A](tableName: String, criteria: A): Boolean =
     CoreExists.byContains(tableName, criteria)
 
   /**
@@ -98,7 +98,7 @@ object Exists:
    * 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 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
    * @throws DocumentException If no connection string has been set, or if called on a SQLite connection
    */
diff --git a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/Find.scala b/src/scala/src/main/scala/Find.scala
similarity index 67%
rename from src/scala/src/main/scala/solutions/bitbadger/documents/scala/Find.scala
rename to src/scala/src/main/scala/Find.scala
index eb6534f..4335be7 100644
--- a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/Find.scala
+++ b/src/scala/src/main/scala/Find.scala
@@ -22,8 +22,8 @@ object Find:
    * @return A list of documents from the given table
    * @throws DocumentException If query execution fails
    */
-  def all[TDoc](tableName: String, orderBy: Seq[Field[?]], conn: Connection)(implicit tag: ClassTag[TDoc]): List[TDoc] =
-    Custom.list[TDoc](FindQuery.all(tableName) + QueryUtils.orderBy(orderBy.asJava), conn, Results.fromData)
+  def all[Doc](tableName: String, orderBy: Seq[Field[?]], conn: Connection)(using tag: ClassTag[Doc]): List[Doc] =
+    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
@@ -33,43 +33,43 @@ object Find:
    * @return A list of documents from the given table
    * @throws DocumentException If query execution fails
    */
-  def all[TDoc](tableName: String, conn: Connection)(implicit tag: ClassTag[TDoc]): List[TDoc] =
-    all[TDoc](tableName, List(), conn)
+  def all[Doc](tableName: String, conn: Connection)(using tag: ClassTag[Doc]): List[Doc] =
+    all[Doc](tableName, List(), conn)
     
   /**
    * Retrieve all documents in the given table (creates connection)
    *
    * @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
    * @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] =
-    Using(Configuration.dbConn()) { conn => all[TDoc](tableName, orderBy, conn) }.get
+  def all[Doc](tableName: String, orderBy: Seq[Field[?]] = List())(using tag: ClassTag[Doc]): List[Doc] =
+    Using(Configuration.dbConn()) { conn => all[Doc](tableName, orderBy, conn) }.get
 
   /**
    * 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
-   * @param conn The connection over which documents should be retrieved
+   * @param docId     The ID of the document to retrieve
+   * @param conn      The connection over which documents should be retrieved
    * @return An `Option` with the document if it is found
    * @throws DocumentException If no dialect has been configured
    */
-  def byId[TKey, TDoc](tableName: String, docId: TKey, conn: Connection)(implicit tag: ClassTag[TDoc]): Option[TDoc] =
-    Custom.single[TDoc](FindQuery.byId(tableName, docId),
+  def byId[Key, Doc](tableName: String, docId: Key, conn: Connection)(using tag: ClassTag[Doc]): Option[Doc] =
+    Custom.single[Doc](FindQuery.byId(tableName, docId),
       Parameters.addFields(Field.equal(Configuration.idField, docId, ":id") :: Nil).toSeq, conn, Results.fromData)
 
   /**
    * Retrieve a document by its ID (creates connection
    *
    * @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
    * @throws DocumentException If no connection string has been set
    */
-  def byId[TKey, TDoc](tableName: String, docId: TKey)(implicit tag: ClassTag[TDoc]): Option[TDoc] =
-    Using(Configuration.dbConn()) { conn => byId[TKey, TDoc](tableName, docId, conn) }.get
+  def byId[Key, Doc](tableName: String, docId: Key)(using tag: ClassTag[Doc]): Option[Doc] =
+    Using(Configuration.dbConn()) { conn => byId[Key, Doc](tableName, docId, conn) }.get
 
   /**
    * 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
    * @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[?]],
-                     conn: Connection)(implicit tag: ClassTag[TDoc]): List[TDoc] =
+  def byFields[Doc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch], orderBy: Seq[Field[?]],
+                    conn: Connection)(using tag: ClassTag[Doc]): List[Doc] =
     val named = Parameters.nameFields(fields)
-    Custom.list[TDoc](
+    Custom.list[Doc](
       FindQuery.byFields(tableName, named.asJava, howMatched.orNull) + QueryUtils.orderBy(orderBy.asJava),
       Parameters.addFields(named).toSeq, conn, Results.fromData)
 
@@ -99,9 +99,9 @@ object Find:
    * @return A list of documents matching the field comparison
    * @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)
-                    (implicit tag: ClassTag[TDoc]): List[TDoc] =
-    byFields[TDoc](tableName, fields, howMatched, List(), conn)
+  def byFields[Doc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch], conn: Connection)
+                   (using tag: ClassTag[Doc]): List[Doc] =
+    byFields[Doc](tableName, fields, howMatched, List(), conn)
 
   /**
    * 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
    * @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)
-                    (implicit tag: ClassTag[TDoc]): List[TDoc] =
-    byFields[TDoc](tableName, fields, None, orderBy, conn)
+  def byFields[Doc](tableName: String, fields: Seq[Field[?]], orderBy: Seq[Field[?]], conn: Connection)
+                   (using tag: ClassTag[Doc]): List[Doc] =
+    byFields[Doc](tableName, fields, None, orderBy, conn)
 
   /**
    * 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
    * @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,
-                     orderBy: Seq[Field[?]] = List())(implicit tag: ClassTag[TDoc]): List[TDoc] =
-    Using(Configuration.dbConn()) { conn => byFields[TDoc](tableName, fields, howMatched, orderBy, conn) }.get
+  def byFields[Doc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch] = None,
+                    orderBy: Seq[Field[?]] = List())(using tag: ClassTag[Doc]): List[Doc] =
+    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)
@@ -141,9 +141,9 @@ object Find:
    * @return A list of documents matching the JSON containment query
    * @throws DocumentException If called on a SQLite connection
    */
-  def byContains[TDoc, TContains](tableName: String, criteria: TContains, orderBy: Seq[Field[?]],
-                                  conn: Connection)(implicit tag: ClassTag[TDoc]): List[TDoc] =
-    Custom.list[TDoc](FindQuery.byContains(tableName) + QueryUtils.orderBy(orderBy.asJava),
+  def byContains[Doc, A](tableName: String, criteria: A, orderBy: Seq[Field[?]], conn: Connection)
+                        (using tag: ClassTag[Doc]): List[Doc] =
+    Custom.list[Doc](FindQuery.byContains(tableName) + QueryUtils.orderBy(orderBy.asJava),
       Parameters.json(":criteria", criteria) :: Nil, conn, Results.fromData)
 
   /**
@@ -155,9 +155,8 @@ object Find:
    * @return A list of documents matching the JSON containment query
    * @throws DocumentException If called on a SQLite connection
    */
-  def byContains[TDoc, TContains](tableName: String, criteria: TContains, conn: Connection)
-                                 (implicit tag: ClassTag[TDoc]): List[TDoc] =
-    byContains[TDoc, TContains](tableName, criteria, List(), conn)
+  def byContains[Doc, A](tableName: String, criteria: A, conn: Connection)(using tag: ClassTag[Doc]): List[Doc] =
+    byContains[Doc, A](tableName, criteria, List(), conn)
 
   /**
    * 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
    * @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())
-                                 (implicit tag: ClassTag[TDoc]): List[TDoc] =
-    Using(Configuration.dbConn()) { conn => byContains[TDoc, TContains](tableName, criteria, orderBy, conn) }.get
+  def byContains[Doc, A](tableName: String, criteria: A, orderBy: Seq[Field[?]] = List())
+                        (using tag: ClassTag[Doc]): List[Doc] =
+    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)
@@ -183,9 +182,9 @@ object Find:
    * @return A list of documents matching the JSON Path match query
    * @throws DocumentException If called on a SQLite connection
    */
-  def byJsonPath[TDoc](tableName: String, path: String, orderBy: Seq[Field[?]], conn: Connection)
-                      (implicit tag: ClassTag[TDoc]): List[TDoc] =
-    Custom.list[TDoc](FindQuery.byJsonPath(tableName) + QueryUtils.orderBy(orderBy.asJava),
+  def byJsonPath[Doc](tableName: String, path: String, orderBy: Seq[Field[?]], conn: Connection)
+                     (using tag: ClassTag[Doc]): List[Doc] =
+    Custom.list[Doc](FindQuery.byJsonPath(tableName) + QueryUtils.orderBy(orderBy.asJava),
       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
    * @throws DocumentException If called on a SQLite connection
    */
-  def byJsonPath[TDoc](tableName: String, path: String, conn: Connection)(implicit tag: ClassTag[TDoc]): List[TDoc] =
-    byJsonPath[TDoc](tableName, path, List(), conn)
+  def byJsonPath[Doc](tableName: String, path: String, conn: Connection)(using tag: ClassTag[Doc]): List[Doc] =
+    byJsonPath[Doc](tableName, path, List(), conn)
 
   /**
    * 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
    * @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())
-                      (implicit tag: ClassTag[TDoc]): List[TDoc] =
-    Using(Configuration.dbConn()) { conn => byJsonPath[TDoc](tableName, path, orderBy, conn) }.get
+  def byJsonPath[Doc](tableName: String, path: String, orderBy: Seq[Field[?]] = List())
+                     (using tag: ClassTag[Doc]): List[Doc] =
+    Using(Configuration.dbConn()) { conn => byJsonPath[Doc](tableName, path, orderBy, conn) }.get
 
   /**
    * 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
    * @throws DocumentException If no dialect has been configured, or if parameters are invalid
    */
-  def firstByFields[TDoc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch],
-                          orderBy: Seq[Field[?]], conn: Connection)(implicit tag: ClassTag[TDoc]): Option[TDoc] =
+  def firstByFields[Doc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch],
+                         orderBy: Seq[Field[?]], conn: Connection)(using tag: ClassTag[Doc]): Option[Doc] =
     val named = Parameters.nameFields(fields)
-    Custom.single[TDoc](
+    Custom.single[Doc](
       FindQuery.byFields(tableName, named.asJava, howMatched.orNull) + QueryUtils.orderBy(orderBy.asJava),
       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
    * @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)
-                         (implicit tag: ClassTag[TDoc]): Option[TDoc] =
-    firstByFields[TDoc](tableName, fields, howMatched, List(), conn)
+  def firstByFields[Doc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch], conn: Connection)
+                        (using tag: ClassTag[Doc]): Option[Doc] =
+    firstByFields[Doc](tableName, fields, howMatched, List(), conn)
 
   /**
    * 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
    * @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)
-                         (implicit tag: ClassTag[TDoc]): Option[TDoc] =
-    firstByFields[TDoc](tableName, fields, None, orderBy, conn)
+  def firstByFields[Doc](tableName: String, fields: Seq[Field[?]], orderBy: Seq[Field[?]], conn: Connection)
+                        (using tag: ClassTag[Doc]): Option[Doc] =
+    firstByFields[Doc](tableName, fields, None, orderBy, conn)
 
   /**
    * 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
    * @throws DocumentException If no dialect has been configured, or if parameters are invalid
    */
-  def firstByFields[TDoc](tableName: String, fields: Seq[Field[?]], conn: Connection)
-                         (implicit tag: ClassTag[TDoc]): Option[TDoc] =
-    firstByFields[TDoc](tableName, fields, None, List(), conn)
+  def firstByFields[Doc](tableName: String, fields: Seq[Field[?]], conn: Connection)
+                        (using tag: ClassTag[Doc]): Option[Doc] =
+    firstByFields[Doc](tableName, fields, None, List(), conn)
 
   /**
    * 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
    * @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,
-                          orderBy: Seq[Field[?]] = List())(implicit tag: ClassTag[TDoc]): Option[TDoc] =
-    Using(Configuration.dbConn()) { conn => firstByFields[TDoc](tableName, fields, howMatched, orderBy, conn) }.get
+  def firstByFields[Doc](tableName: String, fields: Seq[Field[?]], howMatched: Option[FieldMatch] = None,
+                         orderBy: Seq[Field[?]] = List())(using tag: ClassTag[Doc]): Option[Doc] =
+    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)
@@ -297,9 +296,9 @@ object Find:
    * @return An `Option` with the first document matching the JSON containment query if found
    * @throws DocumentException If called on a SQLite connection
    */
-  def firstByContains[TDoc, TContains](tableName: String, criteria: TContains, orderBy: Seq[Field[?]],
-                                       conn: Connection)(implicit tag: ClassTag[TDoc]): Option[TDoc] =
-    Custom.single[TDoc](FindQuery.byContains(tableName) + QueryUtils.orderBy(orderBy.asJava),
+  def firstByContains[Doc, A](tableName: String, criteria: A, orderBy: Seq[Field[?]], conn: Connection)
+                             (using tag: ClassTag[Doc]): Option[Doc] =
+    Custom.single[Doc](FindQuery.byContains(tableName) + QueryUtils.orderBy(orderBy.asJava),
       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
    * @throws DocumentException If called on a SQLite connection
    */
-  def firstByContains[TDoc, TContains](tableName: String, criteria: TContains, conn: Connection)
-                                      (implicit tag: ClassTag[TDoc]): Option[TDoc] =
-    firstByContains[TDoc, TContains](tableName, criteria, List(), conn)
+  def firstByContains[Doc, A](tableName: String, criteria: A, conn: Connection)(using tag: ClassTag[Doc]): Option[Doc] =
+    firstByContains[Doc, A](tableName, criteria, List(), conn)
 
   /**
    * 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
    * @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())
-                                      (implicit tag: ClassTag[TDoc]): Option[TDoc] =
-    Using(Configuration.dbConn()) { conn => firstByContains[TDoc, TContains](tableName, criteria, orderBy, conn) }.get
+  def firstByContains[Doc, A](tableName: String, criteria: A, orderBy: Seq[Field[?]] = List())
+                             (using tag: ClassTag[Doc]): Option[Doc] =
+    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)
    *
    * @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)
-   * @param conn The connection over 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)
+   * @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
    * @throws DocumentException If called on a SQLite connection
    */
-  def firstByJsonPath[TDoc](tableName: String, path: String, orderBy: Seq[Field[?]], conn: Connection)
-                           (implicit tag: ClassTag[TDoc]): Option[TDoc] =
-    Custom.single[TDoc](FindQuery.byJsonPath(tableName) + QueryUtils.orderBy(orderBy.asJava),
+  def firstByJsonPath[Doc](tableName: String, path: String, orderBy: Seq[Field[?]], conn: Connection)
+                          (using tag: ClassTag[Doc]): Option[Doc] =
+    Custom.single[Doc](FindQuery.byJsonPath(tableName) + QueryUtils.orderBy(orderBy.asJava),
       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
    * @throws DocumentException If called on a SQLite connection
    */
-  def firstByJsonPath[TDoc](tableName: String, path: String, conn: Connection)
-                           (implicit tag: ClassTag[TDoc]): Option[TDoc] =
-    firstByJsonPath[TDoc](tableName, path, List(), conn)
+  def firstByJsonPath[Doc](tableName: String, path: String, conn: Connection)(using tag: ClassTag[Doc]): Option[Doc] =
+    firstByJsonPath[Doc](tableName, path, List(), conn)
 
   /**
    * Retrieve the first document using a JSON Path match query and optional ordering fields (PostgreSQL only; creates
    * connection)
    *
    * @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)
+   * @param path      The JSON path comparison to match
+   * @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
    * @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())
-                           (implicit tag: ClassTag[TDoc]): Option[TDoc] =
-    Using(Configuration.dbConn()) { conn => firstByJsonPath[TDoc](tableName, path, orderBy, conn) }.get
+  def firstByJsonPath[Doc](tableName: String, path: String, orderBy: Seq[Field[?]] = List())
+                          (using tag: ClassTag[Doc]): Option[Doc] =
+    Using(Configuration.dbConn()) { conn => firstByJsonPath[Doc](tableName, path, orderBy, conn) }.get
diff --git a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/Parameters.scala b/src/scala/src/main/scala/Parameters.scala
similarity index 90%
rename from src/scala/src/main/scala/solutions/bitbadger/documents/scala/Parameters.scala
rename to src/scala/src/main/scala/Parameters.scala
index 02b2d5d..2499863 100644
--- a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/Parameters.scala
+++ b/src/scala/src/main/scala/Parameters.scala
@@ -38,13 +38,13 @@ object Parameters:
    * @param value The object to be encoded as JSON
    * @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)
 
   /**
    * 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)
    * @return A collection of parameters for the query
    */
@@ -56,7 +56,7 @@ object Parameters:
   /**
    * 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
    * @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
    *
-   * @param conn The active JDBC connection
-   * @param query The query
+   * @param conn       The active JDBC connection
+   * @param query      The query
    * @param parameters The parameters for the query
    * @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
@@ -78,7 +78,7 @@ object Parameters:
   /**
    * 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
    * @return A list of parameters to use for building the query
    * @throws DocumentException If the dialect has not been set
diff --git a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/Patch.scala b/src/scala/src/main/scala/Patch.scala
similarity index 83%
rename from src/scala/src/main/scala/solutions/bitbadger/documents/scala/Patch.scala
rename to src/scala/src/main/scala/Patch.scala
index b53bb83..e90e150 100644
--- a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/Patch.scala
+++ b/src/scala/src/main/scala/Patch.scala
@@ -20,7 +20,7 @@ object Patch:
    * @param conn      The connection on which the update should be executed
    * @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)
 
   /**
@@ -31,7 +31,7 @@ object Patch:
    * @param patch     The object whose properties should be replaced in the document
    * @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)
 
   /**
@@ -44,8 +44,8 @@ object Patch:
    * @param conn       The connection on which the update should be executed
    * @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],
-                       conn: Connection): Unit =
+  def byFields[Patch](tableName: String, fields: Seq[Field[?]], patch: Patch, howMatched: Option[FieldMatch],
+                  conn: Connection): Unit =
     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
    * @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)
 
   /**
@@ -69,8 +69,8 @@ object Patch:
    * @param howMatched How the fields should be matched
    * @throws DocumentException If no connection string has been set, or if parameters are invalid
    */
-  def byFields[TPatch](tableName: String, fields: Seq[Field[?]], patch: TPatch,
-                       howMatched: Option[FieldMatch] = None): Unit =
+  def byFields[Patch](tableName: String, fields: Seq[Field[?]], patch: Patch,
+                      howMatched: Option[FieldMatch] = None): Unit =
     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
    * @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)
 
   /**
@@ -93,7 +93,7 @@ object Patch:
    * @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
    */
-  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)
 
   /**
@@ -105,7 +105,7 @@ object Patch:
    * @param conn      The connection on which the update should be executed
    * @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)
 
   /**
@@ -116,5 +116,5 @@ object Patch:
    * @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
    */
-  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)
diff --git a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/RemoveFields.scala b/src/scala/src/main/scala/RemoveFields.scala
similarity index 93%
rename from src/scala/src/main/scala/solutions/bitbadger/documents/scala/RemoveFields.scala
rename to src/scala/src/main/scala/RemoveFields.scala
index 2701553..a605b7f 100644
--- a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/RemoveFields.scala
+++ b/src/scala/src/main/scala/RemoveFields.scala
@@ -20,7 +20,7 @@ object RemoveFields:
    * @param conn      The connection on which the update should be executed
    * @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)
 
   /**
@@ -31,7 +31,7 @@ object RemoveFields:
    * @param toRemove  The names of the fields to be removed
    * @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)
 
   /**
@@ -82,7 +82,7 @@ object RemoveFields:
    * @param conn      The connection on which the update should be executed
    * @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)
 
   /**
@@ -93,7 +93,7 @@ object RemoveFields:
    * @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
    */
-  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)
 
   /**
diff --git a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/Results.scala b/src/scala/src/main/scala/Results.scala
similarity index 82%
rename from src/scala/src/main/scala/solutions/bitbadger/documents/scala/Results.scala
rename to src/scala/src/main/scala/Results.scala
index bab76e4..18de0c1 100644
--- a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/Results.scala
+++ b/src/scala/src/main/scala/Results.scala
@@ -21,8 +21,8 @@ object Results:
    * @param ignored The class tag (placeholder used for signature; implicit tag used for serialization)
    * @return The constructed domain item
    */
-  def fromDocument[TDoc](field: String, rs: ResultSet, ignored: ClassTag[TDoc])(implicit tag: ClassTag[TDoc]): TDoc =
-    CoreResults.fromDocument(field, rs, tag.runtimeClass.asInstanceOf[Class[TDoc]])
+  def fromDocument[Doc](field: String, rs: ResultSet, ignored: ClassTag[Doc])(using tag: ClassTag[Doc]): Doc =
+    CoreResults.fromDocument(field, rs, tag.runtimeClass.asInstanceOf[Class[Doc]])
 
   /**
    * 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)
    * @return The constructed domain item
    */
-  def fromData[TDoc](rs: ResultSet, ignored: ClassTag[TDoc])(implicit tag: ClassTag[TDoc]): TDoc =
-    fromDocument[TDoc]("data", rs, tag)
+  def fromData[Doc](rs: ResultSet, ignored: ClassTag[Doc])(using tag: ClassTag[Doc]): Doc =
+    fromDocument[Doc]("data", rs, tag)
 
   /**
    * 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
    * @return A list of items from the query's result
    * @throws DocumentException If there is a problem executing the query (unchecked)
    */
-  def toCustomList[TDoc](stmt: PreparedStatement,
-                         mapFunc: (ResultSet, ClassTag[TDoc]) => TDoc)(implicit tag: ClassTag[TDoc]): List[TDoc] =
+  def toCustomList[Doc](stmt: PreparedStatement,mapFunc: (ResultSet, ClassTag[Doc]) => Doc)
+                       (using tag: ClassTag[Doc]): List[Doc] =
     try
-      val buffer = ListBuffer[TDoc]()
+      val buffer = ListBuffer[Doc]()
       Using(stmt.executeQuery()) { rs =>
         while (rs.next()) {
           buffer.append(mapFunc(rs, tag))
diff --git a/src/scala/src/main/scala/extensions/package.scala b/src/scala/src/main/scala/extensions/package.scala
new file mode 100644
index 0000000..c7c4dd6
--- /dev/null
+++ b/src/scala/src/main/scala/extensions/package.scala
@@ -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)
diff --git a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/extensions/package.scala b/src/scala/src/main/scala/solutions/bitbadger/documents/scala/extensions/package.scala
deleted file mode 100644
index 142fd26..0000000
--- a/src/scala/src/main/scala/solutions/bitbadger/documents/scala/extensions/package.scala
+++ /dev/null
@@ -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)
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/AutoIdTest.scala b/src/scala/src/test/scala/AutoIdTest.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/AutoIdTest.scala
rename to src/scala/src/test/scala/AutoIdTest.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/ByteIdClass.scala b/src/scala/src/test/scala/ByteIdClass.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/ByteIdClass.scala
rename to src/scala/src/test/scala/ByteIdClass.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/ConfigurationTest.scala b/src/scala/src/test/scala/ConfigurationTest.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/ConfigurationTest.scala
rename to src/scala/src/test/scala/ConfigurationTest.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/CountQueryTest.scala b/src/scala/src/test/scala/CountQueryTest.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/CountQueryTest.scala
rename to src/scala/src/test/scala/CountQueryTest.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/DefinitionQueryTest.scala b/src/scala/src/test/scala/DefinitionQueryTest.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/DefinitionQueryTest.scala
rename to src/scala/src/test/scala/DefinitionQueryTest.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/DeleteQueryTest.scala b/src/scala/src/test/scala/DeleteQueryTest.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/DeleteQueryTest.scala
rename to src/scala/src/test/scala/DeleteQueryTest.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/DialectTest.scala b/src/scala/src/test/scala/DialectTest.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/DialectTest.scala
rename to src/scala/src/test/scala/DialectTest.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/DocumentIndexTest.scala b/src/scala/src/test/scala/DocumentIndexTest.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/DocumentIndexTest.scala
rename to src/scala/src/test/scala/DocumentIndexTest.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/DocumentQueryTest.scala b/src/scala/src/test/scala/DocumentQueryTest.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/DocumentQueryTest.scala
rename to src/scala/src/test/scala/DocumentQueryTest.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/ExistsQueryTest.scala b/src/scala/src/test/scala/ExistsQueryTest.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/ExistsQueryTest.scala
rename to src/scala/src/test/scala/ExistsQueryTest.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/FieldMatchTest.scala b/src/scala/src/test/scala/FieldMatchTest.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/FieldMatchTest.scala
rename to src/scala/src/test/scala/FieldMatchTest.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/FieldTest.scala b/src/scala/src/test/scala/FieldTest.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/FieldTest.scala
rename to src/scala/src/test/scala/FieldTest.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/FindQueryTest.scala b/src/scala/src/test/scala/FindQueryTest.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/FindQueryTest.scala
rename to src/scala/src/test/scala/FindQueryTest.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/ForceDialect.scala b/src/scala/src/test/scala/ForceDialect.scala
similarity index 83%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/ForceDialect.scala
rename to src/scala/src/test/scala/ForceDialect.scala
index 7665d26..d233bd9 100644
--- a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/ForceDialect.scala
+++ b/src/scala/src/test/scala/ForceDialect.scala
@@ -7,11 +7,11 @@ import solutions.bitbadger.documents.Configuration
  */
 object ForceDialect:
 
-  def postgres (): Unit =
+  def postgres(): Unit =
     Configuration.setConnectionString(":postgresql:")
 
-  def sqlite (): Unit =
+  def sqlite(): Unit =
     Configuration.setConnectionString(":sqlite:")
 
-  def none (): Unit =
+  def none(): Unit =
     Configuration.setConnectionString(null)
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/IntIdClass.scala b/src/scala/src/test/scala/IntIdClass.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/IntIdClass.scala
rename to src/scala/src/test/scala/IntIdClass.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/LongIdClass.scala b/src/scala/src/test/scala/LongIdClass.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/LongIdClass.scala
rename to src/scala/src/test/scala/LongIdClass.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/OpTest.scala b/src/scala/src/test/scala/OpTest.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/OpTest.scala
rename to src/scala/src/test/scala/OpTest.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/ParameterNameTest.scala b/src/scala/src/test/scala/ParameterNameTest.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/ParameterNameTest.scala
rename to src/scala/src/test/scala/ParameterNameTest.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/ParameterTest.scala b/src/scala/src/test/scala/ParameterTest.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/ParameterTest.scala
rename to src/scala/src/test/scala/ParameterTest.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/ParametersTest.scala b/src/scala/src/test/scala/ParametersTest.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/ParametersTest.scala
rename to src/scala/src/test/scala/ParametersTest.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/PatchQueryTest.scala b/src/scala/src/test/scala/PatchQueryTest.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/PatchQueryTest.scala
rename to src/scala/src/test/scala/PatchQueryTest.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/QueryUtilsTest.scala b/src/scala/src/test/scala/QueryUtilsTest.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/QueryUtilsTest.scala
rename to src/scala/src/test/scala/QueryUtilsTest.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/RemoveFieldsQueryTest.scala b/src/scala/src/test/scala/RemoveFieldsQueryTest.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/RemoveFieldsQueryTest.scala
rename to src/scala/src/test/scala/RemoveFieldsQueryTest.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/ShortIdClass.scala b/src/scala/src/test/scala/ShortIdClass.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/ShortIdClass.scala
rename to src/scala/src/test/scala/ShortIdClass.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/StringIdClass.scala b/src/scala/src/test/scala/StringIdClass.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/StringIdClass.scala
rename to src/scala/src/test/scala/StringIdClass.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/WhereTest.scala b/src/scala/src/test/scala/WhereTest.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/WhereTest.scala
rename to src/scala/src/test/scala/WhereTest.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/ArrayDocument.scala b/src/scala/src/test/scala/integration/ArrayDocument.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/ArrayDocument.scala
rename to src/scala/src/test/scala/integration/ArrayDocument.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/CountFunctions.scala b/src/scala/src/test/scala/integration/CountFunctions.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/CountFunctions.scala
rename to src/scala/src/test/scala/integration/CountFunctions.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/CustomFunctions.scala b/src/scala/src/test/scala/integration/CustomFunctions.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/CustomFunctions.scala
rename to src/scala/src/test/scala/integration/CustomFunctions.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/DefinitionFunctions.scala b/src/scala/src/test/scala/integration/DefinitionFunctions.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/DefinitionFunctions.scala
rename to src/scala/src/test/scala/integration/DefinitionFunctions.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/DeleteFunctions.scala b/src/scala/src/test/scala/integration/DeleteFunctions.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/DeleteFunctions.scala
rename to src/scala/src/test/scala/integration/DeleteFunctions.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/DocumentFunctions.scala b/src/scala/src/test/scala/integration/DocumentFunctions.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/DocumentFunctions.scala
rename to src/scala/src/test/scala/integration/DocumentFunctions.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/ExistsFunctions.scala b/src/scala/src/test/scala/integration/ExistsFunctions.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/ExistsFunctions.scala
rename to src/scala/src/test/scala/integration/ExistsFunctions.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/FindFunctions.scala b/src/scala/src/test/scala/integration/FindFunctions.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/FindFunctions.scala
rename to src/scala/src/test/scala/integration/FindFunctions.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/JacksonDocumentSerializer.scala b/src/scala/src/test/scala/integration/JacksonDocumentSerializer.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/JacksonDocumentSerializer.scala
rename to src/scala/src/test/scala/integration/JacksonDocumentSerializer.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/JsonDocument.scala b/src/scala/src/test/scala/integration/JsonDocument.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/JsonDocument.scala
rename to src/scala/src/test/scala/integration/JsonDocument.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/NumIdDocument.scala b/src/scala/src/test/scala/integration/NumIdDocument.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/NumIdDocument.scala
rename to src/scala/src/test/scala/integration/NumIdDocument.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PatchFunctions.scala b/src/scala/src/test/scala/integration/PatchFunctions.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PatchFunctions.scala
rename to src/scala/src/test/scala/integration/PatchFunctions.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PgDB.scala b/src/scala/src/test/scala/integration/PgDB.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PgDB.scala
rename to src/scala/src/test/scala/integration/PgDB.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PostgreSQLCountIT.scala b/src/scala/src/test/scala/integration/PostgreSQLCountIT.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PostgreSQLCountIT.scala
rename to src/scala/src/test/scala/integration/PostgreSQLCountIT.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PostgreSQLCustomIT.scala b/src/scala/src/test/scala/integration/PostgreSQLCustomIT.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PostgreSQLCustomIT.scala
rename to src/scala/src/test/scala/integration/PostgreSQLCustomIT.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PostgreSQLDefinitionIT.scala b/src/scala/src/test/scala/integration/PostgreSQLDefinitionIT.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PostgreSQLDefinitionIT.scala
rename to src/scala/src/test/scala/integration/PostgreSQLDefinitionIT.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PostgreSQLDeleteIT.scala b/src/scala/src/test/scala/integration/PostgreSQLDeleteIT.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PostgreSQLDeleteIT.scala
rename to src/scala/src/test/scala/integration/PostgreSQLDeleteIT.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PostgreSQLDocumentIT.scala b/src/scala/src/test/scala/integration/PostgreSQLDocumentIT.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PostgreSQLDocumentIT.scala
rename to src/scala/src/test/scala/integration/PostgreSQLDocumentIT.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PostgreSQLExistsIT.scala b/src/scala/src/test/scala/integration/PostgreSQLExistsIT.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PostgreSQLExistsIT.scala
rename to src/scala/src/test/scala/integration/PostgreSQLExistsIT.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PostgreSQLFindIT.scala b/src/scala/src/test/scala/integration/PostgreSQLFindIT.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PostgreSQLFindIT.scala
rename to src/scala/src/test/scala/integration/PostgreSQLFindIT.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PostgreSQLPatchIT.scala b/src/scala/src/test/scala/integration/PostgreSQLPatchIT.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PostgreSQLPatchIT.scala
rename to src/scala/src/test/scala/integration/PostgreSQLPatchIT.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PostgreSQLRemoveFieldsIT.scala b/src/scala/src/test/scala/integration/PostgreSQLRemoveFieldsIT.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/PostgreSQLRemoveFieldsIT.scala
rename to src/scala/src/test/scala/integration/PostgreSQLRemoveFieldsIT.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/RemoveFieldsFunctions.scala b/src/scala/src/test/scala/integration/RemoveFieldsFunctions.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/RemoveFieldsFunctions.scala
rename to src/scala/src/test/scala/integration/RemoveFieldsFunctions.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SQLiteCountIT.scala b/src/scala/src/test/scala/integration/SQLiteCountIT.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SQLiteCountIT.scala
rename to src/scala/src/test/scala/integration/SQLiteCountIT.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SQLiteCustomIT.scala b/src/scala/src/test/scala/integration/SQLiteCustomIT.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SQLiteCustomIT.scala
rename to src/scala/src/test/scala/integration/SQLiteCustomIT.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SQLiteDB.scala b/src/scala/src/test/scala/integration/SQLiteDB.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SQLiteDB.scala
rename to src/scala/src/test/scala/integration/SQLiteDB.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SQLiteDefinitionIT.scala b/src/scala/src/test/scala/integration/SQLiteDefinitionIT.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SQLiteDefinitionIT.scala
rename to src/scala/src/test/scala/integration/SQLiteDefinitionIT.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SQLiteDeleteIT.scala b/src/scala/src/test/scala/integration/SQLiteDeleteIT.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SQLiteDeleteIT.scala
rename to src/scala/src/test/scala/integration/SQLiteDeleteIT.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SQLiteDocumentIT.scala b/src/scala/src/test/scala/integration/SQLiteDocumentIT.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SQLiteDocumentIT.scala
rename to src/scala/src/test/scala/integration/SQLiteDocumentIT.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SQLiteExistsIT.scala b/src/scala/src/test/scala/integration/SQLiteExistsIT.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SQLiteExistsIT.scala
rename to src/scala/src/test/scala/integration/SQLiteExistsIT.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SQLiteFindIT.scala b/src/scala/src/test/scala/integration/SQLiteFindIT.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SQLiteFindIT.scala
rename to src/scala/src/test/scala/integration/SQLiteFindIT.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SQLitePatchIT.scala b/src/scala/src/test/scala/integration/SQLitePatchIT.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SQLitePatchIT.scala
rename to src/scala/src/test/scala/integration/SQLitePatchIT.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SQLiteRemoveFieldsIT.scala b/src/scala/src/test/scala/integration/SQLiteRemoveFieldsIT.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SQLiteRemoveFieldsIT.scala
rename to src/scala/src/test/scala/integration/SQLiteRemoveFieldsIT.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SubDocument.scala b/src/scala/src/test/scala/integration/SubDocument.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/SubDocument.scala
rename to src/scala/src/test/scala/integration/SubDocument.scala
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/ThrowawayDatabase.scala b/src/scala/src/test/scala/integration/ThrowawayDatabase.scala
similarity index 100%
rename from src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/integration/ThrowawayDatabase.scala
rename to src/scala/src/test/scala/integration/ThrowawayDatabase.scala
diff --git a/src/scala/src/test/scala/package.scala b/src/scala/src/test/scala/package.scala
new file mode 100644
index 0000000..dc80f93
--- /dev/null
+++ b/src/scala/src/test/scala/package.scala
@@ -0,0 +1,3 @@
+package solutions.bitbadger.documents.scala.tests
+
+def TEST_TABLE = "test_table"
diff --git a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/package.scala b/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/package.scala
deleted file mode 100644
index 8992837..0000000
--- a/src/scala/src/test/scala/solutions/bitbadger/documents/scala/tests/package.scala
+++ /dev/null
@@ -1,6 +0,0 @@
-package solutions.bitbadger.documents.scala
-
-package object tests {
-
-  def TEST_TABLE = "test_table"
-}
\ No newline at end of file