Skip to content

Commit

Permalink
Merge pull request #157 from bshifter/format-csv-refinement
Browse files Browse the repository at this point in the history
Format csv refinement changes
  • Loading branch information
alltilla authored Jun 12, 2024
2 parents 45caab9 + 19d05a3 commit 1a5b322
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 4 deletions.
19 changes: 19 additions & 0 deletions lib/filterx/expr-function.c
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,25 @@ filterx_function_args_get_named_object(FilterXFunctionArgs *self, const gchar *n
return obj;
}

FilterXObject *
filterx_function_args_get_named_literal_object(FilterXFunctionArgs *self, const gchar *name, gboolean *exists)
{
FilterXObject *obj = NULL;
FilterXExpr *expr = filterx_function_args_get_named_expr(self, name);
*exists = !!expr;
if (!expr)
return NULL;

if (!filterx_expr_is_literal(expr))
goto error;

obj = filterx_expr_eval(expr);
error:
filterx_expr_unref(expr);
return obj;
}


const gchar *
filterx_function_args_get_named_literal_string(FilterXFunctionArgs *self, const gchar *name, gsize *len,
gboolean *exists)
Expand Down
2 changes: 2 additions & 0 deletions lib/filterx/expr-function.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ const gchar *filterx_function_args_get_literal_string(FilterXFunctionArgs *self,
gboolean filterx_function_args_is_literal_null(FilterXFunctionArgs *self, guint64 index);
FilterXExpr *filterx_function_args_get_named_expr(FilterXFunctionArgs *self, const gchar *name);
FilterXObject *filterx_function_args_get_named_object(FilterXFunctionArgs *self, const gchar *name, gboolean *exists);
FilterXObject *filterx_function_args_get_named_literal_object(FilterXFunctionArgs *self, const gchar *name,
gboolean *exists);
const gchar *filterx_function_args_get_named_literal_string(FilterXFunctionArgs *self, const gchar *name,
gsize *len, gboolean *exists);
gboolean filterx_function_args_get_named_literal_boolean(FilterXFunctionArgs *self, const gchar *name,
Expand Down
41 changes: 37 additions & 4 deletions modules/csvparser/filterx-func-format-csv.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,25 +31,29 @@
#include "scratch-buffers.h"
#include "utf8utils.h"

#define FILTERX_FUNC_FORMAT_CSV_USAGE "Usage: format_csv($input(list or dict), delimiter=\",\", columns=$columns(list))"
#define FILTERX_FUNC_FORMAT_CSV_USAGE "Usage: format_csv({list or dict}, [" \
FILTERX_FUNC_FORMAT_CSV_ARG_NAME_COLUMNS"={list}," \
FILTERX_FUNC_FORMAT_CSV_ARG_NAME_DELIMITER"={string literal}," \
FILTERX_FUNC_FORMAT_CSV_ARG_NAME_DEFAULT_VALUE"={string literal}])"

typedef struct FilterXFunctionFormatCSV_
{
FilterXFunction super;
FilterXExpr *input;
gchar delimiter;
FilterXExpr *columns;
FilterXObject *default_value;
} FilterXFunctionFormatCSV;

static gboolean
_append_to_buffer(FilterXObject *key, FilterXObject *value, gpointer user_data)
{
if (!value)
return FALSE;

FilterXFunctionFormatCSV *self = ((gpointer *) user_data)[0];
GString *buffer = ((gpointer *) user_data)[1];

if (!value)
value = self->default_value;

if (filterx_object_is_type(value, &FILTERX_TYPE_NAME(dict)) ||
filterx_object_is_type(value, &FILTERX_TYPE_NAME(list)))
{
Expand Down Expand Up @@ -160,6 +164,7 @@ _free(FilterXExpr *s)
{
FilterXFunctionFormatCSV *self = (FilterXFunctionFormatCSV *) s;

filterx_object_unref(self->default_value);
filterx_expr_unref(self->input);
filterx_expr_unref(self->columns);
filterx_function_free_method(&self->super);
Expand Down Expand Up @@ -200,6 +205,30 @@ _extract_delimiter_arg(FilterXFunctionFormatCSV *self, FilterXFunctionArgs *args
return TRUE;
}

static gboolean
_extract_default_value_arg(FilterXFunctionFormatCSV *self, FilterXFunctionArgs *args, GError **error)
{
gboolean exists;
FilterXObject *default_value = filterx_function_args_get_named_literal_object(args,
FILTERX_FUNC_FORMAT_CSV_ARG_NAME_DEFAULT_VALUE, &exists);

if (!exists)
return TRUE;

if (!default_value || !filterx_object_is_type(default_value, &FILTERX_TYPE_NAME(string)))
{
filterx_object_unref(default_value);
g_set_error(error, FILTERX_FUNCTION_ERROR, FILTERX_FUNCTION_ERROR_CTOR_FAIL,
"default_value must be a string literal. " FILTERX_FUNC_FORMAT_CSV_USAGE);
return FALSE;
}

filterx_object_unref(self->default_value);
self->default_value = default_value;

return TRUE;
}

static gboolean
_extract_arguments(FilterXFunctionFormatCSV *self, FilterXFunctionArgs *args, GError **error)
{
Expand All @@ -222,6 +251,9 @@ _extract_arguments(FilterXFunctionFormatCSV *self, FilterXFunctionArgs *args, GE
if (!_extract_delimiter_arg(self, args, error))
return FALSE;

if (!_extract_default_value_arg(self, args, error))
return FALSE;

self->columns = _extract_columns_expr(args, error);

return TRUE;
Expand All @@ -236,6 +268,7 @@ filterx_function_format_csv_new(const gchar *function_name, FilterXFunctionArgs
self->super.super.eval = _eval;
self->super.super.free_fn = _free;
self->delimiter = ',';
self->default_value = filterx_string_new("", -1);

if (!_extract_arguments(self, args, error) ||
!filterx_function_args_check(args, error))
Expand Down
1 change: 1 addition & 0 deletions modules/csvparser/filterx-func-format-csv.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

#define FILTERX_FUNC_FORMAT_CSV_ARG_NAME_COLUMNS "columns"
#define FILTERX_FUNC_FORMAT_CSV_ARG_NAME_DELIMITER "delimiter"
#define FILTERX_FUNC_FORMAT_CSV_ARG_NAME_DEFAULT_VALUE "default_value"

FilterXFunction *filterx_function_format_csv_new(const gchar *function_name, FilterXFunctionArgs *args, GError **error);
gpointer filterx_function_construct_format_csv(Plugin *self);
Expand Down
54 changes: 54 additions & 0 deletions modules/csvparser/tests/test_filterx_func_format_csv.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,60 @@ Test(filterx_func_format_csv, test_escape_existing_double_quotes_in_case_of_addi
_assert_format_csv(args, "\"\\\"fo;o\\\"\";\"b;ar\";\"baz\"");
}

Test(filterx_func_format_csv, test_dict_mode_fills_remaining_cols_with_default_default_value)
{
FilterXExpr *csv_data = filterx_literal_new(
filterx_json_object_new_from_repr("{\"col1\":\"foo\",\"col2\":\"bar\",\"col3\":\"baz\"}", -1));
GList *args = NULL;
args = g_list_append(args, filterx_function_arg_new(NULL, csv_data));
args = g_list_append(args, filterx_function_arg_new(FILTERX_FUNC_FORMAT_CSV_ARG_NAME_COLUMNS,
filterx_non_literal_new(filterx_json_array_new_from_repr("[\"col1\",\"col2\",\"col3\",\"more\",\"cols\"]", -1))));

_assert_format_csv(args, "foo,bar,baz,,");
}

Test(filterx_func_format_csv, test_dict_mode_fills_remaining_cols_with_non_default_default_value)
{
FilterXExpr *csv_data = filterx_literal_new(
filterx_json_object_new_from_repr("{\"col1\":\"foo\",\"col2\":\"bar\",\"col3\":\"baz\"}", -1));
GList *args = NULL;
args = g_list_append(args, filterx_function_arg_new(NULL, csv_data));
args = g_list_append(args, filterx_function_arg_new(FILTERX_FUNC_FORMAT_CSV_ARG_NAME_COLUMNS,
filterx_non_literal_new(filterx_json_array_new_from_repr("[\"col1\",\"col2\",\"col3\",\"more\",\"cols\"]", -1))));
args = g_list_append(args, filterx_function_arg_new(FILTERX_FUNC_FORMAT_CSV_ARG_NAME_DEFAULT_VALUE,
filterx_literal_new(filterx_string_new("null", -1))));

_assert_format_csv(args, "foo,bar,baz,null,null");
}

Test(filterx_func_format_csv, test_dict_mode_default_value_repr_must_be_literal)
{
FilterXExpr *csv_data = filterx_literal_new(
filterx_json_object_new_from_repr("{\"col1\":\"foo\",\"col2\":\"bar\",\"col3\":\"baz\"}", -1));
GList *args = NULL;
args = g_list_append(args, filterx_function_arg_new(NULL, csv_data));
args = g_list_append(args, filterx_function_arg_new(FILTERX_FUNC_FORMAT_CSV_ARG_NAME_COLUMNS,
filterx_non_literal_new(filterx_json_array_new_from_repr("[\"col1\",\"col2\",\"col3\",\"more\",\"cols\"]", -1))));
args = g_list_append(args, filterx_function_arg_new(FILTERX_FUNC_FORMAT_CSV_ARG_NAME_DEFAULT_VALUE,
filterx_non_literal_new(filterx_string_new("null", -1))));

_assert_format_csv_init_fail(args);
}

Test(filterx_func_format_csv, test_dict_mode_default_value_repr_must_be_string)
{
FilterXExpr *csv_data = filterx_literal_new(
filterx_json_object_new_from_repr("{\"col1\":\"foo\",\"col2\":\"bar\",\"col3\":\"baz\"}", -1));
GList *args = NULL;
args = g_list_append(args, filterx_function_arg_new(NULL, csv_data));
args = g_list_append(args, filterx_function_arg_new(FILTERX_FUNC_FORMAT_CSV_ARG_NAME_COLUMNS,
filterx_non_literal_new(filterx_json_array_new_from_repr("[\"col1\",\"col2\",\"col3\",\"more\",\"cols\"]", -1))));
args = g_list_append(args, filterx_function_arg_new(FILTERX_FUNC_FORMAT_CSV_ARG_NAME_DEFAULT_VALUE,
filterx_literal_new(filterx_null_new())));

_assert_format_csv_init_fail(args);
}


static void
setup(void)
Expand Down

0 comments on commit 1a5b322

Please sign in to comment.