[gom] gom: Track whether GomResource objects come from the DB



commit b35e8ce5559e4b2ebe182362ad7a3860e5977f6a
Author: Bastien Nocera <hadess hadess net>
Date:   Wed May 14 16:46:36 2014 +0200

    gom: Track whether GomResource objects come from the DB
    
    We now track whether objects come from the database
    (GomResourceGroup's fetch will tag items as such when getting them),
    so that we can assert whether saves on that object would be an insert or
    an update.
    
    We also track the primary key changing back to zero/null, so that
    something like getting an item from the DB, resetting the ID, and saving
    it will create a duplicate as intended.
    
    This fixes the failing test case introduced in
    8e5602fa15fee310919a2ef087bc4726d4891f00

 gom/Makefile.include      |    2 +-
 gom/gom-command-builder.c |   22 +++++++++++++++++
 gom/gom-resource-group.c  |    2 +
 gom/gom-resource-priv.h   |   31 ++++++++++++++++++++++++
 gom/gom-resource.c        |   57 +++++++++++++++++++++++++++++++++++++++++----
 5 files changed, 108 insertions(+), 6 deletions(-)
---
diff --git a/gom/Makefile.include b/gom/Makefile.include
index 1915c7f..e8855a7 100644
--- a/gom/Makefile.include
+++ b/gom/Makefile.include
@@ -16,7 +16,7 @@ INST_H_FILES += $(top_srcdir)/gom/gom-repository.h
 INST_H_FILES += $(top_srcdir)/gom/gom-resource-group.h
 INST_H_FILES += $(top_srcdir)/gom/gom-resource.h
 
-NOINST_H_FILES =
+NOINST_H_FILES = $(top_srcdir)/gom/gom-resource-priv.h
 
 libgom_1_0_la_SOURCES =
 libgom_1_0_la_SOURCES += $(INST_H_FILES)
diff --git a/gom/gom-command-builder.c b/gom/gom-command-builder.c
index 3574ccf..99e9552 100644
--- a/gom/gom-command-builder.c
+++ b/gom/gom-command-builder.c
@@ -23,6 +23,7 @@
 #include "gom-command-builder.h"
 #include "gom-filter.h"
 #include "gom-resource.h"
+#include "gom-resource-priv.h"
 
 G_DEFINE_TYPE(GomCommandBuilder, gom_command_builder, G_TYPE_OBJECT)
 
@@ -674,6 +675,7 @@ gom_command_builder_build_insert (GomCommandBuilder *builder,
    GomCommand *command = NULL;
    GParamSpec **pspecs = NULL;
    gboolean did_pspec = FALSE;
+   gboolean has_dynamic_pkey;
    GString *str = NULL;
    guint n_pspecs = 0;
    guint i = 0;
@@ -690,6 +692,12 @@ gom_command_builder_build_insert (GomCommandBuilder *builder,
    str = g_string_new("INSERT INTO ");
    g_string_append_printf(str, "%s (", klass->table);
 
+   has_dynamic_pkey = gom_resource_has_dynamic_pkey (priv->resource_type);
+   if (!has_dynamic_pkey) {
+     g_string_append_printf(str, "'%s'", klass->primary_key);
+     did_pspec = TRUE;
+   }
+
    for (i = 0; i < n_pspecs; i++) {
       if (do_prop_on_insert(pspecs[i], klass, priv->resource_type)) {
          if (did_pspec) {
@@ -704,6 +712,11 @@ gom_command_builder_build_insert (GomCommandBuilder *builder,
 
    did_pspec = FALSE;
 
+   if (!has_dynamic_pkey) {
+     g_string_append(str, "?");
+     did_pspec = TRUE;
+   }
+
    for (i = 0; i < n_pspecs; i++) {
       if (do_prop_on_insert(pspecs[i], klass, priv->resource_type)) {
          if (did_pspec) {
@@ -721,6 +734,15 @@ gom_command_builder_build_insert (GomCommandBuilder *builder,
                           "sql", str->str,
                           NULL);
 
+   if (!has_dynamic_pkey) {
+     GValue value = { 0 };
+
+     resource_get_property(G_OBJECT(resource), klass->primary_key, &value);
+     gom_command_set_param(command, idx++, &value);
+     g_value_unset(&value);
+     did_pspec = TRUE;
+   }
+
    for (i = 0; i < n_pspecs; i++) {
       if (do_prop_on_insert(pspecs[i], klass, priv->resource_type)) {
          GValue value = { 0 };
diff --git a/gom/gom-resource-group.c b/gom/gom-resource-group.c
index e832148..4096af2 100644
--- a/gom/gom-resource-group.c
+++ b/gom/gom-resource-group.c
@@ -25,6 +25,7 @@
 #include "gom-filter.h"
 #include "gom-repository.h"
 #include "gom-resource.h"
+#include "gom-resource-priv.h"
 #include "gom-resource-group.h"
 
 G_DEFINE_TYPE(GomResourceGroup, gom_resource_group, G_TYPE_OBJECT)
@@ -303,6 +304,7 @@ gom_resource_group_fetch_cb (GomAdapter *adapter,
                               "repository", repository,
                               NULL);
       set_props(resource, cursor);
+      gom_resource_set_is_from_table(resource, TRUE);
       g_hash_table_insert(group->priv->items, key, resource);
    }
 
diff --git a/gom/gom-resource-priv.h b/gom/gom-resource-priv.h
new file mode 100644
index 0000000..141ada3
--- /dev/null
+++ b/gom/gom-resource-priv.h
@@ -0,0 +1,31 @@
+/* gom-resource.h
+ *
+ * Copyright (C) 2011 Christian Hergert <chris dronelabs com>
+ *
+ * This file 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.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GOM_RESOURCE_PRIV_H
+#define GOM_RESOURCE_PRIV_H
+
+#include "gom-resource.h"
+
+G_BEGIN_DECLS
+
+gboolean gom_resource_get_is_from_table (GomResource *resource);
+void     gom_resource_set_is_from_table (GomResource *resource, gboolean is_from_table);
+gboolean gom_resource_has_dynamic_pkey  (GType type);
+G_END_DECLS
+
+#endif /* GOM_RESOURCE_PRIV_H */
diff --git a/gom/gom-resource.c b/gom/gom-resource.c
index f5982f9..54c2b95 100644
--- a/gom/gom-resource.c
+++ b/gom/gom-resource.c
@@ -25,12 +25,14 @@
 #include "gom-filter.h"
 #include "gom-repository.h"
 #include "gom-resource.h"
+#include "gom-resource-priv.h"
 
 G_DEFINE_ABSTRACT_TYPE(GomResource, gom_resource, G_TYPE_OBJECT)
 
 struct _GomResourcePrivate
 {
    GomRepository *repository;
+   gboolean       is_from_table;
 };
 
 enum
@@ -465,8 +467,8 @@ gom_resource_delete_finish (GomResource   *resource,
    return ret;
 }
 
-static gboolean
-is_dynamic_pkey (GType type)
+gboolean
+gom_resource_has_dynamic_pkey (GType type)
 {
    GomResourceClass *klass;
    GParamSpec *pspec;
@@ -549,6 +551,7 @@ gom_resource_do_save (GomResource  *resource,
    GSList *types = NULL;
    GSList *iter;
    GType resource_type;
+   gboolean has_pkey;
 
    g_return_val_if_fail(GOM_IS_RESOURCE(resource), FALSE);
    g_return_val_if_fail(GOM_IS_ADAPTER(adapter), FALSE);
@@ -560,7 +563,14 @@ gom_resource_do_save (GomResource  *resource,
                           "adapter", adapter,
                           NULL);
 
-   is_insert = !has_primary_key(resource);
+   has_pkey = has_primary_key(resource);
+   if (has_pkey) {
+     /* Could be an insert for a non-automatic primary key,
+      * or an update */
+     is_insert = !resource->priv->is_from_table;
+   } else {
+     is_insert = TRUE;
+   }
 
    do {
       types = g_slist_prepend(types, GINT_TO_POINTER(resource_type));
@@ -586,7 +596,7 @@ gom_resource_do_save (GomResource  *resource,
          goto out;
       }
 
-      if (is_insert && row_id == -1 && is_dynamic_pkey(resource_type)) {
+      if (is_insert && row_id == -1 && gom_resource_has_dynamic_pkey(resource_type)) {
          sqlite3 *handle = gom_adapter_get_handle(adapter);
          GValue value = { 0 };
 
@@ -887,7 +897,8 @@ gom_resource_fetch_m2m_finish (GomResource   *resource,
 static void
 gom_resource_finalize (GObject *object)
 {
-   gom_resource_set_repository(GOM_RESOURCE(object), NULL);
+   GomResource *resource = (GomResource *) object;
+   gom_resource_set_repository(resource, NULL);
    G_OBJECT_CLASS(gom_resource_parent_class)->finalize(object);
 }
 
@@ -973,6 +984,19 @@ gom_resource_class_init (GomResourceClass *klass)
                                    gParamSpecs[PROP_REPOSITORY]);
 }
 
+static void
+pkey_changed_cb (GObject    *gobject,
+                 GParamSpec *pspec,
+                 gpointer    user_data)
+{
+  GomResource *resource = (GomResource *) gobject;
+
+  /* Did the developer reset the primary key? */
+  if (!has_primary_key(GOM_RESOURCE(resource))) {
+     resource->priv->is_from_table = FALSE;
+  }
+}
+
 /**
  * gom_resource_init:
  * @resource: (in): A #GomResource.
@@ -982,10 +1006,33 @@ gom_resource_class_init (GomResourceClass *klass)
 static void
 gom_resource_init (GomResource *resource)
 {
+   char *pkey_signal;
+   GomResourceClass *klass;
+
    resource->priv =
       G_TYPE_INSTANCE_GET_PRIVATE(resource,
                                   GOM_TYPE_RESOURCE,
                                   GomResourcePrivate);
+
+   /* Monitor the primary key */
+   klass = GOM_RESOURCE_CLASS (G_OBJECT_GET_CLASS(resource));
+   pkey_signal = g_strdup_printf("notify::%s", klass->primary_key);
+   g_signal_connect (G_OBJECT (resource), pkey_signal,
+                     G_CALLBACK (pkey_changed_cb), NULL);
+   g_free(pkey_signal);
+}
+
+gboolean
+gom_resource_get_is_from_table (GomResource *resource)
+{
+   return resource->priv->is_from_table;
+}
+
+void
+gom_resource_set_is_from_table (GomResource *resource,
+                                gboolean is_from_table)
+{
+   resource->priv->is_from_table = is_from_table;
 }
 
 GQuark


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