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"
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();
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
) {
65 const base::DictionaryValue
* assoc_dict
= NULL
;
66 if (!dict
->GetDictionaryWithoutPathExpansion(kKeyAssociations
, &assoc_dict
) ||
71 scoped_ptr
<HistoryData::Associations
> data(new HistoryData::Associations
);
72 for (base::DictionaryValue::Iterator
it(*assoc_dict
); !it
.IsAtEnd();
74 const base::DictionaryValue
* entry_dict
= NULL
;
75 if (!it
.value().GetAsDictionary(&entry_dict
))
79 std::string update_time_string
;
80 if (!entry_dict
->GetStringWithoutPathExpansion(kKeyPrimary
, &primary
) ||
81 !entry_dict
->GetStringWithoutPathExpansion(kKeyUpdateTime
,
82 &update_time_string
)) {
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
);
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
) {
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
);
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
));
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();
190 base::DictionaryValue
* assoc_dict
= NULL
;
191 CHECK(cached_dict
->GetDictionary(kKeyAssociations
, &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
);
211 void HistoryDataStore::OnDictionaryLoadedCallback(
212 OnLoadedCallback callback
,
213 scoped_ptr
<base::DictionaryValue
> dict
) {
215 callback
.Run(nullptr);
217 callback
.Run(Parse(dict
.Pass()).Pass());
221 } // namespace app_list