LCOV - code coverage report
Current view: top level - gui/source - gui_search_runner.c (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.70.2_covts Lines: 0.0 % 204 0
Test Date: 2026-05-03 11:56:31 Functions: 0.0 % 5 0

            Line data    Source code
       1              : /* File: gui_search_runner.c; Copyright and License: see below */
       2              : 
       3              : #include "gui_search_runner.h"
       4              : #include "set/data_search_result_list.h"
       5              : #include "utf8stream/utf8stream_writer.h"
       6              : #include "u8/u8_trace.h"
       7              : #include "u8/u8_log.h"
       8              : #include "u8/u8_i32.h"
       9              : #include <assert.h>
      10              : 
      11            0 : void gui_search_runner_init ( gui_search_runner_t *this_,
      12              :                               gui_simple_message_to_user_t *message_to_user,
      13              :                               data_database_reader_t *db_reader,
      14              :                               data_database_t *database,
      15              :                               observer_t result_consumer )
      16              : {
      17            0 :     U8_TRACE_BEGIN();
      18            0 :     assert ( message_to_user != NULL );
      19            0 :     assert ( db_reader != NULL );
      20            0 :     assert ( database != NULL );
      21              : 
      22              :     /* external entities */
      23            0 :     (*this_).message_to_user = message_to_user;
      24            0 :     (*this_).db_reader = db_reader;
      25            0 :     const u8_error_t d_err = data_database_text_search_init ( &((*this_).db_searcher), database );
      26            0 :     if ( U8_ERROR_NONE != d_err )
      27              :     {
      28            0 :         U8_LOG_WARNING_HEX( "data_database_text_search_t could not be constructed.", d_err );
      29              :     }
      30            0 :     (*this_).result_consumer = result_consumer;
      31              : 
      32              :     /* request data */
      33            0 :     utf8stream_writemem_init( &((*this_).search_string_writer),
      34            0 :                               &((*this_).search_string_buf),
      35              :                               sizeof( (*this_).search_string_buf )
      36              :                             );
      37            0 :     (*this_).page_request = pos_scroll_page_new( 0, false /* backwards */ );
      38              : 
      39              :     /* result data */
      40            0 :     (*this_).result_buffer_start = 0;
      41            0 :     DATA_SEARCH_RESULT_LIST_INIT( &((*this_).result_list), (*this_).result_buffer );
      42            0 :     (*this_).result_buffer_more_after = false;
      43              : 
      44            0 :     U8_TRACE_END();
      45            0 : }
      46              : 
      47            0 : void gui_search_runner_destroy ( gui_search_runner_t *this_ )
      48              : {
      49            0 :     U8_TRACE_BEGIN();
      50              : 
      51              :     /* external entities */
      52            0 :     (*this_).message_to_user = NULL;
      53            0 :     (*this_).db_reader = NULL;
      54            0 :     const u8_error_t d_err = data_database_text_search_destroy ( &((*this_).db_searcher) );
      55            0 :     if ( U8_ERROR_NONE != d_err )
      56              :     {
      57            0 :         U8_LOG_WARNING_HEX( "data_database_text_search_t could not be destroyed.", d_err );
      58              :     }
      59            0 :     observer_destroy( &((*this_).result_consumer) );
      60              : 
      61              :     /* request data */
      62            0 :     const u8_error_t str_err = utf8stream_writemem_destroy( &((*this_).search_string_writer) );
      63            0 :     if ( U8_ERROR_NONE != str_err )
      64              :     {
      65            0 :         U8_LOG_WARNING_HEX( "utf8stream_writemem_t could not be destroyed cleanly.", d_err );
      66              :     }
      67              : 
      68              :     /* result data */
      69            0 :     (*this_).result_buffer_start = 0;
      70            0 :     data_search_result_list_destroy( &((*this_).result_list) );
      71            0 :     (*this_).result_buffer_more_after = false;
      72              : 
      73            0 :     U8_TRACE_END();
      74            0 : }
      75              : 
      76            0 : void gui_search_runner_run ( gui_search_runner_t *this_, const char* search_string, pos_scroll_page_t page )
      77              : {
      78            0 :     U8_TRACE_BEGIN();
      79              : 
      80            0 :     if ( search_string != NULL )
      81              :     {
      82              :         /* store parameters internally */
      83            0 :         utf8stream_writemem_reset( &((*this_).search_string_writer) );
      84            0 :         utf8stream_writer_t *write = utf8stream_writemem_get_writer( &((*this_).search_string_writer) );
      85            0 :         u8_error_t u_err = utf8stream_writer_write_str( write, search_string );
      86            0 :         if ( u_err != U8_ERROR_NONE )
      87              :         {
      88            0 :             U8_TRACE_INFO( "search string too long, was truncated." );
      89              :         }
      90              : 
      91            0 :         gui_search_runner_rerun( this_, page );
      92              :     }
      93              :     else
      94              :     {
      95            0 :         assert(false);
      96              :     }
      97              : 
      98            0 :     U8_TRACE_END();
      99            0 : }
     100              : 
     101            0 : void gui_search_runner_rerun ( gui_search_runner_t *this_, pos_scroll_page_t page )
     102              : {
     103            0 :     U8_TRACE_BEGIN();
     104              : 
     105              :     /* store parameters internally */
     106            0 :     (*this_).page_request = page;
     107            0 :     pos_scroll_page_trace( &page );
     108            0 :     const char *const search_string = utf8stream_writemem_get_string( &((*this_).search_string_writer) );
     109            0 :     uint_fast32_t skip_results
     110            0 :         = ( pos_scroll_page_get_backwards( &page ) )
     111            0 :         ? u8_i32_max2( 0, ((signed)( pos_scroll_page_get_anchor_index( &page ) - GUI_SEARCH_RUNNER_MAX_RESULTS + 1 )) )
     112            0 :         : pos_scroll_page_get_anchor_index( &page );
     113            0 :     U8_TRACE_INFO_INT( "skipping", skip_results );
     114              : 
     115              :     /* reset previous errors/warnings/infos */
     116            0 :     gui_simple_message_to_user_hide( (*this_).message_to_user );
     117            0 :     u8_error_t d_err = U8_ERROR_NONE;  /* a data read or data store error */
     118              : 
     119              :     /* prepare search result */
     120            0 :     (*this_).result_buffer_start = 0;
     121            0 :     data_search_result_list_clear( &((*this_).result_list) );
     122            0 :     (*this_).result_buffer_more_after = false;
     123              : 
     124              :     /* check if an id is being searched */
     125              :     data_id_t search_id;
     126            0 :     data_id_init_by_string ( &search_id, search_string );
     127            0 :     data_id_trace ( &search_id );
     128            0 :     const data_row_t search_row = data_id_get_row(&search_id);
     129              : 
     130            0 :     if ( data_id_is_valid( &search_id ))
     131              :     {
     132            0 :         switch ( data_id_get_table(&search_id) )
     133              :         {
     134            0 :             case DATA_TABLE_CLASSIFIER:
     135              :             {
     136            0 :                 d_err = data_database_reader_get_classifier_by_id( (*this_).db_reader,
     137              :                                                                    search_row,
     138              :                                                                    &((*this_).temp_classifier)
     139              :                                                                  );
     140            0 :                 if ( d_err == U8_ERROR_NONE )
     141              :                 {
     142              :                     data_search_result_t half_initialized;
     143            0 :                     data_search_result_init_classifier( &half_initialized,
     144              :                                                         search_row,
     145            0 :                                                         data_classifier_get_main_type( &((*this_).temp_classifier) ),
     146            0 :                                                         data_classifier_get_name_const( &((*this_).temp_classifier) ),
     147              :                                                         DATA_ROW_VOID /* diagram_id */
     148              :                                                       );
     149            0 :                     d_err |= gui_search_runner_private_add_diagrams_of_object( this_,
     150              :                                                                                &half_initialized,
     151              :                                                                                &skip_results
     152              :                                                                              );
     153              : 
     154            0 :                     data_classifier_destroy( &((*this_).temp_classifier) );
     155            0 :                     data_search_result_destroy( &half_initialized );
     156              :                 }
     157              :                 else
     158              :                 {
     159            0 :                     U8_TRACE_INFO( "classifier does not exist or database not open." );
     160              :                 }
     161              :             }
     162            0 :             break;
     163              : 
     164            0 :             case DATA_TABLE_FEATURE:
     165              :             {
     166            0 :                 d_err = data_database_reader_get_feature_by_id( (*this_).db_reader,
     167              :                                                                 search_row,
     168              :                                                                 &((*this_).temp_feature)
     169              :                                                               );
     170            0 :                 if ( d_err == U8_ERROR_NONE )
     171              :                 {
     172            0 :                     data_row_t classifier_id = data_feature_get_classifier_row( &((*this_).temp_feature) );
     173              :                     data_search_result_t half_initialized;
     174            0 :                     data_search_result_init_feature( &half_initialized,
     175            0 :                                                      data_feature_get_row( &((*this_).temp_feature) ),
     176            0 :                                                      data_feature_get_main_type( &((*this_).temp_feature) ),
     177            0 :                                                      data_feature_get_key_const( &((*this_).temp_feature) ),
     178              :                                                      classifier_id,
     179              :                                                      DATA_ROW_VOID /* diagram_id */
     180              :                                                    );
     181            0 :                     d_err |= gui_search_runner_private_add_diagrams_of_object( this_,
     182              :                                                                                &half_initialized,
     183              :                                                                                &skip_results
     184              :                                                                              );
     185              : 
     186            0 :                     data_feature_destroy( &((*this_).temp_feature) );
     187            0 :                     data_search_result_destroy( &half_initialized );
     188              :                 }
     189              :                 else
     190              :                 {
     191            0 :                     U8_TRACE_INFO( "feature does not exist or database not open." );
     192              :                 }
     193              :             }
     194            0 :             break;
     195              : 
     196            0 :             case DATA_TABLE_RELATIONSHIP:
     197              :             {
     198            0 :                 d_err = data_database_reader_get_relationship_by_id( (*this_).db_reader,
     199              :                                                                      search_row,
     200              :                                                                      &((*this_).temp_relationship)
     201              :                                                                    );
     202            0 :                 if ( d_err == U8_ERROR_NONE )
     203              :                 {
     204            0 :                     data_row_t classifier_id = data_relationship_get_from_classifier_row( &((*this_).temp_relationship) );
     205              :                     data_search_result_t half_initialized;
     206            0 :                     data_search_result_init_relationship( &half_initialized,
     207            0 :                                                           data_relationship_get_row( &((*this_).temp_relationship) ),
     208            0 :                                                           data_relationship_get_main_type( &((*this_).temp_relationship) ),
     209            0 :                                                           data_relationship_get_name_const( &((*this_).temp_relationship) ),
     210              :                                                           classifier_id,
     211            0 :                                                           data_relationship_get_to_classifier_row( &((*this_).temp_relationship) ),
     212              :                                                           DATA_ROW_VOID /* diagram_id */
     213              :                                                         );
     214            0 :                     d_err |= gui_search_runner_private_add_diagrams_of_object( this_,
     215              :                                                                                &half_initialized,
     216              :                                                                                &skip_results
     217              :                                                                              );
     218              : 
     219            0 :                     data_relationship_destroy( &((*this_).temp_relationship) );
     220            0 :                     data_search_result_destroy( &half_initialized );
     221              :                 }
     222              :                 else
     223              :                 {
     224            0 :                     U8_TRACE_INFO( "relationship does not exist or database not open." );
     225              :                 }
     226              :             }
     227            0 :             break;
     228              : 
     229            0 :             case DATA_TABLE_DIAGRAMELEMENT:
     230              :             {
     231            0 :                 d_err = data_database_reader_get_diagramelement_by_id( (*this_).db_reader,
     232              :                                                                        search_row,
     233              :                                                                        &((*this_).temp_diagramelement)
     234              :                                                                      );
     235            0 :                 if ( d_err == U8_ERROR_NONE )
     236              :                 {
     237            0 :                     if ( skip_results == 0 )
     238              :                     {
     239              :                         data_search_result_t half_initialized;
     240            0 :                         data_search_result_init_classifier( &half_initialized,
     241            0 :                                                             data_diagramelement_get_classifier_row(&((*this_).temp_diagramelement)),
     242              :                                                             0 /* match_type is unknown */,
     243              :                                                             "" /* match_name */,
     244            0 :                                                             data_diagramelement_get_diagram_row(&((*this_).temp_diagramelement))
     245              :                                                           );
     246            0 :                         const u8_error_t err = data_search_result_list_add( &((*this_).result_list), &half_initialized );
     247            0 :                         if ( err != U8_ERROR_NONE )
     248              :                         {
     249            0 :                             d_err |= U8_ERROR_ARRAY_BUFFER_EXCEEDED;
     250            0 :                             U8_LOG_ANOMALY( "U8_ERROR_ARRAY_BUFFER_EXCEEDED at inserting search result to list" );
     251            0 :                             (*this_).result_buffer_more_after = true;  /* there are more results that cannot be stored in &((*this_).result_list) */
     252              :                         }
     253            0 :                         data_search_result_destroy( &half_initialized );
     254              :                     }
     255              :                     else
     256              :                     {
     257              :                         /* to advance to the requested search result page, skip this entry */
     258            0 :                         skip_results --;
     259            0 :                         (*this_).result_buffer_start ++;
     260              :                     }
     261              : 
     262            0 :                     data_diagramelement_destroy( &((*this_).temp_diagramelement) );
     263              :                 }
     264              :                 else
     265              :                 {
     266            0 :                     U8_TRACE_INFO( "diagramelement does not exist or database not open." );
     267              :                 }
     268              :             }
     269            0 :             break;
     270              : 
     271            0 :             case DATA_TABLE_DIAGRAM:
     272              :             {
     273            0 :                 d_err = data_database_reader_get_diagram_by_id ( (*this_).db_reader, search_row, &((*this_).temp_diagram) );
     274            0 :                 if ( d_err == U8_ERROR_NONE )
     275              :                 {
     276            0 :                     if ( skip_results == 0 )
     277              :                     {
     278              :                         data_search_result_t half_initialized;
     279            0 :                         data_search_result_init_diagram( &half_initialized,
     280              :                                                          search_row,
     281            0 :                                                          data_diagram_get_diagram_type( &((*this_).temp_diagram) ),
     282            0 :                                                          data_diagram_get_name_const( &((*this_).temp_diagram) )
     283              :                                                        );
     284            0 :                         const u8_error_t err = data_search_result_list_add( &((*this_).result_list), &half_initialized );
     285            0 :                         if ( err != U8_ERROR_NONE )
     286              :                         {
     287            0 :                             d_err |= U8_ERROR_ARRAY_BUFFER_EXCEEDED;
     288            0 :                             U8_LOG_ANOMALY( "U8_ERROR_ARRAY_BUFFER_EXCEEDED at inserting search result to list" );
     289            0 :                             (*this_).result_buffer_more_after = true;  /* there are more results that cannot be stored in &((*this_).result_list) */
     290              :                         }
     291            0 :                         data_search_result_destroy( &half_initialized );
     292              :                     }
     293              :                     else
     294              :                     {
     295              :                         /* to advance to the requested search result page, skip this entry */
     296            0 :                         skip_results --;
     297            0 :                         (*this_).result_buffer_start ++;
     298              :                     }
     299              : 
     300            0 :                     data_diagram_destroy( &((*this_).temp_diagram) );
     301              :                 }
     302              :                 else
     303              :                 {
     304            0 :                     U8_TRACE_INFO( "diagram does not exist or database not open." );
     305              :                 }
     306              :             }
     307            0 :             break;
     308              : 
     309            0 :             default:
     310              :             {
     311            0 :                 assert(false);  /* data_id_is_valid should have been false already */
     312              :             }
     313              :             break;
     314              :         }
     315              :     }
     316              :     else
     317              :     {
     318            0 :         U8_LOG_EVENT_STR( "User search input is not an id", search_string );
     319              :     }
     320              : 
     321              :     /* free text search */
     322            0 :     if ( d_err == U8_ERROR_NONE )
     323              :     {
     324              :         data_search_result_iterator_t data_search_result_iterator;
     325            0 :         data_search_result_iterator_init_empty( &data_search_result_iterator );
     326            0 :         d_err = data_database_text_search_get_objects_by_text_fragment( &((*this_).db_searcher),
     327              :                                                                         search_string,
     328              :                                                                         &data_search_result_iterator
     329              :                                                                       );
     330            0 :         while (( data_search_result_iterator_has_next( &data_search_result_iterator ) )&&( d_err == U8_ERROR_NONE ))
     331              :         {
     332              :             data_search_result_t current_search_result;
     333            0 :             d_err |= data_search_result_iterator_next( &data_search_result_iterator,
     334              :                                                        &current_search_result
     335              :                                                      );
     336            0 :             if ( skip_results == 0 )
     337              :             {
     338            0 :                 const u8_error_t err = data_search_result_list_add( &((*this_).result_list), &current_search_result );
     339            0 :                 if ( err != U8_ERROR_NONE )
     340              :                 {
     341            0 :                     d_err |= U8_ERROR_ARRAY_BUFFER_EXCEEDED;
     342            0 :                     U8_LOG_ANOMALY( "U8_ERROR_ARRAY_BUFFER_EXCEEDED at inserting search result to list" );
     343            0 :                     (*this_).result_buffer_more_after = true;  /* there are more results that cannot be stored in &((*this_).result_list) */
     344              :                 }
     345              :             }
     346              :             else
     347              :             {
     348              :                 /* to advance to the requested search result page, skip this entry */
     349            0 :                 skip_results --;
     350            0 :                 (*this_).result_buffer_start ++;
     351              :             }
     352              :         }
     353            0 :         d_err |= data_search_result_iterator_destroy( &data_search_result_iterator );
     354              :     }
     355              : 
     356            0 :     if ( d_err == U8_ERROR_ARRAY_BUFFER_EXCEEDED )
     357              :     {
     358              :         /* it is rather expected than a real error that the result list gets full */
     359            0 :         U8_TRACE_INFO( "U8_ERROR_ARRAY_BUFFER_EXCEEDED at inserting search result to list" );
     360              :     }
     361            0 :     else if ( U8_ERROR_NONE != d_err )
     362              :     {
     363            0 :         U8_LOG_ERROR_HEX( "data_database_text_search_t could not search.", d_err );
     364              :     }
     365              : 
     366              :     /* present the result */
     367            0 :     observer_notify( &((*this_).result_consumer), this_ );
     368              : 
     369              :     /* clear the result (the notification above is synchronous, the search results are already processed.) */
     370            0 :     data_search_result_list_clear( &((*this_).result_list) );
     371              : 
     372            0 :     U8_TRACE_END();
     373            0 : }
     374              : 
     375            0 : u8_error_t gui_search_runner_private_add_diagrams_of_object( gui_search_runner_t *this_,
     376              :                                                              data_search_result_t *result_template,
     377              :                                                              uint_fast32_t *io_skip_results
     378              :                                                            )
     379              : {
     380            0 :     U8_TRACE_BEGIN();
     381            0 :     assert( result_template != NULL );
     382            0 :     u8_error_t d_err = U8_ERROR_NONE;  /* a data read or data store error */
     383              : 
     384              :     /* initialize an iterator to fetch all diagrams where result_template occurs: */
     385              :     data_diagram_iterator_t diagram_iterator;
     386            0 :     data_diagram_iterator_init_empty( &diagram_iterator );
     387            0 :     const data_table_t object_type = data_id_get_table( data_search_result_get_match_id_const( result_template ));
     388            0 :     switch ( object_type )
     389              :     {
     390            0 :         case DATA_TABLE_CLASSIFIER:
     391              :         {
     392              :             const data_row_t classifier_row
     393            0 :                 = data_id_get_row( data_search_result_get_match_id_const( result_template ));
     394            0 :             d_err |= data_database_reader_get_diagrams_by_classifier_id( (*this_).db_reader,
     395              :                                                                          classifier_row,
     396              :                                                                          &diagram_iterator
     397              :                                                                        );
     398              :         }
     399            0 :         break;
     400              : 
     401            0 :         case DATA_TABLE_FEATURE:
     402              :         {
     403              :             const data_row_t classifier_row
     404            0 :                 = data_id_get_row( data_search_result_get_src_classifier_id_const( result_template ));
     405            0 :             d_err |= data_database_reader_get_diagrams_by_classifier_id( (*this_).db_reader,
     406              :                                                                          classifier_row,
     407              :                                                                          &diagram_iterator
     408              :                                                                        );
     409              :         }
     410            0 :         break;
     411              : 
     412            0 :         case DATA_TABLE_RELATIONSHIP:
     413              :         {
     414              :             const data_row_t relationship_row
     415            0 :                 = data_id_get_row( data_search_result_get_match_id_const( result_template ));
     416            0 :             d_err |= data_database_reader_get_diagrams_by_relationship_id( (*this_).db_reader,
     417              :                                                                            relationship_row,
     418              :                                                                            &diagram_iterator
     419              :                                                                          );
     420              :         }
     421            0 :         break;
     422              : 
     423            0 :         default:
     424              :         {
     425            0 :             U8_LOG_ERROR_INT( "gui_search_runner_private_add_diagrams_of_object called with search result of wrong type:",
     426              :                              object_type
     427              :                            );
     428            0 :             assert(false);
     429              :         }
     430              :         break;
     431              :     }
     432              : 
     433            0 :     while (( data_diagram_iterator_has_next( &diagram_iterator ) )&&( d_err == U8_ERROR_NONE ))
     434              :     {
     435              :         /* fetch diagram from iterator */
     436            0 :         d_err |= data_diagram_iterator_next( &diagram_iterator, &((*this_).temp_diagram) );
     437            0 :         const data_row_t diagram_row = data_diagram_get_row( &((*this_).temp_diagram) );
     438              : 
     439            0 :         if ( (*io_skip_results) == 0 )
     440              :         {
     441              :             /* complete the half initialized search result template */
     442            0 :             data_id_reinit( data_search_result_get_diagram_id_ptr( result_template ), DATA_TABLE_DIAGRAM, diagram_row );
     443              : 
     444            0 :             const u8_error_t err = data_search_result_list_add( &((*this_).result_list), result_template );
     445            0 :             if ( err != U8_ERROR_NONE )
     446              :             {
     447            0 :                 d_err |= U8_ERROR_ARRAY_BUFFER_EXCEEDED;
     448            0 :                 U8_LOG_ANOMALY( "U8_ERROR_ARRAY_BUFFER_EXCEEDED at inserting search result to list" );
     449            0 :                 (*this_).result_buffer_more_after = true;  /* there are more results that cannot be stored in &((*this_).result_list) */
     450              :             }
     451              :         }
     452              :         else
     453              :         {
     454              :             /* to advance to the requested search result page, skip this entry */
     455            0 :             *io_skip_results = (*io_skip_results) - 1;
     456            0 :             (*this_).result_buffer_start ++;
     457              :         }
     458              : 
     459            0 :         data_diagram_destroy( &((*this_).temp_diagram) );
     460              :     }
     461              : 
     462            0 :     d_err |= data_diagram_iterator_destroy( &diagram_iterator );
     463              : 
     464            0 :     U8_TRACE_END_ERR( d_err );
     465            0 :     return d_err;
     466              : }
     467              : 
     468              : 
     469              : /*
     470              : Copyright 2020-2026 Andreas Warnke
     471              : 
     472              : Licensed under the Apache License, Version 2.0 (the "License");
     473              : you may not use this file except in compliance with the License.
     474              : You may obtain a copy of the License at
     475              : 
     476              :     http://www.apache.org/licenses/LICENSE-2.0
     477              : 
     478              : Unless required by applicable law or agreed to in writing, software
     479              : distributed under the License is distributed on an "AS IS" BASIS,
     480              : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     481              : See the License for the specific language governing permissions and
     482              : limitations under the License.
     483              : */
        

Generated by: LCOV version 2.0-1