Bug 1446951 - 4 - Make QueriesToQueryString and QueryStringToQueries singular. r=standard8
authorMarco Bonardo <mbonardo@mozilla.com>
Fri, 16 Mar 2018 18:43:57 +0100
changeset 409421 cae9cbaae29e4a47bfd2b49fb86ac78124db6a11
parent 409420 85d301fe0bb082f205f420b9970550ec05fb9563
child 409422 ea8cf03dc221f67f7585005698e23ab79443b918
push id61521
push usermak77@bonardo.net
push dateThu, 22 Mar 2018 09:21:03 +0000
treeherderautoland@d509647cc1d7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersstandard8
bugs1446951
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1446951 - 4 - Make QueriesToQueryString and QueryStringToQueries singular. r=standard8 MozReview-Commit-ID: K8x2x0kARDn
browser/components/places/PlacesUIUtils.jsm
browser/components/places/content/browserPlacesViews.js
browser/components/places/content/tree.xml
browser/components/places/tests/browser/browser_library_middleclick.js
browser/components/places/tests/browser/browser_library_search.js
browser/components/places/tests/chrome/test_bug549192.xul
browser/components/places/tests/chrome/test_bug549491.xul
browser/components/places/tests/chrome/test_treeview_date.xul
toolkit/components/downloads/DownloadHistory.jsm
toolkit/components/places/PlacesUtils.jsm
toolkit/components/places/nsINavHistoryService.idl
toolkit/components/places/nsNavHistoryQuery.cpp
toolkit/components/places/nsNavHistoryResult.cpp
toolkit/components/places/tests/bookmarks/test_405938_restore_queries.js
toolkit/components/places/tests/queries/test_excludeQueries.js
toolkit/components/places/tests/queries/test_options_inherit.js
toolkit/components/places/tests/queries/test_queryMultipleFolder.js
toolkit/components/places/tests/queries/test_querySerialization.js
toolkit/components/places/tests/queries/test_tags.js
toolkit/components/places/tests/queries/test_transitions.js
toolkit/components/places/tests/unit/test_399264_query_to_string.js
toolkit/components/places/tests/unit/test_399264_string_to_query.js
toolkit/components/places/tests/unit/test_433525_hasChildren_crash.js
toolkit/components/places/tests/unit/test_null_interfaces.js
toolkit/components/places/tests/unit/test_placeURIs.js
--- a/browser/components/places/PlacesUIUtils.jsm
+++ b/browser/components/places/PlacesUIUtils.jsm
@@ -816,33 +816,28 @@ var PlacesUIUtils = {
    * @param queryString
    *        the query string to check (a place: href)
    * @return whether or not queryString represents a folder shortcut.
    * @throws if queryString is malformed.
    */
   isFolderShortcutQueryString(queryString) {
     // Based on GetSimpleBookmarksQueryFolder in nsNavHistory.cpp.
 
-    let queriesParam = { }, optionsParam = { };
-    PlacesUtils.history.queryStringToQueries(queryString,
-                                             queriesParam,
-                                             { },
-                                             optionsParam);
-    let queries = queries.value;
-    if (queries.length == 0)
-      throw new Error(`Invalid place: uri: ${queryString}`);
-    return queries.length == 1 &&
-           queries[0].folderCount == 1 &&
-           !queries[0].hasBeginTime &&
-           !queries[0].hasEndTime &&
-           !queries[0].hasDomain &&
-           !queries[0].hasURI &&
-           !queries[0].hasSearchTerms &&
-           !queries[0].tags.length == 0 &&
-           optionsParam.value.maxResults == 0;
+    let query = {}, options = {};
+    PlacesUtils.history.queryStringToQuery(queryString, query, options);
+    query = query.value;
+    options = options.value;
+    return query.folderCount == 1 &&
+           !query.hasBeginTime &&
+           !query.hasEndTime &&
+           !query.hasDomain &&
+           !query.hasURI &&
+           !query.hasSearchTerms &&
+           !query.tags.length == 0 &&
+           options.maxResults == 0;
   },
 
   /**
    * Helpers for consumers of editBookmarkOverlay which don't have a node as their input.
    *
    * Given a bookmark object for either a url bookmark or a folder, returned by
    * Bookmarks.fetch (see Bookmark.jsm), this creates a node-like object suitable for
    * initialising the edit overlay with it.
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -48,20 +48,19 @@ PlacesViewBase.prototype = {
   _place: "",
   get place() {
     return this._place;
   },
   set place(val) {
     this._place = val;
 
     let history = PlacesUtils.history;
-    let queries = { }, options = { };
-    history.queryStringToQueries(val, queries, { }, options);
-    let query = queries.value.length ? queries.value[0] : history.getNewQuery();
-    let result = history.executeQuery(query, options.value);
+    let query = {}, options = {};
+    history.queryStringToQuery(val, query, options);
+    let result = history.executeQuery(query.value, options.value);
     result.addObserver(this);
     return val;
   },
 
   _result: null,
   get result() {
     return this._result;
   },
--- a/browser/components/places/content/tree.xml
+++ b/browser/components/places/content/tree.xml
@@ -282,25 +282,19 @@
       <!-- nsIPlacesView -->
       <property name="place">
         <getter><![CDATA[
           return this.getAttribute("place");
         ]]></getter>
         <setter><![CDATA[
           this.setAttribute("place", val);
 
-          var queriesRef = { };
-          var queryCountRef = { };
-          var optionsRef = { };
-          PlacesUtils.history.queryStringToQueries(val, queriesRef, queryCountRef, optionsRef);
-          if (!optionsRef.value)
-            optionsRef.value = PlacesUtils.history.getNewQueryOptions();
-          let query = queriesRef.value.length ? queriesRef.value[0] : PlacesUtils.history.getNewQuery();
-
-          this.load(query, optionsRef.value);
+          let query = {}, options = {};
+          PlacesUtils.history.queryStringToQuery(val, query, options);
+          this.load(query.value, options.value);
 
           return val;
         ]]></setter>
       </property>
 
       <!-- nsIPlacesView -->
       <property name="hasSelection">
         <getter><![CDATA[
--- a/browser/components/places/tests/browser/browser_library_middleclick.js
+++ b/browser/components/places/tests/browser/browser_library_middleclick.js
@@ -136,17 +136,17 @@ gTests.push({
     // Create a bookmarks query containing our bookmarks.
     var hs = PlacesUtils.history;
     var options = hs.getNewQueryOptions();
     options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS;
     var query = hs.getNewQuery();
     // The colon included in the terms selects only about: URIs. If not included
     // we also may get pages like about.html included in the query result.
     query.searchTerms = "about:";
-    var queryString = hs.queriesToQueryString([query], 1, options);
+    var queryString = hs.queryToQueryString(query, options);
     this._query = await PlacesUtils.bookmarks.insert({
       index: 0, // it must be the first
       parentGuid: PlacesUtils.bookmarks.unfiledGuid,
       title: "Query",
       url: queryString,
     });
 
     // Select unsorted bookmarks root in the left pane.
--- a/browser/components/places/tests/browser/browser_library_search.js
+++ b/browser/components/places/tests/browser/browser_library_search.js
@@ -61,23 +61,23 @@ async function search(aFolderGuid, aSear
     }
   }
 
   // Second, ensure that searching updates the content tree and search UI
   // properly.
   let searchBox = doc.getElementById("searchFilter");
   searchBox.value = aSearchStr;
   gLibrary.PlacesSearchBox.search(searchBox.value);
-  let queries = {};
-  PlacesUtils.history.queryStringToQueries(contentTree.result.root.uri, queries, {}, {});
+  let query = {};
+  PlacesUtils.history.queryStringToQuery(contentTree.result.root.uri, query, {});
   if (aSearchStr) {
-    Assert.equal(queries.value[0].searchTerms, aSearchStr,
+    Assert.equal(query.value.searchTerms, aSearchStr,
       "Content tree's searchTerms should be text in search box");
   } else {
-    Assert.equal(queries.value[0].hasSearchTerms, false,
+    Assert.equal(query.value.hasSearchTerms, false,
       "Content tree's searchTerms should not exist after search reset");
   }
 }
 
 add_task(async function test() {
   // Add visits, a bookmark and a tag.
   await PlacesTestUtils.addVisits(
     [{ uri: Services.io.newURI(TEST_URL), visitDate: Date.now() * 1000,
--- a/browser/components/places/tests/chrome/test_bug549192.xul
+++ b/browser/components/places/tests/chrome/test_bug549192.xul
@@ -85,17 +85,17 @@
              visitDate: newTimeInMicroseconds(), transition: ttype }];
 
         await PlacesTestUtils.addVisits(places);
 
         // Make a history query.
         let query = PlacesUtils.history.getNewQuery();
         let opts = PlacesUtils.history.getNewQueryOptions();
         opts.sortingMode = opts.SORT_BY_DATE_DESCENDING;
-        let queryURI = PlacesUtils.history.queriesToQueryString([query], 1, opts);
+        let queryURI = PlacesUtils.history.queryToQueryString(query, opts);
 
         // Setup the places tree contents.
         var tree = document.getElementById("tree");
         tree.place = queryURI;
 
         // loop through the rows and check them.
         let treeView = tree.view;
         let selection = treeView.selection;
--- a/browser/components/places/tests/chrome/test_bug549491.xul
+++ b/browser/components/places/tests/chrome/test_bug549491.xul
@@ -52,17 +52,17 @@
         await PlacesTestUtils.addVisits({
           uri: Services.io.newURI("http://example.tld/"),
           transition: PlacesUtils.history.TRANSITION_TYPED
         });
 
         // Make a history query.
         let query = PlacesUtils.history.getNewQuery();
         let opts = PlacesUtils.history.getNewQueryOptions();
-        let queryURI = PlacesUtils.history.queriesToQueryString([query], 1, opts);
+        let queryURI = PlacesUtils.history.queryToQueryString(query, opts);
 
         // Setup the places tree contents.
         let tree = document.getElementById("tree");
         tree.place = queryURI;
 
         let rootNode = tree.result.root;
         let obs = tree.view.QueryInterface(Ci.nsINavHistoryResultObserver);
         obs.nodeHistoryDetailsChanged(rootNode, rootNode.time, rootNode.accessCount);
--- a/browser/components/places/tests/chrome/test_treeview_date.xul
+++ b/browser/components/places/tests/chrome/test_treeview_date.xul
@@ -86,17 +86,17 @@
           url: "http://at.midnight.com/",
           title: "A bookmark at midnight",
           type: PlacesUtils.bookmarks.TYPE_BOOKMARK
         });
 
         // Make a history query.
         let query = PlacesUtils.history.getNewQuery();
         let opts = PlacesUtils.history.getNewQueryOptions();
-        let queryURI = PlacesUtils.history.queriesToQueryString([query], 1, opts);
+        let queryURI = PlacesUtils.history.queryToQueryString(query, opts);
 
         // Setup the places tree contents.
         let tree = document.getElementById("tree");
         tree.place = queryURI;
 
         // loop through the rows and check formatting
         let treeView = tree.view;
         let rc = treeView.rowCount;
--- a/toolkit/components/downloads/DownloadHistory.jsm
+++ b/toolkit/components/downloads/DownloadHistory.jsm
@@ -414,21 +414,19 @@ var DownloadHistoryList = function(publi
   // While "this._slots" contains all the data in order, the other properties
   // provide fast access for the most common operations.
   this._slots = [];
   this._slotsForUrl = new Map();
   this._slotForDownload = new WeakMap();
 
   // Start the asynchronous queries to retrieve history and session downloads.
   publicList.addView(this).catch(Cu.reportError);
-  let queries = {}, options = {};
-  PlacesUtils.history.queryStringToQueries(place, queries, {}, options);
-  let query = queries.value.length ? queries.value[0] : PlacesUtils.history.getNewQuery();
-
-  let result = PlacesUtils.history.executeQuery(query, options.value);
+  let query = {}, options = {};
+  PlacesUtils.history.queryStringToQuery(place, query, options);
+  let result = PlacesUtils.history.executeQuery(query.value, options.value);
   result.addObserver(this);
 };
 
 this.DownloadHistoryList.prototype = {
   __proto__: DownloadList.prototype,
 
   /**
    * This is set when executing the Places query.
--- a/toolkit/components/places/PlacesUtils.jsm
+++ b/toolkit/components/places/PlacesUtils.jsm
@@ -1304,21 +1304,21 @@ var PlacesUtils = {
     var expandQueries = asQuery(aNode).queryOptions.expandQueries &&
                         asQuery(aNode.parentResult.root).queryOptions.expandQueries;
 
     // If our options are exactly what we expect, directly return the node.
     if (excludeItems == aExcludeItems && expandQueries == aExpandQueries)
       return aNode;
 
     // Otherwise, get contents manually.
-    var queries = {}, options = {};
-    this.history.queryStringToQueries(aNode.uri, queries, {}, options);
+    var query = {}, options = {};
+    this.history.queryStringToQuery(aNode.uri, query, options);
     options.value.excludeItems = aExcludeItems;
     options.value.expandQueries = aExpandQueries;
-    return this.history.executeQuery(queries.value[0], options.value).root;
+    return this.history.executeQuery(query.value, options.value).root;
   },
 
   /**
    * Returns true if a container has uri nodes in its first level.
    * Has better performance than (getURLsForContainerNode(node).length > 0).
    * @param aNode
    *        The container node to search through.
    * @returns true if the node contains uri nodes, false otherwise.
--- a/toolkit/components/places/nsINavHistoryService.idl
+++ b/toolkit/components/places/nsINavHistoryService.idl
@@ -1334,34 +1334,28 @@ interface nsINavHistoryService : nsISupp
 
   /**
    * Executes a single query.
    */
   nsINavHistoryResult executeQuery(in nsINavHistoryQuery aQuery,
                                    in nsINavHistoryQueryOptions options);
 
   /**
-   * Converts a query URI-like string to an array of actual query objects.
-   * The output query array may be empty if there is
-   * no information. However, there will always be an options structure returned
-   * (if nothing is defined, it will just have the default values).
+   * Converts a query URI-like string to a query object.
    */
-  void queryStringToQueries(in AUTF8String aQueryString,
-    [array, size_is(aResultCount)] out nsINavHistoryQuery aQueries,
-    out unsigned long aResultCount,
-    out nsINavHistoryQueryOptions options);
+  void queryStringToQuery(in AUTF8String aQueryString,
+                          out nsINavHistoryQuery aQuery,
+                          out nsINavHistoryQueryOptions options);
 
   /**
    * Converts a query into an equivalent string that can be persisted. Inverse
-   * of queryStringToQueries()
+   * of queryStringToQuery()
    */
-  AUTF8String queriesToQueryString(
-    [array, size_is(aQueryCount)] in nsINavHistoryQuery aQueries,
-    in unsigned long aQueryCount,
-    in nsINavHistoryQueryOptions options);
+  AUTF8String queryToQueryString(in nsINavHistoryQuery aQuery,
+                                 in nsINavHistoryQueryOptions options);
 
   /**
    * Adds a history observer. If ownsWeak is false, the history service will
    * keep an owning reference to the observer.  If ownsWeak is true, then
    * aObserver must implement nsISupportsWeakReference, and the history service
    * will keep a weak reference to the observer.
    */
   void addObserver(in nsINavHistoryObserver observer,
--- a/toolkit/components/places/nsNavHistoryQuery.cpp
+++ b/toolkit/components/places/nsNavHistoryQuery.cpp
@@ -1,17 +1,17 @@
 //* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /**
  * This file contains the definitions of nsNavHistoryQuery,
  * nsNavHistoryQueryOptions, and those functions in nsINavHistory that directly
- * support queries (specifically QueryStringToQueries and QueriesToQueryString).
+ * support queries (specifically QueryStringToQuery and QueryToQueryString).
  */
 
 #include "mozilla/DebugOnly.h"
 
 #include "nsNavHistory.h"
 #include "nsNavBookmarks.h"
 #include "nsEscape.h"
 #include "nsCOMArray.h"
@@ -109,17 +109,16 @@ static void SetOptionsKeyUint32(const ns
 #define QUERYKEY_MAX_VISITS "maxVisits"
 #define QUERYKEY_ONLY_BOOKMARKED "onlyBookmarked"
 #define QUERYKEY_DOMAIN_IS_HOST "domainIsHost"
 #define QUERYKEY_DOMAIN "domain"
 #define QUERYKEY_FOLDER "folder"
 #define QUERYKEY_NOTANNOTATION "!annotation"
 #define QUERYKEY_ANNOTATION "annotation"
 #define QUERYKEY_URI "uri"
-#define QUERYKEY_SEPARATOR "OR"
 #define QUERYKEY_GROUP "group"
 #define QUERYKEY_SORT "sort"
 #define QUERYKEY_SORTING_ANNOTATION "sortingAnnotation"
 #define QUERYKEY_RESULT_TYPE "type"
 #define QUERYKEY_EXCLUDE_ITEMS "excludeItems"
 #define QUERYKEY_EXCLUDE_QUERIES "excludeQueries"
 #define QUERYKEY_EXCLUDE_READ_ONLY_FOLDERS "excludeReadOnlyFolders"
 #define QUERYKEY_EXPAND_QUERIES "expandQueries"
@@ -238,51 +237,45 @@ namespace PlacesFolderConversion {
       // It wasn't one of our named constants, so just convert it to a string.
       aQuery.AppendInt(aFolderID);
     }
 
     return NS_OK;
   }
 } // namespace PlacesFolderConversion
 
-// nsNavHistory::QueryStringToQueries
-//
 //    From C++ places code, you should use QueryStringToQueryArray, this is
 //    the harder-to-use XPCOM version.
 
 NS_IMETHODIMP
-nsNavHistory::QueryStringToQueries(const nsACString& aQueryString,
-                                   nsINavHistoryQuery*** aQueries,
-                                   uint32_t* aResultCount,
-                                   nsINavHistoryQueryOptions** aOptions)
+nsNavHistory::QueryStringToQuery(const nsACString& aQueryString,
+                                 nsINavHistoryQuery** _query,
+                                 nsINavHistoryQueryOptions** _options)
 {
-  NS_ENSURE_ARG_POINTER(aQueries);
-  NS_ENSURE_ARG_POINTER(aResultCount);
-  NS_ENSURE_ARG_POINTER(aOptions);
+  NS_ENSURE_ARG_POINTER(_query);
+  NS_ENSURE_ARG_POINTER(_options);
 
-  *aQueries = nullptr;
-  *aResultCount = 0;
   nsCOMPtr<nsNavHistoryQueryOptions> options;
   nsCOMArray<nsNavHistoryQuery> queries;
   nsresult rv = QueryStringToQueryArray(aQueryString, &queries,
                                         getter_AddRefs(options));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  *aResultCount = queries.Count();
-  if (queries.Count() > 0) {
-    // convert COM array to raw
-    *aQueries = static_cast<nsINavHistoryQuery**>
-                           (moz_xmalloc(sizeof(nsINavHistoryQuery*) * queries.Count()));
-    NS_ENSURE_TRUE(*aQueries, NS_ERROR_OUT_OF_MEMORY);
-    for (int32_t i = 0; i < queries.Count(); i ++) {
-      (*aQueries)[i] = queries[i];
-      NS_ADDREF((*aQueries)[i]);
-    }
+  nsCOMPtr<nsINavHistoryQuery> query;
+  if (queries.Count() == 0) {
+    NS_WARNING("Invalid Places query: ");
+    NS_WARNING(PromiseFlatCString(aQueryString).get());
+    query = new nsNavHistoryQuery();
+    options = new nsNavHistoryQueryOptions();
+  } else {
+    query = do_QueryInterface(queries[0]);
   }
-  options.forget(aOptions);
+  MOZ_ASSERT(query);
+  query.forget(_query);
+  options.forget(_options);
   return NS_OK;
 }
 
 
 // nsNavHistory::QueryStringToQueryArray
 //
 //    An internal version of QueryStringToQueries that fills a COM array for
 //    ease-of-use.
@@ -311,188 +304,178 @@ nsNavHistory::QueryStringToQueryArray(co
     return rv;
   }
 
   options.forget(aOptions);
   return NS_OK;
 }
 
 
-// nsNavHistory::QueriesToQueryString
-
 NS_IMETHODIMP
-nsNavHistory::QueriesToQueryString(nsINavHistoryQuery **aQueries,
-                                   uint32_t aQueryCount,
-                                   nsINavHistoryQueryOptions* aOptions,
-                                   nsACString& aQueryString)
+nsNavHistory::QueryToQueryString(nsINavHistoryQuery *aQuery,
+                                 nsINavHistoryQueryOptions* aOptions,
+                                 nsACString& aQueryString)
 {
-  NS_ENSURE_ARG(aQueries);
+  NS_ENSURE_ARG(aQuery);
   NS_ENSURE_ARG(aOptions);
 
   nsCOMPtr<nsNavHistoryQueryOptions> options = do_QueryInterface(aOptions);
   NS_ENSURE_TRUE(options, NS_ERROR_INVALID_ARG);
 
+  nsCOMPtr<nsNavHistoryQuery> query = do_QueryObject(aQuery);
   nsAutoCString queryString;
-  for (uint32_t queryIndex = 0; queryIndex < aQueryCount;  queryIndex ++) {
-    nsCOMPtr<nsNavHistoryQuery> query = do_QueryInterface(aQueries[queryIndex]);
-    if (queryIndex > 0) {
-      AppendAmpersandIfNonempty(queryString);
-      queryString += NS_LITERAL_CSTRING(QUERYKEY_SEPARATOR);
-    }
+  bool hasIt;
 
-    bool hasIt;
+  // begin time
+  query->GetHasBeginTime(&hasIt);
+  if (hasIt) {
+    AppendInt64KeyValueIfNonzero(queryString,
+                                 NS_LITERAL_CSTRING(QUERYKEY_BEGIN_TIME),
+                                 query, &nsINavHistoryQuery::GetBeginTime);
+    AppendUint32KeyValueIfNonzero(queryString,
+                                  NS_LITERAL_CSTRING(QUERYKEY_BEGIN_TIME_REFERENCE),
+                                  query, &nsINavHistoryQuery::GetBeginTimeReference);
+  }
 
-    // begin time
-    query->GetHasBeginTime(&hasIt);
-    if (hasIt) {
-      AppendInt64KeyValueIfNonzero(queryString,
-                                   NS_LITERAL_CSTRING(QUERYKEY_BEGIN_TIME),
-                                   query, &nsINavHistoryQuery::GetBeginTime);
-      AppendUint32KeyValueIfNonzero(queryString,
-                                    NS_LITERAL_CSTRING(QUERYKEY_BEGIN_TIME_REFERENCE),
-                                    query, &nsINavHistoryQuery::GetBeginTimeReference);
-    }
+  // end time
+  query->GetHasEndTime(&hasIt);
+  if (hasIt) {
+    AppendInt64KeyValueIfNonzero(queryString,
+                                 NS_LITERAL_CSTRING(QUERYKEY_END_TIME),
+                                 query, &nsINavHistoryQuery::GetEndTime);
+    AppendUint32KeyValueIfNonzero(queryString,
+                                  NS_LITERAL_CSTRING(QUERYKEY_END_TIME_REFERENCE),
+                                  query, &nsINavHistoryQuery::GetEndTimeReference);
+  }
 
-    // end time
-    query->GetHasEndTime(&hasIt);
-    if (hasIt) {
-      AppendInt64KeyValueIfNonzero(queryString,
-                                   NS_LITERAL_CSTRING(QUERYKEY_END_TIME),
-                                   query, &nsINavHistoryQuery::GetEndTime);
-      AppendUint32KeyValueIfNonzero(queryString,
-                                    NS_LITERAL_CSTRING(QUERYKEY_END_TIME_REFERENCE),
-                                    query, &nsINavHistoryQuery::GetEndTimeReference);
-    }
+  // search terms
+  query->GetHasSearchTerms(&hasIt);
+  if (hasIt) {
+    nsAutoString searchTerms;
+    query->GetSearchTerms(searchTerms);
+    nsCString escapedTerms;
+    if (! NS_Escape(NS_ConvertUTF16toUTF8(searchTerms), escapedTerms,
+                    url_XAlphas))
+      return NS_ERROR_OUT_OF_MEMORY;
 
-    // search terms
-    query->GetHasSearchTerms(&hasIt);
-    if (hasIt) {
-      nsAutoString searchTerms;
-      query->GetSearchTerms(searchTerms);
-      nsCString escapedTerms;
-      if (! NS_Escape(NS_ConvertUTF16toUTF8(searchTerms), escapedTerms,
-                      url_XAlphas))
-        return NS_ERROR_OUT_OF_MEMORY;
+    AppendAmpersandIfNonempty(queryString);
+    queryString += NS_LITERAL_CSTRING(QUERYKEY_SEARCH_TERMS "=");
+    queryString += escapedTerms;
+  }
 
-      AppendAmpersandIfNonempty(queryString);
-      queryString += NS_LITERAL_CSTRING(QUERYKEY_SEARCH_TERMS "=");
-      queryString += escapedTerms;
-    }
+  // min and max visits
+  int32_t minVisits;
+  if (NS_SUCCEEDED(query->GetMinVisits(&minVisits)) && minVisits >= 0) {
+    AppendAmpersandIfNonempty(queryString);
+    queryString.AppendLiteral(QUERYKEY_MIN_VISITS "=");
+    AppendInt32(queryString, minVisits);
+  }
+
+  int32_t maxVisits;
+  if (NS_SUCCEEDED(query->GetMaxVisits(&maxVisits)) && maxVisits >= 0) {
+    AppendAmpersandIfNonempty(queryString);
+    queryString.AppendLiteral(QUERYKEY_MAX_VISITS "=");
+    AppendInt32(queryString, maxVisits);
+  }
 
-    // min and max visits
-    int32_t minVisits;
-    if (NS_SUCCEEDED(query->GetMinVisits(&minVisits)) && minVisits >= 0) {
-      AppendAmpersandIfNonempty(queryString);
-      queryString.AppendLiteral(QUERYKEY_MIN_VISITS "=");
-      AppendInt32(queryString, minVisits);
-    }
+  // only bookmarked
+  AppendBoolKeyValueIfTrue(queryString,
+                           NS_LITERAL_CSTRING(QUERYKEY_ONLY_BOOKMARKED),
+                           query, &nsINavHistoryQuery::GetOnlyBookmarked);
 
-    int32_t maxVisits;
-    if (NS_SUCCEEDED(query->GetMaxVisits(&maxVisits)) && maxVisits >= 0) {
-      AppendAmpersandIfNonempty(queryString);
-      queryString.AppendLiteral(QUERYKEY_MAX_VISITS "=");
-      AppendInt32(queryString, maxVisits);
-    }
-
-    // only bookmarked
+  // domain (+ is host), only call if hasDomain, which means non-IsVoid
+  // this means we may get an empty string for the domain in the result,
+  // which is valid
+  query->GetHasDomain(&hasIt);
+  if (hasIt) {
     AppendBoolKeyValueIfTrue(queryString,
-                             NS_LITERAL_CSTRING(QUERYKEY_ONLY_BOOKMARKED),
-                             query, &nsINavHistoryQuery::GetOnlyBookmarked);
+                             NS_LITERAL_CSTRING(QUERYKEY_DOMAIN_IS_HOST),
+                             query, &nsINavHistoryQuery::GetDomainIsHost);
+    nsAutoCString domain;
+    nsresult rv = query->GetDomain(domain);
+    NS_ENSURE_SUCCESS(rv, rv);
+    nsCString escapedDomain;
+    bool success = NS_Escape(domain, escapedDomain, url_XAlphas);
+    NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
 
-    // domain (+ is host), only call if hasDomain, which means non-IsVoid
-    // this means we may get an empty string for the domain in the result,
-    // which is valid
-    query->GetHasDomain(&hasIt);
-    if (hasIt) {
-      AppendBoolKeyValueIfTrue(queryString,
-                               NS_LITERAL_CSTRING(QUERYKEY_DOMAIN_IS_HOST),
-                               query, &nsINavHistoryQuery::GetDomainIsHost);
-      nsAutoCString domain;
-      nsresult rv = query->GetDomain(domain);
-      NS_ENSURE_SUCCESS(rv, rv);
-      nsCString escapedDomain;
-      bool success = NS_Escape(domain, escapedDomain, url_XAlphas);
-      NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
+    AppendAmpersandIfNonempty(queryString);
+    queryString.AppendLiteral(QUERYKEY_DOMAIN "=");
+    queryString.Append(escapedDomain);
+  }
 
-      AppendAmpersandIfNonempty(queryString);
-      queryString.AppendLiteral(QUERYKEY_DOMAIN "=");
-      queryString.Append(escapedDomain);
-    }
+  // uri
+  query->GetHasUri(&hasIt);
+  if (hasIt) {
+    nsCOMPtr<nsIURI> uri;
+    query->GetUri(getter_AddRefs(uri));
+    NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE); // hasURI should tell is if invalid
+    nsAutoCString uriSpec;
+    nsresult rv = uri->GetSpec(uriSpec);
+    NS_ENSURE_SUCCESS(rv, rv);
+    nsAutoCString escaped;
+    bool success = NS_Escape(uriSpec, escaped, url_XAlphas);
+    NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
 
-    // uri
-    query->GetHasUri(&hasIt);
-    if (hasIt) {
-      nsCOMPtr<nsIURI> uri;
-      query->GetUri(getter_AddRefs(uri));
-      NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE); // hasURI should tell is if invalid
-      nsAutoCString uriSpec;
-      nsresult rv = uri->GetSpec(uriSpec);
-      NS_ENSURE_SUCCESS(rv, rv);
-      nsAutoCString escaped;
-      bool success = NS_Escape(uriSpec, escaped, url_XAlphas);
-      NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
-
-      AppendAmpersandIfNonempty(queryString);
-      queryString.AppendLiteral(QUERYKEY_URI "=");
-      queryString.Append(escaped);
-    }
+    AppendAmpersandIfNonempty(queryString);
+    queryString.AppendLiteral(QUERYKEY_URI "=");
+    queryString.Append(escaped);
+  }
 
-    // annotation
-    query->GetHasAnnotation(&hasIt);
-    if (hasIt) {
-      AppendAmpersandIfNonempty(queryString);
-      bool annotationIsNot;
-      query->GetAnnotationIsNot(&annotationIsNot);
-      if (annotationIsNot)
-        queryString.AppendLiteral(QUERYKEY_NOTANNOTATION "=");
-      else
-        queryString.AppendLiteral(QUERYKEY_ANNOTATION "=");
-      nsAutoCString annot;
-      query->GetAnnotation(annot);
-      nsAutoCString escaped;
-      bool success = NS_Escape(annot, escaped, url_XAlphas);
-      NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
-      queryString.Append(escaped);
-    }
+  // annotation
+  query->GetHasAnnotation(&hasIt);
+  if (hasIt) {
+    AppendAmpersandIfNonempty(queryString);
+    bool annotationIsNot;
+    query->GetAnnotationIsNot(&annotationIsNot);
+    if (annotationIsNot)
+      queryString.AppendLiteral(QUERYKEY_NOTANNOTATION "=");
+    else
+      queryString.AppendLiteral(QUERYKEY_ANNOTATION "=");
+    nsAutoCString annot;
+    query->GetAnnotation(annot);
+    nsAutoCString escaped;
+    bool success = NS_Escape(annot, escaped, url_XAlphas);
+    NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
+    queryString.Append(escaped);
+  }
 
-    // folders
-    int64_t *folders = nullptr;
-    uint32_t folderCount = 0;
-    query->GetFolders(&folderCount, &folders);
-    for (uint32_t i = 0; i < folderCount; ++i) {
-      AppendAmpersandIfNonempty(queryString);
-      queryString += NS_LITERAL_CSTRING(QUERYKEY_FOLDER "=");
-      nsresult rv = PlacesFolderConversion::AppendFolder(queryString, folders[i]);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-    free(folders);
+  // folders
+  int64_t *folders = nullptr;
+  uint32_t folderCount = 0;
+  query->GetFolders(&folderCount, &folders);
+  for (uint32_t i = 0; i < folderCount; ++i) {
+    AppendAmpersandIfNonempty(queryString);
+    queryString += NS_LITERAL_CSTRING(QUERYKEY_FOLDER "=");
+    nsresult rv = PlacesFolderConversion::AppendFolder(queryString, folders[i]);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+  free(folders);
 
-    // tags
-    const nsTArray<nsString> &tags = query->Tags();
-    for (uint32_t i = 0; i < tags.Length(); ++i) {
-      nsAutoCString escapedTag;
-      if (!NS_Escape(NS_ConvertUTF16toUTF8(tags[i]), escapedTag, url_XAlphas))
-        return NS_ERROR_OUT_OF_MEMORY;
+  // tags
+  const nsTArray<nsString> &tags = query->Tags();
+  for (uint32_t i = 0; i < tags.Length(); ++i) {
+    nsAutoCString escapedTag;
+    if (!NS_Escape(NS_ConvertUTF16toUTF8(tags[i]), escapedTag, url_XAlphas))
+      return NS_ERROR_OUT_OF_MEMORY;
 
-      AppendAmpersandIfNonempty(queryString);
-      queryString += NS_LITERAL_CSTRING(QUERYKEY_TAG "=");
-      queryString += escapedTag;
-    }
-    AppendBoolKeyValueIfTrue(queryString,
-                             NS_LITERAL_CSTRING(QUERYKEY_NOTTAGS),
-                             query,
-                             &nsINavHistoryQuery::GetTagsAreNot);
+    AppendAmpersandIfNonempty(queryString);
+    queryString += NS_LITERAL_CSTRING(QUERYKEY_TAG "=");
+    queryString += escapedTag;
+  }
+  AppendBoolKeyValueIfTrue(queryString,
+                           NS_LITERAL_CSTRING(QUERYKEY_NOTTAGS),
+                           query,
+                           &nsINavHistoryQuery::GetTagsAreNot);
 
-    // transitions
-    const nsTArray<uint32_t>& transitions = query->Transitions();
-    for (uint32_t i = 0; i < transitions.Length(); ++i) {
-      AppendAmpersandIfNonempty(queryString);
-      queryString += NS_LITERAL_CSTRING(QUERYKEY_TRANSITION "=");
-      AppendInt64(queryString, transitions[i]);
-    }
+  // transitions
+  const nsTArray<uint32_t>& transitions = query->Transitions();
+  for (uint32_t i = 0; i < transitions.Length(); ++i) {
+    AppendAmpersandIfNonempty(queryString);
+    queryString += NS_LITERAL_CSTRING(QUERYKEY_TRANSITION "=");
+    AppendInt64(queryString, transitions[i]);
   }
 
   // sorting
   if (options->SortingMode() != nsINavHistoryQueryOptions::SORT_BY_NONE) {
     AppendAmpersandIfNonempty(queryString);
     queryString += NS_LITERAL_CSTRING(QUERYKEY_SORT "=");
     AppendInt16(queryString, options->SortingMode());
     if (options->SortingMode() == nsINavHistoryQueryOptions::SORT_BY_ANNOTATION_DESCENDING ||
@@ -750,42 +733,16 @@ nsNavHistory::TokensToQueries(const nsTA
         if (!transitions.Contains(transition))
           NS_ENSURE_TRUE(transitions.AppendElement(transition),
                          NS_ERROR_OUT_OF_MEMORY);
       }
       else {
         NS_WARNING("Invalid Int32 transition value.");
       }
 
-    // new query component
-    } else if (kvp.key.EqualsLiteral(QUERYKEY_SEPARATOR)) {
-
-      if (folders.Length() != 0) {
-        query->SetFolders(folders.Elements(), folders.Length());
-        folders.Clear();
-      }
-
-      if (tags.Length() > 0) {
-        rv = query->SetTags(tags);
-        NS_ENSURE_SUCCESS(rv, rv);
-        tags.Clear();
-      }
-
-      if (transitions.Length() > 0) {
-        rv = query->SetTransitions(transitions);
-        NS_ENSURE_SUCCESS(rv, rv);
-        transitions.Clear();
-      }
-
-      query = new nsNavHistoryQuery();
-      if (! query)
-        return NS_ERROR_OUT_OF_MEMORY;
-      if (! aQueries->AppendObject(query))
-        return NS_ERROR_OUT_OF_MEMORY;
-
     // sorting mode
     } else if (kvp.key.EqualsLiteral(QUERYKEY_SORT)) {
       SetOptionsKeyUint16(kvp.value, aOptions,
                           &nsINavHistoryQueryOptions::SetSortingMode);
     // sorting annotation
     } else if (kvp.key.EqualsLiteral(QUERYKEY_SORTING_ANNOTATION)) {
       nsCString sortingAnnotation = kvp.value;
       NS_UnescapeURL(sortingAnnotation);
--- a/toolkit/components/places/nsNavHistoryResult.cpp
+++ b/toolkit/components/places/nsNavHistoryResult.cpp
@@ -2018,28 +2018,20 @@ nsresult
 nsNavHistoryQueryResultNode::VerifyQueriesSerialized()
 {
   if (!mURI.IsEmpty()) {
     return NS_OK;
   }
   MOZ_ASSERT(mQueries.Count() > 0 && mOptions,
              "Query nodes must have either a URI or query/options");
 
-  nsTArray<nsINavHistoryQuery*> flatQueries;
-  flatQueries.SetCapacity(mQueries.Count());
-  for (int32_t i = 0; i < mQueries.Count(); ++i)
-    flatQueries.AppendElement(static_cast<nsINavHistoryQuery*>
-                                         (mQueries.ObjectAt(i)));
-
   nsNavHistory* history = nsNavHistory::GetHistoryService();
   NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
-
-  nsresult rv = history->QueriesToQueryString(flatQueries.Elements(),
-                                              flatQueries.Length(),
-                                              mOriginalOptions, mURI);
+  nsCOMPtr<nsINavHistoryQuery> query = do_QueryInterface(mQueries[0]);
+  nsresult rv = history->QueryToQueryString(query, mOriginalOptions, mURI);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_STATE(!mURI.IsEmpty());
   return NS_OK;
 }
 
 
 nsresult
 nsNavHistoryQueryResultNode::FillChildren()
@@ -3091,21 +3083,19 @@ nsNavHistoryFolderResultNode::GetUri(nsA
     return NS_OK;
   }
 
   nsCOMPtr<nsINavHistoryQuery> query;
   nsresult rv = GetQuery(getter_AddRefs(query));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // make array of our 1 query
-  nsCOMArray<nsINavHistoryQuery> queries;
-  queries.AppendObject(query);
   nsNavHistory* history = nsNavHistory::GetHistoryService();
   NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
-  rv = history->QueriesToQueryString(queries.Elements(), 1, mOriginalOptions, mURI);
+  rv = history->QueryToQueryString(query, mOriginalOptions, mURI);
   NS_ENSURE_SUCCESS(rv, rv);
   aURI = mURI;
   return NS_OK;
 }
 
 
 /**
  * @return the queries that give you this bookmarks folder
--- a/toolkit/components/places/tests/bookmarks/test_405938_restore_queries.js
+++ b/toolkit/components/places/tests/bookmarks/test_405938_restore_queries.js
@@ -102,48 +102,25 @@ var test = {
     this._queryTitle2 = "query2";
     await PlacesUtils.bookmarks.insert({
       parentGuid: insertedBookmarks[0].guid,
       dateAdded,
       url: this._queryURI2,
       title: this._queryTitle2
     });
 
-    // create a query URI with _count queries (each with a folder)
-    // first get a query object for each folder
-    var queries = folderIds.map(function(aFolderId) {
-      var query = PlacesUtils.history.getNewQuery();
-      query.setFolders([aFolderId], 1);
-      return query;
-    });
-
-    var options = PlacesUtils.history.getNewQueryOptions();
-    options.queryType = options.QUERY_TYPE_BOOKMARKS;
-    this._queryURI3 =
-      PlacesUtils.history.queriesToQueryString(queries, queries.length, options);
+    // Create a query URI for most recent bookmarks with NO folders specified.
+    this._queryURI3 = "place:queryType=1&sort=12&maxResults=10&excludeQueries=1";
     this._queryTitle3 = "query3";
     await PlacesUtils.bookmarks.insert({
       parentGuid: insertedBookmarks[0].guid,
       dateAdded,
       url: this._queryURI3,
       title: this._queryTitle3
     });
-
-    // Create a query URI for most recent bookmarks with NO folders specified.
-    this._queryURI4 = "place:queryType=1&sort=12&excludeItemIfParentHasAnnotation=livemark%2FfeedURI&maxResults=10&excludeQueries=1";
-    this._queryTitle4 = "query4";
-    await PlacesUtils.bookmarks.insert({
-      parentGuid: insertedBookmarks[0].guid,
-      dateAdded,
-      url: this._queryURI4,
-      title: this._queryTitle4
-    });
-
-    dump_table("moz_bookmarks");
-    dump_table("moz_places");
   },
 
   clean() {},
 
   validate: async function validate(addExtras) {
     if (addExtras) {
       // Throw a wrench in the works by inserting some new bookmarks,
       // ensuring folder ids won't be the same, when restoring.
@@ -164,17 +141,17 @@ var test = {
 
     var folderNode = toolbar.getChild(0);
     Assert.equal(folderNode.type, folderNode.RESULT_TYPE_FOLDER);
     Assert.equal(folderNode.title, this._testRootTitle);
     folderNode.QueryInterface(Ci.nsINavHistoryQueryResultNode);
     folderNode.containerOpen = true;
 
     // |_count| folders + the query nodes
-    Assert.equal(folderNode.childCount, this._count + 4);
+    Assert.equal(folderNode.childCount, this._count + 3);
 
     for (let i = 0; i < this._count; i++) {
       var subFolder = folderNode.getChild(i);
       Assert.equal(subFolder.title, "folder" + i);
       subFolder.QueryInterface(Ci.nsINavHistoryContainerResultNode);
       subFolder.containerOpen = true;
       Assert.equal(subFolder.childCount, 1);
       var child = subFolder.getChild(0);
@@ -183,22 +160,19 @@ var test = {
     }
 
     // validate folder shortcut
     this.validateQueryNode1(folderNode.getChild(this._count));
 
     // validate folders query
     this.validateQueryNode2(folderNode.getChild(this._count + 1));
 
-    // validate multiple queries query
+    // validate recent folders query
     this.validateQueryNode3(folderNode.getChild(this._count + 2));
 
-    // validate recent folders query
-    this.validateQueryNode4(folderNode.getChild(this._count + 3));
-
     // clean up
     folderNode.containerOpen = false;
     toolbar.containerOpen = false;
   },
 
   validateQueryNode1: function validateQueryNode1(aNode) {
     Assert.equal(aNode.title, this._queryTitle1);
     Assert.ok(PlacesUtils.nodeIsFolder(aNode));
@@ -222,37 +196,22 @@ var test = {
     for (var i = 0; i < aNode.childCount; i++) {
       var child = aNode.getChild(i);
       Assert.ok(uri(child.uri).equals(uri("http://" + i)));
       Assert.equal(child.title, "bookmark" + i);
     }
     aNode.containerOpen = false;
   },
 
-  validateQueryNode3: function validateQueryNode3(aNode) {
+  validateQueryNode3(aNode) {
     Assert.equal(aNode.title, this._queryTitle3);
     Assert.ok(PlacesUtils.nodeIsQuery(aNode));
 
     aNode.QueryInterface(Ci.nsINavHistoryContainerResultNode);
     aNode.containerOpen = true;
-    Assert.equal(aNode.childCount, this._count);
-    for (var i = 0; i < aNode.childCount; i++) {
-      var child = aNode.getChild(i);
-      Assert.ok(uri(child.uri).equals(uri("http://" + i)));
-      Assert.equal(child.title, "bookmark" + i);
-    }
-    aNode.containerOpen = false;
-  },
-
-  validateQueryNode4(aNode) {
-    Assert.equal(aNode.title, this._queryTitle4);
-    Assert.ok(PlacesUtils.nodeIsQuery(aNode));
-
-    aNode.QueryInterface(Ci.nsINavHistoryContainerResultNode);
-    aNode.containerOpen = true;
     // The query will list the extra bookmarks added at the start of validate.
     Assert.equal(aNode.childCount, this._extraBookmarksCount);
     for (var i = 0; i < aNode.childCount; i++) {
       var child = aNode.getChild(i);
       Assert.equal(child.uri, `http://aaaa${i}/`);
     }
     aNode.containerOpen = false;
   },
--- a/toolkit/components/places/tests/queries/test_excludeQueries.js
+++ b/toolkit/components/places/tests/queries/test_excludeQueries.js
@@ -52,22 +52,21 @@ add_task(async function test_bookmarks_u
 
   root.containerOpen = false;
 });
 
 
 add_task(async function test_bookmarks_excludeQueries() {
   // When excluding queries, we exclude actual queries, but not folder shortcuts.
   let expectedGuids = [bm.guid, folderShortcut.guid];
-  let query = {};
-  let options = {};
+  let query = {}, options = {};
   let queryString = `place:folder=${PlacesUtils.unfiledBookmarksFolderId}&excludeQueries=1`;
-  PlacesUtils.history.queryStringToQueries(queryString, query, {}, options);
+  PlacesUtils.history.queryStringToQuery(queryString, query, options);
 
-  let root = PlacesUtils.history.executeQuery(query.value[0], options.value).root;
+  let root = PlacesUtils.history.executeQuery(query.value, options.value).root;
   root.containerOpen = true;
 
   Assert.equal(root.childCount, expectedGuids.length, "Checking root child count");
   for (let i = 0; i < expectedGuids.length; i++) {
     Assert.equal(root.getChild(i).bookmarkGuid, expectedGuids[i],
       "should have got the expected item");
   }
 
--- a/toolkit/components/places/tests/queries/test_options_inherit.js
+++ b/toolkit/components/places/tests/queries/test_options_inherit.js
@@ -81,14 +81,14 @@ async function test_query(opts, expected
   await PlacesUtils.bookmarks.remove(f);
 
   root.containerOpen = false;
 }
 
 function checkURIOptions(uri) {
   info("Checking options for uri " + uri);
   let folderOptions = { };
-  PlacesUtils.history.queryStringToQueries(uri, {}, {}, folderOptions);
+  PlacesUtils.history.queryStringToQuery(uri, {}, folderOptions);
   folderOptions = folderOptions.value;
   Assert.equal(folderOptions.excludeItems, false, "ExcludeItems should not be changed");
   Assert.equal(folderOptions.excludeQueries, false, "ExcludeQueries should not be changed");
   Assert.equal(folderOptions.expandQueries, true, "ExpandQueries should not be changed");
 }
--- a/toolkit/components/places/tests/queries/test_queryMultipleFolder.js
+++ b/toolkit/components/places/tests/queries/test_queryMultipleFolder.js
@@ -20,25 +20,22 @@ add_task(async function test_queryMultip
         parentGuid: (await PlacesUtils.promiseItemGuid(folderIds[i])),
         url: `http://Bookmark${i}_${j}.com`,
         title: ""
       });
       bookmarkIds.push(await PlacesUtils.promiseItemId(bm.guid));
     }
   }
 
-  // using queryStringToQueries
-  let query = {};
-  let options = {};
+  // using queryStringToQuery
+  let query = {}, options = {};
   let maxResults = 20;
-  let queryString = "place:" + folderIds.map((id) => {
-    return "folder=" + id;
-  }).join("&") + "&sort=5&maxResults=" + maxResults;
-  PlacesUtils.history.queryStringToQueries(queryString, query, {}, options);
-  let rootNode = PlacesUtils.history.executeQuery(query.value[0], options.value).root;
+  let queryString = `place:${folderIds.map((id) => "folder=" + id).join("&")}&sort=5&maxResults=${maxResults}`;
+  PlacesUtils.history.queryStringToQuery(queryString, query, options);
+  let rootNode = PlacesUtils.history.executeQuery(query.value, options.value).root;
   rootNode.containerOpen = true;
   let resultLength = rootNode.childCount;
   Assert.equal(resultLength, maxResults);
   for (let i = 0; i < resultLength; ++i) {
     let node = rootNode.getChild(i);
     Assert.equal(bookmarkIds[i], node.itemId, node.uri);
   }
   rootNode.containerOpen = false;
--- a/toolkit/components/places/tests/queries/test_querySerialization.js
+++ b/toolkit/components/places/tests/queries/test_querySerialization.js
@@ -29,48 +29,34 @@
  * we begin by choosing CHOOSE_HOW_MANY_SWITCHES_LO and ramp up to
  * CHOOSE_HOW_MANY_SWITCHES_HI.
  *
  * There are two more wrinkles.  First, for some switches we'd like to be able to
  * test multiple values.  For example, it seems like a good idea to test both an
  * empty string and a non-empty string for switch nsINavHistoryQuery.searchTerms.
  * When switches have more than one value for a test run, we use the Cartesian
  * product of their values to generate all possible combinations of values.
- *
- * Second, we need to also test serialization of multiple nsINavHistoryQuery
- * objects at once.  To do this, we remember the previous NUM_MULTIPLE_QUERIES
- * queries we tested individually and then serialize them together.  We do this
- * each time we test an individual query.  Thus the set of queries we test
- * together loses one query and gains another each time.
- *
+  *
  * To summarize, here's how this test works:
  *
  * - For n = CHOOSE_HOW_MANY_SWITCHES_LO to CHOOSE_HOW_MANY_SWITCHES_HI:
  *   - From the total set of switches choose all possible subsets of size n.
  *     For each of those subsets s:
  *     - Collect the test runs of each switch in subset s and take their
  *       Cartesian product.  For each sequence in the product:
  *       - Create nsINavHistoryQuery and nsINavHistoryQueryOptions objects
  *         with the chosen switches and test run values.
  *       - Serialize the query.
  *       - De-serialize and ensure that the de-serialized query objects equal
  *         the originals.
- *       - For each of the previous NUM_MULTIPLE_QUERIES
- *         nsINavHistoryQueryOptions objects o we created:
- *         - Serialize the previous NUM_MULTIPLE_QUERIES nsINavHistoryQuery
- *           objects together with o.
- *         - De-serialize and ensure that the de-serialized query objects
- *           equal the originals.
  */
 
 const CHOOSE_HOW_MANY_SWITCHES_LO = 1;
 const CHOOSE_HOW_MANY_SWITCHES_HI = 2;
 
-const NUM_MULTIPLE_QUERIES        = 2;
-
 // The switches are represented by objects below, in arrays querySwitches and
 // queryOptionSwitches.  Use them to set up test runs.
 //
 // Some switches have special properties (where noted), but all switches must
 // have the following properties:
 //
 //   matches: A function that takes two nsINavHistoryQuery objects (in the case
 //            of nsINavHistoryQuery switches) or two nsINavHistoryQueryOptions
@@ -654,18 +640,16 @@ function queryObjsEqual(aSwitches, aObj1
  *
  * @param aHowManyLo
  *        the size of the switch subsets to start with
  * @param aHowManyHi
  *        the size of the switch subsets to end with (inclusive)
  */
 function runQuerySequences(aHowManyLo, aHowManyHi) {
   var allSwitches = querySwitches.concat(queryOptionSwitches);
-  var prevQueries = [];
-  var prevOpts = [];
 
   // Choose aHowManyLo switches up to aHowManyHi switches.
   for (let howMany = aHowManyLo; howMany <= aHowManyHi; howMany++) {
     let numIters = 0;
     print("CHOOSING " + howMany + " SWITCHES");
 
     // Choose all subsets of size howMany from allSwitches.
     choose(allSwitches, howMany, function(chosenSwitches) {
@@ -691,79 +675,43 @@ function runQuerySequences(aHowManyLo, a
       // ]
       cartProd(runs, function(runSet) {
         // Create a new query, apply the switches in runSet, and test it.
         var query = PlacesUtils.history.getNewQuery();
         var opts = PlacesUtils.history.getNewQueryOptions();
         for (let i = 0; i < runSet.length; i++) {
           runSet[i](query, opts);
         }
-        serializeDeserialize([query], opts);
-
-        // Test the previous NUM_MULTIPLE_QUERIES queries together.
-        prevQueries.push(query);
-        prevOpts.push(opts);
-        if (prevQueries.length >= NUM_MULTIPLE_QUERIES) {
-          // We can serialize multiple nsINavHistoryQuery objects together but
-          // only one nsINavHistoryQueryOptions object with them.  So, test each
-          // of the previous NUM_MULTIPLE_QUERIES nsINavHistoryQueryOptions.
-          for (let i = 0; i < prevOpts.length; i++) {
-            serializeDeserialize(prevQueries, prevOpts[i]);
-          }
-          prevQueries.shift();
-          prevOpts.shift();
-        }
+        serializeDeserialize(query, opts);
       });
     });
   }
   print("\n");
 }
 
 /**
- * Serializes the nsINavHistoryQuery objects in aQueryArr and the
+ * Serializes the nsINavHistoryQuery objects in aQuery and the
  * nsINavHistoryQueryOptions object aQueryOptions, de-serializes the
  * serialization, and ensures (using do_check_* functions) that the
  * de-serialized objects equal the originals.
  *
- * @param aQueryArr
- *        an array containing nsINavHistoryQuery objects
+ * @param aQuery
+ *        an nsINavHistoryQuery object
  * @param aQueryOptions
  *        an nsINavHistoryQueryOptions object
  */
-function serializeDeserialize(aQueryArr, aQueryOptions) {
-  var queryStr = PlacesUtils.history.queriesToQueryString(aQueryArr,
-                                                        aQueryArr.length,
-                                                        aQueryOptions);
+function serializeDeserialize(aQuery, aQueryOptions) {
+  let queryStr = PlacesUtils.history.queryToQueryString(aQuery, aQueryOptions);
   print("  " + queryStr);
-  var queryArr2 = {};
-  var opts2 = {};
-  PlacesUtils.history.queryStringToQueries(queryStr, queryArr2, {}, opts2);
-  queryArr2 = queryArr2.value;
+  let query2 = {}, opts2 = {};
+  PlacesUtils.history.queryStringToQuery(queryStr, query2, opts2);
+  query2 = query2.value;
   opts2 = opts2.value;
 
-  // The two sets of queries cannot be the same if their lengths differ.
-  Assert.equal(aQueryArr.length, queryArr2.length);
-
-  // Although the query serialization code as it is written now practically
-  // ensures that queries appear in the query string in the same order they
-  // appear in both the array to be serialized and the array resulting from
-  // de-serialization, the interface does not guarantee any ordering.  So, for
-  // each query in aQueryArr, find its equivalent in queryArr2 and delete it
-  // from queryArr2.  If queryArr2 is empty after looping through aQueryArr,
-  // the two sets of queries are equal.
-  for (let i = 0; i < aQueryArr.length; i++) {
-    let j = 0;
-    for (; j < queryArr2.length; j++) {
-      if (queryObjsEqual(querySwitches, aQueryArr[i], queryArr2[j]))
-        break;
-    }
-    if (j < queryArr2.length)
-      queryArr2.splice(j, 1);
-  }
-  Assert.equal(queryArr2.length, 0);
+  Assert.ok(queryObjsEqual(querySwitches, aQuery, query2));
 
   // Finally check the query options objects.
   Assert.ok(queryObjsEqual(queryOptionSwitches, aQueryOptions, opts2));
 }
 
 /**
  * Convenience function for switches that have simple values.  This is attached
  * to switch objects.  See querySwitches and queryOptionSwitches arrays above.
--- a/toolkit/components/places/tests/queries/test_tags.js
+++ b/toolkit/components/places/tests/queries/test_tags.js
@@ -623,17 +623,17 @@ async function task_doWithVisit(aTags, a
   await PlacesTestUtils.addVisits(TEST_URI);
   PlacesUtils.tagging.tagURI(TEST_URI, aTags);
   await aCallback(TEST_URI);
   PlacesUtils.tagging.untagURI(TEST_URI, aTags);
   await task_cleanDatabase();
 }
 
 /**
- * queriesToQueryString() encodes every character in the query URI that doesn't
+ * queryToQueryString() encodes every character in the query URI that doesn't
  * match /[a-zA-Z]/.  There's no simple JavaScript function that does the same,
  * but encodeURIComponent() comes close, only missing some punctuation.  This
  * function takes care of all of that.
  *
  * @param  aTag
  *         A tag name to encode
  * @return A UTF-8 escaped string suitable for inclusion in a query URI
  */
@@ -728,17 +728,17 @@ function queryResultsAre(aResultRoot, aE
  *
  * @param  aQuery
  *         An nsINavHistoryQuery
  * @param  aQueryOpts
  *         An nsINavHistoryQueryOptions
  * @return The query's URI
  */
 function queryURI(aQuery, aQueryOpts) {
-  return PlacesUtils.history.queriesToQueryString([aQuery], 1, aQueryOpts);
+  return PlacesUtils.history.queryToQueryString(aQuery, aQueryOpts);
 }
 
 /**
  * Ensures that the arrays contain the same elements and, optionally, in the
  * same order.
  */
 function setsAreEqual(aArr1, aArr2, aIsOrdered) {
   Assert.equal(aArr1.length, aArr2.length);
--- a/toolkit/components/places/tests/queries/test_transitions.js
+++ b/toolkit/components/places/tests/queries/test_transitions.js
@@ -124,22 +124,20 @@ add_task(async function test_transitions
                          "&transition=" +
                          Ci.nsINavHistoryService.TRANSITION_BOOKMARK,
                          data);
 
   // Tests the live update property of transitions.
   var query = {};
   var options = {};
   PlacesUtils.history.
-    queryStringToQueries("place:transition=" +
+    queryStringToQuery("place:transition=" +
                          Ci.nsINavHistoryService.TRANSITION_DOWNLOAD,
-                         query, {}, options);
-  query = (query.value)[0];
-  options = PlacesUtils.history.getNewQueryOptions();
-  var result = PlacesUtils.history.executeQuery(query, options);
+                         query, options);
+  var result = PlacesUtils.history.executeQuery(query.value, options.value);
   var root = result.root;
   root.containerOpen = true;
   Assert.equal(testDataDownload.length, root.childCount);
   await PlacesTestUtils.addVisits({
     uri: uri("http://getfirefox.com"),
     transition: TRANSITION_DOWNLOAD
   });
   Assert.equal(testDataDownload.length + 1, root.childCount);
@@ -148,19 +146,17 @@ add_task(async function test_transitions
 
 /*
  * Takes a query and a set of indices. The indices correspond to elements
  * of testData that are the result of the query.
  */
 function compareQueryToTestData(queryStr, data) {
   var query = {};
   var options = {};
-  PlacesUtils.history.queryStringToQueries(queryStr, query, {}, options);
-  query = query.value[0];
-  options = options.value;
-  var result = PlacesUtils.history.executeQuery(query, options);
+  PlacesUtils.history.queryStringToQuery(queryStr, query, options);
+  var result = PlacesUtils.history.executeQuery(query.value, options.value);
   var root = result.root;
   for (var i = 0; i < data.length; i++) {
     data[i] = testData[data[i]];
     data[i].isInQuery = true;
   }
   compareArrayToResult(data, root);
 }
--- a/toolkit/components/places/tests/unit/test_399264_query_to_string.js
+++ b/toolkit/components/places/tests/unit/test_399264_query_to_string.js
@@ -13,17 +13,17 @@
  */
 function query_string(aFolderID) {
   var hs = Cc["@mozilla.org/browser/nav-history-service;1"].
            getService(Ci.nsINavHistoryService);
 
   var query = hs.getNewQuery();
   query.setFolders([aFolderID], 1);
   var options = hs.getNewQueryOptions();
-  return hs.queriesToQueryString([query], 1, options);
+  return hs.queryToQueryString(query, options);
 }
 
 function run_test() {
   const QUERIES = [
       "folder=PLACES_ROOT",
       "folder=BOOKMARKS_MENU",
       "folder=TAGS",
       "folder=UNFILED_BOOKMARKS",
--- a/toolkit/components/places/tests/unit/test_399264_string_to_query.js
+++ b/toolkit/components/places/tests/unit/test_399264_string_to_query.js
@@ -8,21 +8,19 @@
  * Obtains the id of the folder obtained from the query.
  *
  * @param aQuery
  *        The query to obtain the folder id from.
  * @returns the folder id of the folder of the root node of the query.
  */
 function folder_id(aQuery) {
   info("Checking query '" + aQuery + "'\n");
-  var options = { };
-  var queries = { };
-  var size = { };
-  PlacesUtils.history.queryStringToQueries(aQuery, queries, size, options);
-  var result = PlacesUtils.history.executeQuery(queries.value, options.value);
+  let query = {}, options = {};
+  PlacesUtils.history.queryStringToQuery(aQuery, query, options);
+  var result = PlacesUtils.history.executeQuery(query.value, options.value);
   var root = result.root;
   root.containerOpen = true;
   Assert.ok(root.hasChildren);
   var folderID = root.getChild(0).parent.itemId;
   root.containerOpen = false;
   return folderID;
 }
 
--- a/toolkit/components/places/tests/unit/test_433525_hasChildren_crash.js
+++ b/toolkit/components/places/tests/unit/test_433525_hasChildren_crash.js
@@ -24,17 +24,17 @@ add_task(async function test_execute() {
   query.uri = testURI;
   var result = histsvc.executeQuery(query, options);
   var root = result.root;
 
   // check hasChildren while the container is closed
   Assert.equal(root.hasChildren, true);
 
   // now check via the saved search path
-  var queryURI = histsvc.queriesToQueryString([query], 1, options);
+  var queryURI = histsvc.queryToQueryString(query, options);
   await PlacesUtils.bookmarks.insert({
     parentGuid: PlacesUtils.bookmarks.toolbarGuid,
     title: "test query",
     url: queryURI,
   });
 
   // query for that query
   options = histsvc.getNewQueryOptions();
--- a/toolkit/components/places/tests/unit/test_null_interfaces.js
+++ b/toolkit/components/places/tests/unit/test_null_interfaces.js
@@ -6,17 +6,17 @@
  * Test bug 489872 to make sure passing nulls to nsNavHistory doesn't crash.
  */
 
 // Make an array of services to test, each specifying a class id, interface
 // and an array of function names that don't throw when passed nulls
 var testServices = [
   ["browser/nav-history-service;1",
     ["nsINavHistoryService"],
-    ["queryStringToQueries", "removePagesByTimeframe", "removePagesFromHost", "getObservers"]
+    ["queryStringToQuery", "removePagesByTimeframe", "removePagesFromHost", "getObservers"]
   ],
   ["browser/nav-bookmarks-service;1",
     ["nsINavBookmarksService", "nsINavHistoryObserver"],
     ["createFolder", "getObservers", "onFrecencyChanged", "onTitleChanged", "onDeleteURI"]
   ],
   ["browser/livemark-service;2", ["mozIAsyncLivemarks"], ["reloadLivemarks"]],
   ["browser/annotation-service;1", ["nsIAnnotationService"], ["getObservers"]],
   ["browser/favicon-service;1", ["nsIFaviconService"], []],
--- a/toolkit/components/places/tests/unit/test_placeURIs.js
+++ b/toolkit/components/places/tests/unit/test_placeURIs.js
@@ -1,40 +1,28 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-
-// Get history service
-try {
-  var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"].getService(Ci.nsINavHistoryService);
-} catch (ex) {
-  do_throw("Could not get history service\n");
-}
+function run_test() {
+  // TODO: Improve testing coverage for QueryToQueryString and QueryStringToQuery
 
-// main
-function run_test() {
-  // XXX Full testing coverage for QueriesToQueryString and
-  // QueryStringToQueries
-
-  const NHQO = Ci.nsINavHistoryQueryOptions;
   // Bug 376798
-  var query = histsvc.getNewQuery();
+  let query = PlacesUtils.history.getNewQuery();
+  let options = PlacesUtils.history.getNewQueryOptions();
   query.setFolders([PlacesUtils.bookmarks.placesRoot], 1);
-  Assert.equal(histsvc.queriesToQueryString([query], 1, histsvc.getNewQueryOptions()),
+  Assert.equal(PlacesUtils.history.queryToQueryString(query, options),
                "place:folder=PLACES_ROOT");
 
   // Bug 378828
-  var options = histsvc.getNewQueryOptions();
   options.sortingAnnotation = "test anno";
-  options.sortingMode = NHQO.SORT_BY_ANNOTATION_DESCENDING;
+  options.sortingMode = Ci.nsINavHistoryQueryOptions.SORT_BY_ANNOTATION_DESCENDING;
   var placeURI =
-    "place:folder=PLACES_ROOT&sort=" + NHQO.SORT_BY_ANNOTATION_DESCENDING +
+    "place:folder=PLACES_ROOT&sort=" + Ci.nsINavHistoryQueryOptions.SORT_BY_ANNOTATION_DESCENDING +
     "&sortingAnnotation=test%20anno";
-  Assert.equal(histsvc.queriesToQueryString([query], 1, options),
-               placeURI);
+  Assert.equal(PlacesUtils.history.queryToQueryString(query, options), placeURI);
   options = {};
-  histsvc.queryStringToQueries(placeURI, { }, {}, options);
+  PlacesUtils.history.queryStringToQuery(placeURI, {}, options);
   Assert.equal(options.value.sortingAnnotation, "test anno");
-  Assert.equal(options.value.sortingMode, NHQO.SORT_BY_ANNOTATION_DESCENDING);
+  Assert.equal(options.value.sortingMode, Ci.nsINavHistoryQueryOptions.SORT_BY_ANNOTATION_DESCENDING);
 }