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);