Views: implemented handling of JSON formatted comments

This commit is contained in:
Celine Mercier
2018-10-07 18:56:46 +02:00
parent bc8c394061
commit 86bb582a17
2 changed files with 150 additions and 139 deletions

View File

@ -38,6 +38,7 @@
#include "linked_list.h" #include "linked_list.h"
#include "utils.h" #include "utils.h"
#include "obiblob.h" #include "obiblob.h"
#include "libjson/json_utils.h"
#define DEBUG_LEVEL 0 // TODO has to be defined somewhere else (cython compil flag?) #define DEBUG_LEVEL 0 // TODO has to be defined somewhere else (cython compil flag?)
@ -122,24 +123,6 @@ static size_t get_platform_view_file_size();
static int enlarge_view_file(Obiview_p view, size_t new_size); static int enlarge_view_file(Obiview_p view, size_t new_size);
/**
* @brief Internal function writing new comments in a view file.
*
* The new comments are concatenated to the pre-existing ones.
* The view file is enlarged if necessary.
*
* @param view A pointer on the view.
* @param comments The new comments that should be added.
*
* @retval 0 if the operation was successfully completed.
* @retval -1 if an error occurred.
*
* @since August 2016
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
static int write_comments_to_view_file(Obiview_p view, const char* comments);
/** /**
* @brief Internal function creating a file containing all the informations on a view. * @brief Internal function creating a file containing all the informations on a view.
* *
@ -490,14 +473,15 @@ static char* view_check_one_predicate(Obiview_p view, char* (*predicate_function
* @brief Internal function checking all the predicates associated with a view. * @brief Internal function checking all the predicates associated with a view.
* *
* @param view The view. * @param view The view.
* @param write Whether the verified predicates should be written in the view comments.
* *
* @returns A character string describing all the predicates separated by line breaks. * @retval 0 if the operation was successfully completed.
* @retval NULL if at least one of the predicates is false or if there was an error. * @retval -1 if at least one of the predicates is false or if there was an error.
* *
* @since July 2016 * @since July 2016
* @author Celine Mercier (celine.mercier@metabarcoding.org) * @author Celine Mercier (celine.mercier@metabarcoding.org)
*/ */
static char* view_check_all_predicates(Obiview_p view); static int view_check_all_predicates(Obiview_p view, bool write);
/************************************************************************ /************************************************************************
@ -694,30 +678,6 @@ static int enlarge_view_file(Obiview_p view, size_t new_size)
} }
static int write_comments_to_view_file(Obiview_p view, const char* comments)
{
size_t new_size;
if (comments == NULL)
return 0; // TODO or error? discuss
new_size = (view->infos)->used_size + strlen(comments);
// Check if the file has to be enlarged
if (new_size >= (view->infos)->file_size)
{
if (enlarge_view_file(view, new_size) < 0)
return -1;
}
strcat((view->infos)->comments, comments);
(view->infos)->used_size = new_size;
return 0;
}
static int create_obiview_file(OBIDMS_p dms, const char* view_name) static int create_obiview_file(OBIDMS_p dms, const char* view_name)
{ {
char* file_name; char* file_name;
@ -1067,7 +1027,6 @@ static int rename_finished_view(Obiview_p view)
static int finish_view(Obiview_p view) static int finish_view(Obiview_p view)
{ {
char* predicates;
int i; int i;
OBIDMS_column_p column; OBIDMS_column_p column;
@ -1100,16 +1059,11 @@ static int finish_view(Obiview_p view)
} }
// Check predicates // Check predicates
predicates = view_check_all_predicates(view); if (view_check_all_predicates(view, true) < 0)
if (predicates == NULL)
{ {
obidebug(1, "\nView predicates not respected"); obidebug(1, "\nView predicates not respected, view rollbacked");
return -1; // TODO reverse view (delete files) obi_rollback_view(view); // TODO discuss, maybe never call from C layer
} return -1;
else
{
write_comments_to_view_file(view, predicates);
free(predicates);
} }
if (save_view(view) < 0) if (save_view(view) < 0)
@ -1419,9 +1373,9 @@ static char* view_check_qual_match_seqs(Obiview_p view)
if ((qual != OBIQual_int_NA) && (seq != OBISeq_NA)) if ((qual != OBIQual_int_NA) && (seq != OBISeq_NA))
{ {
// Test that the lengths of the quality and the sequence are equal // Test that the lengths of the quality and the sequence are equal
if (qual_len != (int)strlen(seq)) if ((size_t)qual_len != strlen(seq))
{ {
obidebug(1, "\nError checking the predicate for view %s: The sequences and sequence quality arrays match. \n%d, %s, %d", (view->infos)->name, j, seq, qual_len); obidebug(1, "\nError checking the predicate for view %s: The sequences and sequence quality arrays match.", (view->infos)->name);
return NULL; return NULL;
} }
} }
@ -1471,78 +1425,37 @@ static char* view_check_one_predicate(Obiview_p view, char* (*predicate_function
} }
static char* view_check_all_predicates(Obiview_p view) static int view_check_all_predicates(Obiview_p view, bool write)
{ {
int i, j; int i;
size_t size_to_allocate;
char* predicate = NULL; char* predicate = NULL;
char* all_predicates_string = NULL;
char** all_predicates = NULL;
if (view->nb_predicates == 0)
{
all_predicates_string = (char*) malloc(1*sizeof(char));
strcpy(all_predicates_string, "");
return all_predicates_string;
}
size_to_allocate = 0;
// Allocate memory for predicate array
all_predicates = (char**) malloc((view->nb_predicates) * sizeof(char*));
if (all_predicates == NULL)
{
obi_set_errno(OBI_MALLOC_ERROR);
obidebug(1, "\nError allocating memory for predicate array.");
return NULL;
}
for (i=0; i < view->nb_predicates; i++) for (i=0; i < view->nb_predicates; i++)
{ {
// Initialize predicate in predicate array // Check predicate
all_predicates[i] = NULL;
// Check the predicate
predicate = view_check_one_predicate(view, (view->predicate_functions)[i]); predicate = view_check_one_predicate(view, (view->predicate_functions)[i]);
if (predicate == NULL) if (predicate == NULL)
{ {
// TODO discuss // TODO discuss what to do
for (j=0; j<=i; j++) return -1;
free(all_predicates[j]);
free(all_predicates);
return NULL;
} }
else else
{ {
all_predicates[i] = predicate; if ((write) && (predicate[0]!='\0'))
size_to_allocate = size_to_allocate + strlen(predicate) + 1; // +1 for '\n' {
// Add predicate in comments
if (obi_view_add_comment(view, PREDICATE_KEY, predicate) < 0)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError adding a verified predicate (%s) in the comments of a view.", predicate);
free(predicate);
return -1;
}
}
free(predicate);
} }
} }
return 0;
size_to_allocate += 1; // +1 for '\0'
all_predicates_string = (char*) malloc(size_to_allocate * sizeof(char));
if (all_predicates_string == NULL)
{
obi_set_errno(OBI_MALLOC_ERROR);
obidebug(1, "\nError allocating memory for predicate character string.");
return NULL;
}
// Build the character string with all the predicates
strcpy(all_predicates_string, all_predicates[0]);
for (i=1; i < view->nb_predicates; i++)
{
if (strlen(all_predicates_string)) // First predicate not empty
strcat(all_predicates_string, "\n");
strcat(all_predicates_string, all_predicates[i]);
}
// Free everything
for (i=0; i < view->nb_predicates; i++)
free(all_predicates[i]);
free(all_predicates);
return all_predicates_string;
} }
@ -1561,8 +1474,8 @@ Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_cl
Obiview_p view; Obiview_p view;
int i; int i;
index_t line_nb; index_t line_nb;
char* clone_comment;
OBIDMS_column_p column; OBIDMS_column_p column;
int comments_ok;
// Check that the DMS is a valid pointer // Check that the DMS is a valid pointer
if (dms == NULL) if (dms == NULL)
@ -1708,27 +1621,6 @@ Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_cl
// Fill informations // Fill informations
strcpy((view->infos)->view_type, (view_to_clone->infos)->view_type); strcpy((view->infos)->view_type, (view_to_clone->infos)->view_type);
strcpy((view->infos)->created_from, (view_to_clone->infos)->name); strcpy((view->infos)->created_from, (view_to_clone->infos)->name);
// Write comment specifying the name of the cloned view
clone_comment = (char*) malloc((strlen((view_to_clone->infos)->name) + 15)*sizeof(char));
if (clone_comment == NULL)
{
obi_set_errno(OBI_MALLOC_ERROR);
obidebug(1, "\nError allocating memory for a view comment");
return NULL;
}
if (sprintf(clone_comment, "Cloned from %s.\n", (view_to_clone->infos)->name) < 0)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError building a view comment");
return NULL;
}
if (write_comments_to_view_file(view, clone_comment) < 0)
{
obidebug(1, "\nError writing comments when creating a view");
close_view(view);
return NULL;
}
} }
// Else, fill empty view structure // Else, fill empty view structure
@ -1759,13 +1651,29 @@ Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_cl
(view->predicate_functions)[0] = view_check_qual_match_seqs; (view->predicate_functions)[0] = view_check_qual_match_seqs;
// Write comments // Write comments
if (write_comments_to_view_file(view, comments) < 0) // Comments must be a json string, even empty
if ((strcmp(comments, "") == 0) || (comments == NULL))
comments_ok = obi_view_write_comments(view, "{}");
else
comments_ok = obi_view_write_comments(view, comments);
if (comments_ok < 0)
{ {
obidebug(1, "\nError writing comments when creating a view"); obidebug(1, "\nError writing comments when creating a view");
close_view(view); close_view(view);
return NULL; return NULL;
} }
// Add the comment specifying the name of the cloned view if there is one
if (view_to_clone != NULL)
{
if (obi_view_add_comment(view, "Cloned from", (view_to_clone->infos)->name) < 0)
{
obidebug(1, "\nError adding comment about cloned view when creating a view");
close_view(view);
return NULL;
}
}
// Store reference for line selection // Store reference for line selection
if (view->line_selection == NULL) if (view->line_selection == NULL)
{ {
@ -2524,6 +2432,69 @@ int obi_view_create_column_alias(Obiview_p view, const char* current_name, const
} }
int obi_view_write_comments(Obiview_p view, const char* comments)
{
size_t new_size;
// Check that the view is not read-only
if (view->read_only)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError trying to write comments in a read-only view");
return -1;
}
if (comments == NULL)
return 0; // TODO or error? discuss
new_size = sizeof(Obiview_infos_t) + strlen(comments) + 1;
// Check if the file has to be enlarged
if (new_size >= (view->infos)->file_size)
{
if (enlarge_view_file(view, new_size) < 0)
return -1;
}
strcpy((view->infos)->comments, comments);
(view->infos)->used_size = new_size;
return 0;
}
int obi_view_add_comment(Obiview_p view, const char* key, const char* value)
{
char* new_comments = NULL;
// Check that the view is not read-only
if (view->read_only)
{
obi_set_errno(OBIVIEW_ERROR);
obidebug(1, "\nError trying to add a comment to a read-only view");
return -1;
}
new_comments = obi_add_comment((view->infos)->comments, key, value);
if (new_comments == NULL)
{
obidebug(1, "\nError adding a comment to a view, key: %s, value: %s", key, value);
return -1;
}
if (obi_view_write_comments(view, new_comments) < 0)
{
obidebug(1, "\nError adding a comment to a view, key: %s, value: %s", key, value);
return -1;
}
free(new_comments);
return 0;
}
int obi_save_and_close_view(Obiview_p view) int obi_save_and_close_view(Obiview_p view)
{ {
// Finish and save the view if it is not read-only // Finish and save the view if it is not read-only

View File

@ -59,6 +59,8 @@
*/ */
#define ID_PREFIX "seq" /**< The default prefix of sequence identifiers in automatic ID columns. #define ID_PREFIX "seq" /**< The default prefix of sequence identifiers in automatic ID columns.
*/ */
#define PREDICATE_KEY "predicates" /**< The key used in the json-formatted view comments to store predicates.
*/
/** /**
@ -484,6 +486,44 @@ OBIDMS_column_p* obi_view_get_pointer_on_column_in_view(Obiview_p view, const ch
int obi_view_create_column_alias(Obiview_p view, const char* current_name, const char* alias); int obi_view_create_column_alias(Obiview_p view, const char* current_name, const char* alias);
/**
* @brief Internal function writing new comments in a view file.
*
* The new comments replace the pre-existing ones.
* The view file is enlarged if necessary.
*
* @param view A pointer on the view.
* @param comments The new comments that should be written.
*
* @retval 0 if the operation was successfully completed.
* @retval -1 if an error occurred.
*
* @since August 2016
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
int obi_view_write_comments(Obiview_p view, const char* comments);
/**
* @brief Adds comments to a view file.
*
* This reads the comments in the JSON format and adds the key value pair.
* If the key already exists, the value format is turned into an array and the new value is appended
* if it is not already in the array.
*
* @param column A pointer on an OBIDMS column.
* @param key The key.
* @param value The value associated with the key.
*
* @retval 0 if the operation was successfully completed.
* @retval -1 if an error occurred.
*
* @since August 2018
* @author Celine Mercier (celine.mercier@metabarcoding.org)
*/
int obi_view_add_comment(Obiview_p view, const char* key, const char* value);
/** /**
* @brief Closes an opened view, and saves it if it is not read-only (meaning it is not already saved in the view file). * @brief Closes an opened view, and saves it if it is not read-only (meaning it is not already saved in the view file).
* *