Commit 86bb582a authored by Celine Mercier's avatar Celine Mercier

Views: implemented handling of JSON formatted comments

parent bc8c3940
......@@ -38,6 +38,7 @@
#include "linked_list.h"
#include "utils.h"
#include "obiblob.h"
#include "libjson/json_utils.h"
#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);
/**
* @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.
*
......@@ -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.
*
* @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 NULL if at least one of the predicates is false or if there was an error.
* @retval 0 if the operation was successfully completed.
* @retval -1 if at least one of the predicates is false or if there was an error.
*
* @since July 2016
* @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)
{
char* file_name;
......@@ -1067,7 +1027,6 @@ static int rename_finished_view(Obiview_p view)
static int finish_view(Obiview_p view)
{
char* predicates;
int i;
OBIDMS_column_p column;
......@@ -1100,16 +1059,11 @@ static int finish_view(Obiview_p view)
}
// Check predicates
predicates = view_check_all_predicates(view);
if (predicates == NULL)
{
obidebug(1, "\nView predicates not respected");
return -1; // TODO reverse view (delete files)
}
else
if (view_check_all_predicates(view, true) < 0)
{
write_comments_to_view_file(view, predicates);
free(predicates);
obidebug(1, "\nView predicates not respected, view rollbacked");
obi_rollback_view(view); // TODO discuss, maybe never call from C layer
return -1;
}
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))
{
// 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;
}
}
......@@ -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;
size_t size_to_allocate;
int i;
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++)
{
// Initialize predicate in predicate array
all_predicates[i] = NULL;
// Check the predicate
// Check predicate
predicate = view_check_one_predicate(view, (view->predicate_functions)[i]);
if (predicate == NULL)
{
// TODO discuss
for (j=0; j<=i; j++)
free(all_predicates[j]);
free(all_predicates);
return NULL;
// TODO discuss what to do
return -1;
}
else
{
all_predicates[i] = predicate;
size_to_allocate = size_to_allocate + strlen(predicate) + 1; // +1 for '\n'
if ((write) && (predicate[0]!='\0'))
{
// 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);
}
}
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;
return 0;
}
......@@ -1561,8 +1474,8 @@ Obiview_p obi_new_view(OBIDMS_p dms, const char* view_name, Obiview_p view_to_cl
Obiview_p view;
int i;
index_t line_nb;
char* clone_comment;
OBIDMS_column_p column;
int comments_ok;
// Check that the DMS is a valid pointer
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
strcpy((view->infos)->view_type, (view_to_clone->infos)->view_type);
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
......@@ -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;
// 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");
close_view(view);
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
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)
{
// Finish and save the view if it is not read-only
......
......@@ -59,6 +59,8 @@
*/
#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);
/**
* @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).
*
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment