labfy-investigation/src/dao/evidence_entity_dao.c
2026-07-28 08:53:31 +02:00

1284 lines
34 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/******************************************************************************
* @file evidence_entity_dao.c
* @brief Persistance des associations entre preuves et entités.
******************************************************************************/
#include "dao/evidence_entity_dao.h"
#include "database/error.h"
#include "database/statement.h"
#include <glib.h>
/**
* @brief Représentation privée du DAO.
*
* La connexion Database est empruntée.
*/
struct EvidenceEntityDao
{
Database *database;
};
/**
* @brief Requête vérifiant l'existence d'une preuve.
*/
static const char *const evidence_entity_dao_evidence_exists_sql =
"SELECT 1 "
"FROM preuves "
"WHERE id = ? "
"LIMIT 1;";
/**
* @brief Requête vérifiant l'existence d'une entité.
*/
static const char *const evidence_entity_dao_entity_exists_sql =
"SELECT 1 "
"FROM entites "
"WHERE id = ? "
"LIMIT 1;";
/**
* @brief Requête vérifiant l'existence d'une association.
*/
static const char *const evidence_entity_dao_association_exists_sql =
"SELECT 1 "
"FROM preuve_entites "
"WHERE preuve_id = ? "
"AND entite_id = ? "
"LIMIT 1;";
/**
* @brief Requête créant une association.
*/
static const char *const evidence_entity_dao_link_sql =
"INSERT INTO preuve_entites"
"("
" preuve_id,"
" entite_id"
")"
"VALUES"
"("
" ?,"
" ?"
");";
/**
* @brief Requête supprimant une association.
*/
static const char *const evidence_entity_dao_unlink_sql =
"DELETE FROM preuve_entites "
"WHERE preuve_id = ? "
"AND entite_id = ?;";
/**
* @brief Requête listant les entités liées à une preuve.
*/
static const char *const
evidence_entity_dao_list_entity_identifiers_sql =
"SELECT entite_id "
"FROM preuve_entites "
"WHERE preuve_id = ? "
"ORDER BY entite_id ASC;";
/**
* @brief Requête listant les preuves liées à une entité.
*/
static const char *const
evidence_entity_dao_list_evidence_identifiers_sql =
"SELECT preuve_id "
"FROM preuve_entites "
"WHERE entite_id = ? "
"ORDER BY preuve_id ASC;";
/**
* @brief Enregistre une erreur littérale du DAO.
*/
static void evidence_entity_dao_set_error_literal(
GError **error,
EvidenceEntityDaoError error_code,
const char *message
)
{
if (error == NULL ||
*error != NULL)
{
return;
}
g_set_error_literal(
error,
EVIDENCE_ENTITY_DAO_ERROR,
error_code,
message
);
}
/**
* @brief Détermine si SQLite signale un schéma incompatible.
*/
static gboolean evidence_entity_dao_is_schema_error(
const char *database_message
)
{
if (database_message == NULL)
{
return FALSE;
}
return g_strstr_len(
database_message,
-1,
"no such table"
) != NULL ||
g_strstr_len(
database_message,
-1,
"no such column"
) != NULL;
}
/**
* @brief Détermine si SQLite signale une contrainte.
*/
static gboolean evidence_entity_dao_is_constraint_error(
const char *database_message
)
{
if (database_message == NULL)
{
return FALSE;
}
return g_strstr_len(
database_message,
-1,
"constraint"
) != NULL ||
g_strstr_len(
database_message,
-1,
"CONSTRAINT"
) != NULL;
}
/**
* @brief Transforme la dernière erreur Database en erreur du DAO.
*/
static void evidence_entity_dao_set_database_error(
EvidenceEntityDao *evidence_entity_dao,
GError **error,
EvidenceEntityDaoError error_code,
const char *context
)
{
const char *database_message =
NULL;
if (error == NULL ||
*error != NULL)
{
return;
}
if (evidence_entity_dao != NULL &&
evidence_entity_dao->database != NULL)
{
database_message =
database_error_get_message(
evidence_entity_dao->database
);
}
if (error_code ==
EVIDENCE_ENTITY_DAO_ERROR_PREPARE &&
evidence_entity_dao_is_schema_error(
database_message
))
{
error_code =
EVIDENCE_ENTITY_DAO_ERROR_SCHEMA;
}
if (database_message != NULL &&
database_message[0] != '\0')
{
g_set_error(
error,
EVIDENCE_ENTITY_DAO_ERROR,
error_code,
"%s : %s",
context,
database_message
);
return;
}
g_set_error_literal(
error,
EVIDENCE_ENTITY_DAO_ERROR,
error_code,
context
);
}
/**
* @brief Vérifie le DAO et les deux UUID d'une association.
*/
static gboolean evidence_entity_dao_validate_association(
EvidenceEntityDao *evidence_entity_dao,
const char *evidence_identifier,
const char *entity_identifier,
GError **error
)
{
if (evidence_entity_dao == NULL ||
evidence_entity_dao->database == NULL)
{
evidence_entity_dao_set_error_literal(
error,
EVIDENCE_ENTITY_DAO_ERROR_INVALID_ARGUMENT,
"Le DAO des associations preuve-entité est invalide."
);
return FALSE;
}
if (evidence_identifier == NULL ||
!g_uuid_string_is_valid(
evidence_identifier
))
{
evidence_entity_dao_set_error_literal(
error,
EVIDENCE_ENTITY_DAO_ERROR_INVALID_ARGUMENT,
"L'identifiant de preuve est invalide."
);
return FALSE;
}
if (entity_identifier == NULL ||
!g_uuid_string_is_valid(
entity_identifier
))
{
evidence_entity_dao_set_error_literal(
error,
EVIDENCE_ENTITY_DAO_ERROR_INVALID_ARGUMENT,
"L'identifiant d'entité est invalide."
);
return FALSE;
}
return TRUE;
}
/**
* @brief Vérifie le DAO et un UUID utilisé pour une liste.
*/
static gboolean evidence_entity_dao_validate_list_request(
EvidenceEntityDao *evidence_entity_dao,
const char *identifier,
const char *invalid_identifier_message,
GError **error
)
{
if (evidence_entity_dao == NULL ||
evidence_entity_dao->database == NULL)
{
evidence_entity_dao_set_error_literal(
error,
EVIDENCE_ENTITY_DAO_ERROR_INVALID_ARGUMENT,
"Le DAO des associations preuve-entité est invalide."
);
return FALSE;
}
if (identifier == NULL ||
!g_uuid_string_is_valid(
identifier
))
{
evidence_entity_dao_set_error_literal(
error,
EVIDENCE_ENTITY_DAO_ERROR_INVALID_ARGUMENT,
invalid_identifier_message
);
return FALSE;
}
return TRUE;
}
/**
* @brief Exécute une requête SELECT 1 avec un ou deux paramètres.
*/
static gboolean evidence_entity_dao_query_exists(
EvidenceEntityDao *evidence_entity_dao,
const char *sql,
const char *first_value,
const char *second_value,
gboolean *out_exists,
GError **error
)
{
DatabaseStatement *statement =
NULL;
DatabaseStatementStepResult step_result =
DATABASE_STATEMENT_STEP_ERROR;
gboolean success =
FALSE;
if (evidence_entity_dao == NULL ||
evidence_entity_dao->database == NULL ||
sql == NULL ||
first_value == NULL ||
out_exists == NULL)
{
evidence_entity_dao_set_error_literal(
error,
EVIDENCE_ENTITY_DAO_ERROR_INVALID_ARGUMENT,
"Les paramètres de la recherche d'existence sont invalides."
);
return FALSE;
}
*out_exists =
FALSE;
statement =
database_statement_prepare(
evidence_entity_dao->database,
sql
);
if (statement == NULL)
{
evidence_entity_dao_set_database_error(
evidence_entity_dao,
error,
EVIDENCE_ENTITY_DAO_ERROR_PREPARE,
"Impossible de préparer la recherche d'existence"
);
goto cleanup;
}
if (!database_statement_bind_text(
statement,
1,
first_value
))
{
evidence_entity_dao_set_database_error(
evidence_entity_dao,
error,
EVIDENCE_ENTITY_DAO_ERROR_BIND,
"Impossible de lier le premier identifiant"
);
goto cleanup;
}
if (second_value != NULL &&
!database_statement_bind_text(
statement,
2,
second_value
))
{
evidence_entity_dao_set_database_error(
evidence_entity_dao,
error,
EVIDENCE_ENTITY_DAO_ERROR_BIND,
"Impossible de lier le second identifiant"
);
goto cleanup;
}
step_result =
database_statement_step(
statement
);
if (step_result ==
DATABASE_STATEMENT_STEP_ERROR)
{
evidence_entity_dao_set_database_error(
evidence_entity_dao,
error,
EVIDENCE_ENTITY_DAO_ERROR_EXECUTE,
"Impossible d'exécuter la recherche d'existence"
);
goto cleanup;
}
*out_exists =
step_result ==
DATABASE_STATEMENT_STEP_ROW;
success =
TRUE;
cleanup:
database_statement_finalize(
statement
);
return success;
}
/**
* @brief Exécute une modification à deux UUID.
*/
static gboolean evidence_entity_dao_execute_pair_statement(
EvidenceEntityDao *evidence_entity_dao,
const char *sql,
const char *evidence_identifier,
const char *entity_identifier,
const char *prepare_context,
const char *bind_context,
const char *execute_context,
GError **error
)
{
DatabaseStatement *statement =
NULL;
DatabaseStatementStepResult step_result =
DATABASE_STATEMENT_STEP_ERROR;
const char *database_message =
NULL;
gboolean success =
FALSE;
statement =
database_statement_prepare(
evidence_entity_dao->database,
sql
);
if (statement == NULL)
{
evidence_entity_dao_set_database_error(
evidence_entity_dao,
error,
EVIDENCE_ENTITY_DAO_ERROR_PREPARE,
prepare_context
);
goto cleanup;
}
if (!database_statement_bind_text(
statement,
1,
evidence_identifier
) ||
!database_statement_bind_text(
statement,
2,
entity_identifier
))
{
evidence_entity_dao_set_database_error(
evidence_entity_dao,
error,
EVIDENCE_ENTITY_DAO_ERROR_BIND,
bind_context
);
goto cleanup;
}
step_result =
database_statement_step(
statement
);
if (step_result !=
DATABASE_STATEMENT_STEP_DONE)
{
database_message =
database_error_get_message(
evidence_entity_dao->database
);
if (evidence_entity_dao_is_constraint_error(
database_message
))
{
evidence_entity_dao_set_database_error(
evidence_entity_dao,
error,
EVIDENCE_ENTITY_DAO_ERROR_CONSTRAINT,
execute_context
);
}
else
{
evidence_entity_dao_set_database_error(
evidence_entity_dao,
error,
EVIDENCE_ENTITY_DAO_ERROR_EXECUTE,
execute_context
);
}
goto cleanup;
}
success =
TRUE;
cleanup:
database_statement_finalize(
statement
);
return success;
}
/**
* @brief Charge une liste d'UUID depuis une requête à un paramètre.
*/
static GPtrArray *evidence_entity_dao_list_identifiers(
EvidenceEntityDao *evidence_entity_dao,
const char *sql,
const char *identifier,
const char *prepare_context,
const char *bind_context,
const char *execute_context,
GError **error
)
{
DatabaseStatement *statement =
NULL;
GPtrArray *identifiers =
NULL;
DatabaseStatementStepResult step_result =
DATABASE_STATEMENT_STEP_ERROR;
identifiers =
g_ptr_array_new_with_free_func(
g_free
);
if (identifiers == NULL)
{
evidence_entity_dao_set_error_literal(
error,
EVIDENCE_ENTITY_DAO_ERROR_MEMORY,
"Impossible d'allouer la liste d'identifiants."
);
return NULL;
}
statement =
database_statement_prepare(
evidence_entity_dao->database,
sql
);
if (statement == NULL)
{
evidence_entity_dao_set_database_error(
evidence_entity_dao,
error,
EVIDENCE_ENTITY_DAO_ERROR_PREPARE,
prepare_context
);
goto failure;
}
if (!database_statement_bind_text(
statement,
1,
identifier
))
{
evidence_entity_dao_set_database_error(
evidence_entity_dao,
error,
EVIDENCE_ENTITY_DAO_ERROR_BIND,
bind_context
);
goto failure;
}
while (TRUE)
{
char *loaded_identifier =
NULL;
step_result =
database_statement_step(
statement
);
if (step_result ==
DATABASE_STATEMENT_STEP_DONE)
{
break;
}
if (step_result ==
DATABASE_STATEMENT_STEP_ERROR)
{
evidence_entity_dao_set_database_error(
evidence_entity_dao,
error,
EVIDENCE_ENTITY_DAO_ERROR_EXECUTE,
execute_context
);
goto failure;
}
if (!database_statement_column_text(
statement,
0,
&loaded_identifier
))
{
evidence_entity_dao_set_database_error(
evidence_entity_dao,
error,
EVIDENCE_ENTITY_DAO_ERROR_READ,
"Impossible de lire un identifiant associé"
);
g_free(
loaded_identifier
);
goto failure;
}
if (loaded_identifier == NULL ||
!g_uuid_string_is_valid(
loaded_identifier
))
{
evidence_entity_dao_set_error_literal(
error,
EVIDENCE_ENTITY_DAO_ERROR_READ,
"La base contient un identifiant associé invalide."
);
g_free(
loaded_identifier
);
goto failure;
}
g_ptr_array_add(
identifiers,
loaded_identifier
);
}
database_statement_finalize(
statement
);
return identifiers;
failure:
database_statement_finalize(
statement
);
g_ptr_array_unref(
identifiers
);
return NULL;
}
GQuark evidence_entity_dao_error_quark(void)
{
return g_quark_from_static_string(
"evidence-entity-dao-error-quark"
);
}
EvidenceEntityDao *evidence_entity_dao_new(
Database *database,
GError **error
)
{
EvidenceEntityDao *evidence_entity_dao =
NULL;
g_return_val_if_fail(
error == NULL || *error == NULL,
NULL
);
if (database == NULL)
{
evidence_entity_dao_set_error_literal(
error,
EVIDENCE_ENTITY_DAO_ERROR_INVALID_ARGUMENT,
"La connexion Database est obligatoire."
);
return NULL;
}
evidence_entity_dao =
g_try_new0(
EvidenceEntityDao,
1
);
if (evidence_entity_dao == NULL)
{
evidence_entity_dao_set_error_literal(
error,
EVIDENCE_ENTITY_DAO_ERROR_MEMORY,
"Impossible d'allouer le DAO des associations preuve-entité."
);
return NULL;
}
evidence_entity_dao->database =
database;
return evidence_entity_dao;
}
void evidence_entity_dao_free(
EvidenceEntityDao *evidence_entity_dao
)
{
if (evidence_entity_dao == NULL)
{
return;
}
evidence_entity_dao->database =
NULL;
g_free(
evidence_entity_dao
);
}
gboolean evidence_entity_dao_link(
EvidenceEntityDao *evidence_entity_dao,
const char *evidence_identifier,
const char *entity_identifier,
GError **error
)
{
gboolean evidence_exists =
FALSE;
gboolean entity_exists =
FALSE;
gboolean association_exists =
FALSE;
g_return_val_if_fail(
error == NULL || *error == NULL,
FALSE
);
if (!evidence_entity_dao_validate_association(
evidence_entity_dao,
evidence_identifier,
entity_identifier,
error
))
{
return FALSE;
}
if (!evidence_entity_dao_query_exists(
evidence_entity_dao,
evidence_entity_dao_evidence_exists_sql,
evidence_identifier,
NULL,
&evidence_exists,
error
))
{
return FALSE;
}
if (!evidence_exists)
{
evidence_entity_dao_set_error_literal(
error,
EVIDENCE_ENTITY_DAO_ERROR_NOT_FOUND,
"La preuve à associer n'existe pas."
);
return FALSE;
}
if (!evidence_entity_dao_query_exists(
evidence_entity_dao,
evidence_entity_dao_entity_exists_sql,
entity_identifier,
NULL,
&entity_exists,
error
))
{
return FALSE;
}
if (!entity_exists)
{
evidence_entity_dao_set_error_literal(
error,
EVIDENCE_ENTITY_DAO_ERROR_NOT_FOUND,
"L'entité à associer n'existe pas."
);
return FALSE;
}
if (!evidence_entity_dao_query_exists(
evidence_entity_dao,
evidence_entity_dao_association_exists_sql,
evidence_identifier,
entity_identifier,
&association_exists,
error
))
{
return FALSE;
}
if (association_exists)
{
evidence_entity_dao_set_error_literal(
error,
EVIDENCE_ENTITY_DAO_ERROR_CONSTRAINT,
"Cette preuve est déjà associée à cette entité."
);
return FALSE;
}
return evidence_entity_dao_execute_pair_statement(
evidence_entity_dao,
evidence_entity_dao_link_sql,
evidence_identifier,
entity_identifier,
"Impossible de préparer la création de l'association",
"Impossible de lier les identifiants de l'association",
"Impossible de créer l'association",
error
);
}
gboolean evidence_entity_dao_unlink(
EvidenceEntityDao *evidence_entity_dao,
const char *evidence_identifier,
const char *entity_identifier,
GError **error
)
{
gboolean association_exists =
FALSE;
g_return_val_if_fail(
error == NULL || *error == NULL,
FALSE
);
if (!evidence_entity_dao_validate_association(
evidence_entity_dao,
evidence_identifier,
entity_identifier,
error
))
{
return FALSE;
}
if (!evidence_entity_dao_query_exists(
evidence_entity_dao,
evidence_entity_dao_association_exists_sql,
evidence_identifier,
entity_identifier,
&association_exists,
error
))
{
return FALSE;
}
if (!association_exists)
{
evidence_entity_dao_set_error_literal(
error,
EVIDENCE_ENTITY_DAO_ERROR_NOT_FOUND,
"L'association entre la preuve et l'entité n'existe pas."
);
return FALSE;
}
return evidence_entity_dao_execute_pair_statement(
evidence_entity_dao,
evidence_entity_dao_unlink_sql,
evidence_identifier,
entity_identifier,
"Impossible de préparer la suppression de l'association",
"Impossible de lier les identifiants de l'association",
"Impossible de supprimer l'association",
error
);
}
gboolean evidence_entity_dao_exists(
EvidenceEntityDao *evidence_entity_dao,
const char *evidence_identifier,
const char *entity_identifier,
gboolean *out_exists,
GError **error
)
{
g_return_val_if_fail(
error == NULL || *error == NULL,
FALSE
);
if (out_exists == NULL)
{
evidence_entity_dao_set_error_literal(
error,
EVIDENCE_ENTITY_DAO_ERROR_INVALID_ARGUMENT,
"La destination du résultat d'existence est obligatoire."
);
return FALSE;
}
if (!evidence_entity_dao_validate_association(
evidence_entity_dao,
evidence_identifier,
entity_identifier,
error
))
{
return FALSE;
}
return evidence_entity_dao_query_exists(
evidence_entity_dao,
evidence_entity_dao_association_exists_sql,
evidence_identifier,
entity_identifier,
out_exists,
error
);
}
GPtrArray *evidence_entity_dao_list_entity_identifiers(
EvidenceEntityDao *evidence_entity_dao,
const char *evidence_identifier,
GError **error
)
{
g_return_val_if_fail(
error == NULL || *error == NULL,
NULL
);
if (!evidence_entity_dao_validate_list_request(
evidence_entity_dao,
evidence_identifier,
"L'identifiant de preuve est invalide.",
error
))
{
return NULL;
}
return evidence_entity_dao_list_identifiers(
evidence_entity_dao,
evidence_entity_dao_list_entity_identifiers_sql,
evidence_identifier,
"Impossible de préparer la liste des entités associées",
"Impossible de lier l'identifiant de preuve",
"Impossible de charger les entités associées",
error
);
}
GPtrArray *evidence_entity_dao_list_evidence_identifiers(
EvidenceEntityDao *evidence_entity_dao,
const char *entity_identifier,
GError **error
)
{
g_return_val_if_fail(
error == NULL || *error == NULL,
NULL
);
if (!evidence_entity_dao_validate_list_request(
evidence_entity_dao,
entity_identifier,
"L'identifiant d'entité est invalide.",
error
))
{
return NULL;
}
return evidence_entity_dao_list_identifiers(
evidence_entity_dao,
evidence_entity_dao_list_evidence_identifiers_sql,
entity_identifier,
"Impossible de préparer la liste des preuves associées",
"Impossible de lier l'identifiant d'entité",
"Impossible de charger les preuves associées",
error
);
}
gboolean evidence_entity_dao_add_observation(EvidenceEntityDao *dao,
const char *evidence_identifier, const char *entity_type,
const char *value_raw,
const char *value_normalized, const char *role,
const char *provenance_kind, const char *source_header,
guint occurrence, const char *verification_status,
const char *created_at, char **out_observation_identifier, GError **error)
{
static const char *sql =
"INSERT OR IGNORE INTO evidence_entity_observations("
"id,evidence_id,entity_type,value_raw,value_normalized,role,"
"provenance_kind,source_header,occurrence,verification_status,"
"observed_at,integrated_at) VALUES(?,?,?,?,?,?,?,?,?,?,?,?);";
static const char *find_sql =
"SELECT id FROM evidence_entity_observations WHERE evidence_id=? "
"AND entity_type=? AND value_normalized=? AND role=? "
"AND source_header=? AND occurrence=? AND provenance_kind=? "
"AND extraction_id IS NULL LIMIT 1;";
DatabaseStatement *statement = NULL;
char *new_identifier = NULL;
gboolean success = FALSE;
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
if (out_observation_identifier != NULL) *out_observation_identifier = NULL;
if (!evidence_entity_dao_validate_list_request(dao, evidence_identifier,
"L'identifiant de preuve est invalide.", error) ||
entity_type == NULL ||
value_raw == NULL || value_normalized == NULL || role == NULL ||
source_header == NULL || occurrence == 0 || created_at == NULL)
return FALSE;
new_identifier = g_uuid_string_random();
statement = database_statement_prepare(dao->database, sql);
if (statement == NULL) goto cleanup;
success =
database_statement_bind_text(statement, 1, new_identifier) &&
database_statement_bind_text(statement, 2, evidence_identifier) &&
database_statement_bind_text(statement, 3, entity_type) &&
database_statement_bind_text(statement, 4, value_raw) &&
database_statement_bind_text(statement, 5, value_normalized) &&
database_statement_bind_text(statement, 6, role) &&
database_statement_bind_text(statement, 7, provenance_kind) &&
database_statement_bind_text(statement, 8, source_header) &&
database_statement_bind_int64(statement, 9, occurrence) &&
database_statement_bind_text(statement, 10, verification_status) &&
database_statement_bind_text(statement, 11, created_at) &&
database_statement_bind_text(statement, 12, created_at) &&
database_statement_step(statement) == DATABASE_STATEMENT_STEP_DONE;
database_statement_finalize(statement); statement = NULL;
if (!success) goto cleanup;
statement = database_statement_prepare(dao->database, find_sql);
success = statement != NULL &&
database_statement_bind_text(statement, 1, evidence_identifier) &&
database_statement_bind_text(statement, 2, entity_type) &&
database_statement_bind_text(statement, 3, value_normalized) &&
database_statement_bind_text(statement, 4, role) &&
database_statement_bind_text(statement, 5, source_header) &&
database_statement_bind_int64(statement, 6, occurrence) &&
database_statement_bind_text(statement, 7, provenance_kind) &&
database_statement_step(statement) == DATABASE_STATEMENT_STEP_ROW &&
database_statement_column_text(statement, 0,
out_observation_identifier);
cleanup:
if (!success)
evidence_entity_dao_set_database_error(dao, error,
EVIDENCE_ENTITY_DAO_ERROR_EXECUTE,
"Impossible denregistrer lobservation preuve-entité");
database_statement_finalize(statement);
g_free(new_identifier);
return success;
}
gboolean evidence_entity_dao_promote_observation(EvidenceEntityDao *dao,
const char *observation_identifier, const char *entity_identifier,
const char *promoted_at, const char *promotion_kind, GError **error)
{
static const char *sql =
"UPDATE evidence_entity_observations SET entity_id=?,promoted_at=?,"
"promotion_kind=? WHERE id=? AND (entity_id IS NULL OR entity_id=?);";
DatabaseStatement *statement = NULL;
gboolean success = FALSE;
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
if (dao == NULL || !g_uuid_string_is_valid(observation_identifier) ||
!g_uuid_string_is_valid(entity_identifier) || promoted_at == NULL ||
(g_strcmp0(promotion_kind, "created") != 0 &&
g_strcmp0(promotion_kind, "reused") != 0)) return FALSE;
statement = database_statement_prepare(dao->database, sql);
success = statement != NULL &&
database_statement_bind_text(statement, 1, entity_identifier) &&
database_statement_bind_text(statement, 2, promoted_at) &&
database_statement_bind_text(statement, 3, promotion_kind) &&
database_statement_bind_text(statement, 4, observation_identifier) &&
database_statement_bind_text(statement, 5, entity_identifier) &&
database_statement_step(statement) == DATABASE_STATEMENT_STEP_DONE;
if (!success)
evidence_entity_dao_set_database_error(dao, error,
EVIDENCE_ENTITY_DAO_ERROR_EXECUTE,
"Impossible de promouvoir lobservation");
database_statement_finalize(statement);
return success;
}
char *evidence_entity_dao_format_observations(EvidenceEntityDao *dao,
const char *evidence_identifier, GError **error)
{
static const char *sql =
"SELECT COALESCE(o.value_normalized,o.value_raw),o.entity_type,o.role,"
"o.source_header,o.occurrence,o.provenance_kind,o.verification_status,"
"o.integrated_at,o.entity_id,o.promotion_kind "
"FROM evidence_entity_observations o WHERE o.evidence_id=? "
"ORDER BY o.source_header,o.occurrence,1,o.role;";
DatabaseStatement *statement = NULL;
GString *text = NULL;
g_return_val_if_fail(error == NULL || *error == NULL, NULL);
if (!evidence_entity_dao_validate_list_request(dao, evidence_identifier,
"L'identifiant de preuve est invalide.", error)) return NULL;
statement = database_statement_prepare(dao->database, sql);
if (statement == NULL ||
!database_statement_bind_text(statement, 1, evidence_identifier))
goto failure;
text = g_string_new(NULL);
for (;;)
{
DatabaseStatementStepResult step = database_statement_step(statement);
if (step == DATABASE_STATEMENT_STEP_DONE) break;
if (step != DATABASE_STATEMENT_STEP_ROW) goto failure;
char *value = NULL, *type = NULL, *role = NULL, *header = NULL;
char *provenance = NULL, *status = NULL, *date = NULL;
char *entity = NULL, *promotion = NULL; int64_t occurrence = 0;
if (!database_statement_column_text(statement, 0, &value) ||
!database_statement_column_text(statement, 1, &type) ||
!database_statement_column_text(statement, 2, &role) ||
!database_statement_column_text(statement, 3, &header) ||
!database_statement_column_int64(statement, 4, &occurrence) ||
!database_statement_column_text(statement, 5, &provenance) ||
!database_statement_column_text(statement, 6, &status) ||
!database_statement_column_text(statement, 7, &date) ||
!database_statement_column_text(statement, 8, &entity) ||
!database_statement_column_text(statement, 9, &promotion))
{ g_free(value); g_free(type); g_free(role); g_free(header);
g_free(provenance); g_free(status); g_free(date); g_free(entity);
g_free(promotion); goto failure; }
g_string_append_printf(text, "%s%s — %s — rôle : %s — origine : %s"
" #%lld — provenance : %s — validation : %s — date : %s — "
"graphe : %s%s%s", text->len > 0 ? "\n" : "",
value, type, role, header, (long long) occurrence, provenance,
status, date, entity != NULL ? "promue" : "non ajoutée",
promotion != NULL ? " (" : "", promotion != NULL ? promotion : "");
if (promotion != NULL) g_string_append_c(text, ')');
g_free(value); g_free(type); g_free(role); g_free(header);
g_free(provenance); g_free(status); g_free(date); g_free(entity);
g_free(promotion);
}
database_statement_finalize(statement);
return g_string_free(text, FALSE);
failure:
evidence_entity_dao_set_database_error(dao, error,
EVIDENCE_ENTITY_DAO_ERROR_EXECUTE,
"Impossible de charger les observations preuve-entité");
database_statement_finalize(statement);
if (text != NULL) g_string_free(text, TRUE);
return NULL;
}
GPtrArray *evidence_entity_dao_list_observations(EvidenceEntityDao *dao,
const char *evidence_identifier, GError **error)
{
static const char *sql =
"SELECT id,COALESCE(value_normalized,value_raw),entity_type,role,"
"source_header,occurrence,provenance_kind,verification_status,"
"integrated_at,entity_id,promotion_kind "
"FROM evidence_entity_observations WHERE evidence_id=? "
"ORDER BY source_header,occurrence,2,role;";
DatabaseStatement *statement = NULL;
GPtrArray *items = NULL;
g_return_val_if_fail(error == NULL || *error == NULL, NULL);
if (!evidence_entity_dao_validate_list_request(dao, evidence_identifier,
"L'identifiant de preuve est invalide.", error)) return NULL;
statement = database_statement_prepare(dao->database, sql);
if (statement == NULL ||
!database_statement_bind_text(statement, 1, evidence_identifier))
goto failure;
items = g_ptr_array_new_with_free_func(
(GDestroyNotify) evidence_observation_free);
for (;;)
{
DatabaseStatementStepResult step = database_statement_step(statement);
if (step == DATABASE_STATEMENT_STEP_DONE) break;
if (step != DATABASE_STATEMENT_STEP_ROW) goto failure;
EvidenceObservation *item = g_new0(EvidenceObservation, 1);
int64_t occurrence = 0;
if (!database_statement_column_text(statement, 0, &item->identifier) ||
!database_statement_column_text(statement, 1, &item->value) ||
!database_statement_column_text(statement, 2, &item->type_identifier) ||
!database_statement_column_text(statement, 3, &item->role) ||
!database_statement_column_text(statement, 4, &item->source_header) ||
!database_statement_column_int64(statement, 5, &occurrence) ||
!database_statement_column_text(statement, 6, &item->provenance_kind) ||
!database_statement_column_text(statement, 7, &item->verification_status) ||
!database_statement_column_text(statement, 8, &item->integrated_at) ||
!database_statement_column_text(statement, 9, &item->entity_identifier) ||
!database_statement_column_text(statement, 10, &item->promotion_kind))
{ evidence_observation_free(item); goto failure; }
item->occurrence = (guint) occurrence;
g_ptr_array_add(items, item);
}
database_statement_finalize(statement);
return items;
failure:
evidence_entity_dao_set_database_error(dao, error,
EVIDENCE_ENTITY_DAO_ERROR_EXECUTE,
"Impossible de charger toutes les observations de la preuve");
database_statement_finalize(statement);
g_clear_pointer(&items, g_ptr_array_unref);
return NULL;
}