зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1438577 - Add API to fetch bookmarks by GUID prefix. r=mak
MozReview-Commit-ID: GPEp5Vxrz5z --HG-- extra : rebase_source : f8be9cfdad6db7f00366cef587751649538f74df
This commit is contained in:
Родитель
4b5191dd1c
Коммит
35c0e50b23
|
@ -968,6 +968,10 @@ var Bookmarks = Object.freeze({
|
|||
* retrieves the most recent bookmark having the given URL.
|
||||
* To retrieve ALL of the bookmarks for that URL, you must pass in an
|
||||
* onResult callback, that will be invoked once for each found bookmark.
|
||||
* - guidPrefix
|
||||
* retrieves the most recent item with the specified guid prefix.
|
||||
* To retrieve ALL of the bookmarks for that guid prefix, you must pass
|
||||
* in an onResult callback, that will be invoked once for each bookmark.
|
||||
*
|
||||
* @param guidOrInfo
|
||||
* The globally unique identifier of the item to fetch, or an
|
||||
|
@ -1003,14 +1007,15 @@ var Bookmarks = Object.freeze({
|
|||
info = { guid: guidOrInfo };
|
||||
} else if (Object.keys(info).length == 1) {
|
||||
// Just a faster code path.
|
||||
if (!["url", "guid", "parentGuid", "index"].includes(Object.keys(info)[0]))
|
||||
if (!["url", "guid", "parentGuid", "index", "guidPrefix"].includes(Object.keys(info)[0]))
|
||||
throw new Error(`Unexpected number of conditions provided: 0`);
|
||||
} else {
|
||||
// Only one condition at a time can be provided.
|
||||
let conditionsCount = [
|
||||
v => v.hasOwnProperty("guid"),
|
||||
v => v.hasOwnProperty("parentGuid") && v.hasOwnProperty("index"),
|
||||
v => v.hasOwnProperty("url")
|
||||
v => v.hasOwnProperty("url"),
|
||||
v => v.hasOwnProperty("guidPrefix")
|
||||
].reduce((old, fn) => old + fn(info) | 0, 0);
|
||||
if (conditionsCount != 1)
|
||||
throw new Error(`Unexpected number of conditions provided: ${conditionsCount}`);
|
||||
|
@ -1039,6 +1044,8 @@ var Bookmarks = Object.freeze({
|
|||
results = await fetchBookmark(fetchInfo, options && options.concurrent);
|
||||
else if (fetchInfo.hasOwnProperty("parentGuid") && fetchInfo.hasOwnProperty("index"))
|
||||
results = await fetchBookmarkByPosition(fetchInfo, options && options.concurrent);
|
||||
else if (fetchInfo.hasOwnProperty("guidPrefix"))
|
||||
results = await fetchBookmarksByGUIDPrefix(fetchInfo, options && options.concurrent);
|
||||
|
||||
if (!results)
|
||||
return null;
|
||||
|
@ -1781,6 +1788,32 @@ async function fetchBookmarkByPosition(info, concurrent) {
|
|||
query);
|
||||
}
|
||||
|
||||
async function fetchBookmarksByGUIDPrefix(info, concurrent) {
|
||||
let query = async function(db) {
|
||||
let rows = await db.executeCached(
|
||||
`SELECT b.guid, IFNULL(p.guid, "") AS parentGuid, b.position AS 'index',
|
||||
b.dateAdded, b.lastModified, b.type, IFNULL(b.title, "") AS title,
|
||||
h.url AS url, b.id AS _id, b.parent AS _parentId,
|
||||
NULL AS _childCount,
|
||||
p.parent AS _grandParentId, b.syncStatus AS _syncStatus
|
||||
FROM moz_bookmarks b
|
||||
LEFT JOIN moz_bookmarks p ON p.id = b.parent
|
||||
LEFT JOIN moz_places h ON h.id = b.fk
|
||||
WHERE b.guid LIKE :guidPrefix
|
||||
ORDER BY b.lastModified DESC
|
||||
`, { guidPrefix: info.guidPrefix + "%" });
|
||||
|
||||
return rows.length ? rowsToItemsArray(rows) : null;
|
||||
};
|
||||
|
||||
if (concurrent) {
|
||||
let db = await PlacesUtils.promiseDBConnection();
|
||||
return query(db);
|
||||
}
|
||||
return PlacesUtils.withConnectionWrapper("Bookmarks.jsm: fetchBookmarksByGUIDPrefix",
|
||||
query);
|
||||
}
|
||||
|
||||
async function fetchBookmarksByURL(info, concurrent) {
|
||||
let query = async function(db) {
|
||||
let tagsFolderId = await promiseTagsFolderId();
|
||||
|
|
|
@ -197,8 +197,8 @@ const DB_DESCRIPTION_LENGTH_MAX = 256;
|
|||
*/
|
||||
const BOOKMARK_VALIDATORS = Object.freeze({
|
||||
guid: simpleValidateFunc(v => PlacesUtils.isValidGuid(v)),
|
||||
parentGuid: simpleValidateFunc(v => typeof(v) == "string" &&
|
||||
/^[a-zA-Z0-9\-_]{12}$/.test(v)),
|
||||
parentGuid: simpleValidateFunc(v => PlacesUtils.isValidGuid(v)),
|
||||
guidPrefix: simpleValidateFunc(v => PlacesUtils.isValidGuidPrefix(v)),
|
||||
index: simpleValidateFunc(v => Number.isInteger(v) &&
|
||||
v >= PlacesUtils.bookmarks.DEFAULT_INDEX),
|
||||
dateAdded: simpleValidateFunc(v => v.constructor.name == "Date"),
|
||||
|
@ -340,6 +340,17 @@ this.PlacesUtils = {
|
|||
(/^[a-zA-Z0-9\-_]{12}$/.test(guid));
|
||||
},
|
||||
|
||||
/**
|
||||
* Is a string a valid GUID prefix?
|
||||
*
|
||||
* @param guidPrefix: (String)
|
||||
* @return (Boolean)
|
||||
*/
|
||||
isValidGuidPrefix(guidPrefix) {
|
||||
return typeof guidPrefix == "string" && guidPrefix &&
|
||||
(/^[a-zA-Z0-9\-_]{1,11}$/.test(guidPrefix));
|
||||
},
|
||||
|
||||
/**
|
||||
* Converts a string or n URL object to an nsIURI.
|
||||
*
|
||||
|
@ -2414,7 +2425,7 @@ var GuidHelper = {
|
|||
updateCache(aItemId, aGuid) {
|
||||
if (typeof(aItemId) != "number" || aItemId <= 0)
|
||||
throw new Error("Trying to update the GUIDs cache with an invalid itemId");
|
||||
if (typeof(aGuid) != "string" || !/^[a-zA-Z0-9\-_]{12}$/.test(aGuid))
|
||||
if (!PlacesUtils.isValidGuid(aGuid))
|
||||
throw new Error("Trying to update the GUIDs cache with an invalid GUID");
|
||||
this.ensureObservingRemovedItems();
|
||||
this.guidsForIds.set(aItemId, aGuid);
|
||||
|
|
|
@ -45,6 +45,17 @@ add_task(async function invalid_input_throws() {
|
|||
Assert.throws(() => PlacesUtils.bookmarks.fetch({ guid: 123 }),
|
||||
/Invalid value for property 'guid'/);
|
||||
|
||||
Assert.throws(() => PlacesUtils.bookmarks.fetch({ guidPrefix: "" }),
|
||||
/Invalid value for property 'guidPrefix'/);
|
||||
Assert.throws(() => PlacesUtils.bookmarks.fetch({ guidPrefix: null }),
|
||||
/Invalid value for property 'guidPrefix'/);
|
||||
Assert.throws(() => PlacesUtils.bookmarks.fetch({ guidPrefix: 123 }),
|
||||
/Invalid value for property 'guidPrefix'/);
|
||||
Assert.throws(() => PlacesUtils.bookmarks.fetch({ guidPrefix: "123456789012" }),
|
||||
/Invalid value for property 'guidPrefix'/);
|
||||
Assert.throws(() => PlacesUtils.bookmarks.fetch({ guidPrefix: "@" }),
|
||||
/Invalid value for property 'guidPrefix'/);
|
||||
|
||||
Assert.throws(() => PlacesUtils.bookmarks.fetch({ parentGuid: "test",
|
||||
index: 0 }),
|
||||
/Invalid value for property 'parentGuid'/);
|
||||
|
@ -182,6 +193,57 @@ add_task(async function fetch_separator() {
|
|||
await PlacesUtils.bookmarks.remove(bm1.guid);
|
||||
});
|
||||
|
||||
add_task(async function fetch_byguid_prefix() {
|
||||
function generateGuidWithPrefix(prefix) {
|
||||
return prefix + PlacesUtils.history.makeGuid().substring(prefix.length);
|
||||
}
|
||||
|
||||
const PREFIX = "PREFIX-";
|
||||
|
||||
let bm1 = await PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
guid: generateGuidWithPrefix(PREFIX),
|
||||
url: "http://bm1.example.com/",
|
||||
title: "bookmark 1" });
|
||||
checkBookmarkObject(bm1);
|
||||
Assert.ok(bm1.guid.startsWith(PREFIX));
|
||||
|
||||
let bm2 = await PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
guid: generateGuidWithPrefix(PREFIX),
|
||||
url: "http://bm2.example.com/",
|
||||
title: "bookmark 2" });
|
||||
checkBookmarkObject(bm2);
|
||||
Assert.ok(bm2.guid.startsWith(PREFIX));
|
||||
|
||||
let bm3 = await PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
type: PlacesUtils.bookmarks.TYPE_FOLDER,
|
||||
guid: generateGuidWithPrefix(PREFIX),
|
||||
title: "a folder" });
|
||||
checkBookmarkObject(bm3);
|
||||
Assert.ok(bm3.guid.startsWith(PREFIX));
|
||||
|
||||
// Bookmark 4 doesn't have the same guid prefix, so it shouldn't be returned in the results.
|
||||
let bm4 = await PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
url: "http://bm3.example.com/",
|
||||
title: "bookmark 4" });
|
||||
checkBookmarkObject(bm4);
|
||||
Assert.ok(!bm4.guid.startsWith(PREFIX));
|
||||
|
||||
await PlacesUtils.bookmarks.fetch({ guidPrefix: PREFIX }, gAccumulator.callback);
|
||||
|
||||
Assert.equal(gAccumulator.results.length, 3);
|
||||
|
||||
// The results are returned by most recent first, so the first bookmark
|
||||
// inserted is the last one in the returned array.
|
||||
Assert.deepEqual(bm1, gAccumulator.results[2]);
|
||||
Assert.deepEqual(bm2, gAccumulator.results[1]);
|
||||
Assert.deepEqual(bm3, gAccumulator.results[0]);
|
||||
|
||||
await PlacesUtils.bookmarks.remove(bm1);
|
||||
await PlacesUtils.bookmarks.remove(bm2);
|
||||
await PlacesUtils.bookmarks.remove(bm3);
|
||||
await PlacesUtils.bookmarks.remove(bm4);
|
||||
});
|
||||
|
||||
add_task(async function fetch_byposition_nonexisting_parentGuid() {
|
||||
let bm = await PlacesUtils.bookmarks.fetch({ parentGuid: "123456789012",
|
||||
index: 0 },
|
||||
|
|
Загрузка…
Ссылка в новой задаче