diff options
| author | 2020-12-21 21:41:58 +0100 | |
|---|---|---|
| committer | 2020-12-21 21:44:18 +0100 | |
| commit | 5d24758af869360e296d53e161e5f81669ff082c (patch) | |
| tree | 55db43fc53cf9ec9808a57cff212fd0eee8f3c8d | |
| parent | Merge branch 'improve-readme' (diff) | |
| download | zig-sqlite-5d24758af869360e296d53e161e5f81669ff082c.tar.gz zig-sqlite-5d24758af869360e296d53e161e5f81669ff082c.tar.xz zig-sqlite-5d24758af869360e296d53e161e5f81669ff082c.zip | |
document the iterator
| -rw-r--r-- | README.md | 56 |
1 files changed, 55 insertions, 1 deletions
| @@ -114,7 +114,7 @@ for (rows) |row| { | |||
| 114 | } | 114 | } |
| 115 | ``` | 115 | ``` |
| 116 | 116 | ||
| 117 | The `all` method takes a type and an optional tuple. | 117 | The `all` method takes a type and an options tuple. |
| 118 | 118 | ||
| 119 | The type represents a "row", it can be: | 119 | The type represents a "row", it can be: |
| 120 | * a struct where each field maps to the corresponding column in the resultset (so field 0 must map to field 1 and so on). | 120 | * a struct where each field maps to the corresponding column in the resultset (so field 0 must map to field 1 and so on). |
| @@ -122,6 +122,9 @@ The type represents a "row", it can be: | |||
| 122 | 122 | ||
| 123 | Not all types are allowed, see the section "Bind parameters and resultset rows" for more information on the types mapping rules. | 123 | Not all types are allowed, see the section "Bind parameters and resultset rows" for more information on the types mapping rules. |
| 124 | 124 | ||
| 125 | The options tuple is used to pass additional state required for some queries, usually it will be an allocator. | ||
| 126 | Not all queries require an allocator, hence why it's not required for every call. | ||
| 127 | |||
| 125 | The `one` method on a statement works the same way except it returns the first row of the result set: | 128 | The `one` method on a statement works the same way except it returns the first row of the result set: |
| 126 | 129 | ||
| 127 | ```zig | 130 | ```zig |
| @@ -151,6 +154,57 @@ if (row) |age| { | |||
| 151 | } | 154 | } |
| 152 | ``` | 155 | ``` |
| 153 | 156 | ||
| 157 | ### Iterating | ||
| 158 | |||
| 159 | Another way to get the data returned by a query is to use the `sqlite.Iterator` type. | ||
| 160 | |||
| 161 | You can only get one by calling the `iterator` method on a statement: | ||
| 162 | |||
| 163 | ```zig | ||
| 164 | var stmt = try db.prepare("SELECT name FROM user WHERE age < ?"); | ||
| 165 | defer stmt.deinit(); | ||
| 166 | |||
| 167 | var iter = try stmt.iterator([]const u8, .{ | ||
| 168 | .age = 20, | ||
| 169 | }); | ||
| 170 | |||
| 171 | var names = std.ArrayList([]const u8).init(allocator); | ||
| 172 | while (true) { | ||
| 173 | const row = (try iter.next(.{ .allocator = allocator })) orelse break; | ||
| 174 | try rows.append(row); | ||
| 175 | } | ||
| 176 | ``` | ||
| 177 | |||
| 178 | The `iterator` method takes a type which is the same as with `all` or `one`: every row retrieved by calling `next` will have this type. | ||
| 179 | |||
| 180 | Using the iterator is straightforward: call `next` on it in a loop; it can either fail with an error or return an optional value: if that optional is null, iterating is done. | ||
| 181 | |||
| 182 | The `next` method takes an options tuple which serves the same function as the one in `all` or `one`. | ||
| 183 | |||
| 184 | The code example above uses the iterator but it's no different than just calling `all` used like this; the real benefit of the iterator is to be able to process each row | ||
| 185 | sequentially without needing to store all the resultset in memory at the same time. | ||
| 186 | |||
| 187 | Here's an example: | ||
| 188 | ```zig | ||
| 189 | var stmt = try db.prepare("SELECT name FROM user WHERE age < ?"); | ||
| 190 | defer stmt.deinit(); | ||
| 191 | |||
| 192 | var iter = try stmt.iterator([]const u8, .{ | ||
| 193 | .age = 20, | ||
| 194 | }); | ||
| 195 | |||
| 196 | while (true) { | ||
| 197 | var arena = std.heap.ArenaAllocator.init(allocator); | ||
| 198 | defer arena.deinit(); | ||
| 199 | |||
| 200 | const name = (try iter.next(.{ .allocator = &arena.allocator })) orelse break; | ||
| 201 | |||
| 202 | // do stuff with name here | ||
| 203 | } | ||
| 204 | ``` | ||
| 205 | |||
| 206 | Used like this the memory required for the row is only used for one iteration. You can imagine this is especially useful if your resultset contains millions of rows. | ||
| 207 | |||
| 154 | ### Bind parameters and resultset rows | 208 | ### Bind parameters and resultset rows |
| 155 | 209 | ||
| 156 | Since sqlite doesn't have many [types](https://www.sqlite.org/datatype3.html) only a small number of Zig types are allowed in binding parameters and in resultset mapping types. | 210 | Since sqlite doesn't have many [types](https://www.sqlite.org/datatype3.html) only a small number of Zig types are allowed in binding parameters and in resultset mapping types. |