diff --git a/module/ldbc-statement/src/main/scala/ldbc/statement/Delete.scala b/module/ldbc-statement/src/main/scala/ldbc/statement/Delete.scala index a7f12688e..6c99de7e4 100644 --- a/module/ldbc-statement/src/main/scala/ldbc/statement/Delete.scala +++ b/module/ldbc-statement/src/main/scala/ldbc/statement/Delete.scala @@ -49,3 +49,29 @@ case class Delete[A]( statement = statement ++ s" WHERE ${ expression.statement }", params = params ++ expression.parameter ) + + /** + * A method for setting the WHERE condition in a DELETE statement. + * + * {{{ + * TableQuery[City].delete.where(_.name === "Tokyo") + * }}} + * + * @param func + * Function to construct an expression using the columns that Table has. + */ + def whereOpt[B](opt: Option[B])(func: (A, B) => Expression): Where.C[A] = + opt match + case Some(value) => + val expression = func(table, value) + Where.C( + table = table, + statement = statement ++ s" WHERE ${ expression.statement }", + params = params ++ expression.parameter + ) + case None => Where.C( + table, + statement, + params, + isFirst = true + ) diff --git a/module/ldbc-statement/src/main/scala/ldbc/statement/Select.scala b/module/ldbc-statement/src/main/scala/ldbc/statement/Select.scala index 78b62f2fa..bcd2810e5 100644 --- a/module/ldbc-statement/src/main/scala/ldbc/statement/Select.scala +++ b/module/ldbc-statement/src/main/scala/ldbc/statement/Select.scala @@ -61,6 +61,37 @@ case class Select[A, B]( params = params ++ expression.parameter ) + /** + * A method for setting the WHERE condition in a SELECT statement. + * + * {{{ + * TableQuery[City] + * .select(_.name) + * .whereOpt(Some("Tokyo"))((city, value) => city.name === value) + * }}} + * + * @param func + * Function to construct an expression using the columns that Table has. + */ + def whereOpt[C](opt: Option[C])(func: (A, C) => Expression): Where.Q[A, B] = + opt match + case Some(value) => + val expression = func(table, value) + Where.Q[A, B]( + table = table, + columns = columns, + statement = statement ++ s" WHERE ${expression.statement}", + params = params ++ expression.parameter + ) + case None => + Where.Q[A, B]( + table = table, + columns = columns, + statement = statement, + params = params, + isFirst = true + ) + /** * A method for setting the GROUP BY condition in a SELECT statement. * diff --git a/module/ldbc-statement/src/main/scala/ldbc/statement/Update.scala b/module/ldbc-statement/src/main/scala/ldbc/statement/Update.scala index 4723c7098..cc228f5c1 100644 --- a/module/ldbc-statement/src/main/scala/ldbc/statement/Update.scala +++ b/module/ldbc-statement/src/main/scala/ldbc/statement/Update.scala @@ -71,6 +71,21 @@ sealed trait Update[A] extends Command: */ def where(func: A => Expression): Where.C[A] + /** + * A method for setting the WHERE condition in a Update statement. + * + * {{{ + * TableQuery[City] + * .update(...) + * .set(_.population, 13929286) + * .whereOpt(Some("Tokyo"))((city, value) => city.name === value) + * }}} + * + * @param func + * A function that takes a column and returns an expression. + */ + def whereOpt[B](opt: Option[B])(func: (A, B) => Expression): Where.C[A] + object Update: private[ldbc] case class Impl[A]( @@ -99,3 +114,20 @@ object Update: statement = statement ++ s" WHERE ${ expression.statement }", params = params ++ expression.parameter ) + + override def whereOpt[B](opt: Option[B])(func: (A, B) => Expression): Where.C[A] = + opt match + case Some(value) => + val expression = func(table, value) + Where.C[A]( + table = table, + statement = statement ++ s" WHERE ${ expression.statement }", + params = params ++ expression.parameter + ) + case None => + Where.C[A]( + table = table, + statement = statement, + params = params, + isFirst = true + ) diff --git a/module/ldbc-statement/src/main/scala/ldbc/statement/Where.scala b/module/ldbc-statement/src/main/scala/ldbc/statement/Where.scala index 1b1791989..ca69e52ea 100644 --- a/module/ldbc-statement/src/main/scala/ldbc/statement/Where.scala +++ b/module/ldbc-statement/src/main/scala/ldbc/statement/Where.scala @@ -50,6 +50,23 @@ sealed transparent trait Where[A]: */ def and(func: A => Expression): Self = union("AND", func(table)) + /** + * Function to set additional conditions on WHERE statement. + * + * {{{ + * TableQuery[City] + * .select(_.name) + * .where(_.population > 1000000) + * .andOpt(Some("Tokyo"))((city, value) => city.name == value) + * // SELECT name FROM city WHERE population > ? AND name = ? + * }}} + * + * @param func + * Function to construct an expression using the columns that Table has. + */ + def andOpt[B](opt: Option[B])(func: (A, B) => Expression): Self = + opt.fold(self)(value => union("AND", func(table, value))) + /** * Function to set additional conditions on WHERE statement. * @@ -85,6 +102,23 @@ sealed transparent trait Where[A]: */ def or(func: A => Expression): Self = union("OR", func(table)) + /** + * Function to set additional conditions on WHERE statement. + * + * {{{ + * TableQuery[City] + * .select(_.name) + * .where(_.population > 1000000) + * .orOpt(Some("Tokyo"))((city, value) => city.name == value) + * // SELECT name FROM city WHERE population > ? OR name = ? + * }}} + * + * @param func + * Function to construct an expression using the columns that Table has. + */ + def orOpt[B](opt: Option[B])(func: (A, B) => Expression): Self = + opt.fold(self)(value => union("OR", func(table, value))) + /** * Function to set additional conditions on WHERE statement. * @@ -127,6 +161,23 @@ sealed transparent trait Where[A]: */ def xor(func: A => Expression): Self = union("XOR", func(table)) + /** + * Function to set additional conditions on WHERE statement. + * + * {{{ + * TableQuery[City] + * .select(_.name) + * .where(_.population > 1000000) + * .xorOpt(Some("Tokyo"))((city, value) => city.name == value) + * // SELECT name FROM city WHERE population > ? XOR name = ? + * }}} + * + * @param func + * Function to construct an expression using the columns that Table has. + */ + def xorOpt[B](opt: Option[B])(func: (A, B) => Expression): Self = + opt.fold(self)(value => union("XOR", func(table, value))) + /** * Function to set additional conditions on WHERE statement. * @@ -167,6 +218,8 @@ object Where: * @param params * A list of Traits that generate values from Parameter, allowing PreparedStatement to be set to a value by index * only. + * @param isFirst + * If True, this condition is added first, so the specified join condition is ignored and a WHERE statement is started. * @tparam A * The type of Table. in the case of Join, it is a Tuple of type Table. * @tparam B @@ -176,7 +229,8 @@ object Where: table: A, columns: Column[B], statement: String, - params: List[Parameter.Dynamic] + params: List[Parameter.Dynamic], + isFirst: Boolean = false ) extends Where[A], Query[A, B], OrderBy.Provider[A, B], @@ -189,7 +243,9 @@ object Where: this.copy(statement = statement ++ sql.statement, params = params ++ sql.params) override private[ldbc] def union(label: String, expression: Expression): Q[A, B] = - this.copy(statement = statement ++ s" $label ${ expression.statement }", params = params ++ expression.parameter) + if isFirst then + this.copy(statement = statement ++ s" WHERE ${ expression.statement }", params = params ++ expression.parameter, isFirst = false) + else this.copy(statement = statement ++ s" $label ${ expression.statement }", params = params ++ expression.parameter) /** * A method for setting the GROUP BY condition in a SELECT statement. @@ -218,13 +274,16 @@ object Where: * @param params * A list of Traits that generate values from Parameter, allowing PreparedStatement to be set to a value by index * only. + * @param isFirst + * If True, this condition is added first, so the specified join condition is ignored and a WHERE statement is started. * @tparam A * The type of Table. in the case of Join, it is a Tuple of type Table. */ case class C[A]( table: A, statement: String, - params: List[Parameter.Dynamic] + params: List[Parameter.Dynamic], + isFirst: Boolean = false ) extends Where[A], Command, Limit.CommandProvider: @@ -236,4 +295,6 @@ object Where: this.copy(statement = statement ++ sql.statement, params = params ++ sql.params) override private[ldbc] def union(label: String, expression: Expression): C[A] = - this.copy(statement = statement ++ s" $label ${ expression.statement }", params = params ++ expression.parameter) + if isFirst then + this.copy(statement = statement ++ s" WHERE ${ expression.statement }", params = params ++ expression.parameter, isFirst = false) + else this.copy(statement = statement ++ s" $label ${ expression.statement }", params = params ++ expression.parameter)