Initial Development #1

Merged
danieljsummers merged 88 commits from v1-rc into main 2025-04-16 01:29:20 +00:00
5 changed files with 484 additions and 37 deletions
Showing only changes of commit 864477f997 - Show all commits

View File

@ -123,7 +123,7 @@ fun Connection.countByFields(tableName: String, fields: Collection<Field<*>>, ho
* @return A count of the matching documents in the table
* @throws DocumentException If called on a SQLite connection
*/
inline fun <reified T> Connection.countByContains(tableName: String, criteria: T) =
inline fun <reified TContains> Connection.countByContains(tableName: String, criteria: TContains) =
Count.byContains(tableName, criteria, this)
/**
@ -168,7 +168,7 @@ fun Connection.existsByFields(tableName: String, fields: Collection<Field<*>>, h
* @return True if any matching documents exist, false if not
* @throws DocumentException If called on a SQLite connection
*/
inline fun <reified T> Connection.existsByContains(tableName: String, criteria: T) =
inline fun <reified TContains> Connection.existsByContains(tableName: String, criteria: TContains) =
Exists.byContains(tableName, criteria, this)
/**
@ -185,22 +185,122 @@ fun Connection.existsByJsonPath(tableName: String, path: String) =
// ~~~ DOCUMENT RETRIEVAL QUERIES ~~~
/**
* Retrieve all documents in the given table
* 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 <reified TDoc> Connection.findAll(tableName: String) =
Find.all<TDoc>(tableName, this)
inline fun <reified TDoc> Connection.findAll(tableName: String, orderBy: Collection<Field<*>>? = null) =
Find.all<TDoc>(tableName, orderBy, this)
/**
* Retrieve all documents in the given table
* 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 <TKey, reified TDoc> Connection.findById(tableName: String, docId: TKey) =
Find.byId<TKey, TDoc>(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 <reified TDoc> Connection.findByFields(
tableName: String,
fields: Collection<Field<*>>,
howMatched: FieldMatch? = null,
orderBy: Collection<Field<*>>? = null
) =
Find.byFields<TDoc>(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 <reified TDoc, reified TContains> Connection.findByContains(
tableName: String,
criteria: TContains,
orderBy: Collection<Field<*>>? = null
) =
Find.byContains<TDoc, TContains>(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
* @return A list of documents from the given table
* @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 <reified TDoc> Connection.findAll(tableName: String, orderBy: Collection<Field<*>>) =
Find.all<TDoc>(tableName, orderBy, this)
inline fun <reified TDoc> Connection.findByJsonPath(
tableName: String,
path: String,
orderBy: Collection<Field<*>>? = null
) =
Find.byJsonPath<TDoc>(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 <reified TDoc> Connection.findFirstByFields(
tableName: String,
fields: Collection<Field<*>>,
howMatched: FieldMatch? = null,
orderBy: Collection<Field<*>>? = null
) =
Find.firstByFields<TDoc>(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 <reified TDoc, reified TContains> Connection.findFirstByContains(
tableName: String,
criteria: TContains,
orderBy: Collection<Field<*>>? = null
) =
Find.firstByContains<TDoc, TContains>(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 <reified TDoc> Connection.findFirstByJsonPath(
tableName: String,
path: String,
orderBy: Collection<Field<*>>? = null
) =
Find.firstByJsonPath<TDoc>(tableName, path, orderBy, this)
// ~~~ DOCUMENT DELETION QUERIES ~~~
@ -230,7 +330,7 @@ fun Connection.deleteByFields(tableName: String, fields: Collection<Field<*>>, h
* @param criteria The object for which JSON containment should be checked
* @throws DocumentException If called on a SQLite connection
*/
inline fun <reified T> Connection.deleteByContains(tableName: String, criteria: T) =
inline fun <reified TContains> Connection.deleteByContains(tableName: String, criteria: TContains) =
Delete.byContains(tableName, criteria, this)
/**

View File

@ -70,7 +70,7 @@ object Count {
* @return A count of the matching documents in the table
* @throws DocumentException If called on a SQLite connection
*/
inline fun <reified T> byContains(tableName: String, criteria: T, conn: Connection) =
inline fun <reified TContains> byContains(tableName: String, criteria: TContains, conn: Connection) =
conn.customScalar(Count.byContains(tableName), listOf(Parameters.json(":criteria", criteria)), Results::toCount)
/**
@ -81,7 +81,7 @@ object Count {
* @return A count of the matching documents in the table
* @throws DocumentException If called on a SQLite connection
*/
inline fun <reified T> byContains(tableName: String, criteria: T) =
inline fun <reified TContains> byContains(tableName: String, criteria: TContains) =
Configuration.dbConn().use { byContains(tableName, criteria, it) }
/**

View File

@ -61,7 +61,7 @@ object Delete {
* @param conn The connection on which the deletion should be executed
* @throws DocumentException If called on a SQLite connection
*/
inline fun <reified T> byContains(tableName: String, criteria: T, conn: Connection) =
inline fun <reified TContains> byContains(tableName: String, criteria: TContains, conn: Connection) =
conn.customNonQuery(Delete.byContains(tableName), listOf(Parameters.json(":criteria", criteria)))
/**
@ -71,7 +71,7 @@ object Delete {
* @param criteria The object for which JSON containment should be checked
* @throws DocumentException If called on a SQLite connection
*/
inline fun <reified T> byContains(tableName: String, criteria: T) =
inline fun <reified TContains> byContains(tableName: String, criteria: TContains) =
Configuration.dbConn().use { byContains(tableName, criteria, it) }
/**

View File

@ -76,7 +76,7 @@ object Exists {
* @return True if any matching documents exist, false if not
* @throws DocumentException If called on a SQLite connection
*/
inline fun <reified T> byContains(tableName: String, criteria: T, conn: Connection) =
inline fun <reified TContains> byContains(tableName: String, criteria: TContains, conn: Connection) =
conn.customScalar(
Exists.byContains(tableName),
listOf(Parameters.json(":criteria", criteria)),
@ -91,7 +91,7 @@ object Exists {
* @return True if any matching documents exist, false if not
* @throws DocumentException If called on a SQLite connection
*/
inline fun <reified T> byContains(tableName: String, criteria: T) =
inline fun <reified TContains> byContains(tableName: String, criteria: TContains) =
Configuration.dbConn().use { byContains(tableName, criteria, it) }
/**

View File

@ -9,6 +9,27 @@ import solutions.bitbadger.documents.query.orderBy
*/
object Find {
/**
* 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)
* @param conn The connection over which documents should be retrieved
* @return A list of documents from the given table
*/
inline fun <reified TDoc> all(tableName: String, orderBy: Collection<Field<*>>? = null, conn: Connection) =
conn.customList<TDoc>(Find.all(tableName) + (orderBy?.let(::orderBy) ?: ""), mapFunc = Results::fromData)
/**
* Retrieve all documents in the given table
*
* @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 <reified TDoc> all(tableName: String, orderBy: Collection<Field<*>>? = null) =
Configuration.dbConn().use { all<TDoc>(tableName, orderBy, it) }
/**
* Retrieve all documents in the given table
*
@ -17,36 +38,362 @@ object Find {
* @return A list of documents from the given table
*/
inline fun <reified TDoc> all(tableName: String, conn: Connection) =
conn.customList<TDoc>(Find.all(tableName), mapFunc = Results::fromData)
all<TDoc>(tableName, null, conn)
/**
* Retrieve all documents in the given table
* Retrieve a document by its ID
*
* @param tableName The table from which documents should be retrieved
* @return A list of documents from the given table
*/
inline fun <reified TDoc> all(tableName: String) =
Configuration.dbConn().use { all<TDoc>(tableName, it) }
/**
* Retrieve all documents in the given table
*
* @param tableName The table from which documents should be retrieved
* @param orderBy Fields by which the query should be ordered
* @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
* @return A list of documents from the given table
* @return The document if it is found, `null` otherwise
*/
inline fun <reified TDoc> all(tableName: String, orderBy: Collection<Field<*>>, conn: Connection) =
conn.customList<TDoc>(Find.all(tableName) + orderBy(orderBy), mapFunc = Results::fromData)
inline fun <TKey, reified TDoc> byId(tableName: String, docId: TKey, conn: Connection) =
conn.customSingle<TDoc>(
Find.byId(tableName, docId),
Parameters.addFields(listOf(Field.equal(Configuration.idField, docId, ":id"))),
Results::fromData
)
/**
* Retrieve all documents in the given table
* 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 <TKey, reified TDoc> byId(tableName: String, docId: TKey) =
Configuration.dbConn().use { byId<TKey, TDoc>(tableName, docId, it) }
/**
* Retrieve documents using a field comparison, ordering results by the given fields
*
* @param tableName The table from which documents should be retrieved
* @param orderBy Fields by which the query should be ordered
* @return A list of documents from the given table
* @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)
* @param conn The connection over which documents should be retrieved
* @return A list of documents matching the field comparison
*/
inline fun <reified TDoc> all(tableName: String, orderBy: Collection<Field<*>>) =
Configuration.dbConn().use { all<TDoc>(tableName, orderBy, it) }
inline fun <reified TDoc> byFields(
tableName: String,
fields: Collection<Field<*>>,
howMatched: FieldMatch? = null,
orderBy: Collection<Field<*>>? = null,
conn: Connection
): List<TDoc> {
val named = Parameters.nameFields(fields)
return conn.customList<TDoc>(
Find.byFields(tableName, named, howMatched) + (orderBy?.let(::orderBy) ?: ""),
Parameters.addFields(named),
Results::fromData
)
}
/**
* Retrieve documents using a field comparison, ordering results by the given 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
* @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 <reified TDoc> byFields(
tableName: String,
fields: Collection<Field<*>>,
howMatched: FieldMatch? = null,
orderBy: Collection<Field<*>>? = null
) =
Configuration.dbConn().use { byFields<TDoc>(tableName, fields, howMatched, orderBy, it) }
/**
* Retrieve documents using a field comparison
*
* @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
* @param conn The connection over which documents should be retrieved
* @return A list of documents matching the field comparison
*/
inline fun <reified TDoc> byFields(
tableName: String,
fields: Collection<Field<*>>,
howMatched: FieldMatch? = null,
conn: Connection
) =
byFields<TDoc>(tableName, fields, howMatched, null, conn)
/**
* Retrieve documents using a field comparison
*
* @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
* @return A list of documents matching the field comparison
*/
inline fun <reified TDoc> byFields(
tableName: String,
fields: Collection<Field<*>>,
howMatched: FieldMatch? = null
) =
Configuration.dbConn().use { byFields<TDoc>(tableName, fields, howMatched, null, it) }
/**
* Retrieve documents using a JSON containment query, ordering results by the given 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)
* @param conn The connection over which documents should be retrieved
* @return A list of documents matching the JSON containment query
* @throws DocumentException If called on a SQLite connection
*/
inline fun <reified TDoc, reified TContains> byContains(
tableName: String,
criteria: TContains,
orderBy: Collection<Field<*>>? = null,
conn: Connection
) =
conn.customList<TDoc>(
Find.byContains(tableName) + (orderBy?.let(::orderBy) ?: ""),
listOf(Parameters.json(":criteria", criteria)),
Results::fromData
)
/**
* Retrieve documents using a JSON containment query, ordering results by the given 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 A list of documents matching the JSON containment query
* @throws DocumentException If called on a SQLite connection
*/
inline fun <reified TDoc, reified TContains> byContains(
tableName: String,
criteria: TContains,
orderBy: Collection<Field<*>>? = null
) =
Configuration.dbConn().use { byContains<TDoc, TContains>(tableName, criteria, orderBy, it) }
/**
* Retrieve documents using a JSON containment query (PostgreSQL only)
*
* @param tableName The table from which documents should be retrieved
* @param criteria The object for which JSON containment should be checked
* @param conn The connection over which documents should be retrieved
* @return A list of documents matching the JSON containment query
* @throws DocumentException If called on a SQLite connection
*/
inline fun <reified TDoc, reified TContains> byContains(tableName: String, criteria: TContains, conn: Connection) =
byContains<TDoc, TContains>(tableName, criteria, null, conn)
/**
* Retrieve documents using a JSON containment query (PostgreSQL only)
*
* @param tableName The table from which documents should be retrieved
* @param criteria The object for which JSON containment should be checked
* @return A list of documents matching the JSON containment query
* @throws DocumentException If called on a SQLite connection
*/
inline fun <reified TDoc, reified TContains> byContains(tableName: String, criteria: TContains) =
Configuration.dbConn().use { byContains<TDoc, TContains>(tableName, criteria, it) }
/**
* Retrieve documents using a JSON Path match query, ordering results by the 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)
* @param conn The connection over which documents should be retrieved
* @return A list of documents matching the JSON Path match query
* @throws DocumentException If called on a SQLite connection
*/
inline fun <reified TDoc> byJsonPath(
tableName: String,
path: String,
orderBy: Collection<Field<*>>? = null,
conn: Connection
) =
conn.customList<TDoc>(
Find.byJsonPath(tableName) + (orderBy?.let(::orderBy) ?: ""),
listOf(Parameter(":path", ParameterType.STRING, path)),
Results::fromData
)
/**
* Retrieve documents using a JSON Path match query, ordering results by the 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 <reified TDoc> byJsonPath(tableName: String, path: String, orderBy: Collection<Field<*>>? = null) =
Configuration.dbConn().use { byJsonPath<TDoc>(tableName, path, orderBy, it) }
/**
* Retrieve documents using a JSON Path match query (PostgreSQL only)
*
* @param tableName The table from which documents should be retrieved
* @param path The JSON path comparison to match
* @param conn The connection over which documents should be retrieved
* @return A list of documents matching the JSON Path match query
* @throws DocumentException If called on a SQLite connection
*/
inline fun <reified TDoc> byJsonPath(tableName: String, path: String, conn: Connection) =
byJsonPath<TDoc>(tableName, path, null, 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)
* @param conn The connection over which documents should be retrieved
* @return The first document matching the field comparison, or `null` if no matches are found
*/
inline fun <reified TDoc> firstByFields(
tableName: String,
fields: Collection<Field<*>>,
howMatched: FieldMatch? = null,
orderBy: Collection<Field<*>>? = null,
conn: Connection
): TDoc? {
val named = Parameters.nameFields(fields)
return conn.customSingle<TDoc>(
Find.byFields(tableName, named, howMatched) + (orderBy?.let(::orderBy) ?: ""),
Parameters.addFields(named),
Results::fromData
)
}
/**
* 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 <reified TDoc> firstByFields(
tableName: String,
fields: Collection<Field<*>>,
howMatched: FieldMatch? = null,
orderBy: Collection<Field<*>>? = null
) =
Configuration.dbConn().use { firstByFields<TDoc>(tableName, fields, howMatched, orderBy, it) }
/**
* Retrieve the first document using a field comparison
*
* @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 conn The connection over which documents should be retrieved
* @return The first document matching the field comparison, or `null` if no matches are found
*/
inline fun <reified TDoc> firstByFields(
tableName: String,
fields: Collection<Field<*>>,
howMatched: FieldMatch? = null,
conn: Connection
) =
firstByFields<TDoc>(tableName, fields, howMatched, null, 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)
* @param conn The connection over which documents should be retrieved
* @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 <reified TDoc, reified TContains> firstByContains(
tableName: String,
criteria: TContains,
orderBy: Collection<Field<*>>? = null,
conn: Connection
) =
conn.customSingle<TDoc>(
Find.byContains(tableName) + (orderBy?.let(::orderBy) ?: ""),
listOf(Parameters.json(":criteria", criteria)),
Results::fromData
)
/**
* Retrieve the first document using a JSON containment query (PostgreSQL only)
*
* @param tableName The table from which documents should be retrieved
* @param criteria The object for which JSON containment should be checked
* @param conn The connection over which documents should be retrieved
* @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 <reified TDoc, reified TContains> firstByContains(tableName: String, criteria: TContains, conn: Connection) =
firstByContains<TDoc, TContains>(tableName, criteria, null, 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 `null` if no matches are found
* @throws DocumentException If called on a SQLite connection
*/
inline fun <reified TDoc, reified TContains> firstByContains(tableName: String, criteria: TContains, orderBy: Collection<Field<*>>? = null) =
Configuration.dbConn().use { firstByContains<TDoc, TContains>(tableName, criteria, orderBy, it) }
/**
* 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)
* @param conn The connection over which documents should be retrieved
* @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 <reified TDoc> firstByJsonPath(
tableName: String,
path: String,
orderBy: Collection<Field<*>>? = null,
conn: Connection
) =
conn.customSingle<TDoc>(
Find.byJsonPath(tableName) + (orderBy?.let(::orderBy) ?: ""),
listOf(Parameter(":path", ParameterType.STRING, path)),
Results::fromData
)
/**
* Retrieve the first document using a JSON Path match query (PostgreSQL only)
*
* @param tableName The table from which documents should be retrieved
* @param path The JSON path comparison to match
* @param conn The connection over which documents should be retrieved
* @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 <reified TDoc> firstByJsonPath(tableName: String, path: String, conn: Connection) =
firstByJsonPath<TDoc>(tableName, path, null, 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 `null` if no matches are found
* @throws DocumentException If called on a SQLite connection
*/
inline fun <reified TDoc> firstByJsonPath(tableName: String, path: String, orderBy: Collection<Field<*>>? = null) =
Configuration.dbConn().use { firstByJsonPath<TDoc>(tableName, path, orderBy, it) }
}