summaryrefslogtreecommitdiff
path: root/chromium/components/history/core/browser/android/visit_sql_handler.cc
blob: 97222dd43393d5eb3fce6c5cf2f40147b3d72e1c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/history/core/browser/android/visit_sql_handler.h"

#include <stdint.h>

#include "base/logging.h"
#include "base/macros.h"
#include "components/history/core/browser/url_database.h"
#include "components/history/core/browser/visit_database.h"

using base::Time;

namespace history {

namespace {

// The interesting columns of this handler.
const HistoryAndBookmarkRow::ColumnID kInterestingColumns[] = {
    HistoryAndBookmarkRow::CREATED, HistoryAndBookmarkRow::VISIT_COUNT,
    HistoryAndBookmarkRow::LAST_VISIT_TIME };

} // namespace

VisitSQLHandler::VisitSQLHandler(URLDatabase* url_db, VisitDatabase* visit_db)
    : SQLHandler(kInterestingColumns, arraysize(kInterestingColumns)),
      url_db_(url_db),
      visit_db_(visit_db) {
}

VisitSQLHandler::~VisitSQLHandler() {
}

// The created time is updated according the given |row|.
// We simulate updating created time by
// a. Remove all visits.
// b. Insert a new visit which has visit time same as created time.
// c. Insert the number of visits according the visit count in urls table.
//
// Visit row is insertted/removed to keep consistent with urls table.
// a. If the visit count in urls table is less than the visit rows in visit
//    table, all existent visits will be removed. The new visits will be
//    insertted according the value in urls table.
// b. Otherwise, only add the increased number of visit count.
bool VisitSQLHandler::Update(const HistoryAndBookmarkRow& row,
                             const TableIDRows& ids_set) {
  for (TableIDRows::const_iterator id = ids_set.begin();
       id != ids_set.end(); ++id) {
    VisitVector visits;
    if (!visit_db_->GetVisitsForURL(id->url_id, &visits))
      return false;
    int visit_count_in_table = visits.size();
    URLRow url_row;
    if (!url_db_->GetURLRow(id->url_id, &url_row))
      return false;
    int visit_count_needed = url_row.visit_count();

    if (visit_count_needed == 0)
      return Delete(ids_set);

    // If created time is updated or new visit count is less than the current
    // one, delete all visit rows.
    if (row.is_value_set_explicitly(HistoryAndBookmarkRow::CREATED) ||
        visit_count_in_table > visit_count_needed) {
      if (!DeleteVisitsForURL(id->url_id))
        return false;
      visit_count_in_table = 0;
    }

    if (row.is_value_set_explicitly(HistoryAndBookmarkRow::CREATED) &&
        visit_count_needed > 0) {
      if (!AddVisit(id->url_id, row.created()))
        return false;
      visit_count_in_table++;
    }

    if (!AddVisitRows(id->url_id, visit_count_needed - visit_count_in_table,
                       url_row.last_visit()))
      return false;
  }
  return true;
}

bool VisitSQLHandler::Insert(HistoryAndBookmarkRow* row) {
  DCHECK(row->is_value_set_explicitly(HistoryAndBookmarkRow::URL_ID));

  URLRow url_row;
  if (!url_db_->GetURLRow(row->url_id(), &url_row))
    return false;

  int visit_count = url_row.visit_count();

  if (visit_count == 0)
    return true;

  // Add a row if the last visit time is different from created time.
  if (row->is_value_set_explicitly(HistoryAndBookmarkRow::CREATED) &&
      row->created() != url_row.last_visit() && visit_count > 0) {
    if (!AddVisit(row->url_id(), row->created()))
      return false;
    visit_count--;
  }

  if (!AddVisitRows(row->url_id(), visit_count, url_row.last_visit()))
    return false;

  return true;
}

bool VisitSQLHandler::Delete(const TableIDRows& ids_set) {
  for (TableIDRows::const_iterator ids = ids_set.begin();
       ids != ids_set.end(); ++ids) {
    DeleteVisitsForURL(ids->url_id);
  }
  return true;
}

bool VisitSQLHandler::AddVisit(URLID url_id, const Time& visit_time) {
  // TODO : Is 'ui::PAGE_TRANSITION_AUTO_BOOKMARK' proper?
  // if not, a new ui::PageTransition type will need.
  VisitRow visit_row(url_id, visit_time, 0,
                     ui::PAGE_TRANSITION_AUTO_BOOKMARK, 0);
  return visit_db_->AddVisit(&visit_row, SOURCE_BROWSED);
}

bool VisitSQLHandler::AddVisitRows(URLID url_id,
                                   int visit_count,
                                   const Time& last_visit_time) {
  int64_t last_update_value = last_visit_time.ToInternalValue();
  for (int i = 0; i < visit_count; i++) {
    if (!AddVisit(url_id, Time::FromInternalValue(last_update_value - i)))
      return false;
  }
  return true;
}

bool VisitSQLHandler::DeleteVisitsForURL(URLID url_id) {
  VisitVector visits;
  if (!visit_db_->GetVisitsForURL(url_id, &visits))
    return false;

  for (VisitVector::const_iterator v = visits.begin(); v != visits.end(); ++v) {
    visit_db_->DeleteVisit(*v);
  }
  return true;
}

}  // namespace history.