zrm/docs/docs/insert-update.md

147 lines
5.1 KiB
Markdown

# Insert & update
To define and use inserts and updates, you must have a fully defined [repository](/docs/repositories). In this tutorial, we'll be assuming that we have a defined repository for a user model, as it's defined in [this section](/docs/repositories.html#define-a-repository).
Executing inserts and updates also require to [set up a connection to your database](/docs/database). We'll also be assuming that we have a working database connector set up, as it's defined in [this section](/docs/database#pool-connector).
## Insert
Just like queries, we can insert models using the type `Insert` published on repositories. With this type, the inserted shape is the default one of the repository. You can customize this structure by using `InsertCustom` function.
```zig
const insertQuery = UserRepository.Insert.init(allocator, poolConnector.connector());
// or
const insertQuery = UserRepository.InsertCustom(struct {
id: i32,
name: []const u8,
}).init(allocator, poolConnector.connector());
```
If you just need to insert a model without any other parameters, repositories provide a `create` function which do just that. The given model **will be altered** with inserted row data.
```zig
const results = UserRepository.create(allocator, poolConnector.connector(), model);
defer results.deinit();
```
### Values
With an insert query, we can pass our values to insert with the `values` function. This looks like [`set` function of update queries](#values-1).
```zig
// Insert a single model.
try insertQuery.values(model);
// Insert an array of models.
try insertQuery.values(&[_]Model{firstModel, secondModel});
// Insert a table-shaped structure.
try insertQuery.values(table);
// Insert an array of table-shaped structures.
try insertQuery.values(&[_]Model.Table{firstTable, secondTable});
// Insert a structure matching InsertShape.
try insertQuery.values(insertShapeStructure);
// Insert an array of structures matching InsertShape.
try insertQuery.values(&[_]Model.Table.Insert{firstInsertShape, secondInsertShape});
```
### Returning
It's often useful to retrieve inserted data after the query. One use case would for example to get the inserted auto-increment IDs of the models. We can do this using the `returningX` functions of the insert query builder.
::: danger
Never put user-sent values as selected columns. This could lead to severe security issues (like [SQL injections](https://en.wikipedia.org/wiki/SQL_injection)).
:::
#### Returning all
This will return all the columns of the inserted rows.
```zig
try insertQuery.values(...);
insertQuery.returningAll();
```
#### Returning columns
This will return all the provided columns of the inserted rows.
```zig
try insertQuery.values(...);
insertQuery.returningColumns(&[_][]const u8{"id", "name"});
```
#### Raw returning
We can also directly provide raw `RETURNING` clause content.
```zig
try insertQuery.values(...);
insertQuery.returning("id, label AS name");
```
### Results
We can perform the insertion by running `insert` on the insert query.
```zig
const results = try insertQuery.insert(allocator);
defer results.deinit();
```
The results of an insert query are the same as normal queries. You can find the documentation about it in [its dedicated section](/docs/queries#results).
## Update
To make an update query, we must provide the structure of the updated columns (called update shape).
```zig
const updateQuery = UserRepository.Update(struct { name: []const u8 }).init(allocator, poolConnector.connector());
```
If you just need to update a model without any other parameters, repositories provide a `save` function which do just that. The given model **will be altered** with updated row data.
```zig
const results = UserRepository.save(allocator, poolConnector.connector(), model);
defer results.deinit();
```
### Values
With an update query, we can set our updated values with the `set` function. This looks like [`values` function of insert queries](#values).
```zig
// Set data of a single model.
try updateQuery.set(model);
// Set data of an array of models.
try updateQuery.values(&[_]Model{firstModel, secondModel});
// Set data of a table-shaped structure.
try updateQuery.values(table);
// Set data of an array of table-shaped structures.
try updateQuery.values(&[_]Model.Table{firstTable, secondTable});
// Set data of a structure matching UpdateShape.
try updateQuery.values(myUpdate);
// Set data of an array of structures matching UpdateShape.
try updateQuery.values(&[_]UpdateStruct{myFirstUpdate, mySecondUpdate});
```
### Conditions
The conditions building API is the same as normal queries. You can find the documentation about it in [its dedicated section](/docs/queries#conditions).
### Returning
The returning columns API is the same as insert queries. You can find the documentation about it in [its dedicated section](#returning).
### Results
We can perform the update by running `update` on the update query.
```zig
const results = try updateQuery.update(allocator);
defer results.deinit();
```
The results of an update query are the same as normal queries. You can find the documentation about it in [its dedicated section](/docs/queries#results).