aboutsummaryrefslogtreecommitdiffstats
path: root/lib/history/ephy-history-service-urls-table.c
diff options
context:
space:
mode:
authorXan Lopez <xlopez@igalia.com>2011-11-25 20:39:50 +0800
committerXan Lopez <xan@igalia.com>2012-03-07 04:49:42 +0800
commit374d66dd260b989f22eba25dad4fabc49da2d586 (patch)
treed32121ea4f1769a3a725c75f1cf01229cb533f95 /lib/history/ephy-history-service-urls-table.c
parent77ee0fdf4c5383f2134608e741b73f51ef30f430 (diff)
downloadgsoc2013-epiphany-374d66dd260b989f22eba25dad4fabc49da2d586.tar
gsoc2013-epiphany-374d66dd260b989f22eba25dad4fabc49da2d586.tar.gz
gsoc2013-epiphany-374d66dd260b989f22eba25dad4fabc49da2d586.tar.bz2
gsoc2013-epiphany-374d66dd260b989f22eba25dad4fabc49da2d586.tar.lz
gsoc2013-epiphany-374d66dd260b989f22eba25dad4fabc49da2d586.tar.xz
gsoc2013-epiphany-374d66dd260b989f22eba25dad4fabc49da2d586.tar.zst
gsoc2013-epiphany-374d66dd260b989f22eba25dad4fabc49da2d586.zip
Add EphyHistoryService and helper classes
EphyHistoryService provides a high-level API to store history information. It will processed by a worker thread using SQLite to provide a fast, responsive service to the main UI. Based on the code by Martin Robinson (mrobinson@igalia.com) and Claudio Saavedra (csaavedra@igalia.com).
Diffstat (limited to 'lib/history/ephy-history-service-urls-table.c')
-rw-r--r--lib/history/ephy-history-service-urls-table.c371
1 files changed, 371 insertions, 0 deletions
diff --git a/lib/history/ephy-history-service-urls-table.c b/lib/history/ephy-history-service-urls-table.c
new file mode 100644
index 000000000..3c7834bb8
--- /dev/null
+++ b/lib/history/ephy-history-service-urls-table.c
@@ -0,0 +1,371 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/* vim: set sw=2 ts=2 sts=2 et: */
+/*
+ * 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
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "ephy-history-service.h"
+#include "ephy-history-service-private.h"
+
+gboolean
+ephy_history_service_initialize_urls_table (EphyHistoryService *self)
+{
+ EphyHistoryServicePrivate *priv = EPHY_HISTORY_SERVICE (self)->priv;
+ GError *error = NULL;
+
+ if (ephy_sqlite_connection_table_exists (priv->history_database, "visits")) {
+ return TRUE;
+ }
+ ephy_sqlite_connection_execute (priv->history_database,
+ "CREATE TABLE urls ("
+ "id INTEGER PRIMARY KEY,"
+ "host INTEGER NOT NULL REFERENCES hosts(id) ON DELETE CASCADE,"
+ "url LONGVARCAR,"
+ "title LONGVARCAR,"
+ "visit_count INTEGER DEFAULT 0 NOT NULL,"
+ "typed_count INTEGER DEFAULT 0 NOT NULL,"
+ "last_visit_time INTEGER,"
+ "zoom_level REAL DEFAULT 1.0)", &error);
+
+ if (error) {
+ g_error("Could not create urls table: %s", error->message);
+ g_error_free (error);
+ return FALSE;
+ }
+ ephy_history_service_schedule_commit (self);
+ return TRUE;
+}
+
+EphyHistoryURL *
+ephy_history_service_get_url_row (EphyHistoryService *self, const char *url_string, EphyHistoryURL *url)
+{
+ EphyHistoryServicePrivate *priv = EPHY_HISTORY_SERVICE (self)->priv;
+ EphySQLiteStatement *statement = NULL;
+ GError *error = NULL;
+
+ g_assert (priv->history_thread == g_thread_self ());
+ g_assert (priv->history_database != NULL);
+
+ if (url_string == NULL && url != NULL) {
+ url_string = url->url;
+ }
+ g_assert (url_string || url->id != -1);
+
+ if (url != NULL && url->id != -1) {
+ statement = ephy_sqlite_connection_create_statement (priv->history_database,
+ "SELECT id, url, title, visit_count, typed_count, last_visit_time, zoom_level 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, zoom_level FROM urls "
+ "WHERE url=?", &error);
+ }
+
+ if (error) {
+ g_error ("Could not build urls table query statement: %s", error->message);
+ g_error_free (error);
+ return NULL;
+ }
+
+ if (url != NULL && 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 (error) {
+ g_error ("Could not build urls table query statement: %s", error->message);
+ g_error_free (error);
+ g_object_unref (statement);
+ return NULL;
+ }
+
+ if (ephy_sqlite_statement_step (statement, &error) == FALSE) {
+ g_object_unref (statement);
+ return NULL;
+ }
+
+ if (url == NULL) {
+ url = ephy_history_url_new (NULL, NULL, 0, 0, 0, 1.0);
+ } else {
+ if (url->url)
+ g_free (url->url);
+ if (url->title)
+ g_free (url->title);
+ }
+
+ 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);
+ url->zoom_level = ephy_sqlite_statement_get_column_as_double (statement, 6);
+
+ g_object_unref (statement);
+ return url;
+}
+
+void
+ephy_history_service_add_url_row (EphyHistoryService *self, EphyHistoryURL *url)
+{
+ EphyHistoryServicePrivate *priv = EPHY_HISTORY_SERVICE (self)->priv;
+ EphySQLiteStatement *statement = 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,
+ "INSERT INTO urls (url, title, visit_count, typed_count, last_visit_time, zoom_level, host) "
+ " VALUES (?, ?, ?, ?, ?, ?, ?)", &error);
+ if (error) {
+ g_error ("Could not build urls table addition statement: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ if (ephy_sqlite_statement_bind_string (statement, 0, url->url, &error) == FALSE ||
+ ephy_sqlite_statement_bind_string (statement, 1, url->title, &error) == FALSE ||
+ ephy_sqlite_statement_bind_int (statement, 2, url->visit_count, &error) == FALSE ||
+ ephy_sqlite_statement_bind_int (statement, 3, url->typed_count, &error) == FALSE ||
+ ephy_sqlite_statement_bind_int (statement, 4, url->last_visit_time, &error) == FALSE ||
+ ephy_sqlite_statement_bind_double (statement, 5, url->zoom_level, &error) == FALSE ||
+ ephy_sqlite_statement_bind_int (statement, 6, url->host->id, &error) == FALSE) {
+ g_error ("Could not insert URL into urls table: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ ephy_sqlite_statement_step (statement, &error);
+ if (error) {
+ g_error ("Could not insert URL into urls table: %s", error->message);
+ g_error_free (error);
+ } else {
+ url->id = ephy_sqlite_connection_get_last_insert_id (priv->history_database);
+ }
+
+ g_object_unref (statement);
+}
+
+void
+ephy_history_service_update_url_row (EphyHistoryService *self, EphyHistoryURL *url)
+{
+ EphyHistoryServicePrivate *priv = EPHY_HISTORY_SERVICE (self)->priv;
+ EphySQLiteStatement *statement;
+ 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,
+ "UPDATE urls SET title=?, visit_count=?, typed_count=?, last_visit_time=?, zoom_level=? "
+ "WHERE id=?", &error);
+ if (error) {
+ g_error ("Could not build urls table modification statement: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ if (ephy_sqlite_statement_bind_string (statement, 0, url->title, &error) == FALSE ||
+ ephy_sqlite_statement_bind_int (statement, 1, url->visit_count, &error) == FALSE ||
+ ephy_sqlite_statement_bind_int (statement, 2, url->typed_count, &error) == FALSE ||
+ ephy_sqlite_statement_bind_int (statement, 3, url->last_visit_time, &error) == FALSE ||
+ ephy_sqlite_statement_bind_double (statement, 4, url->zoom_level, &error) == FALSE ||
+ ephy_sqlite_statement_bind_int (statement, 5, url->id, &error) == FALSE) {
+ g_error ("Could not modify URL in urls table: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ ephy_sqlite_statement_step (statement, &error);
+ if (error) {
+ g_error ("Could not modify URL in urls table: %s", error->message);
+ g_error_free (error);
+ }
+ g_object_unref (statement);
+}
+
+static EphyHistoryURL *
+create_url_from_statement (EphySQLiteStatement *statement)
+{
+ EphyHistoryURL *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),
+ ephy_sqlite_statement_get_column_as_int (statement, 6));
+
+ url->id = ephy_sqlite_statement_get_column_as_int (statement, 0);
+ url->host = ephy_history_host_new (NULL, NULL, 0);
+ url->host->id = ephy_sqlite_statement_get_column_as_int (statement, 7);
+
+ return url;
+}
+
+GList *
+ephy_history_service_find_url_rows (EphyHistoryService *self, EphyHistoryQuery *query)
+{
+ EphyHistoryServicePrivate *priv = EPHY_HISTORY_SERVICE (self)->priv;
+ EphySQLiteStatement *statement = NULL;
+ GList *substring;
+ GString *statement_str;
+ GList *urls = NULL;
+ GError *error = NULL;
+ const char *base_statement = ""
+ "SELECT "
+ "DISTINCT urls.id, "
+ "urls.url, "
+ "urls.title, "
+ "urls.visit_count, "
+ "urls.typed_count, "
+ "urls.last_visit_time, "
+ "urls.zoom_level, "
+ "urls.host "
+ "FROM "
+ "urls JOIN visits ON visits.url = urls.id "
+ "WHERE ";
+
+ int i = 0;
+
+ g_assert (priv->history_thread == g_thread_self ());
+ g_assert (priv->history_database != NULL);
+
+ statement_str = g_string_new (base_statement);
+
+ if (query->from >= 0)
+ statement_str = g_string_append (statement_str, "visits.visit_time >= ? AND ");
+ if (query->to >= 0)
+ statement_str = g_string_append (statement_str, "visits.visit_time <= ? AND ");
+
+ for (substring = query->substring_list; substring != NULL; substring = substring->next)
+ statement_str = g_string_append (statement_str, "(urls.url LIKE ? OR urls.title LIKE ?) AND ");
+
+ statement_str = g_string_append (statement_str, "1");
+
+ statement = ephy_sqlite_connection_create_statement (priv->history_database,
+ statement_str->str, &error);
+ g_string_free (statement_str, TRUE);
+
+ if (error) {
+ g_error ("Could not build urls table query statement: %s", error->message);
+ g_error_free (error);
+ g_object_unref (statement);
+ return NULL;
+ }
+
+ if (query->from >= 0) {
+ if (ephy_sqlite_statement_bind_int (statement, i++, (int)query->from, &error) == FALSE) {
+ g_error ("Could not build urls table query statement: %s", error->message);
+ g_error_free (error);
+ g_object_unref (statement);
+ return NULL;
+ }
+ }
+ if (query->to >= 0) {
+ if (ephy_sqlite_statement_bind_int (statement, i++, (int)query->to, &error) == FALSE) {
+ g_error ("Could not build urls table query statement: %s", error->message);
+ g_error_free (error);
+ g_object_unref (statement);
+ return NULL;
+ }
+ }
+ for (substring = query->substring_list; substring != NULL; substring = substring->next) {
+ char *string = g_strdup_printf ("%%%s%%", (char*)substring->data);
+ if (ephy_sqlite_statement_bind_string (statement, i++, string, &error) == FALSE) {
+ g_error ("Could not build urls table query statement: %s", error->message);
+ g_error_free (error);
+ g_object_unref (statement);
+ g_free (string);
+ return NULL;
+ }
+ if (ephy_sqlite_statement_bind_string (statement, i++, string, &error) == FALSE) {
+ g_error ("Could not build urls table query statement: %s", error->message);
+ g_error_free (error);
+ g_object_unref (statement);
+ g_free (string);
+ return NULL;
+ }
+ g_free (string);
+ }
+
+ while (ephy_sqlite_statement_step (statement, &error))
+ urls = g_list_prepend (urls, create_url_from_statement (statement));
+
+ urls = g_list_reverse (urls);
+
+ if (error) {
+ g_error ("Could not execute urls table query statement: %s", error->message);
+ g_error_free (error);
+ g_object_unref (statement);
+ g_list_free_full (urls, (GDestroyNotify)ephy_history_url_free);
+ return NULL;
+ }
+
+ g_object_unref (statement);
+ return urls;
+}
+
+void
+ephy_history_service_delete_url (EphyHistoryService *self, EphyHistoryURL *url)
+{
+ EphyHistoryServicePrivate *priv = EPHY_HISTORY_SERVICE (self)->priv;
+ EphySQLiteStatement *statement = NULL;
+ gchar *sql_statement;
+ GError *error = NULL;
+
+ g_assert (priv->history_thread == g_thread_self ());
+ g_assert (priv->history_database != NULL);
+
+ g_assert (url->id != -1 || url->url);
+
+ if (url->id != -1)
+ sql_statement = g_strdup ("DELETE FROM urls WHERE id=?");
+ else
+ sql_statement = g_strdup ("DELETE FROM urls WHERE url=?");
+
+ statement = ephy_sqlite_connection_create_statement (priv->history_database,
+ sql_statement, &error);
+ g_free (sql_statement);
+
+ if (error) {
+ g_error ("Could not build urls table query statement: %s", error->message);
+ g_error_free (error);
+ g_object_unref (statement);
+ return;
+ }
+
+ if (url->id != -1)
+ ephy_sqlite_statement_bind_int (statement, 0, url->id, &error);
+ else
+ ephy_sqlite_statement_bind_string (statement, 0, url->url, &error);
+
+ if (error) {
+ g_error ("Could not build urls table query statement: %s", error->message);
+ g_error_free (error);
+ g_object_unref (statement);
+ return;
+ }
+
+ ephy_sqlite_statement_step (statement, &error);
+ if (error) {
+ g_error ("Could not modify URL in urls table: %s", error->message);
+ g_error_free (error);
+ }
+ g_object_unref (statement);
+}