From 62f62b7f5e7e2e52e7e3e042d2a0c4956266b6fe Mon Sep 17 00:00:00 2001 From: Pavel Salamon Date: Fri, 8 Dec 2023 13:52:22 +0100 Subject: [PATCH] docs for dbfunction and query --- .../main/scala/za/co/absa/fadb/DBEngine.scala | 8 +- .../scala/za/co/absa/fadb/DBFunction.scala | 138 +++++++++++------- .../co/absa/fadb/FunctionStatusWithData.scala | 6 + .../main/scala/za/co/absa/fadb/Query.scala | 22 ++- .../za/co/absa/fadb/doobie/DoobieEngine.scala | 6 +- .../za/co/absa/fadb/slick/SlickPgEngine.scala | 2 +- 6 files changed, 121 insertions(+), 61 deletions(-) diff --git a/core/src/main/scala/za/co/absa/fadb/DBEngine.scala b/core/src/main/scala/za/co/absa/fadb/DBEngine.scala index 0928d351..94348f5a 100644 --- a/core/src/main/scala/za/co/absa/fadb/DBEngine.scala +++ b/core/src/main/scala/za/co/absa/fadb/DBEngine.scala @@ -43,12 +43,12 @@ abstract class DBEngine[F[_]: Monad] { protected def run[R](query: QueryType[R]): F[Seq[R]] /** - * The actual query executioner of the queries of the engine + * The actual query executioner of the queries of the engine with status * @param query - the query to execute * @tparam R - return the of the query * @return - sequence of the results of database query */ - def fetchHeadWithStatus[R](query: QueryWithStatusType[R]): F[Either[StatusException, R]] + def runWithStatus[R](query: QueryWithStatusType[R]): F[Either[StatusException, R]] /** * Public method to execute when query is expected to return multiple results @@ -56,7 +56,9 @@ abstract class DBEngine[F[_]: Monad] { * @tparam R - return the of the query * @return - sequence of the results of database query */ - def fetchAll[R](query: QueryType[R]): F[Seq[R]] = run(query) + def fetchAll[R](query: QueryType[R]): F[Seq[R]] = { + run(query) + } /** * Public method to execute when query is expected to return exactly one row diff --git a/core/src/main/scala/za/co/absa/fadb/DBFunction.scala b/core/src/main/scala/za/co/absa/fadb/DBFunction.scala index 80a2c395..67e62dd4 100644 --- a/core/src/main/scala/za/co/absa/fadb/DBFunction.scala +++ b/core/src/main/scala/za/co/absa/fadb/DBFunction.scala @@ -23,14 +23,14 @@ import za.co.absa.fadb.status.handling.QueryStatusHandling import scala.language.higherKinds /** - * @param functionNameOverride - in case the class name would not match the database function name, this gives the - * possibility of override - * @param schema - the schema the function belongs into - * @param dBEngine - the database engine that is supposed to execute the function (presumably contains - * connection to the database - * @tparam I - the type covering the input fields of the database function - * @tparam R - the type covering the returned fields from the database function - * @tparam E - the type of the [[DBEngine]] engine + * `DBFunction` is an abstract class that represents a database function. + * @param functionNameOverride - Optional parameter to override the class name if it does not match the database function name. + * @param schema - The schema the function belongs to. + * @param dBEngine - The database engine that is supposed to execute the function (contains connection to the database). + * @tparam I - The type covering the input fields of the database function. + * @tparam R - The type covering the returned fields from the database function. + * @tparam E - The type of the [[DBEngine]] engine. + * @tparam F - The type of the context in which the database function is executed. */ abstract class DBFunction[I, R, E <: DBEngine[F], F[_]: Monad](functionNameOverride: Option[String] = None)(implicit override val schema: DBSchema, @@ -44,19 +44,47 @@ abstract class DBFunction[I, R, E <: DBEngine[F], F[_]: Monad](functionNameOverr def this(functionName: String)(implicit schema: DBSchema, dBEngine: E) = this(Some(functionName)) /** - * Function to create the DB function call specific to the provided [[DBEngine]]. Expected to be implemented by the - * DBEngine specific mix-in. - * @param values - the values to pass over to the database function - * @return - the SQL query in the format specific to the provided [[DBEngine]] + * Function to create the DB function call specific to the provided [[DBEngine]]. + * Expected to be implemented by the DBEngine specific mix-in. + * @param values - The values to pass over to the database function. + * @return - The SQL query in the format specific to the provided [[DBEngine]]. */ protected def query(values: I): dBEngine.QueryType[R] - /*these 3 functions has to be defined here and not in the ancestors, as there the query type is not compatible - path-dependent types*/ + /** + * Executes the database function and returns multiple results. + * @param values - The values to pass over to the database function. + * @return - A sequence of results from the database function. + */ protected def multipleResults(values: I): F[Seq[R]] = dBEngine.fetchAll(query(values)) + + /** + * Executes the database function and returns a single result. + * @param values - The values to pass over to the database function. + * @return - A single result from the database function. + */ protected def singleResult(values: I): F[R] = dBEngine.fetchHead(query(values)) + + /** + * Executes the database function and returns an optional result. + * @param values - The values to pass over to the database function. + * @return - An optional result from the database function. + */ protected def optionalResult(values: I): F[Option[R]] = dBEngine.fetchHeadOption(query(values)) } +/** + * `DBFunctionWithStatus` is an abstract class that represents a database function with a status. + * It extends the [[DBFunction]] class and adds handling for the status of the function invocation. + * @param functionNameOverride - Optional parameter to override the class name if it does not match the database function name. + * @param schema - The schema the function belongs to. + * @param dBEngine - The database engine that is supposed to execute the function (contains connection to the database). + * @param queryStatusHandling - The [[QueryStatusHandling]] instance that handles the status of the function invocation. + * @tparam I - The type covering the input fields of the database function. + * @tparam R - The type covering the returned fields from the database function. + * @tparam E - The type of the [[DBEngine]] engine. + * @tparam F - The type of the context in which the database function is executed. + */ abstract class DBFunctionWithStatus[I, R, E <: DBEngine[F], F[_]: Monad](functionNameOverride: Option[String] = None)( implicit override val schema: DBSchema, @@ -73,20 +101,24 @@ abstract class DBFunctionWithStatus[I, R, E <: DBEngine[F], F[_]: Monad](functio /** * Function to create the DB function call specific to the provided [[DBEngine]]. Expected to be implemented by the * DBEngine specific mix-in. - * @param values - the values to pass over to the database function - * @return - the SQL query in the format specific to the provided [[DBEngine]] + * @param values the values to pass over to the database function + * @return the SQL query in the format specific to the provided [[DBEngine]] */ protected def query(values: I): dBEngine.QueryWithStatusType[R] - def apply(values: I): F[Either[StatusException, R]] = dBEngine.fetchHeadWithStatus(query(values)) + /** + * Executes the database function and returns multiple results. + * @param values + * @return A sequence of results from the database function. + */ + def apply(values: I): F[Either[StatusException, R]] = dBEngine.runWithStatus(query(values)) val defaultStatusField = "status" val defaultStatusTextField = "statusText" /** - * A mix-in to add the status fields into the SELECT statement - * - * @return a sequence of fields to use in SELECT + * The fields to select from the database function call + * @return the fields to select from the database function call */ override def fieldsToSelect: Seq[String] = { Seq( @@ -95,23 +127,23 @@ abstract class DBFunctionWithStatus[I, R, E <: DBEngine[F], F[_]: Monad](functio ) ++ super.fieldsToSelect } - // implementation to be mixed in + // To be provided by an implementation of QueryStatusHandling override def checkStatus[A](statusWithData: FunctionStatusWithData[A]): Either[StatusException, A] } object DBFunction { - /** - * Represents a function returning a set (in DB sense) of rows - * @param functionNameOverride - in case the class name would not match the database function name, this gives the - * possibility of override - * @param schema - the schema the function belongs into - * @param dBEngine - the database engine that is supposed to execute the function (presumably contains - * connection to the database - * @tparam I - the type covering the input fields of the database function - * @tparam R - the type covering the returned fields from the database function - * @tparam E - the type of the [[DBEngine]] engine - */ +/** + * `DBMultipleResultFunction` is an abstract class that represents a database function returning multiple results. + * It extends the [[DBFunction]] class and overrides the apply method to return a sequence of results. + * @param functionNameOverride - Optional parameter to override the class name if it does not match the database function name. + * @param schema - The schema the function belongs to. + * @param dBEngine - The database engine that is supposed to execute the function (presumably contains connection to the database). + * @tparam I - The type covering the input fields of the database function. + * @tparam R - The type covering the returned fields from the database function. + * @tparam E - The type of the [[DBEngine]] engine. + * @tparam F - The type of the context in which the database function is executed. + */ abstract class DBMultipleResultFunction[I, R, E <: DBEngine[F], F[_]: Monad]( functionNameOverride: Option[String] = None )(implicit schema: DBSchema, dBEngine: E) @@ -132,17 +164,17 @@ object DBFunction { def apply(values: I): F[Seq[R]] = multipleResults(values) } - /** - * Represents a function returning exactly one record - * @param functionNameOverride - in case the class name would not match the database function name, this gives the - * possibility of override - * @param schema - the schema the function belongs into - * @param dBEngine - the database engine that is supposed to execute the function (presumably contains - * connection to the database - * @tparam I - the type covering the input fields of the database function - * @tparam R - the type covering the returned fields from the database function - * @tparam E - the type of the [[DBEngine]] engine - */ +/** + * `DBSingleResultFunction` is an abstract class that represents a database function returning a single result. + * It extends the [[DBFunction]] class and overrides the apply method to return a single result. + * @param functionNameOverride - Optional parameter to override the class name if it does not match the database function name. + * @param schema - The schema the function belongs to. + * @param dBEngine - The database engine that is supposed to execute the function (presumably contains connection to the database). + * @tparam I - The type covering the input fields of the database function. + * @tparam R - The type covering the returned fields from the database function. + * @tparam E - The type of the [[DBEngine]] engine. + * @tparam F - The type of the context in which the database function is executed. + */ abstract class DBSingleResultFunction[I, R, E <: DBEngine[F], F[_]: Monad]( functionNameOverride: Option[String] = None )(implicit schema: DBSchema, dBEngine: E) @@ -162,17 +194,17 @@ object DBFunction { def apply(values: I): F[R] = singleResult(values) } - /** - * Represents a function returning one optional record - * @param functionNameOverride - in case the class name would not match the database function name, this gives the - * possibility of override - * @param schema - the schema the function belongs into - * @param dBEngine - the database engine that is supposed to execute the function (presumably contains - * connection to the database - * @tparam I - the type covering the input fields of the database function - * @tparam R - the type covering the returned fields from the database function - * @tparam E - the type of the [[DBEngine]] engine - */ +/** + * `DBOptionalResultFunction` is an abstract class that represents a database function returning an optional result. + * It extends the [[DBFunction]] class and overrides the apply method to return an optional result. + * @param functionNameOverride - Optional parameter to override the class name if it does not match the database function name. + * @param schema - The schema the function belongs to. + * @param dBEngine - The database engine that is supposed to execute the function (presumably contains connection to the database). + * @tparam I - The type covering the input fields of the database function. + * @tparam R - The type covering the returned fields from the database function. + * @tparam E - The type of the [[DBEngine]] engine. + * @tparam F - The type of the context in which the database function is executed. + */ abstract class DBOptionalResultFunction[I, R, E <: DBEngine[F], F[_]: Monad]( functionNameOverride: Option[String] = None )(implicit schema: DBSchema, dBEngine: E) diff --git a/core/src/main/scala/za/co/absa/fadb/FunctionStatusWithData.scala b/core/src/main/scala/za/co/absa/fadb/FunctionStatusWithData.scala index db7f0533..f2000d62 100644 --- a/core/src/main/scala/za/co/absa/fadb/FunctionStatusWithData.scala +++ b/core/src/main/scala/za/co/absa/fadb/FunctionStatusWithData.scala @@ -2,4 +2,10 @@ package za.co.absa.fadb import za.co.absa.fadb.status.FunctionStatus +/** + * Represents a function status with data. + * @param functionStatus the function status + * @param data the data + * @tparam A the type of the data + */ case class FunctionStatusWithData[A](functionStatus: FunctionStatus, data: A) diff --git a/core/src/main/scala/za/co/absa/fadb/Query.scala b/core/src/main/scala/za/co/absa/fadb/Query.scala index 87dc1475..0bac83da 100644 --- a/core/src/main/scala/za/co/absa/fadb/Query.scala +++ b/core/src/main/scala/za/co/absa/fadb/Query.scala @@ -20,14 +20,34 @@ import za.co.absa.fadb.exceptions.StatusException /** * The basis for all query types of [[DBEngine]] implementations - * * @tparam R - the return type of the query */ trait Query[R] +/** + * The basis for all query types of [[DBEngine]] implementations with status + * @tparam R - the return type of the query + */ trait QueryWithStatus[A, B, R] { + /** + * Processes the status of the query and returns the status with data + * @param initialResult - the initial result of the query + * @return the status with data + */ def processStatus(initialResult: A): FunctionStatusWithData[B] + + /** + * Converts the status with data to either a status exception or the data + * @param statusWithData - the status with data + * @return either a status exception or the data + */ def toStatusExceptionOrData(statusWithData: FunctionStatusWithData[B]): Either[StatusException, R] + + /** + * Returns the result of the query or a status exception + * @param initialResult - the initial result of the query + * @return the result of the query or a status exception + */ def getResultOrException(initialResult: A): Either[StatusException, R] = toStatusExceptionOrData( processStatus(initialResult) ) diff --git a/doobie/src/main/scala/za/co/absa/fadb/doobie/DoobieEngine.scala b/doobie/src/main/scala/za/co/absa/fadb/doobie/DoobieEngine.scala index d2b315e3..27612fca 100644 --- a/doobie/src/main/scala/za/co/absa/fadb/doobie/DoobieEngine.scala +++ b/doobie/src/main/scala/za/co/absa/fadb/doobie/DoobieEngine.scala @@ -53,7 +53,7 @@ class DoobieEngine[F[_]: Async: Monad](val transactor: Transactor[F]) extends DB query.fragment.query[R].to[Seq].transact(transactor) } - private def executeQueryWithStatusHandling[R]( + private def executeQueryWithStatus[R]( query: QueryWithStatusType[R] )(implicit readStatusWithDataR: Read[StatusWithData[R]]): F[Either[StatusException, R]] = { query.fragment.query[StatusWithData[R]].unique.transact(transactor).map(query.getResultOrException) @@ -68,7 +68,7 @@ class DoobieEngine[F[_]: Async: Monad](val transactor: Transactor[F]) extends DB override def run[R](query: QueryType[R]): F[Seq[R]] = executeQuery(query)(query.readR) - override def fetchHeadWithStatus[R](query: QueryWithStatusType[R]): F[Either[StatusException, R]] = { - executeQueryWithStatusHandling(query)(query.readStatusWithDataR) + override def runWithStatus[R](query: QueryWithStatusType[R]): F[Either[StatusException, R]] = { + executeQueryWithStatus(query)(query.readStatusWithDataR) } } diff --git a/slick/src/main/scala/za/co/absa/fadb/slick/SlickPgEngine.scala b/slick/src/main/scala/za/co/absa/fadb/slick/SlickPgEngine.scala index 985952f1..80bdae97 100644 --- a/slick/src/main/scala/za/co/absa/fadb/slick/SlickPgEngine.scala +++ b/slick/src/main/scala/za/co/absa/fadb/slick/SlickPgEngine.scala @@ -51,7 +51,7 @@ class SlickPgEngine(val db: Database)(implicit val executor: ExecutionContext) e db.run(slickAction) } - override def fetchHeadWithStatus[R](query: QueryWithStatusType[R]): Future[Either[StatusException, R]] = { + override def runWithStatus[R](query: QueryWithStatusType[R]): Future[Either[StatusException, R]] = { val slickAction = query.sql.as[Either[StatusException, R]](query.getStatusExceptionOrData).head db.run(slickAction) }