tmysql4 callback function return

With this:



function Lobby.Game.Find()
	Lobby.Database:Query( "SELECT * FROM table", function(result) 
		return result
	end )
end


Does Lobby.Game.Find() not return result because ‘return result’ is in a callback function as part of Lobby.Database:Query()?

How can I make Lobby.Game.Find() return the result?

Note: I’ve removed the specifics form the query - Assume that the query does return a result table as I’ve checked that.

You’re returning result in the query function. Just widen the scope to the outer function.

Thanks code_gs -

I’ve tried this and it prints the table fine:


function Lobby.Game.Find()
	Lobby.Database:Query( "SELECT * FROM table", function(result) 
                PrintTable(result)
		return result
	end )
end

However this says the below error - can’t find table:


function Lobby.Game.Find()
	Lobby.Database:Query( "SELECT * FROM table", function(result) 
		return result
	end )
        PrintTable(result)
end




> Lobby.Game.Find(1)...

[ERROR] lua/includes/extensions/table.lua:711: bad argument #1 to 'pairs' (table expected, got nil)
  1. pairs - [C]:-1
   2. GetKeys - lua/includes/extensions/table.lua:711
    3. PrintTable - lua/includes/util.lua:42
     4. FindServer - gamemodes/lobby/gamemode/init.lua:112
      5. unknown - lua_run:1



So it seems like result isn’t available outside the scope of :Query()? Please correct me if I’m wrong :slight_smile:

-snip-

Still doesn’t work. Can’t seem to get the ‘result’ table out of the callback function and available in Lobby.Game.Fine()

Is this even possible? I was trying to do this too, but did not figured out how I should do that.

Returning in there will not have the desired effect. The whole reason there is a callback is because there is a delay between the start and result of the Query function and the Lobby.Game.Find function wants an answer (return) right away, so you have to have a callback for it.

To fix this? I’d just have another callback like so:

[lua]function Lobby.Game.Find(callback)
Lobby.Database:Query( “SELECT * FROM table”, function(result)
callback(result)
end )
end[/lua]

or even more directly:

[lua]function Lobby.Game.Find(callback)
Lobby.Database:Query( “SELECT * FROM table”, callback)
end
[/lua]

Calling the function:
[lua]
Lobby.Game.Find(function(result)
– do something with result
end)[/lua]

Thanks thejjoker - I think I’ll use that for now, but it still didn’t achieve my original goal however it’s a work around. Apparently to do what I wanted to do, you need to use closures, which would give the callback function access to the variables in the outer function. However I’ve not used closures before.

Thanks again for the help.

[editline]18th February 2016[/editline]

Coffeee can you explain why you disagreed as it may help me find a solution?

Also doing the above won’t help actually as I need to be able to act directly on the result rather then doing my action in the callback. Eg. if Lobby.Game.Find(1) then - rather then running a callback within Lobby.Game.Find()

You can’t do that, tmysql is asynchronous so you have to use callbacks. There are libraries for promises which you might find tidier if you need to nest a bunch of them but the concept is the same

When you call Lobby.Game.Find(1) the code doesn’t stop and wait for the MySQL query to complete, it continues, which is why you need to use callbacks

(also see below)

you could write a wrapper that pauses coroutines and yields the response, and call that function from a coroutine. Would make your code synchronous, but it’s only useful when called by a non-essential subroutine.

[editline]18th February 2016[/editline]

[lua]

function Lobby.Game.Find()
local thread = coroutine.running()
Lobby.Database:Query( “SELECT * FROM table”, function(result)
coroutine.resume(thread, result)
end )
return coroutine.yield( )
end

local co = coroutine.create( function()
print( Lobby.Game.Find() )
end)
coroutine.resume( co )

[/lua]

something like this

Thanks for explaining - I do know it’s asynchronous however apparently that’s what this closures thing is for which allows you to call a anonymous callback function, then in that callback reference a variable from the parent function ( which could then be used to return a value etc. ) I’m not sure how it works, but apparently it’s a similar method is used in AJAX etc. But I think I’ve found a way to achieve the same goal using the tips here, but it’s not exactly what I wanted.

[editline]18th February 2016[/editline]

As I mentioned, this closure thing is completely new to me, but apparently that’s what it’s for.

You can’t do that.

What are you expecting the execution of Lobby.Game.Find to do if your MySQL server is having a bad day? Say it takes 3 seconds for a query to execute, do you want the function to wait 3 seconds before returning?

The function requires a return in it’s active scope.

There’s a lot I don’t know about Lua - but I don’t like to say ‘That’s not possible’ as usually I end up being wrong. - It’s good to keep an open mind as often things that seem impossible are only so because of gaps in our own knowledge.

I’ve reworked what I’ve done using the information in this thread. As for what do I expect it to do, I don’t know. However I’ve spoken with my father who is a java programmer and he said these kind of situations come up often where a callback function is used and he said there is a way around it - he believes using these closures - whatever they are - as I said I don’t fully understand them. It’s got something to do with making a variable persistent after it’s function has ended.

“A closure is a persistent scope which holds on to local variables even after the code execution has moved out of that block.” - this would let me pass back the result - however it may still not allow me to do Lobby.Game.Find(id) as there would still be a delay. But it gets around the scope issue.

Apparently you can do something with holding an anonymous function in a variable to be called back to once the callback has ended, passing the result of the callback function - to them be returned by the parent function. If we manage to do it I’ll post it here. If this is true, it means I can do ‘if Lobby.Game.Find(id) then’ - with Lobby.Game.Find(id) doing a mysql lookup.

However, you’re right still to say there’s a delay - I could have this completely wrong, as I’m not sure what would happen if I did Lobby.Game.Find(id) as the return wouldn’t be available instantly… Like I said, if I find an answer or a workaround I’ll post it here, if not, then at least I’ve researched this method of getting around scopes and I’ll know it’s not what I needed. This closure technique is a thing, so it must be used for something.

You won’t find a ‘solution’, it just doesn’t work like that. Doing ‘if Lobby.Game.Find(id) then’ is impossible and there’s no way around it because whatever mysql module you’re using is asynchronous

So are there any good mysql modules for lua that are not synchronous? There might be a way to make it asynchronous using this closure thing - do you know anything about that? If the callback function can access the parent functions scope even after it’s finished, maybe that would be a solution?

They’re all asynchronous (you’ve got the two mixed up)
The lua state isn’t going to pause and wait for the MySQL query to complete, imagine if all your code paused and nothing ran for 5 seconds while the query completed, and it doesn’t matter what the function returns because the code has already ran. It’s 100% not possible to do what you’re trying to do. Just write async code it’s better once you learn how it looks anyway

Sorry I meant asynchronous before :stuck_out_tongue:
I’ve actually done that now, and it does make sense, using callback function :slight_smile: So the question still stands, what is this closure thing and whats’ it used for! But thanks for the good discussion - callback functions make sense now! Just means you have to have callbacks within callbacks.