[evolution-data-server] I#254 - Calendar: Add 'has-end?', 'has-due?' and 'has-duration?' into SExp
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] I#254 - Calendar: Add 'has-end?', 'has-due?' and 'has-duration?' into SExp
- Date: Thu, 8 Oct 2020 15:16:42 +0000 (UTC)
commit b77b914a7a54788f1097ec65502ac07d8eebf2b3
Author: Milan Crha <mcrha redhat com>
Date: Thu Oct 8 17:14:33 2020 +0200
I#254 - Calendar: Add 'has-end?', 'has-due?' and 'has-duration?' into SExp
Closes https://gitlab.gnome.org/GNOME/evolution-data-server/-/issues/254
src/calendar/libedata-cal/e-cal-backend-sexp.c | 94 ++++++++++++--
src/calendar/libedata-cal/e-cal-cache.c | 168 ++++++++++++++-----------
tests/libedata-cal/components/event-3.ics | 2 +-
tests/libedata-cal/components/task-6.ics | 1 +
tests/libedata-cal/test-cal-cache-search.c | 53 ++++++++
5 files changed, 230 insertions(+), 88 deletions(-)
---
diff --git a/src/calendar/libedata-cal/e-cal-backend-sexp.c b/src/calendar/libedata-cal/e-cal-backend-sexp.c
index 44ffb2c59..07e342f7f 100644
--- a/src/calendar/libedata-cal/e-cal-backend-sexp.c
+++ b/src/calendar/libedata-cal/e-cal-backend-sexp.c
@@ -759,6 +759,19 @@ func_contains (ESExp *esexp,
return result;
}
+static ESExpResult *
+check_has_property (ESExp *esexp,
+ ECalComponent *comp,
+ ICalPropertyKind kind)
+{
+ ESExpResult *result;
+
+ result = e_sexp_result_new (esexp, ESEXP_RES_BOOL);
+ result->value.boolean = e_cal_util_component_has_property (e_cal_component_get_icalcomponent (comp),
kind);
+
+ return result;
+}
+
/* (has-start?)
*
* A boolean value for components that have/don't have filled start date/time.
@@ -772,24 +785,80 @@ func_has_start (ESExp *esexp,
gpointer data)
{
SearchContext *ctx = data;
- ESExpResult *result;
- ECalComponentDateTime *dt;
- /* Check argument types */
+ if (argc != 0) {
+ e_sexp_fatal_error (esexp, _("“%s” expects no arguments"), "has-start");
+ return NULL;
+ }
+
+ return check_has_property (esexp, ctx->comp, I_CAL_DTSTART_PROPERTY);
+}
+
+/* (has-end?)
+ *
+ * A boolean value for components that have/don't have filled DTEND property.
+ *
+ * Returns: whether the component has DTEND filled
+ */
+static ESExpResult *
+func_has_end (ESExp *esexp,
+ gint argc,
+ ESExpResult **argv,
+ gpointer data)
+{
+ SearchContext *ctx = data;
if (argc != 0) {
- e_sexp_fatal_error (
- esexp, _("“%s” expects no arguments"),
- "has-start");
+ e_sexp_fatal_error (esexp, _("“%s” expects no arguments"), "has-end");
return NULL;
}
- dt = e_cal_component_get_dtstart (ctx->comp);
- result = e_sexp_result_new (esexp, ESEXP_RES_BOOL);
- result->value.boolean = dt && e_cal_component_datetime_get_value (dt);
- e_cal_component_datetime_free (dt);
+ return check_has_property (esexp, ctx->comp, I_CAL_DTEND_PROPERTY);
+}
- return result;
+/* (has-due?)
+ *
+ * A boolean value for components that have/don't have filled DUE property.
+ *
+ * Returns: whether the component has DUE filled
+ */
+static ESExpResult *
+func_has_due (ESExp *esexp,
+ gint argc,
+ ESExpResult **argv,
+ gpointer data)
+{
+ SearchContext *ctx = data;
+
+ if (argc != 0) {
+ e_sexp_fatal_error (esexp, _("“%s” expects no arguments"), "has-due");
+ return NULL;
+ }
+
+ return check_has_property (esexp, ctx->comp, I_CAL_DUE_PROPERTY);
+}
+
+
+/* (has-duration?)
+ *
+ * A boolean value for components that have/don't have filled DURATION property.
+ *
+ * Returns: whether the component has DURATION filled
+ */
+static ESExpResult *
+func_has_duration (ESExp *esexp,
+ gint argc,
+ ESExpResult **argv,
+ gpointer data)
+{
+ SearchContext *ctx = data;
+
+ if (argc != 0) {
+ e_sexp_fatal_error (esexp, _("“%s” expects no arguments"), "has-duration");
+ return NULL;
+ }
+
+ return check_has_property (esexp, ctx->comp, I_CAL_DURATION_PROPERTY);
}
/* (has-alarms?)
@@ -1252,6 +1321,9 @@ static struct {
{ "due-in-time-range?", func_due_in_time_range, 0 },
{ "contains?", func_contains, 0 },
{ "has-start?", func_has_start, 0 },
+ { "has-end?", func_has_end, 0 },
+ { "has-due?", func_has_due, 0 },
+ { "has-duration?", func_has_duration, 0 },
{ "has-alarms?", func_has_alarms, 0 },
{ "has-alarms-in-range?", func_has_alarms_in_range, 0 },
{ "has-recurrences?", func_has_recurrences, 0 },
diff --git a/src/calendar/libedata-cal/e-cal-cache.c b/src/calendar/libedata-cal/e-cal-cache.c
index 86c07f166..add369c9c 100644
--- a/src/calendar/libedata-cal/e-cal-cache.c
+++ b/src/calendar/libedata-cal/e-cal-cache.c
@@ -42,7 +42,7 @@
#include "e-cal-cache.h"
-#define E_CAL_CACHE_VERSION 3
+#define E_CAL_CACHE_VERSION 4
#define ECC_TABLE_TIMEZONES "timezones"
@@ -64,6 +64,9 @@
#define ECC_COLUMN_HAS_ALARM "has_alarm"
#define ECC_COLUMN_HAS_ATTACHMENT "has_attachment"
#define ECC_COLUMN_HAS_START "has_start"
+#define ECC_COLUMN_HAS_END "has_end"
+#define ECC_COLUMN_HAS_DUE "has_due"
+#define ECC_COLUMN_HAS_DURATION "has_duration"
#define ECC_COLUMN_HAS_RECURRENCES "has_recurrences"
#define ECC_COLUMN_EXTRA "bdata"
#define ECC_COLUMN_CUSTOM_FLAGS "custom_flags"
@@ -449,6 +452,9 @@ e_cal_cache_populate_other_columns (ECalCache *cal_cache,
add_column (ECC_COLUMN_HAS_ALARM, "INTEGER", NULL);
add_column (ECC_COLUMN_HAS_ATTACHMENT, "INTEGER", NULL);
add_column (ECC_COLUMN_HAS_START, "INTEGER", NULL);
+ add_column (ECC_COLUMN_HAS_END, "INTEGER", NULL);
+ add_column (ECC_COLUMN_HAS_DUE, "INTEGER", NULL);
+ add_column (ECC_COLUMN_HAS_DURATION, "INTEGER", NULL);
add_column (ECC_COLUMN_HAS_RECURRENCES, "INTEGER", NULL);
add_column (ECC_COLUMN_EXTRA, "TEXT", NULL);
add_column (ECC_COLUMN_CUSTOM_FLAGS, "INTEGER", NULL);
@@ -896,10 +902,19 @@ ecc_fill_other_columns (ECalCache *cal_cache,
add_value (ECC_COLUMN_OCCUR_START, dt && e_cal_component_datetime_get_value (dt) &&
(e_cal_component_datetime_get_tzid (dt) || i_cal_time_is_utc
(e_cal_component_datetime_get_value (dt)))
? ecc_encode_timet_to_sql (cal_cache, occur_start) : NULL);
+ e_cal_component_datetime_free (dt);
- has = dt && e_cal_component_datetime_get_value (dt);
+ has = e_cal_util_component_has_property (icomp, I_CAL_DTSTART_PROPERTY);
add_value (ECC_COLUMN_HAS_START, g_strdup (has ? "1" : "0"));
- e_cal_component_datetime_free (dt);
+
+ has = e_cal_util_component_has_property (icomp, I_CAL_DTEND_PROPERTY);
+ add_value (ECC_COLUMN_HAS_END, g_strdup (has ? "1" : "0"));
+
+ has = e_cal_util_component_has_property (icomp, I_CAL_DUE_PROPERTY);
+ add_value (ECC_COLUMN_HAS_DUE, g_strdup (has ? "1" : "0"));
+
+ has = e_cal_util_component_has_property (icomp, I_CAL_DURATION_PROPERTY);
+ add_value (ECC_COLUMN_HAS_DURATION, g_strdup (has ? "1" : "0"));
dt = e_cal_component_get_dtend (comp);
add_value (ECC_COLUMN_OCCUR_END, dt && e_cal_component_datetime_get_value (dt) &&
@@ -1294,22 +1309,53 @@ ecc_sexp_func_contains (ESExp *esexp,
return result;
}
+static ESExpResult *
+ecc_sexp_has_column_result (ESExp *esexp,
+ const gchar *column_name)
+{
+ ESExpResult *result;
+
+ result = e_sexp_result_new (esexp, ESEXP_RES_STRING);
+ result->value.string = g_strdup_printf ("(%s NOT NULL AND %s=1)",
+ column_name, column_name);
+
+ return result;
+}
+
static ESExpResult *
ecc_sexp_func_has_start (ESExp *esexp,
gint argc,
ESExpResult **argv,
gpointer user_data)
{
- SExpToSqlContext *ctx = user_data;
- ESExpResult *result;
+ return ecc_sexp_has_column_result (esexp, ECC_COLUMN_HAS_START);
+}
- g_return_val_if_fail (ctx != NULL, NULL);
+static ESExpResult *
+ecc_sexp_func_has_end (ESExp *esexp,
+ gint argc,
+ ESExpResult **argv,
+ gpointer user_data)
+{
+ return ecc_sexp_has_column_result (esexp, ECC_COLUMN_HAS_END);
+}
- result = e_sexp_result_new (esexp, ESEXP_RES_STRING);
- result->value.string = g_strdup_printf ("(%s NOT NULL AND %s=1)",
- ECC_COLUMN_HAS_START, ECC_COLUMN_HAS_START);
+static ESExpResult *
+ecc_sexp_func_has_due (ESExp *esexp,
+ gint argc,
+ ESExpResult **argv,
+ gpointer user_data)
+{
+ return ecc_sexp_has_column_result (esexp, ECC_COLUMN_HAS_DUE);
+}
- return result;
+static ESExpResult *
+ecc_sexp_func_has_duration (ESExp *esexp,
+ gint argc,
+ ESExpResult **argv,
+ gpointer user_data)
+{
+ return ecc_sexp_has_column_result (esexp, ECC_COLUMN_HAS_DURATION);
}
static ESExpResult *
@@ -1318,16 +1364,7 @@ ecc_sexp_func_has_alarms (ESExp *esexp,
ESExpResult **argv,
gpointer user_data)
{
- SExpToSqlContext *ctx = user_data;
- ESExpResult *result;
-
- g_return_val_if_fail (ctx != NULL, NULL);
-
- result = e_sexp_result_new (esexp, ESEXP_RES_STRING);
- result->value.string = g_strdup_printf ("(%s NOT NULL AND %s=1)",
- ECC_COLUMN_HAS_ALARM, ECC_COLUMN_HAS_ALARM);
-
- return result;
+ return ecc_sexp_has_column_result (esexp, ECC_COLUMN_HAS_ALARM);
}
static ESExpResult *
@@ -1358,16 +1395,7 @@ ecc_sexp_func_has_recurrences (ESExp *esexp,
ESExpResult **argv,
gpointer user_data)
{
- SExpToSqlContext *ctx = user_data;
- ESExpResult *result;
-
- g_return_val_if_fail (ctx != NULL, NULL);
-
- result = e_sexp_result_new (esexp, ESEXP_RES_STRING);
- result->value.string = g_strdup_printf ("(%s NOT NULL AND %s=1)",
- ECC_COLUMN_HAS_RECURRENCES, ECC_COLUMN_HAS_RECURRENCES);
-
- return result;
+ return ecc_sexp_has_column_result (esexp, ECC_COLUMN_HAS_RECURRENCES);
}
/* (has-categories? STR+)
@@ -1471,16 +1499,7 @@ ecc_sexp_func_has_attachment (ESExp *esexp,
ESExpResult **argv,
gpointer user_data)
{
- SExpToSqlContext *ctx = user_data;
- ESExpResult *result;
-
- g_return_val_if_fail (ctx != NULL, NULL);
-
- result = e_sexp_result_new (esexp, ESEXP_RES_STRING);
- result->value.string = g_strdup_printf ("(%s NOT NULL AND %s=1)",
- ECC_COLUMN_HAS_ATTACHMENT, ECC_COLUMN_HAS_ATTACHMENT);
-
- return result;
+ return ecc_sexp_has_column_result (esexp, ECC_COLUMN_HAS_ATTACHMENT);
}
static ESExpResult *
@@ -1597,6 +1616,9 @@ static struct {
{ "due-in-time-range?", ecc_sexp_func_due_in_time_range, 0 },
{ "contains?", ecc_sexp_func_contains, 0 },
{ "has-start?", ecc_sexp_func_has_start, 0 },
+ { "has-end?", ecc_sexp_func_has_end, 0 },
+ { "has-due?", ecc_sexp_func_has_due, 0 },
+ { "has-duration?", ecc_sexp_func_has_duration, 0 },
{ "has-alarms?", ecc_sexp_func_has_alarms, 0 },
{ "has-alarms-in-range?", ecc_sexp_func_has_alarms_in_range, 0 },
{ "has-recurrences?", ecc_sexp_func_has_recurrences, 0 },
@@ -1854,19 +1876,19 @@ component_info_clear (ComponentInfo *ci)
}
static gboolean
-cal_cache_gather_v1_affected_cb (ECalCache *cal_cache,
- const gchar *uid,
- const gchar *rid,
- const gchar *revision,
- const gchar *object,
- const gchar *extra,
- guint32 custom_flags,
- EOfflineState offline_state,
- gpointer user_data)
+cal_cache_gather_all_cb (ECalCache *cal_cache,
+ const gchar *uid,
+ const gchar *rid,
+ const gchar *revision,
+ const gchar *object,
+ const gchar *extra,
+ guint32 custom_flags,
+ EOfflineState offline_state,
+ gpointer user_data)
{
ComponentInfo *ci = user_data;
ECalComponent *comp;
- ECalComponentDateTime *dt;
+ GSList **pcomps, **pextras, **pcustom_flags;
g_return_val_if_fail (object != NULL, FALSE);
g_return_val_if_fail (ci != NULL, FALSE);
@@ -1878,29 +1900,20 @@ cal_cache_gather_v1_affected_cb (ECalCache *cal_cache,
if (!comp)
return TRUE;
- dt = e_cal_component_get_due (comp);
-
- if (dt && e_cal_component_datetime_get_value (dt) &&
- !i_cal_time_is_utc (e_cal_component_datetime_get_value (dt)) &&
- !e_cal_component_datetime_get_tzid (dt)) {
- GSList **pcomps, **pextras, **pcustom_flags;
-
- if (offline_state == E_OFFLINE_STATE_SYNCED) {
- pcomps = &ci->online_comps;
- pextras = &ci->online_extras;
- pcustom_flags = &ci->online_custom_flags;
- } else {
- pcomps = &ci->offline_comps;
- pextras = &ci->offline_extras;
- pcustom_flags = &ci->offline_custom_flags;
- }
-
- *pcomps = g_slist_prepend (*pcomps, g_object_ref (comp));
- *pextras = g_slist_prepend (*pextras, g_strdup (extra));
- *pcustom_flags = g_slist_prepend (*pcustom_flags, GUINT_TO_POINTER (custom_flags));
+ if (offline_state == E_OFFLINE_STATE_SYNCED) {
+ pcomps = &ci->online_comps;
+ pextras = &ci->online_extras;
+ pcustom_flags = &ci->online_custom_flags;
+ } else {
+ pcomps = &ci->offline_comps;
+ pextras = &ci->offline_extras;
+ pcustom_flags = &ci->offline_custom_flags;
}
- e_cal_component_datetime_free (dt);
+ *pcomps = g_slist_prepend (*pcomps, g_object_ref (comp));
+ *pextras = g_slist_prepend (*pextras, g_strdup (extra));
+ *pcustom_flags = g_slist_prepend (*pcustom_flags, GUINT_TO_POINTER (custom_flags));
+
g_object_unref (comp);
return TRUE;
@@ -2248,13 +2261,16 @@ e_cal_cache_migrate (ECache *cache,
g_rec_mutex_unlock (&cal_cache->priv->timezones_lock);
}
- if (success && from_version == 1) {
- /* Version 1 incorrectly stored DATE-only DUE values */
+ /* Re-add all components, to have properly filled values in the columns.
+ Version 1 incorrectly stored DATE-only DUE values.
+ Version 4 adds ECC_COLUMN_HAS_END, ECC_COLUMN_HAS_DUE and ECC_COLUMN_HAS_DURATION columns.
+ */
+ if (success && from_version > 0 && from_version < 4) {
ComponentInfo ci;
memset (&ci, 0, sizeof (ComponentInfo));
- if (e_cal_cache_search_with_callback (cal_cache, NULL, cal_cache_gather_v1_affected_cb, &ci,
cancellable, NULL)) {
+ if (e_cal_cache_search_with_callback (cal_cache, NULL, cal_cache_gather_all_cb, &ci,
cancellable, NULL)) {
gboolean success = TRUE;
if (ci.online_comps)
@@ -4333,7 +4349,7 @@ e_cal_cache_put_locked (ECache *cache,
success = E_CACHE_CLASS (e_cal_cache_parent_class)->put_locked (cache, uid, revision, object,
other_columns, offline_state,
is_replace, cancellable, error);
- if (success)
+ if (success && timezones)
success = ecc_update_timezones_table (cal_cache, timezones, cancellable, error);
if (timezones)
@@ -4367,7 +4383,7 @@ e_cal_cache_remove_locked (ECache *cache,
success = E_CACHE_CLASS (e_cal_cache_parent_class)->remove_locked (cache, uid, cancellable, error);
- if (success)
+ if (success && timezones)
success = ecc_update_timezones_table (cal_cache, timezones, cancellable, error);
if (timezones)
diff --git a/tests/libedata-cal/components/event-3.ics b/tests/libedata-cal/components/event-3.ics
index 4fcf5bf5c..36e4d4971 100644
--- a/tests/libedata-cal/components/event-3.ics
+++ b/tests/libedata-cal/components/event-3.ics
@@ -5,7 +5,7 @@ CREATED:20170216T155507Z
LAST-MODIFIED:20170216T155543Z
SEQUENCE:3
DTSTART:20170104T100000Z
-DTEND:20170110T120000Z
+DURATION:PT15M
SUMMARY:Lunch prepare
LOCATION:Kitchen
CLASS:PRIVATE
diff --git a/tests/libedata-cal/components/task-6.ics b/tests/libedata-cal/components/task-6.ics
index 1ea777739..aa0a25035 100644
--- a/tests/libedata-cal/components/task-6.ics
+++ b/tests/libedata-cal/components/task-6.ics
@@ -9,6 +9,7 @@ CLASS:CONFIDENTIAL
COMMENT:User commentary text
SEQUENCE:2
DTSTART;TZID=America/New_York:20131213T131313
+DURATION:P7W
CREATED:20170221T130512Z
LAST-MODIFIED:20170221T130610Z
END:VTODO
diff --git a/tests/libedata-cal/test-cal-cache-search.c b/tests/libedata-cal/test-cal-cache-search.c
index ccf34f7be..1b911d6fa 100644
--- a/tests/libedata-cal/test-cal-cache-search.c
+++ b/tests/libedata-cal/test-cal-cache-search.c
@@ -325,6 +325,47 @@ test_search_has_start (TCUFixture *fixture,
test_search (fixture, "(not (has-start?))", searches_events ? "!event-1" : "task-8");
}
+static void
+test_search_has_end (TCUFixture *fixture,
+ gconstpointer user_data)
+{
+ const TCUClosure *closure = user_data;
+ gboolean searches_events = closure && closure->load_set == TCU_LOAD_COMPONENT_SET_EVENTS;
+
+ /* VTODO cannot have DTEND property */
+ test_search (fixture, "(has-end?)", searches_events ? "event-1" : "!task-9");
+ test_search (fixture, "(has-end?)", searches_events ? "event-1" : "!task-8");
+ test_search (fixture, "(not (has-end?))", searches_events ? "!event-1" : "task-9");
+ test_search (fixture, "(not (has-end?))", searches_events ? "!event-1" : "task-8");
+}
+
+static void
+test_search_has_due (TCUFixture *fixture,
+ gconstpointer user_data)
+{
+ const TCUClosure *closure = user_data;
+ gboolean searches_events = closure && closure->load_set == TCU_LOAD_COMPONENT_SET_EVENTS;
+
+ /* VEVENT cannot have DUE property */
+ test_search (fixture, "(has-due?)", searches_events ? "!event-1" : "task-4");
+ test_search (fixture, "(has-due?)", searches_events ? "!event-1" : "!task-8");
+ test_search (fixture, "(not (has-due?))", searches_events ? "event-1" : "!task-4");
+ test_search (fixture, "(not (has-due?))", searches_events ? "event-1" : "task-8");
+}
+
+static void
+test_search_has_duration (TCUFixture *fixture,
+ gconstpointer user_data)
+{
+ const TCUClosure *closure = user_data;
+ gboolean searches_events = closure && closure->load_set == TCU_LOAD_COMPONENT_SET_EVENTS;
+
+ test_search (fixture, "(has-duration?)", searches_events ? "event-3" : "task-6");
+ test_search (fixture, "(has-duration?)", searches_events ? "!event-4" : "!task-4");
+ test_search (fixture, "(not (has-duration?))", searches_events ? "!event-3" : "!task-6");
+ test_search (fixture, "(not (has-duration?))", searches_events ? "event-4" : "task-4");
+}
+
static void
test_search_has_alarms (TCUFixture *fixture,
gconstpointer user_data)
@@ -458,6 +499,18 @@ main (gint argc,
tcu_fixture_setup, test_search_has_start, tcu_fixture_teardown);
g_test_add ("/ECalCache/Search/HasStart/Tasks", TCUFixture, &closure_tasks,
tcu_fixture_setup, test_search_has_start, tcu_fixture_teardown);
+ g_test_add ("/ECalCache/Search/HasEnd/Events", TCUFixture, &closure_events,
+ tcu_fixture_setup, test_search_has_end, tcu_fixture_teardown);
+ g_test_add ("/ECalCache/Search/HasEnd/Tasks", TCUFixture, &closure_tasks,
+ tcu_fixture_setup, test_search_has_end, tcu_fixture_teardown);
+ g_test_add ("/ECalCache/Search/HasDue/Events", TCUFixture, &closure_events,
+ tcu_fixture_setup, test_search_has_due, tcu_fixture_teardown);
+ g_test_add ("/ECalCache/Search/HasDue/Tasks", TCUFixture, &closure_tasks,
+ tcu_fixture_setup, test_search_has_due, tcu_fixture_teardown);
+ g_test_add ("/ECalCache/Search/HasDuration/Events", TCUFixture, &closure_events,
+ tcu_fixture_setup, test_search_has_duration, tcu_fixture_teardown);
+ g_test_add ("/ECalCache/Search/HasDuration/Tasks", TCUFixture, &closure_tasks,
+ tcu_fixture_setup, test_search_has_duration, tcu_fixture_teardown);
g_test_add ("/ECalCache/Search/HasAlarms/Events", TCUFixture, &closure_events,
tcu_fixture_setup, test_search_has_alarms, tcu_fixture_teardown);
g_test_add ("/ECalCache/Search/HasAlarms/Tasks", TCUFixture, &closure_tasks,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]