unreql/cmd/groups/tables.rs
1use unreql_macros::create_cmd;
2use ql2::term::TermType;
3use serde::Serialize;
4
5use crate::{
6 cmd::{
7 args::{Arg, ManyArgs, Opt},
8 options,
9 },
10 Command,
11};
12
13create_cmd!(
14 /// List all table names in a database. The result is a list of strings.
15 ///
16 /// ## Example
17 /// List all tables of the ‘test’ database.
18 ///
19 /// ```
20 /// # unreql::example(|r, conn| {
21 /// r.db("test").table_list().run(conn)
22 /// # })
23 /// ```
24 ///
25 /// # Related commands
26 /// - [table_create](Self::table_create)
27 /// - [table_drop](Self::table_drop)
28 table_list,
29);
30
31create_cmd!(
32 /// Create a table. A RethinkDB table is a collection of JSON documents.
33 ///
34 /// If successful, the command returns an object with two fields:
35 ///
36 /// - `tables_created`: always `1`.
37 /// - `config_changes`: a list containing one two-field object, `old_val` and `new_val`:
38 /// - `old_val`: always `null`.
39 /// - `new_val`: the table’s new [config](Command::config) value.
40 ///
41 /// If a table with the same name already exists, the command throws ReqlOpFailedError.
42 ///
43 /// *Note*: Only alphanumeric characters and underscores are valid for the table name.
44 ///
45 /// Invoking tableCreate without specifying a database using db creates a table in the database specified in connect, or test if no database was specified.
46 ///
47 ///When creating a table you can specify the following options:
48 ///
49 /// - `primaryKey`: the name of the primary key. The default primary key is `id`.
50 /// - `durability`: if set to `soft`, writes will be acknowledged by the server immediately and flushed to disk in the background. The default is `hard`: acknowledgment of writes happens after data has been written to disk.
51 /// - `shards`: the number of shards, an integer from 1-64. Defaults to `1`.
52 /// - `replicas`: either an integer or a mapping object. Defaults to `1`.
53 /// - If `replicas` is an integer, it specifies the number of replicas per shard. Specifying more replicas than there are servers will return an error.
54 /// - If `replicas` is an object, it specifies key-value pairs of server tags and the number of replicas to assign to those servers: `{tag1: 2, tag2: 4, tag3: 2, ...}`.
55 /// - `primaryReplicaTag`: the primary server specified by its server tag. Required if replicas is an object; the tag must be in the object. This must not be specified if replicas is an integer.
56 ///
57 /// The [data type](https://rethinkdb.com/docs/data-types/) of a primary key is usually a string
58 /// (like a UUID) or a number, but it can also be a time, binary object, boolean or an array.
59 /// Data types can be mixed in the primary key field, but all values must be unique.
60 /// Using an array as a primary key causes the primary key to behave like a compound index;
61 /// read the documentation on [compound secondary indexes](https://rethinkdb.com/docs/secondary-indexes/javascript/#compound-indexes) for more information,
62 /// as it applies to primary keys as well. (Note that the primary index still only covers a single field,
63 /// while compound secondary indexes can cover multiple fields in a single index.) Primary keys cannot be objects.
64 ///
65 /// ## Example
66 /// Create a table named 'dc_universe' with the default settings.
67 ///
68 /// ```
69 /// # unreql::example(|r, conn| {
70 /// r.db("heroes").table_create("dc_universe").run(conn)
71 /// # })
72 /// ```
73 ///
74 /// ## Example
75 /// Create a table named 'dc_universe' using the field 'name' as primary key.
76 ///
77 /// ```
78 /// # use unreql::cmd::options::TableCreateOptions;
79 /// # unreql::example(|r, conn| {
80 /// let opts = TableCreateOptions::new().primary_key("name");
81 /// r.db("test").table_create(r.with_opt("dc_universe", opts)).run(conn)
82 /// # })
83 /// ```
84 ///
85 /// ## Example
86 /// Create a table set up for two shards and three replicas per shard. This requires three available servers.
87 ///
88 /// ```
89 /// # use unreql::cmd::options::{TableCreateOptions, Replicas};
90 /// # unreql::example(|r, conn| {
91 /// let opts = TableCreateOptions::new()
92 /// .primary_key("name")
93 /// .replicas(Replicas::Int(3));
94 /// r.db("test").table_create(r.with_opt("dc_universe", opts)).run(conn)
95 /// # })
96 /// ```
97 ///
98 /// Read [Sharding and replication](https://rethinkdb.com/docs/sharding-and-replication/) for a complete discussion of the subject, including advanced topics.
99 ///
100 /// # Related commands
101 /// - [table_list](Self::table_list)
102 /// - [table_drop](Self::table_drop)
103 table_create(table_name:Arg<options::TableCreateOptions>)
104);
105
106create_cmd!(
107 /// Drop a table from a database. The table and all its data will be deleted.
108 ///
109 /// If successful, the command returns an object with two fields:
110 ///
111 /// - `tables_dropped`: always `1`.
112 /// - `config_changes`: a list containing one two-field object, `old_val` and `new_val`:
113 /// - `old_val`: the dropped table’s [config](Command::config) value.
114 /// - `new_val`: always `null`.
115 ///
116 /// If the given table does not exist in the database, the command throws ReqlRuntimeError.
117 ///
118 /// ## Example
119 /// Drop a table named 'dc_universe'.
120 ///
121 /// ```
122 /// # unreql::example(|r, conn| {
123 /// r.db("test").table_drop("dc_universe").run(conn)
124 /// # })
125 /// ```
126 ///
127 /// # Related commands
128 /// - [table_create](Self::table_create)
129 /// - [table_list](Self::table_list)
130 table_drop(table_name: Serialize)
131);
132
133create_cmd!(
134 /// List all the secondary indexes of this table.
135 ///
136 /// ## Example
137 /// List the available secondary indexes for this table.
138 ///
139 /// ```
140 /// # unreql::example(|r, conn| {
141 /// r.table("marvel").index_list().run(conn)
142 /// # })
143 /// ```
144 ///
145 /// # Related commands
146 /// - [index_create](Self::index_create)
147 /// - [index_drop](Self::index_drop)
148 only_command,
149 index_list,
150);
151
152create_cmd!(
153 /// Create a new secondary index on a table.
154 ///
155 /// Secondary indexes improve the speed of many read queries at the slight cost of increased storage space
156 /// and decreased write performance. For more information about secondary indexes,
157 /// read the article "[Using secondary indexes in RethinkDB](https://rethinkdb.com/docs/secondary-indexes/javascript/)."
158 ///
159 /// RethinkDB supports different types of secondary indexes:
160 ///
161 /// - *Simple indexes* based on the value of a single field.
162 /// - *Compound indexes* based on multiple fields.
163 /// - *Multi indexes* based on arrays of values, created when the multi optional argument is true.
164 /// - *Geospatial indexes* based on indexes of geometry objects, created when the geo optional argument is true.
165 /// - Indexes based on *arbitrary expressions*.
166 ///
167 /// The `indexFunction` can be an anonymous function or a binary representation
168 /// obtained from the function field of [`index_status`](Command::index_status).
169 /// The function must be deterministic, and so cannot use a subquery or the r.js command.
170 ///
171 /// If successful, `create_index` will return an object of the form `{"created": 1}`.
172 /// If an index by that name already exists on the table, a `ReqlRuntimeError` will be thrown.
173 ///
174 /// *Note* that an index may not be immediately available after creation.
175 /// If your application needs to use indexes immediately after creation,
176 /// use the [`index_wait`](Command::index_wait) command to ensure the indexes are ready before use.
177 ///
178 /// ## Example
179 /// Create a simple index based on the field `postId`.
180 ///
181 /// ```
182 /// # unreql::example(|r, conn| {
183 /// r.table("comments").index_create("postId").run(conn)
184 /// # })
185 /// ```
186 ///
187 /// ## Example
188 /// Create a geospatial index based on the field `location`.
189 ///
190 /// ```
191 /// # use unreql::cmd::options::IndexCreateOptions;
192 /// # unreql::example(|r, conn| {
193 /// let opts = IndexCreateOptions::new().geo(true);
194 /// r.table("comments").index_create(r.with_opt("location", opts)).run(conn)
195 /// # })
196 /// ```
197 ///
198 /// A geospatial index field should contain only geometry objects.
199 /// It will work with geometry ReQL terms ([get_intersecting](Command::get_intersecting) and [get_nearest](Command::get_nearest))
200 /// as well as index-specific terms ([index_status](Command::index_status), [index_wait](Command::index_wait), [index_drop](Command::index_drop) and [index_list](Command::index_list)).
201 /// Using terms that rely on non-geometric ordering such as getAll, orderBy and between will result in an error.
202 ///
203 /// ## Example
204 /// Create a simple index based on the nested field `author > name`.
205 ///
206 /// ```
207 /// # unreql::example(|r, conn| {
208 /// r.table("comments")
209 /// .index_create(r.args(("authorName", r.row().g("author").g("name"))))
210 /// .run(conn)
211 /// # })
212 /// ```
213 ///
214 /// ## Example
215 /// Create a compound index based on the fields `postId` and `date`.
216 ///
217 /// ```
218 /// # unreql::example(|r, conn| {
219 /// r.table("comments")
220 /// .index_create(r.args(("postAndDate", [r.row().g("postId"), r.row().g("date")])))
221 /// .run(conn)
222 /// # })
223 /// ```
224 ///
225 /// ## Example
226 /// Create a multi index based on the field `authors`.
227 ///
228 /// ```
229 /// # use unreql::cmd::options::IndexCreateOptions;
230 /// # unreql::example(|r, conn| {
231 /// let opts = IndexCreateOptions::new().multi(true);
232 /// r.table("posts").index_create(r.with_opt("authors", opts)).run(conn)
233 /// # })
234 /// ```
235 ///
236 /// ## Example
237 /// Create a geospatial multi index based on the field towers.
238 ///
239 /// ```
240 /// # use unreql::cmd::options::IndexCreateOptions;
241 /// # unreql::example(|r, conn| {
242 /// let opts = IndexCreateOptions::new()
243 /// .multi(true)
244 /// .geo(true);
245 /// r.table("networks").index_create(r.with_opt("towers", opts)).run(conn)
246 /// # })
247 /// ```
248 ///
249 /// ## Example
250 /// Create an index based on an arbitrary expression.
251 ///
252 /// ```
253 /// # use unreql::func;
254 /// # unreql::example(|r, conn| {
255 /// r.table("posts")
256 /// .index_create(r.args(("authors", func!(|doc| {
257 /// r.branch(
258 /// doc.clone().has_fields("updatedAt"),
259 /// doc.clone().g("updatedAt"),
260 /// doc.g("createdAt"),
261 /// )
262 /// }))))
263 /// .run(conn)
264 /// # })
265 /// ```
266 ///
267 /// ## Example
268 /// Rebuild an outdated secondary index on a table.
269 ///
270 /// ```
271 /// # use unreql::{func, cmd::options::IndexRenameOptions};
272 /// # unreql::example(|r, conn| {
273 /// r.table("posts")
274 /// .index_status("oldIndex")
275 /// .nth(0)
276 /// .do_(func!(|oldIndex| {
277 /// r.table("posts").index_create(r.args(("newIndex", oldIndex.g("function")))).do_(func!(|| {
278 /// r.table("posts").index_wait("newIndex").do_(func!(|| {
279 /// let opts = IndexRenameOptions::new().overwrite(true);
280 /// r.table("posts").index_rename("newIndex", "oldIndex", opts)
281 /// }))
282 /// }))
283 /// }))
284 /// .run(conn)
285 /// # })
286 /// ```
287 ///
288 /// # Related commands
289 /// - [index_wait](Self::index_wait)
290 /// - [index_status](Self::index_status)
291 /// - [index_list](Self::index_list)
292 /// - [index_drop](Self::index_drop)
293 only_command,
294 index_create(index: ManyArgs<options::IndexCreateOptions>)
295);
296
297create_cmd!(
298 /// Delete a previously created secondary index of this table.
299 ///
300 /// ## Example
301 /// Drop a secondary index named 'code_name'.
302 ///
303 /// ```
304 /// # unreql::example(|r, conn| {
305 /// r.table("dc").index_drop("code_name").run(conn)
306 /// # })
307 /// ```
308 ///
309 /// # Related commands
310 /// - [index_create](Self::index_create)
311 /// - [index_list](Self::index_list)
312 only_command,
313 index_drop(index_name: Serialize)
314);
315
316create_cmd!(
317 /// Rename an existing secondary index on a table.
318 ///
319 /// If the optional argument `overwrite` is specified as `true`,
320 /// a previously existing index with the new name will be deleted and the index will be renamed.
321 /// If `overwrite` is `false` (the default) an error will be raised if the new index name already exists.
322 ///
323 /// The return value on success will be an object of the format `{renamed: 1}`, or `{renamed: 0}` if the old and new names are the same.
324 ///
325 /// An error will be raised if the old index name does not exist, if the new index name
326 /// is already in use and `overwrite` is `false`, or if either the old or new index name are the same as the primary key field name.
327 ///
328 /// ## Example
329 /// Rename an index on the comments table.
330 ///
331 /// ```
332 /// # unreql::example(|r, conn| {
333 /// r.table("comments").index_rename("postId", "messageId", ()).run(conn)
334 /// # })
335 /// ```
336 ///
337 /// # Related commands
338 /// - [index_create](Self::index_create)
339 /// - [index_status](Self::index_status)
340 /// - [index_list](Self::index_list)
341 /// - [index_drop](Self::index_drop)
342 only_command,
343 index_rename(old_index_name: Serialize, new_index_name: Serialize, opt: Opt<options::IndexRenameOptions>)
344);
345
346create_cmd!(
347 /// Get the status of the specified indexes on this table, or the status of all indexes on this table if no indexes are specified.
348 ///
349 /// The result is an array where for each index, there will be an object like this one:
350 ///
351 /// ```text
352 /// {
353 /// index: <indexName>,
354 /// ready: true,
355 /// function: <binary>,
356 /// multi: <bool>,
357 /// geo: <bool>,
358 /// outdated: <bool>
359 /// }
360 /// ```
361 ///
362 /// or this one:
363 ///
364 /// ```text
365 /// {
366 /// index: <indexName>,
367 /// ready: false,
368 /// progress: <float>,
369 /// function: <binary>,
370 /// multi: <bool>,
371 /// geo: <bool>,
372 /// outdated: <bool>
373 /// }
374 /// ```
375 ///
376 /// The `multi` field will be `true` or `false` depending on whether this index was created as a multi index;
377 /// the `geo` field will be `true` or `false` depending on whether this index was created as a geospatial index.
378 /// See [index_create](Command::index_create) for details. The `outdated` field will be true if the index is outdated
379 /// in the current version of RethinkDB and needs to be rebuilt. The `progress` field is a float between `0` and `1`,
380 /// indicating how far along the server is in constructing indexes after the most recent change to the table
381 /// that would affect them. (`0` indicates no such indexes have been constructed; `1` indicates all of them have.)
382 ///
383 /// The `function` field is a binary object containing an opaque representation of the secondary index
384 /// (including the `multi` argument if specified). It can be passed as the second argument to `index_create`
385 /// to create a new index with the same function; see [index_create] for more information.
386 ///
387 /// ## Example
388 /// Get the status of all the indexes on test:
389 ///
390 /// ```
391 /// # unreql::example(|r, conn| {
392 /// r.table("test").index_status(()).run(conn)
393 /// # })
394 /// ```
395 ///
396 /// ## Example
397 /// Get the status of the timestamp index:
398 ///
399 /// ```
400 /// # unreql::example(|r, conn| {
401 /// r.table("test").index_status("timestamp").run(conn)
402 /// # })
403 /// ```
404 ///
405 /// # Related commands
406 /// - [index_wait](Self::index_wait)
407 only_command,
408 index_status(index: ManyArgs<()>)
409);
410
411create_cmd!(
412 /// Wait for the specified indexes on this table to be ready, or for all indexes on this table to be ready if no indexes are specified.
413 ///
414 /// The result is an array containing one object for each table index:
415 ///
416 /// ```text
417 /// {
418 /// index: <indexName>,
419 /// ready: true,
420 /// function: <binary>,
421 /// multi: <bool>,
422 /// geo: <bool>,
423 /// outdated: <bool>
424 /// }
425 /// ```
426 ///
427 /// See the indexStatus documentation for a description of the field values.
428 ///
429 /// ## Example
430 /// Wait for all indexes on the table test to be ready:
431 ///
432 /// ```
433 /// # unreql::example(|r, conn| {
434 /// r.table("test").index_wait(()).run(conn)
435 /// # })
436 /// ```
437 ///
438 /// ## Example
439 /// Wait for the index timestamp to be ready:
440 ///
441 /// ```
442 /// # unreql::example(|r, conn| {
443 /// r.table("test").index_wait("timestamp").run(conn)
444 /// # })
445 /// ```
446 ///
447 /// # Related commands
448 /// - [index_status](Self::index_status)
449 only_command,
450 index_wait(index: ManyArgs<()>)
451);