From fc751cd01cef4aea0e760dd88d7b762825845be1 Mon Sep 17 00:00:00 2001
From: Yaroslav Dynnikov <yaroslav.dynnikov@gmail.com>
Date: Thu, 15 Jun 2023 15:52:34 +0300
Subject: [PATCH] doc: enhance lua help

---
 src/luamod.rs | 572 ++++++++++++++++++++++++++++++--------------------
 1 file changed, 339 insertions(+), 233 deletions(-)

diff --git a/src/luamod.rs b/src/luamod.rs
index d0a913b576..d584fc8ba0 100644
--- a/src/luamod.rs
+++ b/src/luamod.rs
@@ -94,11 +94,17 @@ pub(crate) fn setup(args: &args::Run) {
         pico.whoami()
         =============
 
-        Returns a table containing the following instance identifiers:
+        Returns the identifiers of the current instance.
 
-        - raft_id (number)
-        - cluster_id (string)
-        - instance_id (string)
+        Returns:
+
+            (table)
+
+        Fields:
+
+            - raft_id (number)
+            - cluster_id (string)
+            - instance_id (string)
 
         Example:
 
@@ -128,37 +134,49 @@ pub(crate) fn setup(args: &args::Run) {
         pico.instance_info([instance_id])
         =================================
 
-        Returns a table containing the following instance information:
-
-        - raft_id (number)
-        - advertised_address (string)
-        - instance_id (string)
-        - instance_uuid (string)
-        - replicaset_id (string)
-        - replicaset_uuid (string)
-        - current_grade (table)
-        - target_grade (table)
+        Provides general information for the given instance.
 
         Params:
 
-            1. instance_id - number
+            1. instance_id (optional string), default: id of the current instance
+
+        Returns:
+
+            (table)
+            or
+            (nil, string) in case of an error
+
+        Fields:
+
+            - raft_id (number)
+            - advertise_address (string)
+            - instance_id (string)
+            - instance_uuid (string)
+            - replicaset_id (string)
+            - replicaset_uuid (string)
+            - current_grade (table),
+                `{variant = string, incarnation = number}`, where variant is one of
+                'Offline' | 'Online' | 'Expelled'
+            - target_grade (table),
+                `{variant = string, incarnation = number}`, where variant is one of
+                'Offline' | 'Replicated' | 'ShardingInitialized' | 'Online' | 'Expelled'
 
         Example:
 
             picodata> pico.instance_info()
             ---
-            - target_grade:
-                variant: Online
-                incarnation: 26
+            - raft_id: 1
+              advertise_address: localhost:3301
               instance_id: i1
               instance_uuid: 68d4a766-4144-3248-aeb4-e212356716e4
-              raft_id: 1
+              replicaset_id: r1
+              replicaset_uuid: e0df68c5-e7f9-395f-86b3-30ad9e1b7b07
               current_grade:
                 variant: Online
                 incarnation: 26
-              replicaset_uuid: e0df68c5-e7f9-395f-86b3-30ad9e1b7b07
-              replicaset_id: r1
-              advertise_address: localhost:3301
+              target_grade:
+                variant: Online
+                incarnation: 26
             ...
         "},
         tlua::function1(|iid: Option<InstanceId>| -> traft::Result<_> {
@@ -184,6 +202,7 @@ pub(crate) fn setup(args: &args::Run) {
         }),
     );
 
+    ///////////////////////////////////////////////////////////////////////////
     luamod_set(
         &l,
         "raft_status",
@@ -191,7 +210,23 @@ pub(crate) fn setup(args: &args::Run) {
         pico.raft_status()
         ==================
 
-        Returns a table `RaftStatus`. See pico.help(\"RaftStatus\")
+        Returns the raft node status of the current instance.
+
+        Returns:
+
+            (table)
+            or
+            (nil) if the raft node is not initialized yet
+
+        Fields:
+
+            - id (number)
+            - term (number)
+            - leader_id (number | nil),
+                absent if there's no leader in the current term
+                or it's unknown yet
+            - raft_state (string),
+                one of 'Follower' | 'Candidate' | 'Leader' | 'PreCandidate'
 
         Example:
 
@@ -203,22 +238,7 @@ pub(crate) fn setup(args: &args::Run) {
               id: 1
             ...
         "},
-        tlua::function0(|| traft::node::global().map(|n| n.status())),
-    );
-    luamod_set_help_only(
-        &l,
-        "RaftStatus",
-        indoc! {"
-        RaftStatus (table)
-        ==================
-
-        Fields:
-
-            - id (number)
-            - leader_id (number)
-            - term (number)
-            - raft_state (string, one of 'Follower' | 'Candidate' | 'Leader' | 'PreCandidate')
-        "},
+        tlua::function0(|| traft::node::global().ok().map(|n| n.status())),
     );
 
     luamod_set(
@@ -226,38 +246,55 @@ pub(crate) fn setup(args: &args::Run) {
         "raft_tick",
         indoc! {"
         pico.raft_tick(n_times)
-        ======================
+        =======================
+
+        Internal API. Makes the raft node to 'tick' `n_times`. It shouldn't
+        be used except for tests and dirty hacks. See `src/luamod.rs` for
+        the details.
 
         Params:
 
-            1. timeout - number
+            1. timeout (number), in seconds
+
+        Returns:
+
+            (true)
+            or
+            (nil, string) in case of an error
+
         "},
-        tlua::function1(|n_times: u32| -> traft::Result<()> {
+        tlua::function1(|n_times: u32| -> traft::Result<bool> {
             traft::node::global()?.tick_and_yield(n_times);
-            Ok(())
+            Ok(true)
         }),
     );
 
+    // raft index
+    ///////////////////////////////////////////////////////////////////////////
+
     luamod_set(
         &l,
         "raft_get_index",
         indoc! {"
         pico.raft_get_index()
-        ======================
+        =====================
+
+        Returns the current applied raft index.
+
+        Returns:
 
-        Returns current applied raft index (number).
+            (number)
+            or
+            (nil) if the raft node is not initialized yet
         "},
-        tlua::function0(|| -> traft::Result<RaftIndex> {
-            let node = traft::node::global()?;
-            Ok(node.get_index())
-        }),
+        tlua::function0(|| traft::node::global().ok().map(|n| n.get_index())),
     );
     luamod_set(
         &l,
         "raft_read_index",
         indoc! {"
         pico.raft_read_index(timeout)
-        ============================
+        =============================
 
         Performs the quorum read operation.
 
@@ -265,20 +302,24 @@ pub(crate) fn setup(args: &args::Run) {
 
         1. The instance forwards a request (`MsgReadIndex`) to a raft
            leader. In case there's no leader at the moment, the function
-           returns `Err(ProposalDropped)`.
+           returns the error 'raft: proposal dropped'.
         2. Raft leader tracks its `commit_index` and broadcasts a
            heartbeat to followers to make certain that it's still a
            leader.
         3. As soon as the heartbeat is acknowlenged by the quorum, the
-           function returns that index.
+           leader returns that index to the instance.
         4. The instance awaits when the index is applied. If timeout
-           expires beforehand, the function returns an error.
-
-        Returns current applied raft index (number).
+           expires beforehand, the function returns the error 'timeout'.
 
         Params:
 
-            1. timeout - number
+            1. timeout (number), in seconds
+
+        Returns:
+
+            (number)
+            or
+            (nil, string) in case of an error
         "},
         tlua::function1(|timeout: f64| -> traft::Result<RaftIndex> {
             traft::node::global()?.read_index(Duration::from_secs_f64(timeout))
@@ -288,19 +329,25 @@ pub(crate) fn setup(args: &args::Run) {
         &l,
         "raft_wait_index",
         indoc! {"
-        pico.raft_wait_index(target_index, timeout)
-        ===========================================
+        pico.raft_wait_index(target, timeout)
+        =====================================
 
-        Waits for target_index to be applied to the storage locally.
+        Waits for the `target` index to be applied to the storage locally.
 
         Returns current applied raft index. It can be equal to or
-        greater than the target one. If timeout expires beforehand, the
-        function returns an error.
+        greater than the requested one. If timeout expires beforehand,
+        the function returns an error.
 
         Params:
 
-            1. target_vclock - table
-            2. timeout - number
+            1. target (number)
+            2. timeout (number), in seconds
+
+        Returns:
+
+            (number)
+            or
+            (nil, string) in case of an error
         "},
         tlua::function2(
             |target: RaftIndex, timeout: f64| -> traft::Result<RaftIndex> {
@@ -309,25 +356,15 @@ pub(crate) fn setup(args: &args::Run) {
             },
         ),
     );
-    luamod_set(
-        &l,
-        "get_vclock",
-        indoc! {"
-        pico.get_vclock()
-        ==================
 
-        Obtains current vclock from Tarantool `box.info.vclock` API.
-
-        Returns a Vclock (table). See pico.help(\"Vclock\")
-        "},
-        tlua::function0(Vclock::current),
-    );
+    // vclock
+    ///////////////////////////////////////////////////////////////////////////
     luamod_set_help_only(
         &l,
         "Vclock",
         indoc! {"
-        Vclock (table)
-        ==============
+        Vclock
+        ======
 
         Vclock is a mapping of replica id (number) to its LSN (number).
 
@@ -343,22 +380,62 @@ pub(crate) fn setup(args: &args::Run) {
         their records, each with it's own LSN. Together, LSNs from different
         replicas form a vector clock (vclock). Vclock defines the database
         state of an instance.
+
+        The zero vclock component is special, it's used for tracking local
+        changes that aren't replicated.
+
+        Example:
+
+            {[0] = 2, [1] = 101}
+            {[0] = 148, [1] = 9086, [3] = 2}
+        "},
+    );
+    luamod_set(
+        &l,
+        "get_vclock",
+        indoc! {"
+        pico.get_vclock()
+        =================
+
+        Returns the current vclock from Tarantool `box.info.vclock` API.
+
+        Returns:
+
+            (table Vclock), see pico.help('Vclock')
+
+        Example:
+
+            picodata> pico.get_vclock()
+            ---
+            - 0: 2
+              1: 101
+            ...
         "},
+        tlua::function0(Vclock::current),
     );
     luamod_set(
         &l,
         "wait_vclock",
         indoc! {"
-        pico.wait_vclock(target_vclock, timeout)
-        ========================================
+        pico.wait_vclock(target, timeout)
+        =================================
+
+        Waits until Tarantool vclock reaches the `target` value.
 
-        Wait until Tarantool vclock reaches the target_vclock. Returns the
-        actual vclock (table). It can be equal to or greater than the target one.
+        Returns the actual vclock. It can be equal to or greater than the
+        target one. If timeout expires beforehand, the function returns an
+        error.
 
         Params:
 
-            1. target_vclock - table. See pico.help(\"Vclock\")
+            1. target (table Vclock), see pico.help('Vclock')
             2. timeout - number
+
+        Returns:
+
+            (table Vclock), see pico.help('Vclock')
+            or
+            (nil, string) in case of an error
         "},
         tlua::function2(
             |target: Vclock, timeout: f64| -> Result<Vclock, sync::TimeoutError> {
@@ -366,6 +443,9 @@ pub(crate) fn setup(args: &args::Run) {
             },
         ),
     );
+
+    // propose
+    ///////////////////////////////////////////////////////////////////////////
     luamod_set(
         &l,
         "raft_propose_nop",
@@ -373,7 +453,8 @@ pub(crate) fn setup(args: &args::Run) {
         pico.raft_propose_nop()
         =======================
 
-        Proposes and waits for Op::Nop to be applied.
+        Internal API. Proposes and waits for Op::Nop to be applied.
+        It shouldn't be used except for tests.
         "},
         tlua::function0(|| {
             traft::node::global()?.propose_and_wait(Op::Nop, Duration::from_secs(1))
@@ -386,16 +467,20 @@ pub(crate) fn setup(args: &args::Run) {
         // TODO: Provide a more Lua friendly interface for `Op` and then document it
         // or maybe mark this function `internal`
         indoc! {"
-        pico.raft_propose(operation)
+        pico.raft_propose(op)
         ============================
 
-        Proposes operation to raft and returns its index (number).
-        Returned index should be supplied to `pico.wait_index`
-        manually if it's necessary.
+        Internal API, see src/luamod.rs for the details.
 
         Params:
 
-            1. operation - table. See pico.help(\"Op\")
+            1. op (table)
+
+        Returns:
+
+            (number)
+            or
+            (nil, string) in case of an error
         "},
         tlua::function1(|lua: tlua::LuaState| -> traft::Result<RaftIndex> {
             use tlua::{AnyLuaString, AsLua, LuaError, LuaTable};
@@ -415,33 +500,33 @@ pub(crate) fn setup(args: &args::Run) {
             Ok(index)
         }),
     );
-    luamod_set_help_only(
-        &l,
-        "Op",
-        indoc! {"
-        Op is an operation on the raft state machine.
 
-        See traft::op::Op in source code.
-        "},
-    );
     luamod_set(
         &l,
         "raft_propose_mp",
         indoc! {"
-        pico.raft_propose_mp(operation_bytes)
-        =====================================
+        pico.raft_propose_mp(op_bytes)
+        ==============================
 
-        Proposes operation to raft and returns its index (number).
+        Internal API, see src/luamod.rs for the details.
 
         Params:
 
-            1. operation_bytes - table. Op encoded with msgpack. See pico.help(\"Op\")
+            1. op_bytes (string), encoded with msgpack
+
+        Returns:
+
+            ()
+            or
+            (nil, string) in case of an error
         "},
         tlua::function1(|op: tlua::AnyLuaString| -> traft::Result<()> {
             let op: Op = Decode::decode(op.as_bytes())?;
             traft::node::global()?.propose_and_wait(op, Duration::from_secs(1))
         }),
     );
+
+    ///////////////////////////////////////////////////////////////////////////
     luamod_set(
         &l,
         "raft_timeout_now",
@@ -449,14 +534,18 @@ pub(crate) fn setup(args: &args::Run) {
         pico.raft_timeout_now()
         =======================
 
-        Causes this instance to artificially timeout on waiting for a heartbeat from raft leader.
-        This instance will then start a new election and transition to a candidate state.
+        Internal API. Causes this instance to artificially timeout on waiting
+        for a heartbeat from raft leader. The instance then will start a new
+        election and transition to a 'PreCandidate' state. See `src/luamod.rs`
+        for the details.
         "},
         tlua::function0(|| -> traft::Result<()> {
             traft::node::global()?.timeout_now();
             Ok(())
         }),
     );
+
+    ///////////////////////////////////////////////////////////////////////////
     #[rustfmt::skip]
     luamod_set(
         &l,
@@ -465,16 +554,18 @@ pub(crate) fn setup(args: &args::Run) {
         pico.exit([code])
         =================
 
-        Terminate the picodata process with the supplied code.
+        Terminates the picodata process with the supplied exit code.
 
         Params:
 
-            1. code - number, default: 0
+            1. code (optional number), default: 0
         "},
         tlua::function1(|code: Option<i32>| {
             crate::tarantool::exit(code.unwrap_or(0))
         }),
     );
+
+    ///////////////////////////////////////////////////////////////////////////
     luamod_set(
         &l,
         "expel",
@@ -486,18 +577,27 @@ pub(crate) fn setup(args: &args::Run) {
 
         Params:
 
-            1. instance_id - number
+            1. instance_id (string)
+
+        Returns:
+
+            (true)
+            or
+            (nil, string) in case of an error
         "},
-        tlua::function1(|instance_id: InstanceId| -> traft::Result<()> {
+        tlua::function1(|instance_id: InstanceId| -> traft::Result<bool> {
             let raft_storage = &traft::node::global()?.raft_storage;
             let cluster_id = raft_storage.cluster_id()?;
             fiber::block_on(rpc::network_call_to_leader(&rpc::expel::Request {
                 instance_id,
                 cluster_id,
             }))?;
-            Ok(())
+            Ok(true)
         }),
     );
+
+    // log
+    ///////////////////////////////////////////////////////////////////////////
     l.get::<tlua::LuaTable<_>, _>("pico")
         .unwrap()
         .set("log", &[()]);
@@ -530,6 +630,7 @@ pub(crate) fn setup(args: &args::Run) {
     )
     .unwrap();
 
+    ///////////////////////////////////////////////////////////////////////////
     #[derive(::tarantool::tlua::LuaRead, Default, Clone, Copy)]
     enum Justify {
         Left,
@@ -546,15 +647,18 @@ pub(crate) fn setup(args: &args::Run) {
         &l,
         "raft_log",
         indoc! {"
-        pico.raft_log()
-        pico.raft_log {
-            return_string=...,    -- boolean
-            justify_contents=...  -- string
-        }
-        =======================================================
+        pico.raft_log([opts])
+        ====================================
+
+        Internal API.
+
+        If `return_string` is true, returns a string with formatted contents of
+        raft log. Otherwise, prints the formatted raft log contents to the
+        standard output.
 
-        If return_string is true, returns a string with formatted contents of raft log.
-        If false, prints the formatted raft log contents to the standard output.
+        Example:
+
+            pico.raft_log({justify_contents = 'center', return_string = false})
         "},
         tlua::function1(
             |opts: Option<RaftLogOpts>| -> traft::Result<Option<String>> {
@@ -662,19 +766,25 @@ pub(crate) fn setup(args: &args::Run) {
             },
         ),
     );
+
+    ///////////////////////////////////////////////////////////////////////////
     luamod_set(
         &l,
         "raft_compact_log",
         indoc! {"
-        pico.raft_compact_log(up_to_index)
-        =================================
+        pico.raft_compact_log(up_to)
+        ============================
 
-        Trims raft log up to the given index (excluding the index
-        itself). Returns the new first_index (number) after the log compaction.
+        Trims raft log up to the given index (excluding the index itself).
+        Returns the new `first_index` after the log compaction.
 
         Params:
 
-            1. up_to_index - number
+            1. up_to (number)
+
+        Returns:
+
+            (number)
         "},
         {
             tlua::function1(|up_to: RaftIndex| -> traft::Result<RaftIndex> {
@@ -684,12 +794,14 @@ pub(crate) fn setup(args: &args::Run) {
             })
         },
     );
+
+    ///////////////////////////////////////////////////////////////////////////
     luamod_set(
         &l,
         "cas",
         indoc! {"
-        pico.cas(op, predicate)
-        ========================
+        pico.cas(dml[, predicate])
+        ==========================
 
         Performs a clusterwide compare and swap operation.
 
@@ -700,140 +812,140 @@ pub(crate) fn setup(args: &args::Run) {
 
         Params:
 
-            1. op - table. Dml operation to be appended. See `pico.help('Dml')`
-            2. predicate - table. See `pico.help('Predicate')`
+            1. dml (table)
+                - kind (string), one of 'insert' | 'replace' | 'update' | 'delete'
+                - space (string)
+                - tuple (optional table), mandatory for insert and replace, see [1, 2]
+                - key (optional table), mandatory for udate and delete, see [3, 4]
+                - ops (optional table), mandatory for update see [3]
 
-        Example:
+            2. predicate (optional table)
+                - index (optional number), default: current applied index
+                - term (optional number), default: current term
+                - ranges (optional table {CasRange,...}), see pico.help('CasRange'),
+                    default: {} (empty table)
 
-            -- Assuming there exists a space \"wonderland\"
-            -- with two fields: string and number,
-            -- we are inserting a tuple (\"roses\", 7) into this space.
-            --
-            -- In this case we are not supplying a predicate as it is optional.
-            pico.cas(
-                {
-                    kind = \"insert\",
-                    space = \"wonderland\",
-                    tuple = {\"roses\", 7},
-                }
-            )
-        "},
-        tlua::function2(
-            |op: op::DmlInLua,
-             predicate: Option<rpc::cas::PredicateInLua>|
-             -> traft::Result<RaftIndex> {
-                let op = op::Dml::from_lua_args(op).map_err(traft::error::Error::other)?;
-                let predicate = rpc::cas::Predicate::from_lua_args(predicate.unwrap_or_default())?;
-                let (index, _) = compare_and_swap(op.into(), predicate)?;
-                Ok(index)
-            },
-        ),
-    );
-    // TODO: describe how to fill these fields for different opts
-    luamod_set_help_only(
-        &l,
-        "Dml",
-        indoc! {"
-        Dml (table)
-        ===========
-
-        Dml describes an operation.
-
-        Fields:
+        See also:
 
-            - kind (string, one of 'insert' | 'replace' | 'update' | 'delete')
-            - space (string)
-            - tuple (optional, table)
-            - key (optional, table)
-            - ops (optional, table)
+            [1]: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/insert/
+            [2]: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/replace/
+            [3]: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/update/
+            [4]: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/delete/
 
         Example:
 
+            -- Assuming there exists a space 'friends_of_peppa' with two
+            -- fields: id (unsigned) and name (string) and corresponding
+            -- unique indexes.
+
+            -- Insert a tuple {1, 'Suzy'} into this space. This will fail
+            -- if the term of the current instance is outdated.
             local op_insert = {
                 kind = 'insert',
                 space = 'friends_of_peppa',
                 tuple = {1, 'Suzy'},
             }
+            pico.cas(op_insert)
 
+            -- Add Rebecca, but only if no other friends were added after
+            -- Suzy.
+            local unbounded = {
+                space = 'friends_of_peppa',
+                key_min = { kind = 'excluded', key = {1,} }
+                key_max = { kind = 'unbounded' }
+            }
             local op_replace = {
                 kind = 'replace',
                 space = 'friends_of_peppa',
                 tuple = {2, 'Rebecca'},
             }
+            pico.cas(op_replace, {ranges = {unbounded}})
 
+            -- Check that there were no other updates, and update the tuple
+            -- by primary key {2}, replacing 'Rebecca' with 'Emily'.
+            local predicate = {
+                ranges = {{
+                    space = 'friends_of_peppa',
+                    key_min = { kind = 'included', key = {2} }
+                    key_max = { kind = 'included', key = {2} }
+                }},
+            }
             local op_update = {
                 kind = 'update',
                 space = 'friends_of_peppa',
                 key = {2},
                 ops = {'=', 2, 'Emily'},
-                -- replace 'Rebecca' with 'Emily'
             }
+            pico.cas(op_update, predicate)
+
+            -- Delete the second Peppa friend, specifying index and term
+            -- explicitly. It's necessary when there are some yileding
+            -- operations between reading and writing.
+            local index, term = {
+                assert(pico.raft_get_index()),
+                assert(pico.raft_status()).term,
+            }
+            local emily = box.space.friends_of_peppa.index.name:get('Emily')
+            fiber.sleep(1) -- do someting yielding
 
-            local op_delete = {
+            pico.cas({
                 kind = 'delete',
                 space = 'friends_of_peppa',
-                key = {2},
-            }
-
-        See also:
-            - https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_space/update/
+                key = {emily.id},
+            }, {
+                index = index,
+                term = term,
+                ranges = {{
+                    space = 'friends_of_peppa',
+                    key_min = { kind = 'included', key = {emily.id} }
+                    key_max = { kind = 'included', key = {emily.id} }
+                }},
+            })
         "},
+        tlua::function2(
+            |op: op::DmlInLua,
+             predicate: Option<rpc::cas::PredicateInLua>|
+             -> traft::Result<RaftIndex> {
+                let op = op::Dml::from_lua_args(op).map_err(traft::error::Error::other)?;
+                let predicate = rpc::cas::Predicate::from_lua_args(predicate.unwrap_or_default())?;
+                let (index, _) = compare_and_swap(op.into(), predicate)?;
+                Ok(index)
+            },
+        ),
     );
-    // TODO: describe ranges
     luamod_set_help_only(
         &l,
-        "Predicate",
+        "CasRange",
         indoc! {"
-        Predicate (table)
-        =================
+        CasRange
+        ========
 
-        The predicate the leader checks during compare and swap operation before accepting it,
-        see `pico.help('cas')`.
+        A Lua table describing a range to be used as a compare-and-swap
+        predicate, see pico.help('cas')
 
         Fields:
 
-            - index (optional, number)
-            - term (optional, number)
-            - ranges (optional, {CasRange, ...}). See pico.help(\"CasRange\")
-
-        If some fields are not supplied, they will be autogenerated. `index` and `term` taken from the
-        raft state on the instance which sends this operation and `ranges` left as an empty
-        vector.
+            - space (string)
+            - key_min (table CasBound), see pico.help('CasBound')
+            - key_max (table CasBound)
 
         Example:
 
-            local predicate = {
-                index = box.space._raft_state:get('applied').value,
-                term = box.space._raft_state:get('term').value,
-                ranges = {
-                    {
-                        spacer = \"my_space\",
-                        key_min = { kind = \"unbounded\" }
-                        key_max = { kind = \"unbounded\" }
-                    }
-                },
-            }
-        "},
-    );
-    luamod_set_help_only(
-        &l,
-        "CasRange",
-        indoc! {"
-        CasRange (table)
-        =================
-
-        Fields:
-
-            - space (string)
-            - key_min (table, CasBound}). See pico.help(\"CasBound\")
-            - key_max (table, CasBound}). See pico.help(\"CasBound\")
+            local unbounded = { kind = 'unbounded' }
+            local including_1 = { kind = 'included', key = {1,} }
+            local excluding_3 = { kind = 'excluded', key = {3,} }
 
-        Example:
+            local range_a = {
+                space = 'friends_of_peppa',
+                key_min = unbounded,
+                key_max = unbounded,
+            }
 
-            local unbounded_range = {
-                spacer = \"my_space\",
-                key_min = { kind = \"unbounded\" }
-                key_max = { kind = \"unbounded\" }
+            -- [1, 3)
+            local range_a = {
+                space = 'friends_of_peppa',
+                key_min = including_1,
+                key_max = excluding_3,
             }
         "},
     );
@@ -841,25 +953,19 @@ pub(crate) fn setup(args: &args::Run) {
         &l,
         "CasBound",
         indoc! {"
-        CasBound (table)
-        =================
+        CasBound
+        ========
 
-        Used in {CasRange}. See pico.help(\"CasRange\")
+        A Lua table representing a range bound (either min or max) used in
+        CasRange, see pico.help('CasRange')
 
         Fields:
 
-            - kind (string, one of 'included' | 'excluded' | 'unbounded')
-            - key (optional, table). Should be set only when kind is included or excluded
-
-        Example:
-
-            local unbounded = { kind = \"unbounded\" }
-
-            local includes_1 = { kind = \"included\", key = {1,} }
-
-            local excludes_3 = { kind = \"excluded\", key = {3,} }
+            - kind (string), one of 'included' | 'excluded' | 'unbounded'
+            - key (optional table), mandatory for included and excluded
         "},
     );
+
     luamod_set(
         &l,
         "create_space",
@@ -867,7 +973,7 @@ pub(crate) fn setup(args: &args::Run) {
         pico.create_space {
             id = ...,             -- number
             name = ...,           -- string
-            format = ...,         -- {Field, ...}, See pico.help(\"Field\")
+            format = ...,         -- {Field, ...}, see pico.help('Field')
             primary_key = ...,    -- {string, ...}
             distribution = ...,   -- string, one of 'global' | 'sharded'
             timeout = ...,    -- number, in seconds
@@ -881,13 +987,13 @@ pub(crate) fn setup(args: &args::Run) {
         of params should be specified:
             - For implicit sharding:
                 - sharding_key - {string, ...}
-                - sharding_fn - optional, string one of 'crc32' | 'murmur3' | 'xxhash' | 'md5'
+                - sharding_fn - optional string one of 'crc32' | 'murmur3' | 'xxhash' | 'md5'
             - For explicit sharding:
                 - by_field - string
 
         Example:
 
-            -- Creates a global space \"wonderland\" with fields key and value
+            -- Creates a global space 'wonderland' with fields key and value
             -- which are of string and unsigned types correspondingly.
             pico.create_space{
                 name = 'wonderland',
@@ -900,7 +1006,7 @@ pub(crate) fn setup(args: &args::Run) {
                 timeout = 3.0
             }
 
-            -- Creates an implicitly sharded space \"faraway\" with fields key and value
+            -- Creates an implicitly sharded space 'faraway' with fields key and value
             -- which are of string and unsigned types correspondingly.
             pico.create_space{
                 name = 'faraway',
@@ -958,7 +1064,7 @@ pub(crate) fn setup(args: &args::Run) {
         =============
 
         Describes a field in a space.
-        
+
         Fields:
 
             - name (number)
-- 
GitLab