Commit daaeb82e authored by Harley Li's avatar Harley Li Committed by Commit Bot

[DevTools] Display number of entries in an IndexedDB object store

The number of entries stored in an object store is an important metadata.

Bug: 941197
Change-Id: I8166a106593fecb34428825787e884f51d11963b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1512692
Commit-Queue: Haihong Li (Harley) <hhli@chromium.org>
Reviewed-by: default avatarPavel Feldman <pfeldman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#641067}
parent e05c7762
......@@ -3029,10 +3029,9 @@ experimental domain IndexedDB
array of DataEntry objectStoreDataEntries
# If true, there are more entries to fetch in the given range.
boolean hasMore
# Gets the auto increment number of an object store. Only meaningful
# when objectStore.autoIncrement is true.
command getKeyGeneratorCurrentNumber
# Gets metadata of an object store
command getMetadata
parameters
# Security origin.
string securityOrigin
......@@ -3041,9 +3040,12 @@ experimental domain IndexedDB
# Object store name.
string objectStoreName
returns
# the entries count
number entriesCount
# the current value of key generator, to become the next inserted
# key into the object store.
number currentNumber
# key into the object store. Valid if objectStore.autoIncrement
# is true.
number keyGeneratorValue
# Requests database with given name in given frame.
command requestDatabase
......
......@@ -48,7 +48,7 @@
},
{
"domain": "IndexedDB",
"async": ["requestDatabaseNames", "requestDatabase", "requestData", "getKeyGeneratorCurrentNumber", "deleteObjectStoreEntries", "clearObjectStore", "deleteDatabase"]
"async": ["requestDatabaseNames", "requestDatabase", "requestData", "getMetadata", "deleteObjectStoreEntries", "clearObjectStore", "deleteDatabase"]
},
{
"domain": "LayerTree"
......
......@@ -430,22 +430,20 @@ Resources.IndexedDBModel = class extends SDK.SDKModel {
/**
* @param {!Resources.IndexedDBModel.DatabaseId} databaseId
* @param {!Resources.IndexedDBModel.ObjectStore} objectStore
* @return {!Promise<?number>}
* @return {!Promise<?Resources.IndexedDBModel.ObjectStoreMetadata>}
*/
async getKeyGeneratorValue(databaseId, objectStore) {
if (!objectStore.autoIncrement)
return null;
async getMetadata(databaseId, objectStore) {
const databaseOrigin = databaseId.securityOrigin;
const databaseName = databaseId.name;
const objectStoreName = objectStore.name;
const response = await this._indexedDBAgent.invoke_getKeyGeneratorCurrentNumber(
{securityOrigin: databaseOrigin, databaseName, objectStoreName});
const response =
await this._indexedDBAgent.invoke_getMetadata({securityOrigin: databaseOrigin, databaseName, objectStoreName});
if (response[Protocol.Error]) {
console.error('IndexedDBAgent error: ' + response[Protocol.Error]);
return null;
}
return response.currentNumber;
return {entriesCount: response.entriesCount, keyGeneratorValue: response.keyGeneratorValue};
}
/**
......@@ -603,6 +601,14 @@ Resources.IndexedDBModel.ObjectStore = class {
}
};
/**
* @typedef {{
* entriesCount: number,
* keyGeneratorValue: number
* }}
*/
Resources.IndexedDBModel.ObjectStoreMetadata;
/**
* @unrestricted
*/
......
......@@ -134,8 +134,6 @@ Resources.IDBDataView = class extends UI.SimpleView {
this._pageSize = 50;
this._skipCount = 0;
/** @type {?number} */
this._keyGeneratorValue = null;
this.update(objectStore, index);
this._entries = [];
......@@ -339,15 +337,6 @@ Resources.IDBDataView = class extends UI.SimpleView {
this._updatedDataForTests();
}
/**
* @param {?number} number
* @this {Resources.IDBDataView}
*/
function callbackKeyGeneratorValue(number) {
this._keyGeneratorValue = number;
this._updateSummaryBar();
}
const idbKeyRange = key ? window.IDBKeyRange.lowerBound(key) : null;
if (this._isIndex) {
this._model.loadIndexData(
......@@ -357,18 +346,28 @@ Resources.IDBDataView = class extends UI.SimpleView {
this._model.loadObjectStoreData(
this._databaseId, this._objectStore.name, idbKeyRange, skipCount, pageSize, callback.bind(this));
}
this._model.getKeyGeneratorValue(this._databaseId, this._objectStore).then(callbackKeyGeneratorValue.bind(this));
this._updateSummaryBar();
this._model.getMetadata(this._databaseId, this._objectStore).then(this._updateSummaryBar.bind(this));
}
_updateSummaryBar() {
if (this._keyGeneratorValue === null)
return;
/**
* @param {?Resources.IndexedDBModel.ObjectStoreMetadata} metadata
*/
_updateSummaryBar(metadata) {
if (!this._summaryBarElement)
this._summaryBarElement = this.element.createChild('div', 'object-store-summary-bar');
this._summaryBarElement.removeChildren();
if (!metadata)
return;
const separator = '\u2002\u2758\u2002';
const span = this._summaryBarElement.createChild('span');
span.textContent = ls`key generator value: ${String(this._keyGeneratorValue)}`;
span.textContent = ls`Total entries: ${String(metadata.entriesCount)}`;
if (this._objectStore.autoIncrement) {
span.textContent += separator;
span.textContent += ls`Key generator value: ${String(metadata.keyGeneratorValue)}`;
}
}
_updatedDataForTests() {
......
......@@ -86,8 +86,8 @@ typedef blink::protocol::IndexedDB::Backend::DeleteObjectStoreEntriesCallback
DeleteObjectStoreEntriesCallback;
typedef blink::protocol::IndexedDB::Backend::ClearObjectStoreCallback
ClearObjectStoreCallback;
typedef blink::protocol::IndexedDB::Backend::
GetKeyGeneratorCurrentNumberCallback GetKeyGeneratorCurrentNumberCallback;
typedef blink::protocol::IndexedDB::Backend::GetMetadataCallback
GetMetadataCallback;
typedef blink::protocol::IndexedDB::Backend::DeleteDatabaseCallback
DeleteDatabaseCallback;
......@@ -830,56 +830,65 @@ void InspectorIndexedDBAgent::requestData(
database_name);
}
class GetKeyGeneratorCurrentNumberListener final : public NativeEventListener {
public:
static GetKeyGeneratorCurrentNumberListener* Create(
std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback) {
return MakeGarbageCollected<GetKeyGeneratorCurrentNumberListener>(
std::move(request_callback));
}
class GetMetadata;
GetKeyGeneratorCurrentNumberListener(
std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback)
: request_callback_(std::move(request_callback)) {}
~GetKeyGeneratorCurrentNumberListener() override = default;
class GetMetadataListener final : public NativeEventListener {
public:
GetMetadataListener(scoped_refptr<GetMetadata> owner, int64_t* result)
: owner_(owner), result_(result) {}
~GetMetadataListener() override = default;
void Invoke(ExecutionContext*, Event* event) override {
if (event->type() != event_type_names::kSuccess) {
request_callback_->sendFailure(
Response::Error("Failed to get current number of key generator."));
NotifySubtaskDone(owner_, "Failed to get meta data of object store.");
return;
}
IDBRequest* idb_request = static_cast<IDBRequest*>(event->target());
IDBAny* request_result = idb_request->ResultAsAny();
if (request_result->GetType() != IDBAny::kIntegerType) {
request_callback_->sendFailure(
Response::Error("Unexpected result type."));
NotifySubtaskDone(owner_, "Unexpected result type.");
return;
}
request_callback_->sendSuccess(request_result->Integer());
*result_ = request_result->Integer();
NotifySubtaskDone(owner_, String());
}
private:
std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback_;
void NotifySubtaskDone(scoped_refptr<GetMetadata> owner,
const String& error) const;
scoped_refptr<GetMetadata> owner_;
int64_t* result_;
};
class GetKeyGeneratorCurrentNumber final
: public ExecutableWithDatabase<GetKeyGeneratorCurrentNumberCallback> {
class GetMetadata final : public ExecutableWithDatabase<GetMetadataCallback> {
public:
static scoped_refptr<GetKeyGeneratorCurrentNumber> Create(
static scoped_refptr<GetMetadata> Create(
const String& object_store_name,
std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback) {
return AdoptRef(new GetKeyGeneratorCurrentNumber(
object_store_name, std::move(request_callback)));
std::unique_ptr<GetMetadataCallback> request_callback) {
return AdoptRef(
new GetMetadata(object_store_name, std::move(request_callback)));
}
void NotifySubtaskDone(const String& error) {
if (!error.IsNull()) {
request_callback_->sendFailure(Response::Error(error));
return;
}
if (--subtask_pending_ == 0) {
request_callback_->sendSuccess(entries_count_,
key_generator_current_number_);
}
}
private:
GetKeyGeneratorCurrentNumber(
const String& object_store_name,
std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback)
GetMetadata(const String& object_store_name,
std::unique_ptr<GetMetadataCallback> request_callback)
: object_store_name_(object_store_name),
request_callback_(std::move(request_callback)) {}
request_callback_(std::move(request_callback)),
subtask_pending_(2),
entries_count_(-1),
key_generator_current_number_(-1) {}
void Execute(IDBDatabase* idb_database, ScriptState* script_state) override {
IDBTransaction* idb_transaction =
......@@ -897,36 +906,64 @@ class GetKeyGeneratorCurrentNumber final
Response::Error("Could not get object store"));
return;
}
IDBRequest* idb_request =
// subtask 1. get entries count
ScriptState::Scope scope(script_state);
DummyExceptionStateForTesting exception_state;
IDBRequest* idb_request_get_entries_count = idb_object_store->count(
script_state, ScriptValue::CreateNull(script_state), exception_state);
DCHECK(!exception_state.HadException());
if (exception_state.HadException()) {
ExceptionCode ec = exception_state.Code();
request_callback_->sendFailure(Response::Error(
String::Format("Could not count entries in object store '%s': %d",
object_store_name_.Utf8().data(), ec)));
return;
}
GetMetadataListener* listener_get_entries_count =
MakeGarbageCollected<GetMetadataListener>(this, &entries_count_);
idb_request_get_entries_count->addEventListener(
event_type_names::kSuccess, listener_get_entries_count, false);
idb_request_get_entries_count->addEventListener(
event_type_names::kError, listener_get_entries_count, false);
// subtask 2. get key generator current number
IDBRequest* idb_request_get_key_generator =
idb_object_store->getKeyGeneratorCurrentNumber(script_state);
idb_request->addEventListener(event_type_names::kSuccess,
GetKeyGeneratorCurrentNumberListener::Create(
std::move(request_callback_)),
false);
idb_request->addEventListener(event_type_names::kError,
GetKeyGeneratorCurrentNumberListener::Create(
std::move(request_callback_)),
false);
GetMetadataListener* listener_get_key_generator =
MakeGarbageCollected<GetMetadataListener>(
this, &key_generator_current_number_);
idb_request_get_key_generator->addEventListener(
event_type_names::kSuccess, listener_get_key_generator, false);
idb_request_get_key_generator->addEventListener(
event_type_names::kError, listener_get_key_generator, false);
}
GetKeyGeneratorCurrentNumberCallback* GetRequestCallback() override {
GetMetadataCallback* GetRequestCallback() override {
return request_callback_.get();
}
private:
const String object_store_name_;
std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback_;
std::unique_ptr<GetMetadataCallback> request_callback_;
uint8_t subtask_pending_;
int64_t entries_count_;
int64_t key_generator_current_number_;
};
void InspectorIndexedDBAgent::getKeyGeneratorCurrentNumber(
void GetMetadataListener::NotifySubtaskDone(scoped_refptr<GetMetadata> owner,
const String& error) const {
owner->NotifySubtaskDone(error);
}
void InspectorIndexedDBAgent::getMetadata(
const String& security_origin,
const String& database_name,
const String& object_store_name,
std::unique_ptr<GetKeyGeneratorCurrentNumberCallback> request_callback) {
scoped_refptr<GetKeyGeneratorCurrentNumber> get_auto_increment_number =
GetKeyGeneratorCurrentNumber::Create(object_store_name,
std::move(request_callback));
get_auto_increment_number->Start(
std::unique_ptr<GetMetadataCallback> request_callback) {
scoped_refptr<GetMetadata> get_metadata =
GetMetadata::Create(object_store_name, std::move(request_callback));
get_metadata->Start(
inspected_frames_->FrameWithSecurityOrigin(security_origin),
database_name);
}
......
......@@ -69,11 +69,10 @@ class MODULES_EXPORT InspectorIndexedDBAgent final
int page_size,
protocol::Maybe<protocol::IndexedDB::KeyRange>,
std::unique_ptr<RequestDataCallback>) override;
void getKeyGeneratorCurrentNumber(
const String& security_origin,
const String& database_name,
const String& object_store_name,
std::unique_ptr<GetKeyGeneratorCurrentNumberCallback>) override;
void getMetadata(const String& security_origin,
const String& database_name,
const String& object_store_name,
std::unique_ptr<GetMetadataCallback>) override;
void deleteObjectStoreEntries(
const String& security_origin,
const String& database_name,
......
Tests that data is correctly loaded by IndexedDBModel from IndexedDB object store and index.
key generator value: 1
key generator value: 7
entries count: 6
key gen value: 1
entries count: 6
key gen value: 7
Dumping values, fromIndex = false, skipCount = 0, pageSize = 2, idbKeyRange = null
Key = key_01, primaryKey = key_01, value = {"key":"key_01","value":"value_01"}
Key = key_02, primaryKey = key_02, value = {"key":"key_02","value":"value_02"}
......
......@@ -112,17 +112,24 @@
async function postFillingActions() {
await new Promise(resolve => {
indexedDBModel.getKeyGeneratorValue(
databaseId, {name: objectStoreName1, autoIncrement: true}).then(printKeyGeneratorValue);
indexedDBModel.getKeyGeneratorValue(
databaseId, {name: objectStoreName2, autoIncrement: true}).then(printKeyGeneratorValue);
indexedDBModel.getMetadata(
databaseId, {name: objectStoreName1, autoIncrement: true}).then(printMetadata);
indexedDBModel.getMetadata(
databaseId, {name: objectStoreName2, autoIncrement: true}).then(printMetadata);
resolve();
});
TestRunner.addSniffer(Resources.IndexedDBModel.prototype, '_updateOriginDatabaseNames', refreshDatabase, false);
indexedDBModel.refreshDatabaseNames();
function printKeyGeneratorValue(number) {
TestRunner.addResult('key generator value: ' + (number ? String(number) : 'null'));
function printMetadata(metadata) {
if (!metadata) {
TestRunner.addResult('backend returns an error response');
return;
}
const entriesCount = metadata.entriesCount;
const keyGenNumber = metadata.keyGeneratorValue;
TestRunner.addResult('entries count: ' + String(entriesCount));
TestRunner.addResult('key gen value: ' + String(keyGenNumber));
}
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment