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

Generated by: LCOV version 1.16