Initial Development #1
@ -1,8 +1,7 @@
 | 
				
			|||||||
package solutions.bitbadger.documents.common
 | 
					package solutions.bitbadger.documents.common
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import solutions.bitbadger.documents.*
 | 
					import solutions.bitbadger.documents.*
 | 
				
			||||||
import kotlin.test.assertEquals
 | 
					import kotlin.test.*
 | 
				
			||||||
import kotlin.test.fail
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Integration tests for the `Document` object / `insert`, `save`, `update` connection extension functions
 | 
					 * Integration tests for the `Document` object / `insert`, `save`, `update` connection extension functions
 | 
				
			||||||
@ -85,4 +84,44 @@ object Document {
 | 
				
			|||||||
            Configuration.idStringLength = 16
 | 
					            Configuration.idStringLength = 16
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun saveMatch(db: ThrowawayDatabase) {
 | 
				
			||||||
 | 
					        JsonDocument.load(db)
 | 
				
			||||||
 | 
					        db.conn.save(TEST_TABLE, JsonDocument("two", numValue = 44))
 | 
				
			||||||
 | 
					        val doc = db.conn.findById<String, JsonDocument>(TEST_TABLE, "two")
 | 
				
			||||||
 | 
					        assertNotNull(doc, "There should have been a document returned")
 | 
				
			||||||
 | 
					        assertEquals("two", doc.id, "An incorrect document was returned")
 | 
				
			||||||
 | 
					        assertEquals("", doc.value, "The \"value\" field was not updated")
 | 
				
			||||||
 | 
					        assertEquals(44, doc.numValue, "The \"numValue\" field was not updated")
 | 
				
			||||||
 | 
					        assertNull(doc.sub, "The \"sub\" field was not updated")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun saveNoMatch(db: ThrowawayDatabase) {
 | 
				
			||||||
 | 
					        JsonDocument.load(db)
 | 
				
			||||||
 | 
					        db.conn.save(TEST_TABLE, JsonDocument("test", sub = SubDocument("a", "b")))
 | 
				
			||||||
 | 
					        assertNotNull(
 | 
				
			||||||
 | 
					            db.conn.findById<String, JsonDocument>(TEST_TABLE, "test"),
 | 
				
			||||||
 | 
					            "The test document should have been saved"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun updateMatch(db: ThrowawayDatabase) {
 | 
				
			||||||
 | 
					        JsonDocument.load(db)
 | 
				
			||||||
 | 
					        db.conn.update(TEST_TABLE, "one", JsonDocument("one", "howdy", 8, SubDocument("y", "z")))
 | 
				
			||||||
 | 
					        val doc = db.conn.findById<String, JsonDocument>(TEST_TABLE, "one")
 | 
				
			||||||
 | 
					        assertNotNull(doc, "There should have been a document returned")
 | 
				
			||||||
 | 
					        assertEquals("one", doc.id, "An incorrect document was returned")
 | 
				
			||||||
 | 
					        assertEquals("howdy", doc.value, "The \"value\" field was not updated")
 | 
				
			||||||
 | 
					        assertEquals(8, doc.numValue, "The \"numValue\" field was not updated")
 | 
				
			||||||
 | 
					        assertNotNull(doc.sub, "The sub-document should not be null")
 | 
				
			||||||
 | 
					        assertEquals("y", doc.sub.foo, "The sub-document \"foo\" field was not updated")
 | 
				
			||||||
 | 
					        assertEquals("z", doc.sub.bar, "The sub-document \"bar\" field was not updated")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun updateNoMatch(db: ThrowawayDatabase) {
 | 
				
			||||||
 | 
					        JsonDocument.load(db)
 | 
				
			||||||
 | 
					        assertFalse { db.conn.existsById(TEST_TABLE, "two-hundred") }
 | 
				
			||||||
 | 
					        db.conn.update(TEST_TABLE, "two-hundred", JsonDocument("two-hundred", numValue = 200))
 | 
				
			||||||
 | 
					        assertFalse { db.conn.existsById(TEST_TABLE, "two-hundred") }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -34,4 +34,24 @@ class DocumentIT {
 | 
				
			|||||||
    @DisplayName("insert succeeds with random string auto ID")
 | 
					    @DisplayName("insert succeeds with random string auto ID")
 | 
				
			||||||
    fun insertStringAutoId() =
 | 
					    fun insertStringAutoId() =
 | 
				
			||||||
        PgDB().use(Document::insertStringAutoId)
 | 
					        PgDB().use(Document::insertStringAutoId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    @DisplayName("save updates an existing document")
 | 
				
			||||||
 | 
					    fun saveMatch() =
 | 
				
			||||||
 | 
					        PgDB().use(Document::saveMatch)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    @DisplayName("save inserts a new document")
 | 
				
			||||||
 | 
					    fun saveNoMatch() =
 | 
				
			||||||
 | 
					        PgDB().use(Document::saveNoMatch)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    @DisplayName("update replaces an existing document")
 | 
				
			||||||
 | 
					    fun updateMatch() =
 | 
				
			||||||
 | 
					        PgDB().use(Document::updateMatch)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    @DisplayName("update succeeds when no document exists")
 | 
				
			||||||
 | 
					    fun updateNoMatch() =
 | 
				
			||||||
 | 
					        PgDB().use(Document::updateNoMatch)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -34,4 +34,24 @@ class DocumentIT {
 | 
				
			|||||||
    @DisplayName("insert succeeds with random string auto ID")
 | 
					    @DisplayName("insert succeeds with random string auto ID")
 | 
				
			||||||
    fun insertStringAutoId() =
 | 
					    fun insertStringAutoId() =
 | 
				
			||||||
        SQLiteDB().use(Document::insertStringAutoId)
 | 
					        SQLiteDB().use(Document::insertStringAutoId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    @DisplayName("save updates an existing document")
 | 
				
			||||||
 | 
					    fun saveMatch() =
 | 
				
			||||||
 | 
					        SQLiteDB().use(Document::saveMatch)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    @DisplayName("save inserts a new document")
 | 
				
			||||||
 | 
					    fun saveNoMatch() =
 | 
				
			||||||
 | 
					        SQLiteDB().use(Document::saveNoMatch)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    @DisplayName("update replaces an existing document")
 | 
				
			||||||
 | 
					    fun updateMatch() =
 | 
				
			||||||
 | 
					        SQLiteDB().use(Document::updateMatch)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    @DisplayName("update succeeds when no document exists")
 | 
				
			||||||
 | 
					    fun updateNoMatch() =
 | 
				
			||||||
 | 
					        SQLiteDB().use(Document::updateNoMatch)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -93,6 +93,25 @@ fun Connection.ensureDocumentIndex(tableName: String, indexType: DocumentIndex)
 | 
				
			|||||||
inline fun <reified TDoc> Connection.insert(tableName: String, document: TDoc) =
 | 
					inline fun <reified TDoc> Connection.insert(tableName: String, document: TDoc) =
 | 
				
			||||||
    Document.insert(tableName, document, this)
 | 
					    Document.insert(tableName, document, this)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					inline fun <reified TDoc> Connection.save(tableName: String, document: TDoc) =
 | 
				
			||||||
 | 
					    Document.save(tableName, document, this)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					inline fun <TKey, reified TDoc> Connection.update(tableName: String, docId: TKey, document: TDoc) =
 | 
				
			||||||
 | 
					    Document.update(tableName, docId, document, this)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ~~~ DOCUMENT COUNT QUERIES ~~~
 | 
					// ~~~ DOCUMENT COUNT QUERIES ~~~
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,8 @@ package solutions.bitbadger.documents
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import java.sql.Connection
 | 
					import java.sql.Connection
 | 
				
			||||||
import solutions.bitbadger.documents.query.Document
 | 
					import solutions.bitbadger.documents.query.Document
 | 
				
			||||||
 | 
					import solutions.bitbadger.documents.query.Where
 | 
				
			||||||
 | 
					import solutions.bitbadger.documents.query.statementWhere
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Functions for manipulating documents
 | 
					 * Functions for manipulating documents
 | 
				
			||||||
@ -26,7 +28,8 @@ object Document {
 | 
				
			|||||||
                when (dialect) {
 | 
					                when (dialect) {
 | 
				
			||||||
                    Dialect.POSTGRESQL ->
 | 
					                    Dialect.POSTGRESQL ->
 | 
				
			||||||
                        when (strategy) {
 | 
					                        when (strategy) {
 | 
				
			||||||
                            AutoId.NUMBER -> "' || (SELECT coalesce(max(data->>'$idField')::numeric, 0) + 1 FROM $tableName) || '"
 | 
					                            AutoId.NUMBER        -> "' || (SELECT coalesce(max(data->>'$idField')::numeric, 0) + 1 " +
 | 
				
			||||||
 | 
					                                                            "FROM $tableName) || '"
 | 
				
			||||||
                            AutoId.UUID          -> "\"${AutoId.generateUUID()}\""
 | 
					                            AutoId.UUID          -> "\"${AutoId.generateUUID()}\""
 | 
				
			||||||
                            AutoId.RANDOM_STRING -> "\"${AutoId.generateRandomString()}\""
 | 
					                            AutoId.RANDOM_STRING -> "\"${AutoId.generateRandomString()}\""
 | 
				
			||||||
                            else                 -> "\"' || (:data)->>'$idField' || '\""
 | 
					                            else                 -> "\"' || (:data)->>'$idField' || '\""
 | 
				
			||||||
@ -57,4 +60,50 @@ object Document {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    inline fun <reified TDoc> insert(tableName: String, document: TDoc) =
 | 
					    inline fun <reified TDoc> insert(tableName: String, document: TDoc) =
 | 
				
			||||||
        Configuration.dbConn().use { insert(tableName, document, it) }
 | 
					        Configuration.dbConn().use { insert(tableName, document, it) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 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
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    inline fun <reified TDoc> save(tableName: String, document: TDoc, conn: Connection) =
 | 
				
			||||||
 | 
					        conn.customNonQuery(Document.save(tableName), listOf(Parameters.json(":data", 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
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    inline fun <reified TDoc> save(tableName: String, document: TDoc) =
 | 
				
			||||||
 | 
					        Configuration.dbConn().use { save(tableName, document, it) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 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
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    inline fun <TKey, reified TDoc> update(tableName: String, docId: TKey, document: TDoc, conn: Connection) =
 | 
				
			||||||
 | 
					        conn.customNonQuery(
 | 
				
			||||||
 | 
					            statementWhere(Document.update(tableName), Where.byId(":id", docId)),
 | 
				
			||||||
 | 
					            Parameters.addFields(
 | 
				
			||||||
 | 
					                listOf(Field.equal(Configuration.idField, docId, ":id")),
 | 
				
			||||||
 | 
					                mutableListOf(Parameters.json(":data", 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
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    inline fun <TKey, reified TDoc> update(tableName: String, docId: TKey, document: TDoc) =
 | 
				
			||||||
 | 
					        Configuration.dbConn().use { update(tableName, docId, document, it) }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user