<appendix xmlns="http://docbook.org/ns/docbook" version="5.0"
      xmlns:xlink="http://www.w3.org/1999/xlink"
      xml:id="lua-tutorial">

<title>Lua tutorial</title>

<section xml:id="lua-tutorial-insert">
<title>Insert one million tuples with a Lua stored procedure</title>

<para>
This is an exercise assignment: <quote>Insert one million tuples.
Each tuple should have a constantly-increasing numeric primary-key field
and a random alphabetic 10-character string field.</quote>
</para>

<para>
The purpose of the exercise is to show what Lua functions
look like inside Tarantool. It will be necessary to employ
the Lua math library, the Lua string library, the Tarantool
box library, the Tarantool box.tuple library, loops, and concatenations. It should be easy
to follow even for a person who has not used either Lua
or Tarantool before. The only requirement is a knowledge
of how other programming languages work and a memory of
the first two chapters of this manual. But for better understanding,
follow the comments and the links, which point to the Lua
manual or to elsewhere in this Tarantool manual.
To further enhance learning, type the statements
in with the tarantool client while reading along.
</para>

<para>
<bridgehead renderas="sect4">Configure</bridgehead>
We are going to use the "tarantool_sandbox" that was created in section
<olink targetptr="getting-started-start-stop">Starting Tarantool and making your first database</olink>.
So there is a single space, and a numeric primary key,
a running tarantool_box server, and a running tarantool client.
</para>

<para>
<bridgehead renderas="sect4">Delimiter</bridgehead>
We'll be making functions which go over one line. We don't want the client to send to the server after every line.
So we <link linkend="utility-tarantool-delim">declare a delimiter</link>.
This means <quote>Do not send to the server until you see an exclamation mark.</quote>

<programlisting>
localhost> <userinput>SETOPT DELIMITER = '!'</userinput>
</programlisting>
From now on it will be possible to use multiple-line statements,
but it will be necessary to end all statements with exclamation marks.
</para>

<para>
<bridgehead renderas="sect4">Create a function that returns a string</bridgehead>

We will start by making a function that returns a fixed string, <quote>Hello world</quote>.
<programlisting>
lua function string_function()
  return "hello world"
  end!
</programlisting>
The word <link linkend="utility-tarantool-lua">LUA</link>
is a Tarantool keyword that means <quote>we're about to go into Lua.</quote>
The function name is string_function.
The function has one executable statement, <code>return "hello world"</code>.
The string "hello world" is enclosed in double quotes here,
although Lua doesn't care -- one could use single quotes instead.
The word "end" means <quote>this is the end of the Lua function declaration.</quote>
The word "end" is followed by "!" because "!" happens to be the delimiter that we chose in the previous step.

To confirm that the function works, we can say
<programlisting>
call string_function()!
</programlisting>
The word <link linkend="utility-tarantool-call">CALL</link> is a Tarantool keyword that means <quote>invoke the Lua function.</quote>
The effect is that the string which the function returns will end up on the screen.
</para>

<para>
For more about Lua strings see Lua manual chapter 2.4 "Strings"
<productname xlink:href="http://www.lua.org/pil/2.4.html">http://www.lua.org/pil/2.4.html</productname>.

For more about functions see Lua manual chapter 5 "Functions"
<productname xlink:href="http://www.lua.org/pil/5.html">http://www.lua.org/pil/5.html</productname>.
</para>

<para>
The screen now looks like this:
<programlisting>
localhost&gt; <userinput>lua function string_function()</userinput>
        -&gt;   <userinput>return "hello world"</userinput>
        -&gt;   <userinput>end!</userinput>
---
...
localhost&gt; <userinput>call string_function()!</userinput>
Call OK, 1 rows affected
['hello world']
localhost&gt;
</programlisting>
</para>

 <para>
<bridgehead renderas="sect4">Create a function that calls another function and sets a variable</bridgehead>

Now that string_function exists, we can invoke it from another function.
<programlisting>
lua function main_function()
  local string_value
  string_value = string_function()
  return string_value
  end!
</programlisting>
We begin by declaring a variable "string_value".
The word "local" means that string_value appears only in main_function.
If we didn't use "local" then string_value would be visible everywhere
-- even by other users using other clients connected to this server!
Sometimes that's a very desirable feature for inter-client communication, but not this time.
</para>

<para>
Then we assign a value to string_value, namely, the result of string_function().
We don't need the word CALL for this (CALL is only meaningful to the tarantool client, not to the Lua compiler).
But we will CALL main_function() to check that it got the value.
</para>

<para>
For more about Lua variables see Lua manual chapter 4.2 "Local Variables and Blocks"
<productname xlink:href="http://www.lua.org/pil/4.2.html">http://www.lua.org/pil/4.2.html</productname>.
</para>

<para>
The screen now looks like this:
<programlisting>
localhost&gt; <userinput>lua function main_function()</userinput>
        -&gt;   <userinput>local string_value</userinput>
        -&gt;   <userinput>string_value = string_function()</userinput>
        -&gt;   <userinput>return string_value</userinput>
        -&gt;   <userinput>end!</userinput>
---
...
localhost&gt; <userinput>call main_function()!</userinput>
Call OK, 1 rows affected
['hello world']
localhost&gt;
</programlisting>
</para>

<para>
<bridgehead renderas="sect4">Modify the function so it returns a one-letter random string</bridgehead>

Now that it's a bit clearer how to make a variable, we can change string_function()
so that, instead of returning a fixed literal 'Hello world", it returns a random letter between 'A' and 'Z'.
<programlisting>
lua function string_function()
  local random_number
  local random_string
  random_number = math.random(65,90)
  random_string = string.char(random_number)
  return random_string
  end!
</programlisting>
It is not necessary to destroy the old string_function() contents, they're simply overwritten.
The first assignment invokes a random-number function in Lua's math library; the parameters mean <quote>the number must be an integer between 65 and 90.</quote>
The second assignment invokes an integer-to-character function in Lua's string library; the parameter is the code point of the character.
Luckily the ASCII value of 'A' is 65 and the ASCII value of 'Z' is 90 so the result will always be a letter between A and Z.
</para>

<para>
For more about Lua math-library functions see Lua users "Math Library Tutorial"
<productname xlink:href="http://lua-users.org/wiki/MathLibraryTutorial">http://lua-users.org/wiki/MathLibraryTutorial</productname>.
For more about Lua string-library functions see Lua users "String Library Tutorial"
<productname xlink:href="http://lua-users.org/wiki/StringLibraryTutorial">http://lua-users.org/wiki/StringLibraryTutorial</productname>.
</para>

<para>
Once again the string_function() can be invoked from main_function() which can be invoked with
</para>
<para>
call main_function()
</para>

<para>
The screen now looks like this:
<programlisting>
localhost&gt; <userinput>lua function string_function()</userinput>
        -&gt;   <userinput>local random_number</userinput>
        -&gt;   <userinput>local random_string</userinput>
        -&gt;   <userinput>random_number = math.random(65,90)</userinput>
        -&gt;   <userinput>random_string = string.char(random_number)</userinput>
        -&gt;   <userinput>return random_string</userinput>
        -&gt;   <userinput>end!</userinput>
---
...
localhost&gt; <userinput>call main_function()!</userinput>
Call OK, 1 rows affected
['C']
localhost&gt;
</programlisting>
... Well, actually it won't always look like this because math.random() produces random numbers.
But for the illustration purposes it won't matter what the random string values are.
</para>

<para>
<bridgehead renderas="sect4">Modify the function so it returns a ten-letter random string</bridgehead>
Now that it's clear how to produce one-letter random strings, we can reach our goal
of producing a ten-letter string by concatenating ten one-letter strings, in a loop.
<programlisting>
lua function string_function()
  local random_number
  local random_string
  random_string = ""
  for x = 1,10,1 do
    random_number = math.random(65,90)
    random_string = random_string .. string.char(random_number)
    end
  return random_string
  end!
</programlisting>
The words "for x = 1,10,1" mean <quote>start with x equals 1, loop until x equals 10, increment x by 1 for each iteration.</quote>
The symbol ".." means "concatenate", that is, add the string on the right of the ".." sign to the string on the left of the ".." sign.
Since we start by saying that random_string is "" (a blank string), the end result is that random_string has 10 random letters.

Once again the string_function() can be invoked from main_function() which can be invoked with
</para>
<para>
call main_function()
</para>

<para>
For more about Lua loops see Lua manual chapter 4.3.4 "Numeric for"
<productname xlink:href="http://www.lua.org/pil/4.3.4.html">http://www.lua.org/pil/4.3.4.html</productname>.
</para>

<para>
The screen now looks like this:
<programlisting>
localhost&gt; <userinput>lua function string_function()</userinput>
        -&gt;   <userinput>local random_number</userinput>
        -&gt;   <userinput>local random_string</userinput>
        -&gt;   <userinput>random_string = ""</userinput>
        -&gt;   <userinput>for x = 1,10,1 do</userinput>
        -&gt;     <userinput>random_number = math.random(65,90)</userinput>
        -&gt;     <userinput>random_string = random_string .. string.char(random_number)</userinput>
        -&gt;     <userinput>end</userinput>
        -&gt;   <userinput>return random_string</userinput>
        -&gt;   <userinput>end!</userinput>
---
...
localhost&gt; <userinput>call main_function()!</userinput>
Call OK, 1 rows affected
['ZUDJBHKEFM']
localhost&gt;
</programlisting>
</para>

<para>
<bridgehead renderas="sect4">Make a tuple out of a number and a string</bridgehead>

Now that it's clear how to make a 10-letter random string, it's possible to
make a tuple that contains a number and a 10-letter random string, by invoking
a function in Tarantool's library of Lua functions.
<programlisting>
lua function main_function()
  local string_value
  string_value = string_function()
  t = box.tuple.new({1,string_value})
  return t
  end!
</programlisting>
Once this is done, t will be the value of a new tuple which has two
fields. The first field is numeric: 1. The second field is a random string.

Once again the string_function() can be invoked from main_function() which can be invoked with
</para>
<para>
call main_function()
</para>

<para>
For more about Tarantool tuples see Tarantool manual section
<olink targetptr="sp-box-tuple">Package box.tuple</olink>.
</para>

<para>
The screen now looks like this:
<programlisting>
localhost&gt; <userinput>lua function main_function()</userinput>
        -&gt;   <userinput>local string_value</userinput>
        -&gt;   <userinput>string_value = string_function()</userinput>
        -&gt;   <userinput>t = box.tuple.new({1,string_value})</userinput>
        -&gt;   <userinput>return t</userinput>
        -&gt;   <userinput>end!</userinput>
---
...
localhost&gt; <userinput>call main_function()!</userinput>
Call OK, 1 rows affected
[1, 'PNPZPCOOKA']
localhost&gt;
</programlisting>
</para>

<para>
<bridgehead renderas="sect4">Modify main_function to insert a tuple into the database</bridgehead>

Now that it's clear how to make a tuple that contains a number and a 10-letter random string,
the only trick remaining is putting that tuple into space[0]. Remember that space[0] is
the first space that was defined in the configuration file, so it's like a database table.
<programlisting>
lua function main_function()
  local string_value
  string_value = string_function()
  t = box.tuple.new({1,string_value})
  box.replace(0,t)
  end!
</programlisting>
The new line here is box.replace(0,t). The first parameter is 0, because the
insertion is going to be to space[0]. The second parameter is the tuple value.
To be perfectly correct we could have said box.insert(0,t) here, rather than
box.replace(0,t), but "replace" means <quote>insert even if there is already a tuple
whose primary-key value is a duplicate</quote>, and that makes it easier to re-run
the exercise even if the sandbox database isn't empty.

Once this is done, space[0] will contain a tuple with two fields. The first
field will be 1. The second field will be a random 10-letter string.

Once again the string_function() can be invoked from main_function() which can be invoked with
call main_function(). But main_function() won't tell the whole story, because it does not
return t, it only puts t into the database. To confirm that something got inserted, we'll
use a <link linkend="utility-tarantool-select">SELECT statement</link>.

<programlisting>
call main_function()!
SELECT * FROM t0 WHERE k0 = 1!
</programlisting>
</para>

<para>
For more about Tarantool insert and replace calls, see Tarantool manual section
<olink targetptr="sp-box">Package box</olink>.
</para>

<para>
The screen now looks like this:
<programlisting>
localhost&gt; <userinput>lua function main_function()</userinput>
        -&gt;   <userinput>local string_value</userinput>
        -&gt;   <userinput>string_value = string_function()</userinput>
        -&gt;   <userinput>t = box.tuple.new({1,string_value})</userinput>
        -&gt;   <userinput>box.replace(0,t)</userinput>
        -&gt;   <userinput>end!</userinput>
---
...
localhost&gt; <userinput>call main_function()!</userinput>
Call OK, 0 rows affected
localhost&gt; <userinput>SELECT * FROM t0 WHERE k0 = 1!</userinput>
Select OK, 1 rows affected
[1, 'EUJYVEECIL']
localhost&gt;
</programlisting>
</para>

<para>
<bridgehead renderas="sect4">Modify main_function to insert a million tuples into the database</bridgehead>

Now that it's clear how to insert one tuple into the database,
it's no big deal to figure out how to scale up: instead of
inserting with a literal value = 1 for the primary key, insert
with a variable value = between 1 and 1 million, in a loop.
Since we already saw how to loop, that's a simple thing.
The only extra wrinkle that we add here is a timing function.
<programlisting>
lua function main_function()
  local string_value
  start_time = os.clock()
  for i = 1,1000000,1 do
    string_value = string_function()
    t = box.tuple.new({i,string_value})
    box.replace(0,t)
    end
  end_time = os.clock()
  end!
call main_function()!
lua print('insert done in ' .. end_time - start_time .. ' seconds')!
</programlisting>

The Lua os.clock() function will return the number of seconds since the start.
Therefore, by getting start_time = number of seconds just before the inserting,
and then getting end_time = number of seconds just after the inserting,
we can calculate (end_time - start_time) = elapsed time in seconds.
We will display that value with Lua's answer to the C printf() function, which is print().
</para>

<para>
For more on Lua os.clock() see Lua manual chapter 22.1 "Date and Time"
<productname xlink:href="http://www.lua.org/pil/22.1.html">http://www.lua.org/pil/22.1.html</productname>.
For more on Lua print() see Lua manual chapter 5 "Functions"
<productname xlink:href="http://www.lua.org/pil/5.html">http://www.lua.org/pil/5.html</productname>.
</para>

<para>
Since this is the grand finale, we will redo the final versions of all the necessary
statements: the SETOPT DELIMITER statement, the statement that created string_function(),
the statement that created main_function(), and the statement that invokes main_function().


<programlisting>
#Skip the following statement if you have already said "setopt delimiter = '!'"
setopt delimiter = '!'

lua function string_function()
  local random_number
  local random_string
  random_string = ""
  for x = 1,10,1 do
    random_number = math.random(65,90)
    random_string = random_string .. string.char(random_number)
    end
  return random_string
  end!

lua function main_function()
  local string_value
  start_time = os.clock()
  for i = 1,1000000,1 do
    string_value = string_function()
    t = box.tuple.new({i,string_value})
    box.replace(0,t)
    end
  end_time = os.clock()
  end!
call main_function()!
lua print('insert done in ' .. end_time - start_time .. ' seconds')!
</programlisting>

The screen now looks like this:

<programlisting>
localhost&gt; <userinput>setopt delimiter = '!'!</userinput>
localhost&gt; <userinput>lua function string_function()</userinput>
        -&gt;   <userinput>local random_number</userinput>
        -&gt;   <userinput>local random_string</userinput>
        -&gt;   <userinput>random_string = ""</userinput>
        -&gt;   <userinput>for x = 1,10,1 do</userinput>
        -&gt;     <userinput>random_number = math.random(65,90)</userinput>
        -&gt;     <userinput>random_string = random_string .. string.char(random_number)</userinput>
        -&gt;     <userinput>end</userinput>
        -&gt;   <userinput>return random_string</userinput>
        -&gt;   <userinput>end!</userinput>
---
...
localhost&gt; <userinput>lua function main_function()</userinput>
        -&gt;   <userinput>local string_value</userinput>
        -&gt;   <userinput>start_time = os.clock()</userinput>
        -&gt;   <userinput>for i = 1,1000000,1 do</userinput>
        -&gt;     <userinput>string_value = string_function()</userinput>
        -&gt;     <userinput>t = box.tuple.new({i,string_value})</userinput>
        -&gt;     <userinput>box.replace(0,t)</userinput>
        -&gt;     <userinput>end</userinput>
        -&gt;   <userinput>end_time = os.clock()</userinput>
        -&gt;   <userinput>end!</userinput>
---
...
localhost&gt; <userinput>call main_function()!</userinput>
Call OK, 0 rows affected
localhost&gt; <userinput>lua print('insert done in ' .. end_time - start_time .. ' seconds')!</userinput>
---
insert done in 41.66 seconds
...
localhost&gt;
</programlisting>
</para>

<para>
What has been shown is that Lua functions are quite expressive
(in fact one can do more with Tarantool's Lua stored procedures
than one can do with stored procedures in some SQL DBMSs), and
that it's straightforward to combine Lua-library functions and
Tarantool-library functions.
</para>

<para>
What has also been shown is that inserting a million
tuples took 42 seconds. The host computer was a Toshiba
laptop with a 2.2-GHz Intel Core Duo CPU.
</para>

</section>

<section xml:id="lua-tutorial-sum">
<title>Sum a JSON field for all tuples</title>

<para>
This is an exercise assignment: <quote>Assume that inside every tuple there
is a string formatted as JSON. Inside that string there is a JSON numeric
field. For each tuple, find the numeric field's value and add it to a
'sum' variable. At end, return the 'sum' variable.</quote>
</para>

<para>
The purpose of the exercise is to show one way to read and process tuples.
This is harder than the first exercise because the function is useful.
A function which is useful, and therefore is going to be used more than
once by more than one person, has to be robust and understandable.
So here is the function. It's best to start by looking at each line --
there are only twelve lines so it will only take a few minutes to guess what they do.
Then it will take somewhat longer to read the detailed
comments about the function, and follow the links wherever necessary.
Once again, to further enhance learning, type the statements
in with the tarantool client while reading along. At the very end there
is an example that shows how to make a few tuples and invoke the function.
</para>

<programlisting language="lua">
SETOPT DELIMITER='!'
lua function sum_json_field(field_name)
  local v, t, sum, field_value, is_valid_json, lua_table                --[[1]]
  sum = 0                                                               --[[2]]
  v = box.space[0].index[0]:iterator(box.index.ALL)                     --[[3]]
  for t in v do                                                         --[[4]]
    is_valid_json, lua_table = pcall(box.cjson.decode, t[1])            --[[5]]
    if is_valid_json then                                               --[[6]]
      field_value = lua_table[field_name]                               --[[7]]
      if type(field_value) == "number" then sum = sum + field_value end --[[8]]
    end                                                                 --[[9]]
  end                                                                   --[[10]]
  return sum                                                            --[[11]]
  end!
SETOPT DELIMITER=''!
</programlisting>

<para>
SPACES. There is one space after every comma (line 3, line 5). There is one space
before and one space after every operator such as '<code>=</code>' or '<code>==</code>' or '<code>+</code>' (line 2,
line 3, line 5, line 7, line 8). There are no spaces around parentheses.
Each indentation is two spaces (actually Tarantool developers often use four
spaces but we follow the unofficial <link xlink:href="http://lua-users.org/wiki/LuaStyleGuide">Lua Style Guide</link> here).
Indentation starts within a function, and within every block that is introduced
by "<code>for</code>" or "<code>if</code>", and ends when the block ends with "<code>end</code>" (lines 4 to 10, lines 6 to 9).
</para>

<para>
COMMENTS. Every comment begins with "<code>--[[</code>" and ends with "<code>]]</code>". Although this example uses comments to
indicate line numbers, the normal practice is to put comments when the
meaning of the code would not be clear by merely looking at the code.
</para>

<para>
LINE 1: WHY "LOCAL". This line declares all the variables that will be used
in the function. Actually it's not necessary to declare all variables at the start,
and in a long function it would be better to declare variables just before using
them. In fact it's not even necessary to declare variables at all, but an
undeclared variable is "global". That's not desirable for any of the variables
that are declared in line 1, because all of them are for use only within the
function.
</para>

<para>
LINE 1: NAMES. Single-letter variable names like <code>'v</code>' are okay when they're
strictly for use as an iterator -- '<code>v</code>' is going to be the thing that goes
up in the "<code>for t in v do</code>" statement in line 4. Terse names like '<code>sum</code>'
are okay for local variables when there's only one sum and the name is
not an abbreviation. The prefix "is_" in the name "<code>is_valid_json</code>" is
there because the variable will get a Boolean (true/false) value and
will be true only for a string that "is valid [according to] JSON [format rules]".
</para>

<para>
LINE 2: INITIALIZING. The only variable that needs initializing is <code>sum</code>, which
must start at zero, so line 2 is "<code>sum = 0</code>". It's easier to do initialization
on the declaration line, that is, we could have said "<code>local sum = 0</code>". We
chose to put it on a separate line to make sure that it's visible.
</para>

<para>
LINE 3: WHY INDEX ITERATOR". Our job is to go through all the rows and there are two ways
to do it: with <olink targetptr="box.select_range">box.select_range()</olink> or with
<olink targetptr="box.index.iterator">index[].iterator</olink>. We preferred
index[].iterator because it works regardless of the index type, that is,
it works with HASH, TREE, and BITSET indexes.
</para>

<para>
LINE 3: MEANING. The value zero is hard-coded so this will only work for space[0]
and index[0] -- we're making some hopeful assumptions here. The meaning is "variable <code>v</code> gets
the iterator for the primary index of the first space".
</para>

<para>
LINE 4: START THE MAIN LOOP. Everything inside this "<code>for</code>" loop will be repeated
as long as there is another index key. A tuple is fetched and can be referenced
with variable <code>t</code>.
</para>

<para>
LINE 5: WHY "PCALL". If we simply said "<code>lua_table = box.cjson.decode(t[1]))</code>",
then the function would abort with an error if it encountered something wrong
with the JSON string -- a missing colon, for example. By putting the function
inside "<code>pcall</code>" (<link xlink:href="http://www.lua.org/pil/8.4.html">protected call</link>), we're saying: we want to intercept that sort
of error, so if there's a problem just set <code>is_valid_json = false</code> and we
will know what to do about it later.
</para>

<para>
LINE 5: MEANING. The function is <olink targetptr="box.cjson">box.cjson.decode</olink> which means decode a JSON
string, and the parameter is <code>t[1]</code> which is a reference to a JSON string.
Once again there's a bit of hard coding here, we're assuming that the second
field in the tuple is where the JSON string was inserted. For example, we're assuming a tuple looks like <programlisting>field[0]: 444
field[1]: '{"Hello": "world", "Quantity": 15}'
</programlisting>meaning that the tuple's first field, the primary key field, is a number
while the tuple's second field, the JSON string, is a string. Thus the
entire statement means "decode <code>t[1]</code> (the tuple's second field) as a JSON
string; if there's an error set <code>is_valid_json = false</code>; if there's no error
set <code>is_valid_json = true</code> and set <code>lua_table</code> = a Lua table which has the
decoded string".
</para>

<para>
LINE 6. This "<code>if</code>" statement means "if the <code>box.cjson.decode</code> function failed,
don't execute the next indented lines", so <code>sum</code> will be unchanged if
<code>box.cjson.decode</code> failed. Although "<code>if is_valid_json == true</code>" would be clearer, the
usual style is to say "<code>if is_valid_json</code>" and let "<code>== true</code>" be assumed.
</para>

<para>
LINE 7. At last we are ready to get the JSON field value from the Lua
table that came from the JSON string.
The value in <code>field_name</code>, which is the parameter for the whole function,
must be a name of a JSON field. For example, inside the JSON string
'{"Hello": "world", "Quantity": 15}', there are two JSON fields: "Hello"
and "Quantity". If the whole function is invoked with <code>sum_json_field("Quantity")</code>,
then <code>field_value = lua_table[field_name]</code> is effectively the same as
<code>field_value = lua_table["Quantity"]</code> or even <code>field_value = lua_table.Quantity</code>.
Those are just three different ways of saying: for the Quantity field
in the Lua table, get the value and put it in variable <code>field_value</code>.
</para>

<para>
LINE 8: WHY "IF". Suppose that the JSON string is well formed but the
JSON field is not a number, or is missing. In that case, the function
would be aborted when there was an attempt to add it to the sum.
By first checking <code>type(field_value) == "number"</code>, we avoid that abortion.
Again, as in line 5, this is slightly paranoid -- anyone who knows
that the database is in perfect shape can skip this kind of thing.
Incidentally the "<code>if ... end</code>" statement is so short that it fits on
a single line, which is acceptable but optional practice.
</para>

<para>
LINE 8: MEANING. The meat, the whole reason for the function's existence,
is in the words "<code>sum = sum + field_value</code>". This addition of <code>field_value</code>
to <code>sum</code> will happen for every tuple, provided the field is there and is
numeric.
</para>

<para>
LINE 9. This "<code>end</code>" statement matches the "<code>if is_valid_json</code>" statement
in line 6.
</para>

<para>
LINE 10. This "<code>end</code>" statement matches the "<code>for t in v do</code>" statement
in line 4. The effect is that another iteration of the loop will take
place, unless there are no more tuples.
</para>

<para>
LINE 11: This is after the end of the "<code>for t in v do</code>" loop. Return <code>sum</code> to the caller.
This effectively ends the execution of the whole function, so all the
local variables are destroyed and the function's caller gets the result.
</para>

<para>
LINE 12: This "<code>end</code>" statement matches the start of the function.
</para>

<para>
And the function is complete. Time to test it.
Starting with an empty database, defined the same way as the
sandbox database that was introduced in
<olink
targetptr="getting-started-start-stop"><quote>Starting Tarantool and making your first database</quote></olink>,
add some tuples where the first field is a number and the second field is a string.
</para>
<programlisting>
INSERT INTO t0 VALUES (444,'{"Item": "widget", "Quantity": 15}')
INSERT INTO t0 VALUES (445,'{"Item": "widget", "Quantity": 7}')
INSERT INTO t0 VALUES (446,'{"Item": "golf club", "Quantity": "sunshine"}')
INSERT INTO t0 VALUES (447,'{"Item": "waffle iron", "Quantit": 3}')
</programlisting>
<para>
Since this is a test, there are deliberate errors. The "golf club" and
the "waffle iron" do not have numeric Quantity fields, so must be ignored.
Therefore the real sum of the Quantity field in the JSON strings should be:
15 + 7 = 22.
</para>

<para>
Invoke the function with either <code>CALL sum_json_field("Quantity")</code> or
<code>lua sum_json_field("Quantity")</code>.
<programlisting language="lua">
<prompt>localhost&gt;</prompt> <userinput>lua sum_json_field("Quantity")</userinput>
---
 - 22
...
</programlisting>
</para>

<para>
It works. We'll just leave, as exercises for future improvement, the possibility
that the "hard coding" assumptions could be removed, that there might have to be
an overflow check if some field values are huge, and that the function should
contain a "yield" instruction if the count of tuples is huge.
</para>

<para>
What has been shown is that a 12-line Lua function can scan a database and
process JSON strings, in a way that's useful, robust, and -- now that
this tutorial exercise is over -- understandable.
</para>

</section>

</appendix>

<!--
vim: tw=66 syntax=docbk
vim: spell spelllang=en_us
-->
