From c88df2e12c4393b574f5ce835de7277d0525db74 Mon Sep 17 00:00:00 2001 From: Celine Mercier Date: Mon, 17 Jul 2017 17:31:09 +0200 Subject: [PATCH] First version of automatic ID and COUNT columns, to discuss (for now, columns created when NUC_SEQ views are closed if the columns don't already exist) --- src/obiview.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++--- src/obiview.h | 35 +++++++++++++++++ src/utils.c | 38 +++++++++++++++++++ src/utils.h | 30 +++++++++++++++ 4 files changed, 200 insertions(+), 5 deletions(-) diff --git a/src/obiview.c b/src/obiview.c index e84d506..66af350 100644 --- a/src/obiview.c +++ b/src/obiview.c @@ -1072,6 +1072,26 @@ static int finish_view(Obiview_p view) return -1; } + // Add count column if it's a NUC_SEQ_VIEW with no count column // TODO discuss + if ((!strcmp((view->infos)->view_type, VIEW_TYPE_NUC_SEQS)) && (!obi_view_column_exists(view, COUNT_COLUMN))) + { + if (obi_create_auto_count_column(view) < 0) + { + obidebug(1, "\nError creating an automatic count column when finishing a view"); + return -1; + } + } + + // Add id column if it's a NUC_SEQ_VIEW with no id column // TODO discuss + if ((!strcmp((view->infos)->view_type, VIEW_TYPE_NUC_SEQS)) && (!obi_view_column_exists(view, ID_COLUMN))) + { + if (obi_create_auto_id_column(view, NULL) < 0) + { + obidebug(1, "\nError creating an automatic id column when finishing a view"); + return -1; + } + } + // Check predicates predicates = view_check_all_predicates(view); if (predicates == NULL) @@ -1824,7 +1844,7 @@ Obiview_p obi_new_view_nuc_seqs(OBIDMS_p dms, const char* view_name, Obiview_p v return NULL; } // Adding id column - if (obi_view_add_column(view, ID_COLUMN, -1, ID_COLUMN, OBI_STR, 0, 1, NULL, "", NULL, -1, "Ids", true) < 0) + if (obi_view_add_column(view, ID_COLUMN, -1, ID_COLUMN, OBI_STR, 0, 1, NULL, "", NULL, -1, "Sequence identifiers", true) < 0) { obidebug(1, "Error adding an obligatory column in a nucleotide sequences view"); return NULL; @@ -2391,6 +2411,15 @@ OBIDMS_column_p obi_view_get_column(Obiview_p view, const char* column_name) } +bool obi_view_column_exists(Obiview_p view, const char* column_name) +{ + if (obi_view_get_column(view, column_name) == NULL) + return false; + else + return true; +} + + OBIDMS_column_p* obi_view_get_pointer_on_column_in_view(Obiview_p view, const char* column_name) { return (OBIDMS_column_p*)(ht_get(view->column_dict, column_name)); @@ -2459,8 +2488,8 @@ int obi_save_and_close_view(Obiview_p view) int obi_create_auto_count_column(Obiview_p view) { - index_t i; - OBIDMS_p column; + index_t i; + OBIDMS_column_p column; // Check that the view is not read-only if (view->read_only) @@ -2470,7 +2499,7 @@ int obi_create_auto_count_column(Obiview_p view) return -1; } - if (obi_view_add_column(view, COUNT_COLUMN, -1, NULL, OBI_INT, 0, 1, NULL, NULL, NULL, NULL, "Sequence counts", true) < 0) + if (obi_view_add_column(view, COUNT_COLUMN, -1, NULL, OBI_INT, 0, 1, NULL, NULL, NULL, -1, "Sequence counts", true) < 0) { obidebug(1, "Error adding an automatic count column in a view"); return -1; @@ -2486,7 +2515,7 @@ int obi_create_auto_count_column(Obiview_p view) // Fill the column with 1s for (i=0; i < (view->infos)->line_count; i++) { - if (obi_column_set_obiint_with_elt_idx(column, i, 0, 1) < 0) + if (obi_set_int_with_elt_idx_and_col_p_in_view(view, column, i, 0, 1) < 0) { obidebug(1, "Error adding an automatic count column in a view"); return -1; @@ -2497,6 +2526,69 @@ int obi_create_auto_count_column(Obiview_p view) } +int obi_create_auto_id_column(Obiview_p view, const char* prefix) +{ + index_t i; + OBIDMS_column_p column; + char* id; + + // Check that the view is not read-only + if (view->read_only) + { + obi_set_errno(OBIVIEW_ERROR); + obidebug(1, "\nError trying to create an automatic count column in a read-only view"); + return -1; + } + + // Delete old ID column if it exists + if (obi_view_get_column(view, ID_COLUMN) != NULL) + { + if (obi_view_delete_column(view, ID_COLUMN) < 0) + { + obidebug(1, "Error deleting an ID column to replace it in a view"); + return -1; + } + } + + // Create the new ID column + if (obi_view_add_column(view, ID_COLUMN, -1, NULL, OBI_STR, 0, 1, NULL, NULL, NULL, -1, "Sequence identifiers", true) < 0) + { + obidebug(1, "Error adding an automatic ID column in a view"); + return -1; + } + + column = obi_view_get_column(view, ID_COLUMN); + if (column == NULL) + { + obidebug(1, "Error adding an automatic ID column in a view"); + return -1; + } + + // If prefix is NULL, use default prefix + if (prefix == NULL) + prefix = ID_PREFIX; + + // Fill the column with automatic ids + for (i=0; i < (view->infos)->line_count; i++) + { + id = build_word_with_idx(prefix, i); + if (id == NULL) + { + obidebug(1, "Error building an id for an automatic ID column"); + return -1; + } + if (obi_set_str_with_elt_idx_and_col_p_in_view(view, column, i, 0, id) < 0) + { + obidebug(1, "Error adding an automatic count column in a view"); + return -1; + } + free(id); + } + + return 0; +} + + // TODO Move to another file? /*********** FOR BLOB COLUMNS ***********/ diff --git a/src/obiview.h b/src/obiview.h index 7a4bef8..961e2c4 100644 --- a/src/obiview.h +++ b/src/obiview.h @@ -55,6 +55,8 @@ #define COUNT_COLUMN "COUNT" /**< The name of the column containing the sequence counts * in NUC_SEQS_VIEW views. */ +#define ID_PREFIX "seq" /**< The default prefix of sequence identifiers in automatic ID columns. + */ /** @@ -409,6 +411,20 @@ int obi_view_delete_column(Obiview_p view, const char* column_name); OBIDMS_column_p obi_view_get_column(Obiview_p view, const char* column_name); +/** + * @brief Checks if a column exists in a view. + * + * @param view A pointer on the view. + * @param column_name The name of the column in the view. + * + * @returns A boolean indicating whether or not the column exists in the view. + * + * @since July 2017 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +bool obi_view_column_exists(Obiview_p view, const char* column_name); + + /** * @brief Gets the pointer on the pointer on a column from its name in a view. * @@ -527,6 +543,25 @@ int obi_save_and_close_view(Obiview_p view); int obi_create_auto_count_column(Obiview_p view); +/** + * @brief Creates an OBI_STR column with the line count of the view it belongs to, and sets all lines with automatic identifiers + * with the form prefix_index. + * + * @warning The number of lines set corresponds to the line count of the view. + * + * @param view A pointer on the view. + * @param prefix The prefix of automatic ids. The ids have the form prefix_index. If NULL, the default ID_PREFIX is used. + * + * @returns A value indicating the success of the operation. + * @retval 0 if the operation was successfully completed. + * @retval -1 if an error occurred. + * + * @since July 2017 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +int obi_create_auto_id_column(Obiview_p view, const char* prefix); + + /** * @brief Recovers an obiblob from an OBIDMS column containing indices referring to obiblobs, * using the index of the element in the line, and the column pointer, in the context of a view. diff --git a/src/utils.c b/src/utils.c index 37e5f0c..606f154 100644 --- a/src/utils.c +++ b/src/utils.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "utils.h" #include "obidebug.h" @@ -35,6 +36,43 @@ **********************************************************************/ +int digit_count(index_t i) +{ + int n_digits; + + if (i == 0) + n_digits = 1; + else + n_digits = floor(log10(llabs(i))) + 1; + + return n_digits; +} + + +char* build_word_with_idx(const char* prefix, index_t idx) +{ + char* word; + int n_digits; + + n_digits = digit_count(idx); + word = (char*) malloc((strlen(prefix) + 1+ n_digits + 1)*sizeof(char)); + if (word == NULL) + { + obi_set_errno(OBI_MALLOC_ERROR); + obidebug(1, "\nError allocating memory for a character string"); + return NULL; + } + if (sprintf(word, "%s_%lld", prefix, idx) < 0) + { + obi_set_errno(OBI_UTILS_ERROR); + obidebug(1, "\nProblem building a word from a prefix and an index"); + return NULL; + } + + return word; +} + + int count_dir(char* dir_path) { struct dirent* dp; diff --git a/src/utils.h b/src/utils.h index ecab62e..752747d 100644 --- a/src/utils.h +++ b/src/utils.h @@ -17,6 +17,7 @@ #include #include "obidms.h" +#include "obitypes.h" #define FORMATTED_TIME_LENGTH (1024) /**< The length allocated for the character string containing a formatted date. @@ -25,6 +26,35 @@ */ +/** + * @brief Counts the number of digits of a number. + * + * @param i The number. + * + * @returns The number of digits of the number. + * + * @since July 2017 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +int digit_count(index_t i); + + +/** + * @brief Builds a word from a prefix and an index, with the form prefix_index. + * + * @warning The returned pointer has to be freed by the caller. + * + * @param prefix The prefix for the word. + * @param idx The index to use as suffix. + * + * @returns The built word. + * + * @since July 2017 + * @author Celine Mercier (celine.mercier@metabarcoding.org) + */ +char* build_word_with_idx(const char* prefix, index_t idx); + + /** * @brief Counts the number of files and directories in a directory. *