From 6c48d4dd1ebf39ab7fd5f5d7d7e3b7ad9ab741af Mon Sep 17 00:00:00 2001 From: "Dr. Patrick Urbanke" Date: Sun, 11 May 2025 05:24:17 +0200 Subject: [PATCH] Added documentation for update --- docs/README.md | 1 + docs/update.md | 143 +++++++++++++++++++++++++++++++++++ tests/sqlite/test_update.cpp | 2 - 3 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 docs/update.md diff --git a/docs/README.md b/docs/README.md index 2c983a7..fb28da5 100644 --- a/docs/README.md +++ b/docs/README.md @@ -13,6 +13,7 @@ Welcome to the sqlgen documentation. This guide provides detailed information ab - [sqlgen::read](reading.md) - How to read data from a database - [sqlgen::write](writing.md) - How to write data to a database +- [sqlgen::update](update.md) - How to update data in a table - [sqlgen::delete_from](delete_from.md) - How to delete data from a table - [sqlgen::drop](drop.md) - How to drop a table diff --git a/docs/update.md b/docs/update.md new file mode 100644 index 0000000..d8f4908 --- /dev/null +++ b/docs/update.md @@ -0,0 +1,143 @@ +# `sqlgen::update` + +The `sqlgen::update` interface provides a type-safe way to update records in a SQL database. It supports composable query building with `where` clauses to specify which records should be updated, and allows setting multiple columns to either literal values or other column values. + +## Usage + +### Basic Update + +Update specific columns in a table: + +```cpp +const auto conn = sqlgen::sqlite::connect("database.db"); + +using namespace sqlgen; + +const auto query = update("age"_c.set(100), "first_name"_c.set("New Name")); + +query(conn).value(); +``` + +This generates the following SQL: + +```sql +UPDATE "Person" +SET "age" = 100, "first_name" = 'New Name'; +``` + +Note that `conn` is actually a connection wrapped into an `sqlgen::Result<...>`. +This means you can use monadic error handling and fit this into a single line: + +```cpp +// sqlgen::Result +const auto result = sqlgen::sqlite::connect("database.db").and_then( + update("age"_c.set(100), "first_name"_c.set("New Name"))); +``` + +Please refer to the documentation on `sqlgen::Result<...>` for more information on error handling. + +### With `where` clause + +Update specific records using a `where` clause: + +```cpp +using namespace sqlgen; + +const auto query = update("age"_c.set(100)) | + where("first_name"_c == "Hugo"); + +query(conn).value(); +``` + +This generates the following SQL: + +```sql +UPDATE "Person" +SET "age" = 100 +WHERE "first_name" = 'Hugo'; +``` + +Note that `"..."_c` refers to the name of the column. If such a field does not +exist on the struct `Person`, the code will fail to compile. + +You can also use monadic error handling here: + +```cpp +using namespace sqlgen; + +const auto query = update("age"_c.set(100)) | + where("first_name"_c == "Hugo"); + +// sqlgen::Result +const auto result = sqlite::connect("database.db").and_then(query); +``` + +### Setting Columns to Other Column Values + +You can set a column's value to another column's value: + +```cpp +using namespace sqlgen; + +const auto query = update("first_name"_c.set("last_name"_c)) | + where("age"_c > 18); + +query(conn).value(); +``` + +This generates the following SQL: + +```sql +UPDATE "Person" +SET "first_name" = "last_name" +WHERE "age" > 18; +``` + +## Example: Full Query Composition + +```cpp +using namespace sqlgen; + +const auto query = update( + "first_name"_c.set("last_name"_c), + "age"_c.set(100)) | + where("age"_c > 0); + +const auto result = query(conn); + +if (!result) { + // Error handling +} +``` + +This generates the following SQL: + +```sql +UPDATE "Person" +SET + "first_name" = "last_name", + "age" = 100 +WHERE "age" > 0; +``` + +It is strongly recommended that you use `using namespace sqlgen`. However, +if you do not want to do that, you can rewrite the example above as follows: + +```cpp +const auto query = sqlgen::update( + sqlgen::col<"first_name">.set(sqlgen::col<"last_name">), + sqlgen::col<"age">.set(100)) | + sqlgen::where(sqlgen::col<"age"> > 0); + +const auto result = query(conn); +``` + +## Notes + +- You must specify at least one column to update +- The `where` clause is optional - if omitted, all records will be updated +- The `Result` type provides error handling; use `.value()` to extract the result (will throw an exception if there's an error) or handle errors as needed or refer to the documentation on `sqlgen::Result<...>` for other forms of error handling +- `"..."_c` refers to the name of the column +- You can set columns to either literal values or other column values +- The update operation is atomic - either all specified columns are updated or none are + diff --git a/tests/sqlite/test_update.cpp b/tests/sqlite/test_update.cpp index b41e360..2cfed3d 100644 --- a/tests/sqlite/test_update.cpp +++ b/tests/sqlite/test_update.cpp @@ -40,8 +40,6 @@ TEST(sqlite, test_update) { const auto people2 = sqlgen::read>(conn).value(); - std::cout << rfl::json::write(people2) << std::endl; - const std::string expected = R"([{"id":0,"first_name":"Homer","last_name":"Simpson","age":45},{"id":1,"first_name":"Bart","last_name":"Simpson","age":10},{"id":2,"first_name":"Lisa","last_name":"Simpson","age":8},{"id":3,"first_name":"Maggie","last_name":"Simpson","age":0},{"id":4,"first_name":"Simpson","last_name":"Simpson","age":100}])";