Drive: Add BatchableRequest subclass.
[chromium-blink-merge.git] / ui / app_list / search / history_data_store.cc
blob533822037bdce8dec9803dd4ef04cefe6359e982
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/app_list/search/history_data_store.h"
7 #include "base/callback.h"
8 #include "base/json/json_file_value_serializer.h"
9 #include "base/json/json_string_value_serializer.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/values.h"
13 namespace app_list {
15 namespace {
17 const char kKeyVersion[] = "version";
18 const char kCurrentVersion[] = "1";
20 const char kKeyAssociations[] = "associations";
21 const char kKeyPrimary[] = "p";
22 const char kKeySecondary[] = "s";
23 const char kKeyUpdateTime[] = "t";
25 // Extracts strings from ListValue.
26 void GetSecondary(const base::ListValue* list,
27 HistoryData::SecondaryDeque* secondary) {
28 HistoryData::SecondaryDeque results;
29 for (base::ListValue::const_iterator it = list->begin(); it != list->end();
30 ++it) {
31 std::string str;
32 if (!(*it)->GetAsString(&str))
33 return;
35 results.push_back(str);
38 secondary->swap(results);
41 // V1 format json dictionary:
42 // {
43 // "version": "1",
44 // "associations": {
45 // "user typed query": {
46 // "p" : "result id of primary association",
47 // "s" : [
48 // "result id of 1st (oldest) secondary association",
49 // ...
50 // "result id of the newest secondary association"
51 // ],
52 // "t" : "last_update_timestamp"
53 // },
54 // ...
55 // }
56 // }
57 scoped_ptr<HistoryData::Associations> Parse(
58 scoped_ptr<base::DictionaryValue> dict) {
59 std::string version;
60 if (!dict->GetStringWithoutPathExpansion(kKeyVersion, &version) ||
61 version != kCurrentVersion) {
62 return nullptr;
65 const base::DictionaryValue* assoc_dict = NULL;
66 if (!dict->GetDictionaryWithoutPathExpansion(kKeyAssociations, &assoc_dict) ||
67 !assoc_dict) {
68 return nullptr;
71 scoped_ptr<HistoryData::Associations> data(new HistoryData::Associations);
72 for (base::DictionaryValue::Iterator it(*assoc_dict); !it.IsAtEnd();
73 it.Advance()) {
74 const base::DictionaryValue* entry_dict = NULL;
75 if (!it.value().GetAsDictionary(&entry_dict))
76 continue;
78 std::string primary;
79 std::string update_time_string;
80 if (!entry_dict->GetStringWithoutPathExpansion(kKeyPrimary, &primary) ||
81 !entry_dict->GetStringWithoutPathExpansion(kKeyUpdateTime,
82 &update_time_string)) {
83 continue;
86 const base::ListValue* secondary_list = NULL;
87 HistoryData::SecondaryDeque secondary;
88 if (entry_dict->GetListWithoutPathExpansion(kKeySecondary, &secondary_list))
89 GetSecondary(secondary_list, &secondary);
91 const std::string& query = it.key();
92 HistoryData::Data& association_data = (*data.get())[query];
93 association_data.primary = primary;
94 association_data.secondary.swap(secondary);
96 int64 update_time_val;
97 base::StringToInt64(update_time_string, &update_time_val);
98 association_data.update_time =
99 base::Time::FromInternalValue(update_time_val);
102 return data.Pass();
105 } // namespace
107 HistoryDataStore::HistoryDataStore()
108 : cached_dict_(new base::DictionaryValue()) {
109 Init(cached_dict_.get());
112 HistoryDataStore::HistoryDataStore(
113 scoped_refptr<DictionaryDataStore> data_store)
114 : data_store_(data_store) {
115 Init(data_store_->cached_dict());
118 HistoryDataStore::~HistoryDataStore() {
121 void HistoryDataStore::Init(base::DictionaryValue* cached_dict) {
122 DCHECK(cached_dict);
123 cached_dict->SetString(kKeyVersion, kCurrentVersion);
124 cached_dict->Set(kKeyAssociations, new base::DictionaryValue);
127 void HistoryDataStore::Flush(
128 const DictionaryDataStore::OnFlushedCallback& on_flushed) {
129 if (data_store_.get())
130 data_store_->Flush(on_flushed);
131 else
132 on_flushed.Run();
135 void HistoryDataStore::Load(
136 const HistoryDataStore::OnLoadedCallback& on_loaded) {
137 if (data_store_.get()) {
138 data_store_->Load(base::Bind(
139 &HistoryDataStore::OnDictionaryLoadedCallback, this, on_loaded));
140 } else {
141 OnDictionaryLoadedCallback(on_loaded,
142 make_scoped_ptr(cached_dict_->DeepCopy()));
146 void HistoryDataStore::SetPrimary(const std::string& query,
147 const std::string& result) {
148 base::DictionaryValue* entry_dict = GetEntryDict(query);
149 entry_dict->SetWithoutPathExpansion(kKeyPrimary,
150 new base::StringValue(result));
151 if (data_store_.get())
152 data_store_->ScheduleWrite();
155 void HistoryDataStore::SetSecondary(
156 const std::string& query,
157 const HistoryData::SecondaryDeque& results) {
158 scoped_ptr<base::ListValue> results_list(new base::ListValue);
159 for (size_t i = 0; i < results.size(); ++i)
160 results_list->AppendString(results[i]);
162 base::DictionaryValue* entry_dict = GetEntryDict(query);
163 entry_dict->SetWithoutPathExpansion(kKeySecondary, results_list.release());
164 if (data_store_.get())
165 data_store_->ScheduleWrite();
168 void HistoryDataStore::SetUpdateTime(const std::string& query,
169 const base::Time& update_time) {
170 base::DictionaryValue* entry_dict = GetEntryDict(query);
171 entry_dict->SetWithoutPathExpansion(kKeyUpdateTime,
172 new base::StringValue(base::Int64ToString(
173 update_time.ToInternalValue())));
174 if (data_store_.get())
175 data_store_->ScheduleWrite();
178 void HistoryDataStore::Delete(const std::string& query) {
179 base::DictionaryValue* assoc_dict = GetAssociationDict();
180 assoc_dict->RemoveWithoutPathExpansion(query, NULL);
181 if (data_store_.get())
182 data_store_->ScheduleWrite();
185 base::DictionaryValue* HistoryDataStore::GetAssociationDict() {
186 base::DictionaryValue* cached_dict =
187 cached_dict_ ? cached_dict_.get() : data_store_->cached_dict();
188 DCHECK(cached_dict);
190 base::DictionaryValue* assoc_dict = NULL;
191 CHECK(cached_dict->GetDictionary(kKeyAssociations, &assoc_dict) &&
192 assoc_dict);
194 return assoc_dict;
197 base::DictionaryValue* HistoryDataStore::GetEntryDict(
198 const std::string& query) {
199 base::DictionaryValue* assoc_dict = GetAssociationDict();
201 base::DictionaryValue* entry_dict = NULL;
202 if (!assoc_dict->GetDictionaryWithoutPathExpansion(query, &entry_dict)) {
203 // Creates one if none exists. Ownership is taken in the set call after.
204 entry_dict = new base::DictionaryValue;
205 assoc_dict->SetWithoutPathExpansion(query, entry_dict);
208 return entry_dict;
211 void HistoryDataStore::OnDictionaryLoadedCallback(
212 OnLoadedCallback callback,
213 scoped_ptr<base::DictionaryValue> dict) {
214 if (!dict) {
215 callback.Run(nullptr);
216 } else {
217 callback.Run(Parse(dict.Pass()).Pass());
221 } // namespace app_list