@@ -26,13 +26,14 @@ use quickwit_indexing::check_source_connectivity;
2626use quickwit_metastore:: {
2727 AddSourceRequestExt , CreateIndexResponseExt , IndexMetadata , IndexMetadataResponseExt ,
2828 ListIndexesMetadataResponseExt , ListSplitsQuery , ListSplitsRequestExt ,
29- MetastoreServiceStreamSplitsExt , SplitInfo , SplitMetadata , SplitState , UpdateSourceRequestExt ,
29+ MetastoreServiceStreamSplitsExt , SplitInfo , SplitMetadata , SplitState , UpdateIndexRequestExt ,
30+ UpdateSourceRequestExt ,
3031} ;
3132use quickwit_proto:: metastore:: {
3233 AddSourceRequest , CreateIndexRequest , DeleteIndexRequest , EntityKind , IndexMetadataRequest ,
3334 ListIndexesMetadataRequest , ListSplitsRequest , MarkSplitsForDeletionRequest , MetastoreError ,
34- MetastoreService , MetastoreServiceClient , ResetSourceCheckpointRequest , UpdateSourceRequest ,
35- serde_utils,
35+ MetastoreService , MetastoreServiceClient , ResetSourceCheckpointRequest , UpdateIndexRequest ,
36+ UpdateSourceRequest , serde_utils,
3637} ;
3738use quickwit_proto:: types:: { IndexUid , SplitId } ;
3839use quickwit_proto:: { ServiceError , ServiceErrorCode } ;
@@ -155,6 +156,41 @@ impl IndexService {
155156 Ok ( index_metadata)
156157 }
157158
159+ /// Returns the index metadata for the given index ID if it exists.
160+ pub async fn index_metadata_opt (
161+ & self ,
162+ index_metadata_request : IndexMetadataRequest ,
163+ ) -> Result < Option < IndexMetadata > , IndexServiceError > {
164+ let index_metadata_response = self . metastore . index_metadata ( index_metadata_request) . await ;
165+ match index_metadata_response {
166+ Ok ( index_metadata_response) => {
167+ let index_metadata = index_metadata_response. deserialize_index_metadata ( ) ?;
168+ Ok ( Some ( index_metadata) )
169+ }
170+ Err ( MetastoreError :: NotFound ( _) ) => Ok ( None ) ,
171+ Err ( error) => Err ( IndexServiceError :: Metastore ( error) ) ,
172+ }
173+ }
174+
175+ /// Updates an index with the given index config.
176+ pub async fn update_index (
177+ & self ,
178+ index_uid : IndexUid ,
179+ index_config : IndexConfig ,
180+ ) -> Result < IndexMetadata , IndexServiceError > {
181+ let update_index_request = UpdateIndexRequest :: try_from_updates (
182+ index_uid,
183+ & index_config. doc_mapping ,
184+ & index_config. indexing_settings ,
185+ & index_config. ingest_settings ,
186+ & index_config. search_settings ,
187+ & index_config. retention_policy_opt ,
188+ ) ?;
189+ let update_index_response = self . metastore . update_index ( update_index_request) . await ?;
190+ let index_metadata = update_index_response. deserialize_index_metadata ( ) ?;
191+ Ok ( index_metadata)
192+ }
193+
158194 /// Deletes the index specified with `index_id`.
159195 /// This is equivalent to running `rm -rf <index path>` for a local index or
160196 /// `aws s3 rm --recursive <index path>` for a remote Amazon S3 index.
@@ -553,7 +589,9 @@ pub async fn validate_storage_uri(
553589mod tests {
554590
555591 use quickwit_common:: uri:: Uri ;
556- use quickwit_config:: { CLI_SOURCE_ID , INGEST_API_SOURCE_ID , INGEST_V2_SOURCE_ID , IndexConfig } ;
592+ use quickwit_config:: {
593+ CLI_SOURCE_ID , INGEST_API_SOURCE_ID , INGEST_V2_SOURCE_ID , IndexConfig , RetentionPolicy ,
594+ } ;
557595 use quickwit_metastore:: {
558596 MetastoreServiceExt , SplitMetadata , StageSplitsRequestExt , metastore_for_test,
559597 } ;
@@ -609,6 +647,68 @@ mod tests {
609647 assert ! ( index_metadata_0. index_uid != index_metadata_1. index_uid) ;
610648 }
611649
650+ #[ tokio:: test]
651+ async fn test_index_metadata_opt ( ) {
652+ let metastore = metastore_for_test ( ) ;
653+ let storage_resolver = StorageResolver :: for_test ( ) ;
654+ let mut index_service = IndexService :: new ( metastore. clone ( ) , storage_resolver) ;
655+
656+ let index_id = "test-index" ;
657+ let index_metadata_request = IndexMetadataRequest :: for_index_id ( index_id. to_string ( ) ) ;
658+ let index_metadata = index_service
659+ . index_metadata_opt ( index_metadata_request)
660+ . await
661+ . unwrap ( ) ;
662+ assert ! ( index_metadata. is_none( ) ) ;
663+
664+ let index_uri = "ram://indexes/test-index" ;
665+ let index_config = IndexConfig :: for_test ( index_id, index_uri) ;
666+ let index_uid = index_service
667+ . create_index ( index_config. clone ( ) , false )
668+ . await
669+ . unwrap ( )
670+ . index_uid ;
671+ let index_metadata_request = IndexMetadataRequest :: for_index_uid ( index_uid. clone ( ) ) ;
672+ let index_metadata = index_service
673+ . index_metadata_opt ( index_metadata_request)
674+ . await
675+ . unwrap ( )
676+ . unwrap ( ) ;
677+ assert_eq ! ( index_metadata. index_uid, index_uid) ;
678+ }
679+
680+ #[ tokio:: test]
681+ async fn test_update_index ( ) {
682+ let metastore = metastore_for_test ( ) ;
683+ let storage_resolver = StorageResolver :: for_test ( ) ;
684+ let mut index_service = IndexService :: new ( metastore. clone ( ) , storage_resolver) ;
685+
686+ let index_id = "test-index" ;
687+ let index_uri = "ram://indexes/test-index" ;
688+ let mut index_config = IndexConfig :: for_test ( index_id, index_uri) ;
689+ let index_uid = index_service
690+ . create_index ( index_config. clone ( ) , false )
691+ . await
692+ . unwrap ( )
693+ . index_uid ;
694+
695+ let retention_policy = RetentionPolicy {
696+ retention_period : "42 hours" . to_string ( ) ,
697+ evaluation_schedule : "hourly" . to_string ( ) ,
698+ } ;
699+ index_config. retention_policy_opt = Some ( retention_policy. clone ( ) ) ;
700+
701+ let updated_index_metadata = index_service
702+ . update_index ( index_uid, index_config)
703+ . await
704+ . unwrap ( ) ;
705+ let updated_retention_policy = updated_index_metadata
706+ . index_config
707+ . retention_policy_opt
708+ . unwrap ( ) ;
709+ assert_eq ! ( updated_retention_policy, retention_policy) ;
710+ }
711+
612712 #[ tokio:: test]
613713 async fn test_delete_index ( ) {
614714 let mut metastore = metastore_for_test ( ) ;
0 commit comments