[evolution-data-server/openismus-work-master: 69/118] Added EDataBookCursorSqlite
- From: Tristan Van Berkom <tvb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server/openismus-work-master: 69/118] Added EDataBookCursorSqlite
- Date: Sat, 12 Oct 2013 02:00:45 +0000 (UTC)
commit 2424c0d62fee7a71533063fa13dbb6b9b56e5cc0
Author: Tristan Van Berkom <tristanvb openismus com>
Date: Tue Jul 2 17:42:58 2013 +0900
Added EDataBookCursorSqlite
EDataBookCursorSqlite is a cursor implementation using EBookBackendSqliteDB
.../libedata-book/e-data-book-cursor-sqlite.c | 515 ++++++++++++++++++++
.../libedata-book/e-data-book-cursor-sqlite.h | 65 +++
2 files changed, 580 insertions(+), 0 deletions(-)
---
diff --git a/addressbook/libedata-book/e-data-book-cursor-sqlite.c
b/addressbook/libedata-book/e-data-book-cursor-sqlite.c
new file mode 100644
index 0000000..7a3b721
--- /dev/null
+++ b/addressbook/libedata-book/e-data-book-cursor-sqlite.c
@@ -0,0 +1,515 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ * Author: Tristan Van Berkom <tristanvb openismus com>
+ */
+
+/**
+ * SECTION: e-data-book-cursor-sqlite
+ * @include: libedata-book/libedata-book.h
+ * @short_description: The SQLite cursor implementation
+ *
+ * This cursor implementation can be used with any backend which
+ * stores contacts using #EBookBackendSqliteDB.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-data-book-cursor-sqlite.h"
+
+/* GObjectClass */
+static void e_data_book_cursor_sqlite_dispose (GObject *object);
+static void e_data_book_cursor_sqlite_finalize (GObject *object);
+static void e_data_book_cursor_sqlite_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+/* EDataBookCursorClass */
+static gboolean e_data_book_cursor_sqlite_set_sexp (EDataBookCursor *cursor,
+ const gchar *sexp,
+ GError **error);
+static gboolean e_data_book_cursor_sqlite_move_by (EDataBookCursor *cursor,
+ const gchar *revision_guard,
+ EBookCursorOrigin origin,
+ gint count,
+ GSList **results,
+ GError **error);
+static gboolean e_data_book_cursor_sqlite_set_alphabetic_index (EDataBookCursor *cursor,
+ gint index,
+ const gchar *locale,
+ GError **error);
+static gboolean e_data_book_cursor_sqlite_get_position (EDataBookCursor *cursor,
+ gint *total,
+ gint *position,
+ GError **error);
+static gint e_data_book_cursor_sqlite_compare (EDataBookCursor *cursor,
+ EContact *contact,
+ gboolean *matches_sexp);
+static gboolean e_data_book_cursor_sqlite_load_locale (EDataBookCursor *cursor,
+ gchar **locale,
+ GError **error);
+
+struct _EDataBookCursorSqlitePrivate {
+ EBookBackendSqliteDB *ebsdb;
+ EbSdbCursor *cursor;
+ gchar *folder_id;
+};
+
+enum {
+ PROP_0,
+ PROP_EBSDB,
+ PROP_FOLDER_ID,
+ PROP_CURSOR,
+};
+
+G_DEFINE_TYPE (EDataBookCursorSqlite, e_data_book_cursor_sqlite, E_TYPE_DATA_BOOK_CURSOR);
+
+/************************************************
+ * GObjectClass *
+ ************************************************/
+static void
+e_data_book_cursor_sqlite_class_init (EDataBookCursorSqliteClass *class)
+{
+ GObjectClass *object_class;
+ EDataBookCursorClass *cursor_class;
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = e_data_book_cursor_sqlite_dispose;
+ object_class->finalize = e_data_book_cursor_sqlite_finalize;
+ object_class->set_property = e_data_book_cursor_sqlite_set_property;
+
+ cursor_class = E_DATA_BOOK_CURSOR_CLASS (class);
+ cursor_class->set_sexp = e_data_book_cursor_sqlite_set_sexp;
+ cursor_class->move_by = e_data_book_cursor_sqlite_move_by;
+ cursor_class->set_alphabetic_index = e_data_book_cursor_sqlite_set_alphabetic_index;
+ cursor_class->get_position = e_data_book_cursor_sqlite_get_position;
+ cursor_class->compare = e_data_book_cursor_sqlite_compare;
+ cursor_class->load_locale = e_data_book_cursor_sqlite_load_locale;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_EBSDB,
+ g_param_spec_object (
+ "ebsdb", "EBookBackendSqliteDB",
+ "The EBookBackendSqliteDB to use for queries",
+ E_TYPE_BOOK_BACKEND_SQLITEDB,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FOLDER_ID,
+ g_param_spec_string (
+ "folder-id", "Folder ID",
+ "The folder identifier to use with the EBookBackendSqliteDB object",
+ NULL,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_CURSOR,
+ g_param_spec_pointer (
+ "cursor", "Cursor",
+ "The EbSdbCursor pointer",
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_type_class_add_private (class, sizeof (EDataBookCursorSqlitePrivate));
+}
+
+static void
+e_data_book_cursor_sqlite_init (EDataBookCursorSqlite *cursor)
+{
+ cursor->priv =
+ G_TYPE_INSTANCE_GET_PRIVATE (cursor,
+ E_TYPE_DATA_BOOK_CURSOR_SQLITE,
+ EDataBookCursorSqlitePrivate);
+}
+
+static void
+e_data_book_cursor_sqlite_dispose (GObject *object)
+{
+ EDataBookCursorSqlite *cursor = E_DATA_BOOK_CURSOR_SQLITE (object);
+ EDataBookCursorSqlitePrivate *priv = cursor->priv;
+
+ if (priv->ebsdb) {
+
+ if (priv->cursor)
+ e_book_backend_sqlitedb_cursor_free (priv->ebsdb,
+ priv->cursor);
+
+ g_object_unref (priv->ebsdb);
+ priv->ebsdb = NULL;
+ priv->cursor = NULL;
+ }
+
+ G_OBJECT_CLASS (e_data_book_cursor_sqlite_parent_class)->dispose (object);
+}
+
+static void
+e_data_book_cursor_sqlite_finalize (GObject *object)
+{
+ EDataBookCursorSqlite *cursor = E_DATA_BOOK_CURSOR_SQLITE (object);
+ EDataBookCursorSqlitePrivate *priv = cursor->priv;
+
+ g_free (priv->folder_id);
+
+ G_OBJECT_CLASS (e_data_book_cursor_sqlite_parent_class)->finalize (object);
+}
+
+static void
+e_data_book_cursor_sqlite_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EDataBookCursorSqlite *cursor = E_DATA_BOOK_CURSOR_SQLITE (object);
+ EDataBookCursorSqlitePrivate *priv = cursor->priv;
+
+ switch (property_id) {
+ case PROP_EBSDB:
+ /* Construct-only, can only be set once */
+ priv->ebsdb = g_value_dup_object (value);
+ break;
+ case PROP_FOLDER_ID:
+ /* Construct-only, can only be set once */
+ priv->folder_id = g_value_dup_string (value);
+ break;
+ case PROP_CURSOR:
+ /* Construct-only, can only be set once */
+ priv->cursor = g_value_get_pointer (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+/************************************************
+ * EDataBookCursorClass *
+ ************************************************/
+static gboolean
+e_data_book_cursor_sqlite_set_sexp (EDataBookCursor *cursor,
+ const gchar *sexp,
+ GError **error)
+{
+ EDataBookCursorSqlite *cursor_sqlite;
+ EDataBookCursorSqlitePrivate *priv;
+ GError *local_error = NULL;
+ gboolean success;
+
+ cursor_sqlite = E_DATA_BOOK_CURSOR_SQLITE (cursor);
+ priv = cursor_sqlite->priv;
+
+ success = e_book_backend_sqlitedb_cursor_set_sexp (priv->ebsdb,
+ priv->cursor,
+ sexp,
+ &local_error);
+
+ if (!success) {
+ if (g_error_matches (local_error,
+ E_BOOK_SDB_ERROR,
+ E_BOOK_SDB_ERROR_INVALID_QUERY)) {
+ g_set_error_literal (error,
+ E_CLIENT_ERROR,
+ E_CLIENT_ERROR_INVALID_QUERY,
+ local_error->message);
+ g_clear_error (&local_error);
+ } else {
+ g_propagate_error (error, local_error);
+ }
+ }
+
+ return success;
+}
+
+static gboolean
+convert_origin (EBookCursorOrigin src_origin,
+ EbSdbCurorOrigin *dest_origin,
+ GError **error)
+{
+ gboolean success = TRUE;
+
+ switch (src_origin) {
+ case E_BOOK_CURSOR_ORIGIN_CURRENT:
+ *dest_origin = EBSDB_CURSOR_ORIGIN_CURRENT;
+ break;
+ case E_BOOK_CURSOR_ORIGIN_PREVIOUS:
+ *dest_origin = EBSDB_CURSOR_ORIGIN_PREVIOUS;
+ break;
+ case E_BOOK_CURSOR_ORIGIN_RESET:
+ *dest_origin = EBSDB_CURSOR_ORIGIN_RESET;
+ break;
+ default:
+ success = FALSE;
+ g_set_error (error,
+ E_CLIENT_ERROR,
+ E_CLIENT_ERROR_INVALID_ARG,
+ "Unrecognized cursor origin");
+ break;
+ }
+
+ return success;
+}
+
+static gboolean
+e_data_book_cursor_sqlite_move_by (EDataBookCursor *cursor,
+ const gchar *revision_guard,
+ EBookCursorOrigin origin,
+ gint count,
+ GSList **results,
+ GError **error)
+{
+ EDataBookCursorSqlite *cursor_sqlite;
+ EDataBookCursorSqlitePrivate *priv;
+ GSList *local_results = NULL, *local_converted_results = NULL, *l;
+ EbSdbCurorOrigin sqlitedb_origin = 0;
+ gchar *revision = NULL;
+ gboolean success = FALSE;
+
+ cursor_sqlite = E_DATA_BOOK_CURSOR_SQLITE (cursor);
+ priv = cursor_sqlite->priv;
+
+ if (!convert_origin (origin, &sqlitedb_origin, error))
+ return FALSE;
+
+ /* Here we check the EBookBackendSqliteDB revision
+ * against the revision_guard with an atomic transaction
+ * with the sqlite.
+ *
+ * The addressbook modifications and revision changes
+ * are also atomically commit to the SQLite.
+ */
+ success = e_book_backend_sqlitedb_lock_updates (priv->ebsdb, error);
+
+ if (success && revision_guard)
+ success = e_book_backend_sqlitedb_get_revision (priv->ebsdb,
+ priv->folder_id,
+ &revision,
+ error);
+
+ if (success && revision_guard &&
+ g_strcmp0 (revision, revision_guard) != 0) {
+
+ g_set_error (error,
+ E_CLIENT_ERROR,
+ E_CLIENT_ERROR_OUT_OF_SYNC,
+ "Out of sync revision while moving cursor");
+ success = FALSE;
+ }
+
+ if (success)
+ success = e_book_backend_sqlitedb_cursor_move_by (priv->ebsdb,
+ priv->cursor,
+ sqlitedb_origin,
+ count,
+ &local_results,
+ error);
+
+ if (success) {
+ success = e_book_backend_sqlitedb_unlock_updates (priv->ebsdb, TRUE, error);
+
+ } else {
+ GError *local_error = NULL;
+
+ /* Rollback transaction */
+ if (!e_book_backend_sqlitedb_unlock_updates (priv->ebsdb, FALSE, &local_error)) {
+ g_warning ("Failed to rollback transaction after failing move cursor: %s",
+ local_error->message);
+ g_clear_error (&local_error);
+ }
+ }
+
+ for (l = local_results; l; l = l->next) {
+ EbSdbSearchData *data = l->data;
+
+ local_converted_results =
+ g_slist_prepend (local_converted_results, data->vcard);
+ data->vcard = NULL;
+ }
+
+ g_slist_free_full (local_results, (GDestroyNotify)e_book_backend_sqlitedb_search_data_free);
+
+ if (results)
+ *results = g_slist_reverse (local_converted_results);
+ else
+ g_slist_free_full (local_converted_results, (GDestroyNotify)g_free);
+
+ g_free (revision);
+
+ return success;
+}
+
+static gboolean
+e_data_book_cursor_sqlite_set_alphabetic_index (EDataBookCursor *cursor,
+ gint index,
+ const gchar *locale,
+ GError **error)
+{
+ EDataBookCursorSqlite *cursor_sqlite;
+ EDataBookCursorSqlitePrivate *priv;
+ gchar *current_locale = NULL;
+
+ cursor_sqlite = E_DATA_BOOK_CURSOR_SQLITE (cursor);
+ priv = cursor_sqlite->priv;
+
+ if (!e_book_backend_sqlitedb_get_locale (priv->ebsdb, priv->folder_id,
+ ¤t_locale, error))
+ return FALSE;
+
+ /* Locale mismatch, need to report error */
+ if (g_strcmp0 (current_locale, locale) != 0) {
+ g_set_error (error,
+ E_CLIENT_ERROR,
+ E_CLIENT_ERROR_OUT_OF_SYNC,
+ "Alphabetic index was set for incorrect locale");
+ g_free (current_locale);
+ return FALSE;
+ }
+
+ e_book_backend_sqlitedb_cursor_set_target_alphabetic_index (priv->ebsdb,
+ priv->cursor,
+ index);
+ g_free (current_locale);
+ return TRUE;
+}
+
+static gboolean
+e_data_book_cursor_sqlite_get_position (EDataBookCursor *cursor,
+ gint *total,
+ gint *position,
+ GError **error)
+{
+ EDataBookCursorSqlite *cursor_sqlite;
+ EDataBookCursorSqlitePrivate *priv;
+
+ cursor_sqlite = E_DATA_BOOK_CURSOR_SQLITE (cursor);
+ priv = cursor_sqlite->priv;
+
+ return e_book_backend_sqlitedb_cursor_calculate (priv->ebsdb,
+ priv->cursor,
+ total, position,
+ error);
+}
+
+static gint
+e_data_book_cursor_sqlite_compare (EDataBookCursor *cursor,
+ EContact *contact,
+ gboolean *matches_sexp)
+{
+ EDataBookCursorSqlite *cursor_sqlite;
+ EDataBookCursorSqlitePrivate *priv;
+
+ cursor_sqlite = E_DATA_BOOK_CURSOR_SQLITE (cursor);
+ priv = cursor_sqlite->priv;
+
+ return e_book_backend_sqlitedb_cursor_compare (priv->ebsdb,
+ priv->cursor,
+ contact,
+ matches_sexp);
+}
+
+static gboolean
+e_data_book_cursor_sqlite_load_locale (EDataBookCursor *cursor,
+ gchar **locale,
+ GError **error)
+{
+ EDataBookCursorSqlite *cursor_sqlite;
+ EDataBookCursorSqlitePrivate *priv;
+
+ cursor_sqlite = E_DATA_BOOK_CURSOR_SQLITE (cursor);
+ priv = cursor_sqlite->priv;
+
+ return e_book_backend_sqlitedb_get_locale (priv->ebsdb,
+ priv->folder_id,
+ locale,
+ error);
+}
+
+/************************************************
+ * API *
+ ************************************************/
+/**
+ * e_data_book_cursor_sqlite_new:
+ * @backend: the #EBookBackend creating this cursor
+ * @ebsdb: the #EBookBackendSqliteDB object to base this cursor on
+ * @folder_id: the folder identifier to be used in EBookBackendSqliteDB API calls
+ * @sort_fields: (array length=n_fields): an array of #EContactFields as sort keys in order of priority
+ * @sort_types: (array length=n_fields): an array of #EBookSortTypes, one for each field in @sort_fields
+ * @n_fields: the number of fields to sort results by.
+ * @error: a return location to story any error that might be reported.
+ *
+ * Creates an #EDataBookCursor and implements all of the cursor methods
+ * using the delegate @ebsdb object.
+ *
+ * This is a suitable cursor type for any backend which stores it's contacts
+ * using the #EBookBackendSqliteDB object.
+ *
+ * Returns: (transfer full): A newly created #EDataBookCursor, or %NULL if cursor creation failed.
+ */
+EDataBookCursor *
+e_data_book_cursor_sqlite_new (EBookBackend *backend,
+ EBookBackendSqliteDB *ebsdb,
+ const gchar *folder_id,
+ EContactField *sort_fields,
+ EBookSortType *sort_types,
+ guint n_fields,
+ GError **error)
+{
+ EDataBookCursor *cursor = NULL;
+ EbSdbCursor *ebsdb_cursor;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), NULL);
+ g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
+ g_return_val_if_fail (folder_id && folder_id[0], NULL);
+
+ ebsdb_cursor = e_book_backend_sqlitedb_cursor_new (ebsdb, folder_id, NULL,
+ sort_fields,
+ sort_types,
+ n_fields,
+ &local_error);
+
+ if (ebsdb_cursor) {
+ cursor = g_object_new (E_TYPE_DATA_BOOK_CURSOR_SQLITE,
+ "backend", backend,
+ "ebsdb", ebsdb,
+ "folder-id", folder_id,
+ "cursor", ebsdb_cursor,
+ NULL);
+
+ /* Initially created cursors should have a position & total */
+ if (!e_data_book_cursor_load_locale (E_DATA_BOOK_CURSOR (cursor),
+ NULL, error))
+ g_clear_object (&cursor);
+
+ } else if (g_error_matches (local_error,
+ E_BOOK_SDB_ERROR,
+ E_BOOK_SDB_ERROR_INVALID_QUERY)) {
+ g_set_error_literal (error,
+ E_CLIENT_ERROR,
+ E_CLIENT_ERROR_INVALID_QUERY,
+ local_error->message);
+ g_clear_error (&local_error);
+ } else {
+ g_propagate_error (error, local_error);
+ }
+
+ return cursor;
+}
diff --git a/addressbook/libedata-book/e-data-book-cursor-sqlite.h
b/addressbook/libedata-book/e-data-book-cursor-sqlite.h
new file mode 100644
index 0000000..1b6f9de
--- /dev/null
+++ b/addressbook/libedata-book/e-data-book-cursor-sqlite.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ * Author: Tristan Van Berkom <tristanvb openismus com>
+ */
+
+#if !defined (__LIBEDATA_BOOK_H_INSIDE__) && !defined (LIBEDATA_BOOK_COMPILATION)
+#error "Only <libedata-book/libedata-book.h> should be included directly."
+#endif
+
+#ifndef E_DATA_BOOK_CURSOR_SQLITE_H
+#define E_DATA_BOOK_CURSOR_SQLITE_H
+
+#include <libedata-book/e-data-book-cursor.h>
+#include <libedata-book/e-book-backend-sqlitedb.h>
+#include <libedata-book/e-book-backend.h>
+
+#define E_TYPE_DATA_BOOK_CURSOR_SQLITE (e_data_book_cursor_sqlite_get_type ())
+#define E_DATA_BOOK_CURSOR_SQLITE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o),
E_TYPE_DATA_BOOK_CURSOR_SQLITE, EDataBookCursorSqlite))
+#define E_DATA_BOOK_CURSOR_SQLITE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_DATA_BOOK_CURSOR_SQLITE,
EDataBookCursorSqliteClass))
+#define E_IS_DATA_BOOK_CURSOR_SQLITE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o),
E_TYPE_DATA_BOOK_CURSOR_SQLITE))
+#define E_IS_DATA_BOOK_CURSOR_SQLITE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_DATA_BOOK_CURSOR_SQLITE))
+#define E_DATA_BOOK_CURSOR_SQLITE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o),
E_TYPE_DATA_BOOK_CURSOR_SQLITE, EDataBookCursorSqliteClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EDataBookCursorSqlite EDataBookCursorSqlite;
+typedef struct _EDataBookCursorSqliteClass EDataBookCursorSqliteClass;
+typedef struct _EDataBookCursorSqlitePrivate EDataBookCursorSqlitePrivate;
+
+struct _EDataBookCursorSqlite {
+ EDataBookCursor parent;
+ EDataBookCursorSqlitePrivate *priv;
+};
+
+struct _EDataBookCursorSqliteClass {
+ EDataBookCursorClass parent;
+};
+
+GType e_data_book_cursor_sqlite_get_type (void);
+EDataBookCursor *e_data_book_cursor_sqlite_new (EBookBackend *backend,
+ EBookBackendSqliteDB *ebsdb,
+ const gchar *folder_id,
+ EContactField *sort_fields,
+ EBookSortType *sort_types,
+ guint n_fields,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* E_DATA_BOOK_CURSOR_SQLITE_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]