B2G/gecko/storage/test/unit/test_statement_executeAsync.js
/**
 * Execute the given statement asynchronously, spinning an event loop until the
 * async statement completes.
 *
 * @param aStmt
 *        The statement to execute.
 * @param [aOptions={}]
 * @param [aOptions.error=false]
 *        If true we should expect an error whose code we do not care about.  If
 *        a numeric value, that's the error code we expect and require.  If we
 *        are expecting an error, we expect a completion reason of REASON_ERROR.
 *        Otherwise we expect no error notification and a completion reason of
 *        REASON_FINISHED.
 * @param [aOptions.cancel]
 *        If true we cancel the pending statement and additionally return the
 *        pending statement in case you want to further manipulate it.
 * @param [aOptions.returnPending=false]
 *        If true we keep the pending statement around and return it to you.  We
 *        normally avoid doing this to try and minimize the amount of time a
 *        reference is held to the returned pending statement.
 * @param [aResults]
 *        If omitted, we assume no results rows are expected.  If it is a
 *        number, we assume it is the number of results rows expected.  If it is
 *        a function, we assume it is a function that takes the 1) result row
 *        number, 2) result tuple, 3) call stack for the original call to
 *        execAsync as arguments.  If it is a list, we currently assume it is a
 *        list of functions where each function is intended to evaluate the
 *        result row at that ordinal position and takes the result tuple and
 *        the call stack for the original call.
 */
Execute the given statement asynchronously, spinning an event loop until the
async statement completes.

@param aStmt
The statement to execute.
@param [aOptions={}]
@param [aOptions.error=false]
If true we should expect an error whose code we do not care about.  If
a numeric value, that's the error code we expect and require.  If we
are expecting an error, we expect a completion reason of REASON_ERROR.
Otherwise we expect no error notification and a completion reason of
REASON_FINISHED.
@param [aOptions.cancel]
If true we cancel the pending statement and additionally return the
pending statement in case you want to further manipulate it.
@param [aOptions.returnPending=false]
If true we keep the pending statement around and return it to you.  We
normally avoid doing this to try and minimize the amount of time a
reference is held to the returned pending statement.
@param [aResults]
If omitted, we assume no results rows are expected.  If it is a
number, we assume it is the number of results rows expected.  If it is
a function, we assume it is a function that takes the 1) result row
number, 2) result tuple, 3) call stack for the original call to
execAsync as arguments.  If it is a list, we currently assume it is a
list of functions where each function is intended to evaluate the
result row at that ordinal position and takes the result tuple and
the call stack for the original call.
Execute the given statement asynchronously spinning an event loop until the async statement completes . @param aStmt The statement to execute . @param [ aOptions = {} ] @param [ aOptions . error = false ] If true we should expect an error whose code we do not care about . If a numeric value that ' s the error code we expect and require . If we are expecting an error we expect a completion reason of REASON_ERROR . Otherwise we expect no error notification and a completion reason of REASON_FINISHED . @param [ aOptions . cancel ] If true we cancel the pending statement and additionally return the pending statement in case you want to further manipulate it . @param [ aOptions . returnPending = false ] If true we keep the pending statement around and return it to you . We normally avoid doing this to try and minimize the amount of time a reference is held to the returned pending statement . @param [ aResults ] If omitted we assume no results rows are expected . If it is a number we assume it is the number of results rows expected . If it is a function we assume it is a function that takes the 1 ) result row number 2 ) result tuple 3 ) call stack for the original call to execAsync as arguments . If it is a list we currently assume it is a list of functions where each function is intended to evaluate the result row at that ordinal position and takes the result tuple and the call stack for the original call .
function execAsync(aStmt, aOptions, aResults)
{
  let caller = Components.stack.caller;
  if (aOptions == null)
    aOptions = {};
  let resultsExpected;
  let resultsChecker;
  if (aResults == null) {
    resultsExpected = 0;
  }
  else if (typeof(aResults) == "number") {
    resultsExpected = aResults;
  }
  else if (typeof(aResults) == "function") {
    resultsChecker = aResults;
  }
  else { 
    resultsExpected = aResults.length;
    resultsChecker = function(aResultNum, aTup, aCaller) {
      aResults[aResultNum](aTup, aCaller);
    };
  }
  let resultsSeen = 0;
  let errorCodeExpected = false;
  let reasonExpected = Ci.mozIStorageStatementCallback.REASON_FINISHED;
  let altReasonExpected = null;
  if ("error" in aOptions) {
    errorCodeExpected = aOptions.error;
    if (errorCodeExpected)
      reasonExpected = Ci.mozIStorageStatementCallback.REASON_ERROR;
  }
  let errorCodeSeen = false;
  if ("cancel" in aOptions && aOptions.cancel)
    altReasonExpected = Ci.mozIStorageStatementCallback.REASON_CANCELED;
  let completed = false;
  let listener = {
    handleResult: function(aResultSet)
    {
      let row, resultsSeenThisCall = 0;
      while ((row = aResultSet.getNextRow()) != null) {
        if (resultsChecker)
          resultsChecker(resultsSeen, row, caller);
        resultsSeen++;
        resultsSeenThisCall++;
      }
      if (!resultsSeenThisCall)
        do_throw("handleResult invoked with 0 result rows!");
    },
    handleError: function(aError)
    {
      if (errorCodeSeen != false)
        do_throw("handleError called when we already had an error!");
      errorCodeSeen = aError.result;
    },
    handleCompletion: function(aReason)
    {
      if (completed) 
        do_throw("Received a second handleCompletion notification!", caller);
      if (resultsSeen != resultsExpected)
        do_throw("Expected " + resultsExpected + " rows of results but " +
                 "got " + resultsSeen + " rows!", caller);
      if (errorCodeExpected == true && errorCodeSeen == false)
        do_throw("Expected an error, but did not see one.", caller);
      else if (errorCodeExpected != errorCodeSeen)
        do_throw("Expected error code " + errorCodeExpected + " but got " +
                 errorCodeSeen, caller);
      if (aReason != reasonExpected && aReason != altReasonExpected)
        do_throw("Expected reason " + reasonExpected +
                 (altReasonExpected ? (" or " + altReasonExpected) : "") +
                 " but got " + aReason, caller);
      completed = true;
    }
  };
  let pending;
  if (("cancel" in aOptions && aOptions.cancel) ||
      ("returnPending" in aOptions && aOptions.returnPending)) {
    pending = aStmt.executeAsync(listener);
  }
  else {
    aStmt.executeAsync(listener);
  }
  if ("cancel" in aOptions && aOptions.cancel)
    pending.cancel();
  let curThread = Components.classes["@mozilla.org/thread-manager;1"]
                            .getService().currentThread;
  while (!completed && !_quit)
    curThread.processNextEvent(true);
  return pending;
}
function execAsync ( aStmt , aOptions , aResults ) { let caller = Components . stack . caller ; if ( aOptions == null ) aOptions = { } ; let resultsExpected ; let resultsChecker ; if ( aResults == null ) { resultsExpected = 0 ; } else if ( typeof ( aResults ) == "number" ) { resultsExpected = aResults ; } else if ( typeof ( aResults ) == "function" ) { resultsChecker = aResults ; } else { resultsExpected = aResults . length ; resultsChecker = function ( aResultNum , aTup , aCaller ) { aResults [ aResultNum ] ( aTup , aCaller ) ; } ; } let resultsSeen = 0 ; let errorCodeExpected = false ; let reasonExpected = Ci . mozIStorageStatementCallback . REASON_FINISHED ; let altReasonExpected = null ; if ( "error" in aOptions ) { errorCodeExpected = aOptions . error ; if ( errorCodeExpected ) reasonExpected = Ci . mozIStorageStatementCallback . REASON_ERROR ; } let errorCodeSeen = false ; if ( "cancel" in aOptions && aOptions . cancel ) altReasonExpected = Ci . mozIStorageStatementCallback . REASON_CANCELED ; let completed = false ; let listener = { handleResult : function ( aResultSet ) { let row , resultsSeenThisCall = 0 ; while ( ( row = aResultSet . getNextRow ( ) ) != null ) { if ( resultsChecker ) resultsChecker ( resultsSeen , row , caller ) ; resultsSeen ++ ; resultsSeenThisCall ++ ; } if ( ! resultsSeenThisCall ) do_throw ( "handleResult invoked with 0 result rows!" ) ; } , handleError : function ( aError ) { if ( errorCodeSeen != false ) do_throw ( "handleError called when we already had an error!" ) ; errorCodeSeen = aError . result ; } , handleCompletion : function ( aReason ) { if ( completed ) do_throw ( "Received a second handleCompletion notification!" , caller ) ; if ( resultsSeen != resultsExpected ) do_throw ( "Expected " + resultsExpected + " rows of results but " + "got " + resultsSeen + " rows!" , caller ) ; if ( errorCodeExpected == true && errorCodeSeen == false ) do_throw ( "Expected an error, but did not see one." , caller ) ; else if ( errorCodeExpected != errorCodeSeen ) do_throw ( "Expected error code " + errorCodeExpected + " but got " + errorCodeSeen , caller ) ; if ( aReason != reasonExpected && aReason != altReasonExpected ) do_throw ( "Expected reason " + reasonExpected + ( altReasonExpected ? ( " or " + altReasonExpected ) : "" ) + " but got " + aReason , caller ) ; completed = true ; } } ; let pending ; if ( ( "cancel" in aOptions && aOptions . cancel ) || ( "returnPending" in aOptions && aOptions . returnPending ) ) { pending = aStmt . executeAsync ( listener ) ; } else { aStmt . executeAsync ( listener ) ; } if ( "cancel" in aOptions && aOptions . cancel ) pending . cancel ( ) ; let curThread = Components . classes [ "@mozilla.org/thread-manager;1" ] . getService ( ) . currentThread ; while ( ! completed && ! _quit ) curThread . processNextEvent ( true ) ; return pending ; }
Execute the given statement asynchronously, spinning an event loop until the
 async statement completes.
Execute the given statement asynchronously spinning an event loop until the async statement completes .
// array // paranoia check // Only get a pending reference if we're supposed to do. // (note: This does not stop XPConnect from holding onto one currently.)