diff --git a/docs/reference.md b/docs/reference.md index 6fdb8ee4..37f25361 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -4556,6 +4556,37 @@ Buyer.insert +---- + +with `insert.values` + +```scala +Buyer.insert + .values( + Buyer[Sc]( + id = 1, + name = "test buyer", + dateOfBirth = LocalDate.parse("2023-09-09") + ) + ) + .onConflictIgnore(_.id) +``` + + +* + ```sql + INSERT INTO buyer (id, name, date_of_birth) VALUES (?, ?, ?) ON CONFLICT (id) DO NOTHING + ``` + + + +* + ```scala + 0 + ``` + + + ### OnConflict.ignore.returningEmpty @@ -4588,6 +4619,40 @@ Buyer.insert +---- + +with `insert.values` + +```scala +Buyer.insert + .values( + Buyer[Sc]( + id = 1, + name = "test buyer", + dateOfBirth = LocalDate.parse("2023-09-09") + ) + ) + .onConflictIgnore(_.id) + .returning(_.name) +``` + + +* + ```sql + INSERT INTO buyer (id, name, date_of_birth) VALUES (?, ?, ?) + ON CONFLICT (id) DO NOTHING + RETURNING buyer.name AS res + ``` + + + +* + ```scala + Seq.empty[String] + ``` + + + ### OnConflict.ignore.returningOne @@ -4597,7 +4662,7 @@ Buyer.insert .columns( _.name := "test buyer", _.dateOfBirth := LocalDate.parse("2023-09-09"), - _.id := 4 // This should cause a primary key conflict + _.id := 4 ) .onConflictIgnore(_.id) .returning(_.name) @@ -4620,6 +4685,40 @@ Buyer.insert +---- + +with `insert.values` + +```scala +Buyer.insert + .values( + Buyer[Sc]( + id = 5, + name = "test buyer", + dateOfBirth = LocalDate.parse("2023-09-09") + ) + ) + .onConflictIgnore(_.id) + .returning(_.name) +``` + + +* + ```sql + INSERT INTO buyer (id, name, date_of_birth) VALUES (?, ?, ?) + ON CONFLICT (id) DO NOTHING + RETURNING buyer.name AS res + ``` + + + +* + ```scala + Seq("test buyer") + ``` + + + ### OnConflict.update ScalaSql's `.onConflictUpdate` translates into SQL's `ON CONFLICT DO UPDATE` @@ -4649,6 +4748,37 @@ Buyer.insert +---- + +with `insert.values` + +```scala +Buyer.insert + .values( + Buyer[Sc]( + id = 1, + name = "test buyer", + dateOfBirth = LocalDate.parse("2023-09-09") + ) + ) + .onConflictUpdate(_.id)(_.dateOfBirth := LocalDate.parse("2023-10-10")) +``` + + +* + ```sql + INSERT INTO buyer (id, name, date_of_birth) VALUES (?, ?, ?) ON CONFLICT (id) DO UPDATE SET date_of_birth = ? + ``` + + + +* + ```scala + 1 + ``` + + + ---- @@ -4663,7 +4793,7 @@ Buyer.select * ```scala Seq( - Buyer[Sc](1, "TEST BUYER CONFLICT", LocalDate.parse("2001-02-03")), + Buyer[Sc](1, "TEST BUYER CONFLICT", LocalDate.parse("2023-10-10")), Buyer[Sc](2, "叉烧包", LocalDate.parse("1923-11-12")), Buyer[Sc](3, "Li Haoyi", LocalDate.parse("1965-08-09")) ) @@ -4700,6 +4830,37 @@ Buyer.insert +---- + +with `insert.values` + +```scala +Buyer.insert + .values( + Buyer[Sc]( + id = 3, + name = "test buyer", + dateOfBirth = LocalDate.parse("2023-09-09") + ) + ) + .onConflictUpdate(_.id)(v => v.name := v.name.toUpperCase) +``` + + +* + ```sql + INSERT INTO buyer (id, name, date_of_birth) VALUES (?, ?, ?) ON CONFLICT (id) DO UPDATE SET name = UPPER(buyer.name) + ``` + + + +* + ```scala + 1 + ``` + + + ---- @@ -4716,7 +4877,7 @@ Buyer.select Seq( Buyer[Sc](1, "JAMES BOND", LocalDate.parse("2001-02-03")), Buyer[Sc](2, "叉烧包", LocalDate.parse("1923-11-12")), - Buyer[Sc](3, "Li Haoyi", LocalDate.parse("1965-08-09")) + Buyer[Sc](3, "LI HAOYI", LocalDate.parse("1965-08-09")) ) ``` @@ -4756,6 +4917,42 @@ Buyer.insert +---- + +with `insert.values` + +```scala +Buyer.insert + .values( + Buyer[Sc]( + id = 1, + name = "test buyer", + dateOfBirth = LocalDate.parse("2023-09-09") + ) + ) + .onConflictUpdate(_.id)(v => v.name := v.name.toLowerCase) + .returning(_.name) + .single +``` + + +* + ```sql + INSERT INTO buyer (id, name, date_of_birth) VALUES (?, ?, ?) + ON CONFLICT (id) DO UPDATE + SET name = LOWER(buyer.name) + RETURNING buyer.name AS res + ``` + + + +* + ```scala + "james bond" + ``` + + + ## Values Basic `VALUES` operations ### Values.basic diff --git a/scalasql/query/src/InsertValues.scala b/scalasql/query/src/InsertValues.scala index a2146527..686160fd 100644 --- a/scalasql/query/src/InsertValues.scala +++ b/scalasql/query/src/InsertValues.scala @@ -3,7 +3,9 @@ package scalasql.query import scalasql.core.{Context, DialectTypeMappers, Expr, Queryable, SqlStr, WithSqlExpr} import scalasql.core.SqlStr.SqlStringSyntax -trait InsertValues[V[_[_]], R] extends Returning.InsertBase[V[Expr]] with Query.ExecuteUpdate[Int] { +trait InsertValues[V[_[_]], R] + extends Returning.InsertBase[V[Column]] + with Query.ExecuteUpdate[Int] { def skipColumns(x: (V[Column] => Column[?])*): InsertValues[V, R] } object InsertValues { @@ -16,7 +18,7 @@ object InsertValues { ) extends InsertValues[V, R] { def table = insert.table - protected def expr = WithSqlExpr.get(insert).asInstanceOf[V[Expr]] + protected def expr: V[Column] = WithSqlExpr.get(insert) override protected def queryConstruct(args: Queryable.ResultSetIterator): Int = args.get(dialect.IntType) diff --git a/scalasql/src/dialects/OnConflictOps.scala b/scalasql/src/dialects/OnConflictOps.scala index 877771a0..6948b5c4 100644 --- a/scalasql/src/dialects/OnConflictOps.scala +++ b/scalasql/src/dialects/OnConflictOps.scala @@ -4,11 +4,16 @@ import scalasql.core.{Expr, WithSqlExpr} import scalasql.query._ trait OnConflictOps { - implicit def OnConflictableInsertValues[V[_[_]], R]( + implicit def OnConflictableInsertColumns[V[_[_]], R]( query: InsertColumns[V, R] ): OnConflict[V[Column], Int] = new OnConflict[V[Column], Int](query, WithSqlExpr.get(query), query.table) + implicit def OnConflictableInsertValues[V[_[_]], R]( + query: InsertValues[V, R] + ): OnConflict[V[Column], Int] = + new OnConflict[V[Column], Int](query, WithSqlExpr.get(query), query.table) + implicit def OnConflictableInsertSelect[V[_[_]], C, R, R2]( query: InsertSelect[V, C, R, R2] ): OnConflict[V[Expr], Int] = { diff --git a/scalasql/test/src/query/OnConflictTests.scala b/scalasql/test/src/query/OnConflictTests.scala index aa0e1e2b..32afe170 100644 --- a/scalasql/test/src/query/OnConflictTests.scala +++ b/scalasql/test/src/query/OnConflictTests.scala @@ -36,6 +36,24 @@ trait OnConflictTests extends ScalaSqlSuite { """ ) + checker( + query = Text { + Buyer.insert + .values( + Buyer[Sc]( + id = 1, + name = "test buyer", + dateOfBirth = LocalDate.parse("2023-09-09") + ) + ) + .onConflictIgnore(_.id) + }, + sql = + "INSERT INTO buyer (id, name, date_of_birth) VALUES (?, ?, ?) ON CONFLICT (id) DO NOTHING", + value = 0, + docs = "with `insert.values`" + ) + test("returningEmpty") - { checker( query = Text { @@ -55,6 +73,28 @@ trait OnConflictTests extends ScalaSqlSuite { """, value = Seq.empty[String] ) + + checker( + query = Text { + Buyer.insert + .values( + Buyer[Sc]( + id = 1, + name = "test buyer", + dateOfBirth = LocalDate.parse("2023-09-09") + ) + ) + .onConflictIgnore(_.id) + .returning(_.name) + }, + sql = """ + INSERT INTO buyer (id, name, date_of_birth) VALUES (?, ?, ?) + ON CONFLICT (id) DO NOTHING + RETURNING buyer.name AS res + """, + value = Seq.empty[String], + docs = "with `insert.values`" + ) } test("returningOne") - { @@ -64,7 +104,7 @@ trait OnConflictTests extends ScalaSqlSuite { .columns( _.name := "test buyer", _.dateOfBirth := LocalDate.parse("2023-09-09"), - _.id := 4 // This should cause a primary key conflict + _.id := 4 ) .onConflictIgnore(_.id) .returning(_.name) @@ -76,6 +116,28 @@ trait OnConflictTests extends ScalaSqlSuite { """, value = Seq("test buyer") ) + + checker( + query = Text { + Buyer.insert + .values( + Buyer[Sc]( + id = 5, + name = "test buyer", + dateOfBirth = LocalDate.parse("2023-09-09") + ) + ) + .onConflictIgnore(_.id) + .returning(_.name) + }, + sql = """ + INSERT INTO buyer (id, name, date_of_birth) VALUES (?, ?, ?) + ON CONFLICT (id) DO NOTHING + RETURNING buyer.name AS res + """, + value = Seq("test buyer"), + docs = "with `insert.values`" + ) } } @@ -99,10 +161,28 @@ trait OnConflictTests extends ScalaSqlSuite { """ ) + checker( + query = Text { + Buyer.insert + .values( + Buyer[Sc]( + id = 1, + name = "test buyer", + dateOfBirth = LocalDate.parse("2023-09-09") + ) + ) + .onConflictUpdate(_.id)(_.dateOfBirth := LocalDate.parse("2023-10-10")) + }, + sql = + "INSERT INTO buyer (id, name, date_of_birth) VALUES (?, ?, ?) ON CONFLICT (id) DO UPDATE SET date_of_birth = ?", + value = 1, + docs = "with `insert.values`" + ) + checker( query = Text { Buyer.select }, value = Seq( - Buyer[Sc](1, "TEST BUYER CONFLICT", LocalDate.parse("2001-02-03")), + Buyer[Sc](1, "TEST BUYER CONFLICT", LocalDate.parse("2023-10-10")), Buyer[Sc](2, "叉烧包", LocalDate.parse("1923-11-12")), Buyer[Sc](3, "Li Haoyi", LocalDate.parse("1965-08-09")) ), @@ -126,12 +206,30 @@ trait OnConflictTests extends ScalaSqlSuite { value = 1 ) + checker( + query = Text { + Buyer.insert + .values( + Buyer[Sc]( + id = 3, + name = "test buyer", + dateOfBirth = LocalDate.parse("2023-09-09") + ) + ) + .onConflictUpdate(_.id)(v => v.name := v.name.toUpperCase) + }, + sql = + "INSERT INTO buyer (id, name, date_of_birth) VALUES (?, ?, ?) ON CONFLICT (id) DO UPDATE SET name = UPPER(buyer.name)", + value = 1, + docs = "with `insert.values`" + ) + checker( query = Text { Buyer.select }, value = Seq( Buyer[Sc](1, "JAMES BOND", LocalDate.parse("2001-02-03")), Buyer[Sc](2, "叉烧包", LocalDate.parse("1923-11-12")), - Buyer[Sc](3, "Li Haoyi", LocalDate.parse("1965-08-09")) + Buyer[Sc](3, "LI HAOYI", LocalDate.parse("1965-08-09")) ), normalize = (x: Seq[Buyer[Sc]]) => x.sortBy(_.id) ) @@ -158,6 +256,30 @@ trait OnConflictTests extends ScalaSqlSuite { """, value = "JAMES BOND" ) + + checker( + query = Text { + Buyer.insert + .values( + Buyer[Sc]( + id = 1, + name = "test buyer", + dateOfBirth = LocalDate.parse("2023-09-09") + ) + ) + .onConflictUpdate(_.id)(v => v.name := v.name.toLowerCase) + .returning(_.name) + .single + }, + sql = """ + INSERT INTO buyer (id, name, date_of_birth) VALUES (?, ?, ?) + ON CONFLICT (id) DO UPDATE + SET name = LOWER(buyer.name) + RETURNING buyer.name AS res + """, + value = "james bond", + docs = "with `insert.values`" + ) } } }