Search code examples
lualuasql

lua test and assign inside loop control


Is there / please suggest a syntax to achieve a compact 'test and assign' in lua?

Consider this segment from luasql examples ( http://keplerproject.org/luasql/examples.html )

-- retrieve a cursor
cur = assert (con:execute"SELECT name, email from people")
-- print all rows, the rows will be indexed by field names
row = cur:fetch ({}, "a")
while row do
  print(string.format("Name: %s, E-mail: %s", row.name, row.email))
  -- reusing the table of results
  row = cur:fetch (row, "a")
end

I am learning lua, and really struggling to accept the duplicated call to cur:fetch(). I see that repeat/until trivially fixes the issue, but then it seems I have to test twice:

repeat
  row = cur:fetch ({}, "a")
  if row then
    print ...
  end
until nil == row

I consider this less error prone for the case of 'row = ...' getting more complex, but still seems inelegant.


Solution

  • You can simplify the first loop to this:

    local row = {}
    while row do
      row = cur:fetch(row, "a")
    end
    

    EDIT: The sample page hits at a possible solution using iterators and a for loop, like @doukremt is suggesting. Unfortunately it also contains a couple errors (it assumes that the rows get "unpacked" in the second example but not in the first, does not declare everything local, and omits more parenthesis than it's sane to in a sample code). Here's how you can transform a cursor in an iterator:

    local iterate = function(cur)
      return function() return cur:fetch() end
    end
    

    Here's how you use it:

    local cur = assert(con:execute("SELECT name, email from people"))
    
    for row in iterate(cur) do
      print(string.format ("%s: %s", row.name, row.email))
    end
    

    I must warn you that iterators are in general more expensive than while/repeat loops. Execute performance tests if you are worried about speed.