package solutions.bitbadger.documents import java.sql.Connection import java.sql.ResultSet // ~~~ 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 */ inline fun Connection.customList( query: String, parameters: Collection> = listOf(), mapFunc: (ResultSet) -> TDoc ) = Custom.list(query, parameters, this, 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 The document if one matches the query, `null` otherwise */ inline fun Connection.customSingle( query: String, parameters: Collection> = listOf(), mapFunc: (ResultSet) -> TDoc ) = Custom.single(query, parameters, this, mapFunc) /** * Execute a query that returns no results * * @param query The query to retrieve the results * @param parameters Parameters to use for the query */ fun Connection.customNonQuery(query: String, parameters: Collection> = listOf()) = Custom.nonQuery(query, parameters, this) /** * 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 */ inline fun Connection.customScalar( query: String, parameters: Collection> = listOf(), mapFunc: (ResultSet) -> T & Any ) = Custom.scalar(query, parameters, this, mapFunc) // ~~~ DEFINITION QUERIES ~~~ /** * Create a document table if necessary * * @param tableName The table whose existence should be ensured (may include schema) */ fun Connection.ensureTable(tableName: String) = Definition.ensureTable(tableName, this) /** * 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< */ fun Connection.ensureFieldIndex(tableName: String, indexName: String, fields: Collection) = Definition.ensureFieldIndex(tableName, indexName, fields, this) /** * 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 */ fun Connection.ensureDocumentIndex(tableName: String, indexType: DocumentIndex) = Definition.ensureDocumentIndex(tableName, indexType, this) // ~~~ 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 */ inline fun Connection.insert(tableName: String, document: TDoc) = 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 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 Connection.update(tableName: String, docId: TKey, document: TDoc) = Document.update(tableName, docId, document, this) // ~~~ 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 */ fun Connection.countAll(tableName: String) = Count.all(tableName, this) /** * 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 * @return A count of the matching documents in the table */ fun Connection.countByFields(tableName: String, fields: Collection>, howMatched: FieldMatch? = null) = Count.byFields(tableName, fields, howMatched, this) /** * 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 */ inline fun Connection.countByContains(tableName: String, criteria: TContains) = Count.byContains(tableName, criteria, this) /** * 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 */ fun Connection.countByJsonPath(tableName: String, path: String) = Count.byJsonPath(tableName, path, this) // ~~~ 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 */ fun Connection.existsById(tableName: String, docId: TKey) = Exists.byId(tableName, docId, this) /** * 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 */ fun Connection.existsByFields(tableName: String, fields: Collection>, howMatched: FieldMatch? = null) = Exists.byFields(tableName, fields, howMatched, this) /** * 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 */ inline fun Connection.existsByContains(tableName: String, criteria: TContains) = Exists.byContains(tableName, criteria, this) /** * 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 */ fun Connection.existsByJsonPath(tableName: String, path: String) = Exists.byJsonPath(tableName, path, this) // ~~~ 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 */ inline fun Connection.findAll(tableName: String, orderBy: Collection>? = null) = Find.all(tableName, orderBy, this) /** * 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, `null` otherwise */ inline fun Connection.findById(tableName: String, docId: TKey) = Find.byId(tableName, docId, this) /** * 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 */ inline fun Connection.findByFields( tableName: String, fields: Collection>, howMatched: FieldMatch? = null, orderBy: Collection>? = null ) = Find.byFields(tableName, fields, howMatched, orderBy, this) /** * 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 */ inline fun Connection.findByContains( tableName: String, criteria: TContains, orderBy: Collection>? = null ) = Find.byContains(tableName, criteria, orderBy, this) /** * 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 */ inline fun Connection.findByJsonPath( tableName: String, path: String, orderBy: Collection>? = null ) = Find.byJsonPath(tableName, path, orderBy, this) /** * 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 `null` if no matches are found */ inline fun Connection.findFirstByFields( tableName: String, fields: Collection>, howMatched: FieldMatch? = null, orderBy: Collection>? = null ) = Find.firstByFields(tableName, fields, howMatched, orderBy, this) /** * 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 `null` if no matches are found * @throws DocumentException If called on a SQLite connection */ inline fun Connection.findFirstByContains( tableName: String, criteria: TContains, orderBy: Collection>? = null ) = Find.firstByContains(tableName, criteria, orderBy, this) /** * 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 `null` if no matches are found * @throws DocumentException If called on a SQLite connection */ inline fun Connection.findFirstByJsonPath( tableName: String, path: String, orderBy: Collection>? = null ) = Find.firstByJsonPath(tableName, path, orderBy, this) // ~~~ 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 */ inline fun Connection.patchById(tableName: String, docId: TKey, patch: TPatch) = Patch.byId(tableName, docId, patch, this) /** * 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 */ inline fun Connection.patchByFields( tableName: String, fields: Collection>, patch: TPatch, howMatched: FieldMatch? = null ) = Patch.byFields(tableName, fields, patch, howMatched, this) /** * 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 */ inline fun Connection.patchByContains( tableName: String, criteria: TContains, patch: TPatch ) = Patch.byContains(tableName, criteria, patch, this) /** * 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 */ inline fun Connection.patchByJsonPath(tableName: String, path: String, patch: TPatch) = Patch.byJsonPath(tableName, path, patch, this) // ~~~ 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 */ fun Connection.removeFieldsById(tableName: String, docId: TKey, toRemove: Collection) = RemoveFields.byId(tableName, docId, toRemove, this) /** * 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 */ fun Connection.removeFieldsByFields( tableName: String, fields: Collection>, toRemove: Collection, howMatched: FieldMatch? = null ) = RemoveFields.byFields(tableName, fields, toRemove, howMatched, this) /** * 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 */ inline fun Connection.removeFieldsByContains( tableName: String, criteria: TContains, toRemove: Collection ) = RemoveFields.byContains(tableName, criteria, toRemove, this) /** * 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 */ fun Connection.removeFieldsByJsonPath(tableName: String, path: String, toRemove: Collection) = RemoveFields.byJsonPath(tableName, path, toRemove, this) // ~~~ 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 */ fun Connection.deleteById(tableName: String, docId: TKey) = Delete.byId(tableName, docId, this) /** * 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 */ fun Connection.deleteByFields(tableName: String, fields: Collection>, howMatched: FieldMatch? = null) = Delete.byFields(tableName, fields, howMatched, this) /** * 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 */ inline fun Connection.deleteByContains(tableName: String, criteria: TContains) = Delete.byContains(tableName, criteria, this) /** * 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 */ fun Connection.deleteByJsonPath(tableName: String, path: String) = Delete.byJsonPath(tableName, path, this)