On 01/05/2013 10:49 AM, Igor Galić wrote: > >> Implied semantics matter a LOT in API design. > > +1 > >>> >>> Check your errors :-) >> I don't need to check errors, I just need to check whether 'rows' is >> a >> table or a nil value in the case of an error. I could've checked if >> 'err' was anything, but the result is the same. >> >> An API which returns (foo, err) should be error checked on the error, >> not the foo. This style of API will sometimes return a foo in a bad >> state, and an err to let you know. In your example this is fine, I >> am just being a pedant because if an API is designed a certain way, >> we should use it that way :-) >> > > My take away is that we want mod_dbd bindings in mod_lua, but we > want the API to be more carefully crafted. > > i > My attempt at humour seems to have failed, so I'll be more to the point. Yes, calling it acquire rather than open makes sense, and it's a good suggestion that I have applied to my draft.
Regarding the return values of 'acquire' (dbacquire, as it's currently called), this, as well as the query/run (or should it be called select/query? I'm not sure, but running db:select("SELECT...") seems a bit redundant in my mind) will never return a 'bad state', they will return nil if an error occurred, followed by an error message. How one chooses to check for an error, whether it be checking the nil value or checking for an error message, the result will be the same. However, in my documentation addition to mod_lua, I have consistently made the examples check for an error message, so no need to worry there - I was only being brief in my example snippets in the previous email, apologies. Return values are as follows: r:dbacquire(type, connstring): DB handle on success, nil + error on failure (error is either can't connect, can't load driver or mod_dbd not loaded) db:query("SELECT ...."): Result set on success, nil + error on failure (syntax error, permission issue or db handle not connected to backend) db:run("DELETE ...."): Number of affected rows on success, nil + error on failure (same errors as :query) With regards to how :query should work, this could either be done synchronously, wherein all rows are fetched at once, or async where rows are fetched as needed. The sync way is rather easy, but could fill up more memory than needed, while the async has a smaller footprint but proves rather difficult to implement, as the darn dbd driver keeps wanting to free up the result set before it's finished being used (apr_dbd_get_row keeps segfaulting when I request a row that is out of bounds... :( ). Also,there is the consideration of what happens if you query a db, get a result set, close the db handle and try to fetch more rows - this would most likely result in a segfault, as the db handle would have been freed when you try to use it again (how to check that?). Also, getting the number of rows, or even doing: for k, v in pairs(rows) ... proves to be quite difficult with the async method. What I've pieced together so far would work something like this: local results, err = db:query("SELECT .....") it not err then -- Async method here: local x = 1 local row = results(x) -- fetch row 1 while row do .... x = x + 1 row = results(x) -- fetch row 2,3,4,5...N end -- Sync method here: local rows = results() -- fetch all rows at once for index, row in pairs(rows) do .... end end As usual, suggestions and comments are most welcome! And as for the inject/prepare stuff, I'm working on a new approach to that as well, will keep you guys posted. With regards, Daniel.