[epiphany/history-rewrite: 5/26] Add the ability to fetch a series of page visits in a time range.



commit fd92c010595b98f20dd57fa35e86564c41d08036
Author: Martin Robinson <mrobinson igalia com>
Date:   Sat Apr 23 18:55:50 2011 -0700

    Add the ability to fetch a series of page visits in a time range.

 embed/history/ephy-history-service-private.h      |    3 +-
 embed/history/ephy-history-service-urls-table.c   |   48 +++++++++---
 embed/history/ephy-history-service-visits-table.c |   54 +++++++++++++
 embed/history/ephy-history-service.c              |   85 +++++++++++++++------
 embed/history/ephy-history-service.h              |    1 +
 tests/ephy-history.c                              |   68 ++++++++++++++--
 6 files changed, 212 insertions(+), 47 deletions(-)
---
diff --git a/embed/history/ephy-history-service-private.h b/embed/history/ephy-history-service-private.h
index b6c0667..a940bb0 100644
--- a/embed/history/ephy-history-service-private.h
+++ b/embed/history/ephy-history-service-private.h
@@ -35,11 +35,12 @@ struct _EphyHistoryServicePrivate {
 
 void                     ephy_history_service_schedule_commit         (EphyHistoryService *self);
 gboolean                 ephy_history_service_initialize_urls_table   (EphyHistoryService *self);
-EphyHistoryURL *         ephy_history_service_get_url_row             (EphyHistoryService *self, const char *url);
+EphyHistoryURL *         ephy_history_service_get_url_row             (EphyHistoryService *self, const char *url_string, EphyHistoryURL *url);
 void                     ephy_history_service_add_url_row             (EphyHistoryService *self, EphyHistoryURL *url);
 void                     ephy_history_service_update_url_row          (EphyHistoryService *self, EphyHistoryURL *url);
 
 gboolean                 ephy_history_service_initialize_visits_table (EphyHistoryService *self);
 void                     ephy_history_service_add_visit_row           (EphyHistoryService *self, EphyHistoryPageVisit *visit);
+GList *                  ephy_history_service_find_visit_rows_in_time (EphyHistoryService *self, gint64 from, gint64 to);
 
 #endif /* EPHY_HISTORY_SERVICE_PRIVATE_H */
diff --git a/embed/history/ephy-history-service-urls-table.c b/embed/history/ephy-history-service-urls-table.c
index 018a5c7..68c5a46 100644
--- a/embed/history/ephy-history-service-urls-table.c
+++ b/embed/history/ephy-history-service-urls-table.c
@@ -52,40 +52,62 @@ ephy_history_service_initialize_urls_table (EphyHistoryService *self)
 }
 
 EphyHistoryURL *
-ephy_history_service_get_url_row (EphyHistoryService *self, const char *url_string)
+ephy_history_service_get_url_row (EphyHistoryService *self, const char *url_string, EphyHistoryURL *url)
 {
   EphyHistoryServicePrivate *priv = EPHY_HISTORY_SERVICE (self)->priv;
   EphySQLiteStatement *statement = NULL;  
-  EphyHistoryURL *url = NULL;
   GError *error = NULL;
 
   g_assert (priv->history_thread == g_thread_self ());
   g_assert (priv->history_database != NULL);
 
-  statement = ephy_sqlite_connection_create_statement (priv->history_database,
-    "SELECT id, url, title, visit_count, typed_count, last_visit_time, favicon_id FROM urls "
-    "WHERE url=?", &error);
+  if (url_string == NULL && url != NULL) {
+    url_string = url->url;
+  }
+  g_assert (url_string || url->id != -1);
+
+  if (url->id != -1) {
+    statement = ephy_sqlite_connection_create_statement (priv->history_database,
+      "SELECT id, url, title, visit_count, typed_count, last_visit_time FROM urls "
+      "WHERE id=?", &error);
+  } else {
+    statement = ephy_sqlite_connection_create_statement (priv->history_database,
+      "SELECT id, url, title, visit_count, typed_count, last_visit_time FROM urls "
+      "WHERE url=?", &error);
+  }
+
   if (NULL != error) {
     g_error ("Could not build urls table query statement: %s", error->message);
     g_error_free (error);
     return NULL;
   }
 
-  ephy_sqlite_statement_bind_string (statement, 0, url_string, &error);
+  if (url->id != -1) {
+    ephy_sqlite_statement_bind_int (statement, 0, url->id, &error);
+  } else {
+    ephy_sqlite_statement_bind_string (statement, 0, url_string, &error);
+  }
   if (NULL != error) {
     g_error ("Could not build urls table query statement: %s", error->message);
     g_error_free (error);
+    g_object_unref (statement);
+    return NULL;
+  }
+
+  if (FALSE == ephy_sqlite_statement_step (statement, &error)) {
+    g_object_unref (statement);
     return NULL;
   }
 
-  if (ephy_sqlite_statement_step (statement, &error)) {
-    url = ephy_history_url_new (ephy_sqlite_statement_get_column_as_string (statement, 1),
-                                ephy_sqlite_statement_get_column_as_string (statement, 2),
-                                ephy_sqlite_statement_get_column_as_int (statement, 3),
-                                ephy_sqlite_statement_get_column_as_int (statement, 4),
-                                ephy_sqlite_statement_get_column_as_int (statement, 5));
-    url->id = ephy_sqlite_statement_get_column_as_int (statement, 0);
+  if (url == NULL) {
+    url = ephy_history_url_new (NULL, NULL, 0, 0, 0);
   }
+  url->id = ephy_sqlite_statement_get_column_as_int (statement, 0);
+  url->url = g_strdup (ephy_sqlite_statement_get_column_as_string (statement, 1)),
+  url->title = g_strdup (ephy_sqlite_statement_get_column_as_string (statement, 2)),
+  url->visit_count = ephy_sqlite_statement_get_column_as_int (statement, 3),
+  url->typed_count = ephy_sqlite_statement_get_column_as_int (statement, 4),
+  url->last_visit_time = ephy_sqlite_statement_get_column_as_int (statement, 5);
 
   g_object_unref (statement);
   return url;
diff --git a/embed/history/ephy-history-service-visits-table.c b/embed/history/ephy-history-service-visits-table.c
index a55fd6b..94fa8c7 100644
--- a/embed/history/ephy-history-service-visits-table.c
+++ b/embed/history/ephy-history-service-visits-table.c
@@ -88,3 +88,57 @@ ephy_history_service_add_visit_row (EphyHistoryService *self, EphyHistoryPageVis
   ephy_history_service_schedule_commit (self);
   g_object_unref (statement);
 }
+
+static EphyHistoryPageVisit *
+create_page_visit_from_statement (EphySQLiteStatement *statement)
+{
+  EphyHistoryPageVisit *visit = 
+    ephy_history_page_visit_new (NULL,
+                                 ephy_sqlite_statement_get_column_as_int (statement, 1),
+                                 ephy_sqlite_statement_get_column_as_int (statement, 2));
+  visit->url->id = ephy_sqlite_statement_get_column_as_int (statement, 0);
+  return visit;
+}
+
+GList *
+ephy_history_service_find_visit_rows_in_time (EphyHistoryService *self, gint64 from, gint64 to)
+{
+  EphyHistoryServicePrivate *priv = EPHY_HISTORY_SERVICE (self)->priv;
+  EphySQLiteStatement *statement = NULL;
+  GList *visits = NULL;
+  GError *error = NULL;
+
+  g_assert (priv->history_thread == g_thread_self ());
+  g_assert (priv->history_database != NULL);
+
+  statement = ephy_sqlite_connection_create_statement (priv->history_database,
+    "SELECT url, visit_time, visit_type FROM visits WHERE visit_time >= ? and visit_time <= ?", &error);
+  if (NULL != error) {
+    g_error ("Could not build visits table query statement: %s", error->message);
+    g_error_free (error);
+    return NULL;
+  }
+
+  if (FALSE == ephy_sqlite_statement_bind_int (statement, 0, (int) from, &error) ||
+      FALSE == ephy_sqlite_statement_bind_int (statement, 1, (int) to, &error)) {
+    g_error ("Could not build urls table query statement: %s", error->message);
+    g_error_free (error);
+    g_object_unref (statement);
+    return NULL;
+  }
+
+  while (ephy_sqlite_statement_step (statement, &error)) {
+    visits = g_list_append (visits, create_page_visit_from_statement (statement));
+  }
+
+  if (NULL != error) {
+    g_error ("Could not execute urls table query statement: %s", error->message);
+    g_error_free (error);
+    g_object_unref (statement);
+    ephy_history_page_visit_list_free (visits);
+    return NULL;
+  }
+
+  g_object_unref (statement);
+  return visits;
+}
diff --git a/embed/history/ephy-history-service.c b/embed/history/ephy-history-service.c
index 4b85c71..a95101d 100644
--- a/embed/history/ephy-history-service.c
+++ b/embed/history/ephy-history-service.c
@@ -1,5 +1,4 @@
-/*
- *  Copyright  2011 Igalia S.L.
+/* *  Copyright  2011 Igalia S.L.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -25,7 +24,7 @@
 #include "ephy-history-types.h"
 #include "../sqlite/ephy-sqlite-connection.h"
 
-typedef gpointer (*EphyHistoryJobMethod)                                  (EphyHistoryService *self, gpointer data, gboolean *result);
+typedef gboolean (*EphyHistoryJobMethod)                                  (EphyHistoryService *self, gpointer data, gpointer *result);
 
 static void ephy_history_service_class_init                               (EphyHistoryServiceClass *klass);
 static void ephy_history_service_init                                     (EphyHistoryService *self);
@@ -370,8 +369,8 @@ ephy_history_service_execute_job_on_history_thread (gpointer data)
   /* TODO: Here we must check if the history thread is shutting down
      in which case we need to free the details and abort */
 
-  details->success = TRUE; /* Successful by default */
-  details->result = details->method (details->service, details->method_argument, &details->success);
+  details->result = NULL;
+  details->success = details->method (details->service, details->method_argument, &details->result);
 
   if (details->callback) {
     g_idle_add (ephy_history_service_execute_job_callback, details);
@@ -385,9 +384,8 @@ ephy_history_service_execute_job_on_history_thread (gpointer data)
 static gboolean
 ephy_history_service_execute_add_visit_helper (EphyHistoryService *self, EphyHistoryPageVisit *visit)
 {
-  EphyHistoryURL *url = ephy_history_service_get_url_row (self, visit->url->url);
-
-  if (NULL == url) { /* This URL does not yet exist in the history table */
+  /* A NULL return here means that the URL does not yet exist in the database */
+  if (NULL == ephy_history_service_get_url_row (self, visit->url->url, visit->url)) {
     visit->url->last_visit_time = visit->visit_time;
     ephy_history_service_add_url_row (self, visit->url);
 
@@ -397,42 +395,63 @@ ephy_history_service_execute_add_visit_helper (EphyHistoryService *self, EphyHis
     }
 
   } else {
-    url->visit_count++;
-    if (visit->visit_time > url->last_visit_time) {
-      url->last_visit_time = visit->visit_time;
+    visit->url->visit_count++;
+    if (visit->visit_time > visit->url->last_visit_time) {
+      visit->url->last_visit_time = visit->visit_time;
     }
-    ephy_history_service_update_url_row (self, url);
-
-    visit->url->id = url->id;
-    ephy_history_url_free (url);
+    ephy_history_service_update_url_row (self, visit->url);
   }
 
-
   ephy_history_service_add_visit_row (self, visit);
   return visit->id != -1;
 }
 
-static gpointer
-ephy_history_service_execute_add_visit (EphyHistoryService *self, EphyHistoryPageVisit *visit, gboolean *success)
+static gboolean
+ephy_history_service_execute_add_visit (EphyHistoryService *self, EphyHistoryPageVisit *visit, gpointer *result)
 {
+  gboolean success;
   g_assert (self->priv->history_thread == g_thread_self ());
-  *success = ephy_history_service_execute_add_visit_helper (self, visit);
+
+  success = ephy_history_service_execute_add_visit_helper (self, visit);
   ephy_history_service_schedule_commit (self);
-  return NULL;
+  return success;
 }
 
-static gpointer
-ephy_history_service_execute_add_visits (EphyHistoryService *self, GList *visits, gboolean *success)
+static gboolean
+ephy_history_service_execute_add_visits (EphyHistoryService *self, GList *visits, gpointer *result)
 {
+  gboolean success = TRUE;
   g_assert (self->priv->history_thread == g_thread_self ());
 
   while (visits) {
-    *success = success && ephy_history_service_execute_add_visit_helper (self, (EphyHistoryPageVisit *) visits->data);
+    success = success && ephy_history_service_execute_add_visit_helper (self, (EphyHistoryPageVisit *) visits->data);
     visits = visits->next;
   }
 
   ephy_history_service_schedule_commit (self);
-  return NULL;
+  return success;
+}
+
+static gboolean
+ephy_history_service_execute_find_visits_in_time (EphyHistoryService *self, gint64 *times, gpointer *result)
+{
+  GList *visits = ephy_history_service_find_visit_rows_in_time (self, times[0], times[1]);
+  GList *current = visits;
+
+  /* FIXME: We don't have a good way to tell the difference between failures and empty returns */
+  while (current) {
+    EphyHistoryPageVisit *visit = (EphyHistoryPageVisit *) current->data;
+    if (NULL == ephy_history_service_get_url_row (self, NULL, visit->url)) {
+      ephy_history_page_visit_list_free (visits);
+      g_error ("Tried to process an orphaned page visit");
+      return FALSE;
+    }
+
+    current = current->next;
+  }
+
+  *result = visits;
+  return TRUE;
 }
 
 void
@@ -463,3 +482,21 @@ ephy_history_service_add_visits (EphyHistoryService *self, GList *visits, EphyHi
                                       details);
 
 }
+
+void
+ephy_history_service_find_visits_in_time (EphyHistoryService *self, gint64 from, gint64 to, EphyHistoryJobCallback callback)
+{
+  EphyHistoryThreadJobDetails *details;
+
+  gint64 *times = g_malloc(2 * sizeof(gint64));
+  times[0] = from;
+  times[1] = to;
+
+  details = ephy_history_thread_job_details_new (self, 
+                                                 (EphyHistoryJobMethod) ephy_history_service_execute_find_visits_in_time,
+                                                 times, g_free, callback);
+  ephy_history_service_schedule_idle (self, G_PRIORITY_DEFAULT, 
+                                      ephy_history_service_execute_job_on_history_thread, 
+                                      details);
+
+}
diff --git a/embed/history/ephy-history-service.h b/embed/history/ephy-history-service.h
index d0f4981..ee065f9 100644
--- a/embed/history/ephy-history-service.h
+++ b/embed/history/ephy-history-service.h
@@ -56,6 +56,7 @@ EphyHistoryService *     ephy_history_service_new                     (const cha
 
 void                     ephy_history_service_add_visit               (EphyHistoryService *self, EphyHistoryPageVisit *visit, EphyHistoryJobCallback callback);
 void                     ephy_history_service_add_visits              (EphyHistoryService *self, GList *visits, EphyHistoryJobCallback callback);
+void                     ephy_history_service_find_visits_in_time     (EphyHistoryService *self, gint64 from, gint64 to, EphyHistoryJobCallback callback);
 
 G_END_DECLS
 
diff --git a/tests/ephy-history.c b/tests/ephy-history.c
index 8220538..e20c4ac 100644
--- a/tests/ephy-history.c
+++ b/tests/ephy-history.c
@@ -90,21 +90,71 @@ test_create_history_entry (void)
   gtk_main ();
 }
 
+static GList *
+create_test_page_visit_list ()
+{
+  GList *visits = NULL;
+  int i;
+  for (i = 0; i < 100; i++) {
+    visits = g_list_append (visits, ephy_history_page_visit_new ("http://www.gnome.org";, 3, EphyPageVisitTypeTyped));
+    visits = g_list_append (visits, ephy_history_page_visit_new ("http://www.gnome.org";, 5, EphyPageVisitTypeTyped));
+    visits = g_list_append (visits, ephy_history_page_visit_new ("http://www.cuteoverload.com";, 7, EphyPageVisitTypeTyped));
+    visits = g_list_append (visits, ephy_history_page_visit_new ("http://www.cuteoverload.com";, 8, EphyPageVisitTypeTyped));
+  }
+  return visits;
+}
+
+static void
+verify_create_history_entry_cb (EphyHistoryService *service, gboolean success, gpointer result)
+{
+  GList *visits = (GList *) result;
+  GList *baseline_visits = create_test_page_visit_list ();
+  GList *current = visits;
+  GList *current_baseline = baseline_visits;
+
+  g_assert (success);
+  g_assert (visits != NULL);
+  g_assert_cmpint (g_list_length (visits), ==, g_list_length (baseline_visits));
+
+  while (current_baseline) {
+    EphyHistoryPageVisit *visit, *baseline_visit;
+
+    g_assert (current);
+    visit = (EphyHistoryPageVisit *) current->data;
+    baseline_visit = (EphyHistoryPageVisit *) current_baseline->data;
+
+    g_assert_cmpstr (visit->url->url, ==, baseline_visit->url->url);
+    g_assert_cmpstr (visit->url->title, ==, baseline_visit->url->title);
+    g_assert_cmpint (visit->visit_time, ==, baseline_visit->visit_time);
+    g_assert_cmpint (visit->visit_type, ==, baseline_visit->visit_type);
+
+    current = current->next;
+    current_baseline = current_baseline->next;
+  }
+
+  ephy_history_page_visit_list_free (visits);
+  ephy_history_page_visit_list_free (baseline_visits);
+
+  g_object_unref (service);
+  gtk_main_quit ();
+}
+
+static void
+verify_create_history_entry (EphyHistoryService *service, gboolean success, gpointer result)
+{
+  g_assert (result == NULL);
+  g_assert (success);
+  ephy_history_service_find_visits_in_time (service, 0, 8, verify_create_history_entry_cb);
+}
+
 static void
 test_create_history_entries (void)
 {
   gchar *temporary_file = g_build_filename (g_get_tmp_dir (), "epiphany-history-test.db", NULL);
   EphyHistoryService *service = ensure_empty_history(temporary_file);
 
-  GList *visits = NULL;
-  visits = g_list_append (visits, ephy_history_page_visit_new ("http://www.gnome.org";, 0, EphyPageVisitTypeTyped));
-  visits = g_list_append (visits, ephy_history_page_visit_new ("http://www.gnome.org";, 3, EphyPageVisitTypeTyped));
-  visits = g_list_append (visits, ephy_history_page_visit_new ("http://www.gnome.org";, 5, EphyPageVisitTypeTyped));
-  visits = g_list_append (visits, ephy_history_page_visit_new ("http://www.cuteoverload.com";, 7, EphyPageVisitTypeTyped));
-  visits = g_list_append (visits, ephy_history_page_visit_new ("http://www.cuteoverload.com";, 8, EphyPageVisitTypeTyped));
-
-  ephy_history_service_add_visits (service, visits, page_vist_created);
-
+  GList *visits = create_test_page_visit_list ();
+  ephy_history_service_add_visits (service, visits, verify_create_history_entry);
   ephy_history_page_visit_list_free (visits);
 
   gtk_main ();



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]