Bug 489897 - implement StatementRow::NewEnumerate
authorDavid Dahl <ddahl@mozilla.com>, Shawn Wilsher <sdwilsh@shawnwilsher.com>
Mon, 12 Oct 2009 17:49:00 -0500
changeset 36770 64d3466e396454c417f26054e4a7303b68285a8a
parent 36769 b0e993f4f07e77120add72f2d0db5ad4020b28db
child 36771 6453f3ca39fce96a8528a5ff1ef737515f212d7a
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs489897
milestone1.9.3a1pre
Bug 489897 - implement StatementRow::NewEnumerate for (let colName in stmt.row) now works! r=sdwilsh r=ddahl sr=mrbkap
storage/src/mozStorageStatementRow.cpp
storage/src/mozStorageStatementRow.h
storage/test/unit/test_js_helpers_enumerate.js
--- a/storage/src/mozStorageStatementRow.cpp
+++ b/storage/src/mozStorageStatementRow.cpp
@@ -51,47 +51,55 @@ namespace mozilla {
 namespace storage {
 
 ////////////////////////////////////////////////////////////////////////////////
 //// StatementRow
 
 StatementRow::StatementRow(Statement *aStatement)
 : mStatement(aStatement)
 {
+  // Get the column count.
+  (void)mStatement->GetColumnCount(&mColumnCount);
 }
 
 NS_IMPL_ISUPPORTS2(
   StatementRow,
   mozIStorageStatementRow,
   nsIXPCScriptable
 )
 
 ////////////////////////////////////////////////////////////////////////////////
 //// nsIXPCScriptable
 
 #define XPC_MAP_CLASSNAME StatementRow
 #define XPC_MAP_QUOTED_CLASSNAME "StatementRow"
 #define XPC_MAP_WANT_GETPROPERTY
 #define XPC_MAP_WANT_NEWRESOLVE
+#define XPC_MAP_WANT_NEWENUMERATE
 #define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE
 #include "xpc_map_end.h"
 
 NS_IMETHODIMP
 StatementRow::GetProperty(nsIXPConnectWrappedNative *aWrapper,
                           JSContext *aCtx,
                           JSObject *aScopeObj,
                           jsval aId,
                           jsval *_vp,
                           PRBool *_retval)
 {
   NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED);
 
   if (JSVAL_IS_STRING(aId)) {
     nsDependentCString jsid(::JS_GetStringBytes(JSVAL_TO_STRING(aId)));
 
+    // If we are trying to get the __iterator__ property, return early.  Our
+    // NewEnumerate function will handle that.
+    if (0 == jsid.EqualsLiteral("__iterator__"))
+      return NS_OK;
+
     PRUint32 idx;
     nsresult rv = mStatement->GetColumnIndex(jsid, &idx);
     NS_ENSURE_SUCCESS(rv, rv);
     PRInt32 type;
     rv = mStatement->GetTypeOfIndex(idx, &type);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (type == mozIStorageValueArray::VALUE_TYPE_INTEGER ||
@@ -142,16 +150,79 @@ StatementRow::GetProperty(nsIXPConnectWr
       NS_ERROR("unknown column type returned, what's going on?");
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+StatementRow::NewEnumerate(nsIXPConnectWrappedNative *aWrapper,
+                           JSContext *aCtx,
+                           JSObject *aScopeObj,
+                           PRUint32 aEnumOp,
+                           jsval *_statep,
+                           jsid *_idp,
+                           PRBool *_retval)
+{
+  NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED);
+
+  switch (aEnumOp) {
+    case JSENUMERATE_INIT:
+    {
+      // Start our internal index at zero.
+      *_statep = JSVAL_ZERO;
+
+      if (_idp)
+        *_idp = INT_TO_JSVAL(mColumnCount);
+      break;
+    }
+    case JSENUMERATE_NEXT:
+    {
+      NS_ASSERTION(*_statep != JSVAL_NULL, "Internal state is null!");
+
+      // Make sure we are in range first.
+      PRUint32 index = static_cast<PRUint32>(JSVAL_TO_INT(*_statep));
+      if (index >= mColumnCount) {
+        *_statep = JSVAL_NULL;
+        return NS_OK;
+      }
+
+      // Get the name of our column.
+      nsCAutoString name;
+      nsresult rv = mStatement->GetColumnName(index, name);
+      NS_ENSURE_SUCCESS(rv, rv);
+      
+      JSString *jsname = ::JS_NewStringCopyN(aCtx, name.get(), name.Length());
+      NS_ENSURE_TRUE(jsname, NS_ERROR_OUT_OF_MEMORY);
+
+      // Set our name.
+      if (!::JS_ValueToId(aCtx, STRING_TO_JSVAL(jsname), _idp)) {
+        *_retval = PR_FALSE;
+        return NS_OK;
+      }
+
+      // And increment our index.
+      *_statep = INT_TO_JSVAL(++index);
+
+      break;
+    }
+    case JSENUMERATE_DESTROY:
+    {
+      // Clear our state.
+      *_statep = JSVAL_NULL;
+
+      break;
+    }
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 StatementRow::NewResolve(nsIXPConnectWrappedNative *aWrapper,
                          JSContext *aCtx,
                          JSObject *aScopeObj,
                          jsval aId,
                          PRUint32 aFlags,
                          JSObject **_objp,
                          PRBool *_retval)
 {
--- a/storage/src/mozStorageStatementRow.h
+++ b/storage/src/mozStorageStatementRow.h
@@ -55,16 +55,17 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_MOZISTORAGESTATEMENTROW
   NS_DECL_NSIXPCSCRIPTABLE
 
   StatementRow(Statement *aStatement);
 protected:
 
   Statement *mStatement;
+  PRUint32 mColumnCount;
 
   friend class Statement;
 };
 
 } // namespace storage
 } // namespace mozilla
 
 #endif /* _MOZSTORAGESTATEMENTROW_H_ */
--- a/storage/test/unit/test_js_helpers_enumerate.js
+++ b/storage/test/unit/test_js_helpers_enumerate.js
@@ -53,29 +53,59 @@ function test_params_enumerate()
 
   // Make sure they are right.
   let expected = ["a", "b", "c"];
   let index = 0;
   for (let name in stmt.params)
     do_check_eq(name, expected[index++]);
 }
 
+function test_row_enumerate()
+{
+  var db = getOpenedDatabase();
+  let stmt = createStatement("INSERT INTO test (driver, car) VALUES (:driver, :car)");
+  stmt.params.driver = "David";
+  stmt.params.car = "Fiat 500";
+  try {
+    stmt.execute();
+  }
+  finally {
+    stmt.finalize();
+  }
+
+  stmt = createStatement("SELECT driver, car FROM test WHERE driver = :driver");
+  stmt.params.driver = "David";
+
+  try {
+    do_check_true(stmt.executeStep());
+    let expected = ["driver", "car"];
+    let index = 0;
+    for (let colName in stmt.row)
+      do_check_eq(colName, expected[index++]);
+  }
+  finally {
+    stmt.finalize();
+  }
+}
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Test Runner
 
 let tests = [
   test_params_enumerate,
+  test_row_enumerate,
 ];
 function run_test()
 {
   cleanup();
 
   // Create our database.
   getOpenedDatabase().executeSimpleSQL(
     "CREATE TABLE test (" +
-      "id INTEGER PRIMARY KEY " +
+      "id INTEGER PRIMARY KEY, " +
+      "driver VARCHAR(32) NULL, " +
+      "car VARCHAR(32) NULL" +
     ")"
   );
 
   // Run the tests.
   tests.forEach(function(test) test());
 }