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 "chrome/browser/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"
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();
30 it != list->end(); ++it) {
32 if (!(*it)->GetAsString(&str))
35 results.push_back(str);
38 secondary->swap(results);
41 // V1 format json dictionary:
45 // "user typed query": {
46 // "p" : "result id of primary association",
48 // "result id of 1st (oldest) secondary association",
50 // "result id of the newest secondary association"
52 // "t" : "last_update_timestamp"
57 scoped_ptr<HistoryData::Associations> Parse(
58 scoped_ptr<base::DictionaryValue> dict) {
60 if (!dict->GetStringWithoutPathExpansion(kKeyVersion, &version) ||
61 version != kCurrentVersion) {
62 return scoped_ptr<HistoryData::Associations>();
65 const base::DictionaryValue* assoc_dict = NULL;
66 if (!dict->GetDictionaryWithoutPathExpansion(kKeyAssociations,
69 return scoped_ptr<HistoryData::Associations>();
72 scoped_ptr<HistoryData::Associations> data(new HistoryData::Associations);
73 for (base::DictionaryValue::Iterator it(*assoc_dict);
74 !it.IsAtEnd(); it.Advance()) {
75 const base::DictionaryValue* entry_dict = NULL;
76 if (!it.value().GetAsDictionary(&entry_dict))
80 std::string update_time_string;
81 if (!entry_dict->GetStringWithoutPathExpansion(kKeyPrimary, &primary) ||
82 !entry_dict->GetStringWithoutPathExpansion(kKeyUpdateTime,
83 &update_time_string)) {
87 const base::ListValue* secondary_list = NULL;
88 HistoryData::SecondaryDeque secondary;
89 if (entry_dict->GetListWithoutPathExpansion(kKeySecondary, &secondary_list))
90 GetSecondary(secondary_list, &secondary);
92 const std::string& query = it.key();
93 HistoryData::Data& association_data = (*data.get())[query];
94 association_data.primary = primary;
95 association_data.secondary.swap(secondary);
97 int64 update_time_val;
98 base::StringToInt64(update_time_string, &update_time_val);
99 association_data.update_time =
100 base::Time::FromInternalValue(update_time_val);
108 HistoryDataStore::HistoryDataStore()
109 : cached_dict_(new base::DictionaryValue()) {
110 Init(cached_dict_.get());
113 HistoryDataStore::HistoryDataStore(
114 scoped_refptr<DictionaryDataStore> data_store)
115 : data_store_(data_store) {
116 Init(data_store_->cached_dict());
119 HistoryDataStore::~HistoryDataStore() {
122 void HistoryDataStore::Init(base::DictionaryValue* cached_dict) {
124 cached_dict->SetString(kKeyVersion, kCurrentVersion);
125 cached_dict->Set(kKeyAssociations, new base::DictionaryValue);
128 void HistoryDataStore::Flush(
129 const DictionaryDataStore::OnFlushedCallback& on_flushed) {
130 if (data_store_.get())
131 data_store_->Flush(on_flushed);
136 void HistoryDataStore::Load(
137 const HistoryDataStore::OnLoadedCallback& on_loaded) {
138 if (data_store_.get()) {
139 data_store_->Load(base::Bind(&HistoryDataStore::OnDictionaryLoadedCallback,
143 OnDictionaryLoadedCallback(
144 on_loaded, make_scoped_ptr(cached_dict_->DeepCopy()));
148 void HistoryDataStore::SetPrimary(const std::string& query,
149 const std::string& result) {
150 base::DictionaryValue* entry_dict = GetEntryDict(query);
151 entry_dict->SetWithoutPathExpansion(kKeyPrimary,
152 new base::StringValue(result));
153 if (data_store_.get())
154 data_store_->ScheduleWrite();
157 void HistoryDataStore::SetSecondary(
158 const std::string& query,
159 const HistoryData::SecondaryDeque& results) {
160 scoped_ptr<base::ListValue> results_list(new base::ListValue);
161 for (size_t i = 0; i< results.size(); ++i)
162 results_list->AppendString(results[i]);
164 base::DictionaryValue* entry_dict = GetEntryDict(query);
165 entry_dict->SetWithoutPathExpansion(kKeySecondary, results_list.release());
166 if (data_store_.get())
167 data_store_->ScheduleWrite();
170 void HistoryDataStore::SetUpdateTime(const std::string& query,
171 const base::Time& update_time) {
172 base::DictionaryValue* entry_dict = GetEntryDict(query);
173 entry_dict->SetWithoutPathExpansion(kKeyUpdateTime,
174 new base::StringValue(base::Int64ToString(
175 update_time.ToInternalValue())));
176 if (data_store_.get())
177 data_store_->ScheduleWrite();
180 void HistoryDataStore::Delete(const std::string& query) {
181 base::DictionaryValue* assoc_dict = GetAssociationDict();
182 assoc_dict->RemoveWithoutPathExpansion(query, NULL);
183 if (data_store_.get())
184 data_store_->ScheduleWrite();
187 base::DictionaryValue* HistoryDataStore::GetAssociationDict() {
188 base::DictionaryValue* cached_dict =
189 cached_dict_ ? cached_dict_.get() : data_store_->cached_dict();
192 base::DictionaryValue* assoc_dict = NULL;
193 CHECK(cached_dict->GetDictionary(kKeyAssociations, &assoc_dict) &&
199 base::DictionaryValue* HistoryDataStore::GetEntryDict(
200 const std::string& query) {
201 base::DictionaryValue* assoc_dict = GetAssociationDict();
203 base::DictionaryValue* entry_dict = NULL;
204 if (!assoc_dict->GetDictionaryWithoutPathExpansion(query, &entry_dict)) {
205 // Creates one if none exists. Ownership is taken in the set call after.
206 entry_dict = new base::DictionaryValue;
207 assoc_dict->SetWithoutPathExpansion(query, entry_dict);
213 void HistoryDataStore::OnDictionaryLoadedCallback(
214 OnLoadedCallback callback, scoped_ptr<base::DictionaryValue> dict) {
216 callback.Run(scoped_ptr<HistoryData::Associations>());
218 callback.Run(Parse(dict.Pass()).Pass());
222 } // namespace app_list