Bug 627487 - Bookmark JSON backup should contain new-style GUIDs. r=mano

This commit is contained in:
Raymond Lee 2013-09-03 11:56:25 +08:00
parent cd3248ea14
commit fcf5512d6d
9 changed files with 202 additions and 25 deletions

View File

@ -23,7 +23,7 @@ interface nsINavHistoryQueryOptions;
interface nsINavHistoryResult;
interface nsINavHistoryBatchCallback;
[scriptable, uuid(081452e5-be5c-4038-a5ea-f1f34cb6fd81)]
[scriptable, uuid(91d104bb-17ef-404b-9f9a-d9ed8de6824c)]
interface nsINavHistoryResultNode : nsISupports
{
/**
@ -154,6 +154,19 @@ interface nsINavHistoryResultNode : nsISupports
* for the uri represented by this node. Otherwise this is an empty string.
*/
readonly attribute AString tags;
/**
* The unique ID associated with the page. It my return an empty string
* if the result node is a non-URI node.
*/
readonly attribute ACString pageGuid;
/**
* The unique ID associated with the bookmark. It returns an empty string
* if the result node is not associated with a bookmark, a folder or a
* separator.
*/
readonly attribute ACString bookmarkGuid;
};
@ -162,7 +175,7 @@ interface nsINavHistoryResultNode : nsISupports
* Bookmark folders and places queries will be QueryResultNodes which extends
* these items.
*/
[scriptable, uuid(62534d3c-1b3f-401e-b3ba-b911f57f8a29)]
[scriptable, uuid(5bac9734-c0ff-44eb-8d19-da88462ff6da)]
interface nsINavHistoryContainerResultNode : nsINavHistoryResultNode
{
@ -262,7 +275,7 @@ interface nsINavHistoryContainerResultNode : nsINavHistoryResultNode
* generated this node, this item will report it has no children and never try
* to populate itself.
*/
[scriptable, uuid(ea17745a-1852-4155-a98f-d1dd1763b3df)]
[scriptable, uuid(a4144c3e-8125-46d5-a719-831bec8095f4)]
interface nsINavHistoryQueryResultNode : nsINavHistoryContainerResultNode
{
/**

View File

@ -50,10 +50,10 @@
using namespace mozilla;
// These columns sit to the right of the kGetInfoIndex_* columns.
const int32_t nsNavBookmarks::kGetChildrenIndex_Position = 14;
const int32_t nsNavBookmarks::kGetChildrenIndex_Type = 15;
const int32_t nsNavBookmarks::kGetChildrenIndex_PlaceID = 16;
const int32_t nsNavBookmarks::kGetChildrenIndex_Guid = 17;
const int32_t nsNavBookmarks::kGetChildrenIndex_Guid = 15;
const int32_t nsNavBookmarks::kGetChildrenIndex_Position = 16;
const int32_t nsNavBookmarks::kGetChildrenIndex_Type = 17;
const int32_t nsNavBookmarks::kGetChildrenIndex_PlaceID = 18;
using namespace mozilla::places;
@ -1062,8 +1062,8 @@ nsNavBookmarks::GetDescendantChildren(int64_t aFolderId,
nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
"SELECT h.id, h.url, IFNULL(b.title, h.title), h.rev_host, h.visit_count, "
"h.last_visit_date, f.url, b.id, b.dateAdded, b.lastModified, "
"b.parent, null, h.frecency, h.hidden, b.position, b.type, b.fk, "
"b.guid "
"b.parent, null, h.frecency, h.hidden, h.guid, b.guid, "
"b.position, b.type, b.fk "
"FROM moz_bookmarks b "
"LEFT JOIN moz_places h ON b.fk = h.id "
"LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
@ -1743,6 +1743,7 @@ nsNavBookmarks::ResultNodeForContainer(int64_t aItemId,
(*aNode)->mDateAdded = bookmark.dateAdded;
(*aNode)->mLastModified = bookmark.lastModified;
(*aNode)->mBookmarkGuid = bookmark.guid;
NS_ADDREF(*aNode);
return NS_OK;
@ -1766,8 +1767,8 @@ nsNavBookmarks::QueryFolderChildren(
nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
"SELECT h.id, h.url, IFNULL(b.title, h.title), h.rev_host, h.visit_count, "
"h.last_visit_date, f.url, b.id, b.dateAdded, b.lastModified, "
"b.parent, null, h.frecency, h.hidden, b.position, b.type, b.fk, "
"b.guid "
"b.parent, null, h.frecency, h.hidden, h.guid, b.guid, "
"b.position, b.type, b.fk "
"FROM moz_bookmarks b "
"LEFT JOIN moz_places h ON b.fk = h.id "
"LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
@ -1877,6 +1878,9 @@ nsNavBookmarks::ProcessFolderNodeRow(
// moz_bookmarks.position.
node->mBookmarkIndex = aCurrentIndex;
rv = aRow->GetUTF8String(kGetChildrenIndex_Guid, node->mBookmarkGuid);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(aChildren->AppendObject(node), NS_ERROR_OUT_OF_MEMORY);
return NS_OK;
@ -1900,8 +1904,8 @@ nsNavBookmarks::QueryFolderChildrenAsync(
nsCOMPtr<mozIStorageAsyncStatement> stmt = mDB->GetAsyncStatement(
"SELECT h.id, h.url, IFNULL(b.title, h.title), h.rev_host, h.visit_count, "
"h.last_visit_date, f.url, b.id, b.dateAdded, b.lastModified, "
"b.parent, null, h.frecency, h.hidden, b.position, b.type, b.fk, "
"b.guid "
"b.parent, null, h.frecency, h.hidden, h.guid, b.guid, "
"b.position, b.type, b.fk "
"FROM moz_bookmarks b "
"LEFT JOIN moz_places h ON b.fk = h.id "
"LEFT JOIN moz_favicons f ON h.favicon_id = f.id "

View File

@ -368,7 +368,6 @@ private:
static const int32_t kGetChildrenIndex_Position;
static const int32_t kGetChildrenIndex_Type;
static const int32_t kGetChildrenIndex_PlaceID;
static const int32_t kGetChildrenIndex_FolderTitle;
static const int32_t kGetChildrenIndex_Guid;
class RemoveFolderTransaction MOZ_FINAL : public nsITransaction {

View File

@ -250,6 +250,7 @@ const int32_t nsNavHistory::kGetInfoIndex_ItemParentId = 10;
const int32_t nsNavHistory::kGetInfoIndex_ItemTags = 11;
const int32_t nsNavHistory::kGetInfoIndex_Frecency = 12;
const int32_t nsNavHistory::kGetInfoIndex_Hidden = 13;
const int32_t nsNavHistory::kGetInfoIndex_Guid = 14;
PLACES_FACTORY_SINGLETON_IMPLEMENTATION(nsNavHistory, gHistoryService)
@ -1395,7 +1396,7 @@ PlacesSQLQueryBuilder::SelectAsURI()
mQueryString = NS_LITERAL_CSTRING(
"SELECT h.id, h.url, h.title AS page_title, h.rev_host, h.visit_count, "
"h.last_visit_date, f.url, null, null, null, null, ") +
tagsSqlFragment + NS_LITERAL_CSTRING(", h.frecency, h.hidden "
tagsSqlFragment + NS_LITERAL_CSTRING(", h.frecency, h.hidden, h.guid "
"FROM moz_places h "
"LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
// WHERE 1 is a no-op since additonal conditions will start with AND.
@ -1421,7 +1422,7 @@ PlacesSQLQueryBuilder::SelectAsURI()
"SELECT b2.fk, h.url, COALESCE(b2.title, h.title) AS page_title, "
"h.rev_host, h.visit_count, h.last_visit_date, f.url, b2.id, "
"b2.dateAdded, b2.lastModified, b2.parent, ") +
tagsSqlFragment + NS_LITERAL_CSTRING(", h.frecency, h.hidden "
tagsSqlFragment + NS_LITERAL_CSTRING(", h.frecency, h.hidden, h.guid "
"FROM moz_bookmarks b2 "
"JOIN (SELECT b.fk "
"FROM moz_bookmarks b "
@ -1445,7 +1446,7 @@ PlacesSQLQueryBuilder::SelectAsURI()
"SELECT b.fk, h.url, COALESCE(b.title, h.title) AS page_title, "
"h.rev_host, h.visit_count, h.last_visit_date, f.url, b.id, "
"b.dateAdded, b.lastModified, b.parent, ") +
tagsSqlFragment + NS_LITERAL_CSTRING(", h.frecency, h.hidden "
tagsSqlFragment + NS_LITERAL_CSTRING(", h.frecency, h.hidden, h.guid "
"FROM moz_bookmarks b "
"JOIN moz_places h ON b.fk = h.id "
"LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
@ -1477,7 +1478,7 @@ PlacesSQLQueryBuilder::SelectAsVisit()
mQueryString = NS_LITERAL_CSTRING(
"SELECT h.id, h.url, h.title AS page_title, h.rev_host, h.visit_count, "
"v.visit_date, f.url, null, null, null, null, ") +
tagsSqlFragment + NS_LITERAL_CSTRING(", h.frecency, h.hidden "
tagsSqlFragment + NS_LITERAL_CSTRING(", h.frecency, h.hidden, h.guid "
"FROM moz_places h "
"JOIN moz_historyvisits v ON h.id = v.place_id "
"LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
@ -2002,7 +2003,7 @@ nsNavHistory::ConstructQueryString(
queryString = NS_LITERAL_CSTRING(
"SELECT h.id, h.url, h.title AS page_title, h.rev_host, h.visit_count, h.last_visit_date, "
"f.url, null, null, null, null, ") +
tagsSqlFragment + NS_LITERAL_CSTRING(", h.frecency, h.hidden "
tagsSqlFragment + NS_LITERAL_CSTRING(", h.frecency, h.hidden, h.guid "
"FROM moz_places h "
"LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
"WHERE h.hidden = 0 "
@ -3800,7 +3801,7 @@ nsNavHistory::RowToResult(mozIStorageValueArray* aRow,
if (IsQueryURI(url)) {
// special case "place:" URIs: turn them into containers
// We should never expose the history title for query nodes if the
// bookmark-item's title is set to null (the history title may be the
// query string without the place: prefix). Thus we call getItemTitle
@ -3855,6 +3856,9 @@ nsNavHistory::RowToResult(mozIStorageValueArray* aRow,
resultNode->mTags.Assign(tags);
}
rv = aRow->GetUTF8String(kGetInfoIndex_Guid, resultNode->mPageGuid);
NS_ENSURE_SUCCESS(rv, rv);
resultNode.forget(aResult);
return NS_OK;
}
@ -3868,6 +3872,9 @@ nsNavHistory::RowToResult(mozIStorageValueArray* aRow,
if (!tags.IsVoid())
resultNode->mTags.Assign(tags);
rv = aRow->GetUTF8String(kGetInfoIndex_Guid, resultNode->mPageGuid);
NS_ENSURE_SUCCESS(rv, rv);
resultNode.forget(aResult);
return NS_OK;
}
@ -3966,7 +3973,7 @@ nsNavHistory::VisitIdToResultNode(int64_t visitId,
statement = mDB->GetStatement(NS_LITERAL_CSTRING(
"SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
"v.visit_date, f.url, null, null, null, null, "
) + tagsFragment + NS_LITERAL_CSTRING(", h.frecency, h.hidden "
) + tagsFragment + NS_LITERAL_CSTRING(", h.frecency, h.hidden, h.guid "
"FROM moz_places h "
"JOIN moz_historyvisits v ON h.id = v.place_id "
"LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
@ -3980,7 +3987,7 @@ nsNavHistory::VisitIdToResultNode(int64_t visitId,
statement = mDB->GetStatement(NS_LITERAL_CSTRING(
"SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
"h.last_visit_date, f.url, null, null, null, null, "
) + tagsFragment + NS_LITERAL_CSTRING(", h.frecency, h.hidden "
) + tagsFragment + NS_LITERAL_CSTRING(", h.frecency, h.hidden, h.guid "
"FROM moz_places h "
"JOIN moz_historyvisits v ON h.id = v.place_id "
"LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
@ -4026,7 +4033,7 @@ nsNavHistory::BookmarkIdToResultNode(int64_t aBookmarkId, nsNavHistoryQueryOptio
"SELECT b.fk, h.url, COALESCE(b.title, h.title), "
"h.rev_host, h.visit_count, h.last_visit_date, f.url, b.id, "
"b.dateAdded, b.lastModified, b.parent, "
) + tagsFragment + NS_LITERAL_CSTRING(", h.frecency, h.hidden "
) + tagsFragment + NS_LITERAL_CSTRING(", h.frecency, h.hidden, h.guid "
"FROM moz_bookmarks b "
"JOIN moz_places h ON b.fk = h.id "
"LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
@ -4065,7 +4072,7 @@ nsNavHistory::URIToResultNode(nsIURI* aURI,
nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(NS_LITERAL_CSTRING(
"SELECT h.id, :page_url, h.title, h.rev_host, h.visit_count, "
"h.last_visit_date, f.url, null, null, null, null, "
) + tagsFragment + NS_LITERAL_CSTRING(", h.frecency, h.hidden "
) + tagsFragment + NS_LITERAL_CSTRING(", h.frecency, h.hidden, h.guid "
"FROM moz_places h "
"LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
"WHERE h.url = :page_url ")

View File

@ -217,6 +217,7 @@ public:
static const int32_t kGetInfoIndex_ItemTags;
static const int32_t kGetInfoIndex_Frecency;
static const int32_t kGetInfoIndex_Hidden;
static const int32_t kGetInfoIndex_Guid;
int64_t GetTagsFolder();

View File

@ -233,6 +233,19 @@ nsNavHistoryResultNode::GetTags(nsAString& aTags) {
return NS_OK;
}
NS_IMETHODIMP
nsNavHistoryResultNode::GetPageGuid(nsACString& aPageGuid) {
aPageGuid = mPageGuid;
return NS_OK;
}
NS_IMETHODIMP
nsNavHistoryResultNode::GetBookmarkGuid(nsACString& aBookmarkGuid) {
aBookmarkGuid = mBookmarkGuid;
return NS_OK;
}
void
nsNavHistoryResultNode::OnRemoving()

View File

@ -245,7 +245,11 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryResult, NS_NAVHISTORYRESULT_IID)
NS_IMETHOD GetParentResult(nsINavHistoryResult** aResult) \
{ return nsNavHistoryResultNode::GetParentResult(aResult); } \
NS_IMETHOD GetTags(nsAString& aTags) \
{ return nsNavHistoryResultNode::GetTags(aTags); }
{ return nsNavHistoryResultNode::GetTags(aTags); } \
NS_IMETHOD GetPageGuid(nsACString& aPageGuid) \
{ return nsNavHistoryResultNode::GetPageGuid(aPageGuid); } \
NS_IMETHOD GetBookmarkGuid(nsACString& aBookmarkGuid) \
{ return nsNavHistoryResultNode::GetBookmarkGuid(aBookmarkGuid); }
#define NS_FORWARD_COMMON_RESULTNODE_TO_BASE \
NS_FORWARD_COMMON_RESULTNODE_TO_BASE_NO_GETITEMMID \
@ -274,6 +278,8 @@ public:
NS_IMETHOD GetUri(nsACString& aURI)
{ aURI = mURI; return NS_OK; }
NS_IMETHOD GetTags(nsAString& aTags);
NS_IMETHOD GetPageGuid(nsACString& aPageGuid);
NS_IMETHOD GetBookmarkGuid(nsACString& aBookmarkGuid);
virtual void OnRemoving();
@ -376,6 +382,12 @@ public:
// Transition type used when this node represents a single visit.
uint32_t mTransitionType;
// Unique Id of the page.
nsCString mPageGuid;
// Unique Id of the bookmark.
nsCString mBookmarkGuid;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryResultNode, NS_NAVHISTORYRESULTNODE_IID)

View File

@ -0,0 +1,127 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
const bmsvc = PlacesUtils.bookmarks;
const histsvc = PlacesUtils.history;
function run_test() {
run_next_test();
}
add_task(function test_addBookmarksAndCheckGuids() {
let folder = bmsvc.createFolder(bmsvc.placesRoot, "test folder", bmsvc.DEFAULT_INDEX);
let b1 = bmsvc.insertBookmark(folder, uri("http://test1.com/"),
bmsvc.DEFAULT_INDEX, "1 title");
let b2 = bmsvc.insertBookmark(folder, uri("http://test2.com/"),
bmsvc.DEFAULT_INDEX, "2 title");
let b3 = bmsvc.insertBookmark(folder, uri("http://test3.com/"),
bmsvc.DEFAULT_INDEX, "3 title");
let s1 = bmsvc.insertSeparator(folder, bmsvc.DEFAULT_INDEX);
let f1 = bmsvc.createFolder(folder, "test folder 2", bmsvc.DEFAULT_INDEX);
let options = histsvc.getNewQueryOptions();
options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS;
let query = histsvc.getNewQuery();
query.setFolders([folder], 1);
let result = histsvc.executeQuery(query, options);
let root = result.root;
root.containerOpen = true;
do_check_eq(root.childCount, 5);
// check bookmark guids
let bookmarkGuidZero = root.getChild(0).bookmarkGuid;
do_check_eq(bookmarkGuidZero.length, 12);
// bookmarks have bookmark guids
do_check_eq(root.getChild(1).bookmarkGuid.length, 12);
do_check_eq(root.getChild(2).bookmarkGuid.length, 12);
// separator has bookmark guid
do_check_eq(root.getChild(3).bookmarkGuid.length, 12);
// folder has bookmark guid
do_check_eq(root.getChild(4).bookmarkGuid.length, 12);
// all bookmark guids are different.
do_check_neq(bookmarkGuidZero, root.getChild(1).bookmarkGuid);
do_check_neq(root.getChild(1).bookmarkGuid, root.getChild(2).bookmarkGuid);
do_check_neq(root.getChild(2).bookmarkGuid, root.getChild(3).bookmarkGuid);
do_check_neq(root.getChild(3).bookmarkGuid, root.getChild(4).bookmarkGuid);
// check page guids
let pageGuidZero = root.getChild(0).pageGuid;
do_check_eq(pageGuidZero.length, 12);
// bookmarks have page guids
do_check_eq(root.getChild(1).pageGuid.length, 12);
do_check_eq(root.getChild(2).pageGuid.length, 12);
// folder and separator don't have page guids
do_check_eq(root.getChild(3).pageGuid, "");
do_check_eq(root.getChild(4).pageGuid, "");
do_check_neq(pageGuidZero, root.getChild(1).pageGuid);
do_check_neq(root.getChild(1).pageGuid, root.getChild(2).pageGuid);
root.containerOpen = false;
remove_all_bookmarks();
});
add_task(function test_updateBookmarksAndCheckGuids() {
let folder = bmsvc.createFolder(bmsvc.placesRoot, "test folder", bmsvc.DEFAULT_INDEX);
let b1 = bmsvc.insertBookmark(folder, uri("http://test1.com/"),
bmsvc.DEFAULT_INDEX, "1 title");
let f1 = bmsvc.createFolder(folder, "test folder 2", bmsvc.DEFAULT_INDEX);
let options = histsvc.getNewQueryOptions();
options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS;
let query = histsvc.getNewQuery();
query.setFolders([folder], 1);
let result = histsvc.executeQuery(query, options);
let root = result.root;
root.containerOpen = true;
do_check_eq(root.childCount, 2);
// ensure the bookmark and page guids remain the same after modifing other property.
let bookmarkGuidZero = root.getChild(0).bookmarkGuid;
let pageGuidZero = root.getChild(0).pageGuid;
bmsvc.setItemTitle(b1, "1 title mod");
do_check_eq(root.getChild(0).title, "1 title mod");
do_check_eq(root.getChild(0).bookmarkGuid, bookmarkGuidZero);
do_check_eq(root.getChild(0).pageGuid, pageGuidZero);
let bookmarkGuidOne = root.getChild(1).bookmarkGuid;
let pageGuidOne = root.getChild(1).pageGuid;
bmsvc.setItemTitle(f1, "test foolder 234");
do_check_eq(root.getChild(1).title, "test foolder 234");
do_check_eq(root.getChild(1).bookmarkGuid, bookmarkGuidOne);
do_check_eq(root.getChild(1).pageGuid, pageGuidOne);
root.containerOpen = false;
remove_all_bookmarks();
});
add_task(function test_addVisitAndCheckGuid() {
// add a visit and test page guid and non-existing bookmark guids.
let now = Date.now() * 1000;
let sourceURI = uri("http://test4.com/");
yield promiseAddVisits({ uri: sourceURI });
do_check_eq(bmsvc.getBookmarkedURIFor(sourceURI), null);
let options = histsvc.getNewQueryOptions();
let query = histsvc.getNewQuery();
query.uri = sourceURI;
result = histsvc.executeQuery(query, options);
let root = result.root;
root.containerOpen = true;
do_check_eq(root.childCount, 1);
pageGuidZero = root.getChild(0).pageGuid;
do_check_eq(pageGuidZero.length, 12);
do_check_eq(root.getChild(0).bookmarkGuid, "");
root.containerOpen = false;
yield promiseClearHistory();
});

View File

@ -126,3 +126,4 @@ skip-if = os == "android"
[test_placesTxn.js]
[test_telemetry.js]
[test_getPlacesInfo.js]
[test_pageGuid_bookmarkGuid.js]