Parents
Children
Initial revision basic query validation done
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore Wed Oct 20 04:33:12 2021 -0500
@@ -0,0 +1,3 @@
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gobquery/gobquery-query.c Wed Oct 20 04:33:12 2021 -0500
@@ -0,0 +1,95 @@
+#include <gobquery-query.h> +gobquery_query_validate(gchar **query, GType type, GError **error) { + GObjectClass *obj_class = g_type_class_ref(type); + /* Walk through each item in the query, splitting it on the first :, and + * then look to see if a property exists for the type with that name. + for(i = 0; query[i] != NULL; i++) { + gchar **parts = g_strsplit(query[i], ":", 2); + if(!g_object_class_find_property(obj_class, parts[0])) { + g_set_error(error, GOBQUERY_DOMAIN, 0, + "%s has no property named %s", + g_type_name(type), parts[0]); + g_type_class_unref(obj_class); +gobquery_query_matches(gchar **query, GObject *object) { +/****************************************************************************** + *****************************************************************************/ +gobquery_query_valid(const gchar *query, GType type, GError **error) { + g_return_val_if_fail(query != NULL, FALSE); + g_return_val_if_fail(g_type_is_a(type, G_TYPE_OBJECT), FALSE); + if(!g_shell_parse_argv(query, NULL, &parts, error)) { + ret = gobquery_query_validate(parts, type, error); +gobquery_query_list(GListModel *model, const gchar *query, GError **error) { + GListStore *store = NULL; + GType type = G_TYPE_NONE; + guint i = 0, items = 0; + g_return_val_if_fail(G_IS_LIST_MODEL(model), NULL); + g_return_val_if_fail(query != NULL, NULL); + type = g_list_model_get_item_type(model); + if(!g_shell_parse_argv(query, NULL, &parts, error)) { + if(!gobquery_query_validate(parts, type, error)) { + store = g_list_store_new(type); + items = g_list_model_get_n_items(model); + for(i = 0; i < items; i++) { + GObject *object = g_list_model_get_item(model, i); + if(gobquery_query_matches(parts, object)) { + g_list_store_insert(store, 0, object); --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gobquery/gobquery-query.h Wed Oct 20 04:33:12 2021 -0500
@@ -0,0 +1,42 @@
+#ifndef GOBQUERY_QUERY_H +#define GOBQUERY_QUERY_H +#include <glib-object.h> +#define GOBQUERY_DOMAIN (g_quark_from_static_string("gobquery")) + * gobquery_query_valid: + * @query: The query string. + * @type: The GType that's being queried. + * @error: A return address from an error. + * Validates that @query is valid for @type. This is useful for showing + * validation in an entry before querying a large list. If the list is small, + * it might be easier to just call gobquery_query_list(). + * Returns: %TRUE if @query is valid for @type, otherwise %FALSE with @error +gboolean gobquery_query_valid(const gchar *query, GType type, GError **error); + * @model: The list model to query. + * @query: The query string. + * @error: A return address for an error. + * Run @query against @model and return a new GListModel with the results. + * Returns: (transfer full): The results or NULL on error with @error set. +GListStore *gobquery_query_list(GListModel *model, const gchar *query, GError **error); +#endif /* GOBQUERY_QUERY_H */ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gobquery/meson.build Wed Oct 20 04:33:12 2021 -0500
@@ -0,0 +1,19 @@
+ dependencies : [GIO, GLIB, GOBJECT], +libgobquery_dep = declare_dependency( + sources : gobquery_sources, + include_directories : include_directories('.'), + link_with : libgobquery, + dependencies : [GIO, GLIB, GOBJECT], --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gobquery/tests/meson.build Wed Oct 20 04:33:12 2021 -0500
@@ -0,0 +1,7 @@
+ 'test-gobquery-query.c', + dependencies : [libgobquery_dep, GLIB, GIO, GOBJECT] +test('test-gobquery-query', e) --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gobquery/tests/test-gobquery-query.c Wed Oct 20 04:33:12 2021 -0500
@@ -0,0 +1,218 @@
+#include <gobquery-query.h> +/****************************************************************************** + *****************************************************************************/ +static GParamSpec *properties[N_PROPERTIES] = {NULL, }; +#define TEST_GOBQUERY_TYPE_OBJECT (test_gobquery_object_get_type()) +G_DECLARE_FINAL_TYPE(TestGOBQueryObject, test_gobquery_object, TEST_GOBQUERY, +struct _TestGOBQueryObject { +G_DEFINE_TYPE(TestGOBQueryObject, test_gobquery_object, G_TYPE_OBJECT) +test_gobquery_object_get_property(GObject *obj, guint param_id, GValue *value, + TestGOBQueryObject *object = TEST_GOBQUERY_OBJECT(obj); + g_value_set_boolean(value, object->enabled); + g_value_set_string(value, object->name); + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); +test_gobquery_object_set_property(GObject *obj, guint param_id, + const GValue *value, GParamSpec *pspec) + TestGOBQueryObject *object = TEST_GOBQUERY_OBJECT(obj); + object->enabled = g_value_get_boolean(value); + object->name = g_value_dup_string(value); + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); +test_gobquery_object_init(TestGOBQueryObject *object) { +test_gobquery_object_finalize(GObject *obj) { + TestGOBQueryObject *object = TEST_GOBQUERY_OBJECT(obj); + g_clear_pointer(&object->name, g_free); + G_OBJECT_CLASS(test_gobquery_object_parent_class)->finalize(obj); +test_gobquery_object_class_init(TestGOBQueryObjectClass *klass) { + GObjectClass *obj_class = G_OBJECT_CLASS(klass); + obj_class->finalize = test_gobquery_object_finalize; + obj_class->get_property = test_gobquery_object_get_property; + obj_class->set_property = test_gobquery_object_set_property; + properties[PROP_ENABLED] = g_param_spec_boolean( + "enabled", "enabled", "whether this object is enabled", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); + properties[PROP_NAME] = g_param_spec_string( + "name", "name", "the name of this object", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties(obj_class, N_PROPERTIES, properties); +/****************************************************************************** + *****************************************************************************/ +test_gobquery_query_valid_null(void) { + if(g_test_subprocess()) { + /* This test should trigger a g_return_val_if_fail which will return + * False, not set the error, but will output a warning on stderr. + ret = gobquery_query_valid(NULL, TEST_GOBQUERY_TYPE_OBJECT, &error); + g_assert_no_error(error); + g_test_trap_subprocess(NULL, 0, 0); + g_test_trap_assert_stderr("*CRITICAL*query != NULL*"); +test_gobquery_query_valid_empty(void) { + ret = gobquery_query_valid("", TEST_GOBQUERY_TYPE_OBJECT, &error); + g_assert_error(error, G_SHELL_ERROR, 1); +test_gobquery_query_valid_single(void) { + ret = gobquery_query_valid("enabled:true", + TEST_GOBQUERY_TYPE_OBJECT, + g_assert_no_error(error); +test_gobquery_query_valid_multiple(void) { + ret = gobquery_query_valid("enabled:true name:foo", + TEST_GOBQUERY_TYPE_OBJECT, + g_assert_no_error(error); +test_gobquery_query_valid_quoted(void) { + ret = gobquery_query_valid("name:\"foo bar\"", + TEST_GOBQUERY_TYPE_OBJECT, + g_assert_no_error(error); +test_gobquery_query_valid_unknown(void) { + ret = gobquery_query_valid("foo:bar", + TEST_GOBQUERY_TYPE_OBJECT, + g_assert_error(error, GOBQUERY_DOMAIN, 0); +/****************************************************************************** + *****************************************************************************/ +main(gint argc, gchar *argv[]) { + g_test_init(&argc, &argv, NULL); + g_test_add_func("/gobquery/query-valid/null", + test_gobquery_query_valid_null); + g_test_add_func("/gobquery/query-valid/empty", + test_gobquery_query_valid_empty); + g_test_add_func("/gobquery/query-valid/single", + test_gobquery_query_valid_single); + g_test_add_func("/gobquery/query-valid/multiple", + test_gobquery_query_valid_multiple); + g_test_add_func("/gobquery/query-valid/quoted", + test_gobquery_query_valid_quoted); + g_test_add_func("/gobquery/query-valid/unknown", + test_gobquery_query_valid_unknown); --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/meson.build Wed Oct 20 04:33:12 2021 -0500
@@ -0,0 +1,33 @@
+ license : 'LGPL-2.0-or-later', + meson_version : '>=0.56.0', + default_options : ['c_std=c99'] +parts = meson.project_version().split('-') +parts = parts[0].split('.') +GOBQUERY_MAJOR_VERSION = parts[0] +version_conf = configuration_data() +version_conf.set('GOBQUERY_MAJOR_VERSION', GOBQUERY_MAJOR_VERSION) +version_conf.set('GOBQUERY_MINOR_VERSION', parts[1]) +version_conf.set('GOBQUERY_MICRO_VERSION', parts[2]) +version_conf.set('GOBQUERY_EXTRA_VERSION', extra) +version_conf.set('GOBQUERY_VERSION', meson.project_version()) +GLIB = dependency('glib-2.0', version: '>=2.64.0') +GIO = dependency('gio-2.0', version: '>=2.64.0') +GOBJECT = dependency('gobject-2.0', version: '>=2.64.0')