@@ -2,27 +2,34 @@ use crate::prelude::*;
22
33use super :: schema:: { EnrichedValueType , FieldSchema } ;
44use serde:: { Deserialize , Serialize } ;
5- use serde_json:: Value ;
65use std:: fmt;
76use std:: ops:: Deref ;
87
9- // Define SpecFormatMode enum for type-safe formatting
8+ /// OutputMode enum for displaying spec info in different granularity
109#[ derive( Debug , Clone , Copy , PartialEq ) ]
11- pub enum SpecFormatMode {
10+ pub enum OutputMode {
1211 Concise ,
1312 Verbose ,
1413}
1514
16- impl SpecFormatMode {
17- pub fn from_str ( s : & str ) -> Result < Self , String > {
15+ impl OutputMode {
16+ pub fn from_str ( s : & str ) -> Self {
1817 match s. to_lowercase ( ) . as_str ( ) {
19- "concise" => Ok ( SpecFormatMode :: Concise ) ,
20- "verbose" => Ok ( SpecFormatMode :: Verbose ) ,
21- _ => Err ( format ! ( "Invalid format mode: {}" , s) ) ,
18+ "concise" => OutputMode :: Concise ,
19+ "verbose" => OutputMode :: Verbose ,
20+ _ => unreachable ! (
21+ "Invalid format mode: {}. Expected 'concise' or 'verbose'." ,
22+ s
23+ ) ,
2224 }
2325 }
2426}
2527
28+ /// Formatting spec per output mode
29+ pub trait SpecFormatter {
30+ fn format ( & self , mode : OutputMode ) -> String ;
31+ }
32+
2633#[ derive( Debug , Clone , Serialize , Deserialize ) ]
2734#[ serde( tag = "kind" ) ]
2835pub enum SpecString {
@@ -233,69 +240,31 @@ pub struct OpSpec {
233240 pub spec : serde_json:: Map < String , serde_json:: Value > ,
234241}
235242
236- impl OpSpec {
237- pub fn format_concise ( & self ) -> String {
238- let mut parts = vec ! [ ] ;
239- for ( key, value) in self . spec . iter ( ) {
240- match value {
241- Value :: String ( s) => parts. push ( format ! ( "{}={}" , key, s) ) ,
242- Value :: Array ( arr) => {
243- let items = arr
244- . iter ( )
245- . filter_map ( |v| v. as_str ( ) )
246- . collect :: < Vec < _ > > ( )
247- . join ( "," ) ;
248- if !items. is_empty ( ) {
249- parts. push ( format ! ( "{}={}" , key, items) ) ;
250- }
251- }
252- Value :: Object ( obj) => {
253- if let Some ( model) = obj. get ( "model" ) . and_then ( |v| v. as_str ( ) ) {
254- parts. push ( format ! ( "{}={}" , key, model) ) ;
255- }
256- }
257- _ => { }
258- }
259- }
260- if parts. is_empty ( ) {
261- self . kind . clone ( )
262- } else {
263- format ! ( "{}({})" , self . kind, parts. join( ", " ) )
264- }
265- }
266-
267- pub fn format_verbose ( & self ) -> String {
268- let spec_str = serde_json:: to_string_pretty ( & self . spec )
269- . map ( |s| {
270- let lines: Vec < & str > = s. lines ( ) . collect ( ) ;
271- if lines. len ( ) < s. lines ( ) . count ( ) {
272- lines
273- . into_iter ( )
274- . chain ( [ "..." ] )
275- . collect :: < Vec < _ > > ( )
276- . join ( "\n " )
277- } else {
278- lines. join ( "\n " )
279- }
280- } )
281- . unwrap_or ( "#serde_error" . to_string ( ) ) ;
282- format ! ( "{}({})" , self . kind, spec_str)
283- }
284-
285- pub fn format ( & self , mode : SpecFormatMode ) -> String {
243+ impl SpecFormatter for OpSpec {
244+ fn format ( & self , mode : OutputMode ) -> String {
286245 match mode {
287- SpecFormatMode :: Concise => self . format_concise ( ) ,
288- SpecFormatMode :: Verbose => self . format_verbose ( ) ,
246+ OutputMode :: Concise => self . kind . clone ( ) ,
247+ OutputMode :: Verbose => {
248+ let spec_str = serde_json:: to_string_pretty ( & self . spec )
249+ . map ( |s| {
250+ let lines: Vec < & str > = s. lines ( ) . collect ( ) ;
251+ if lines. len ( ) < s. lines ( ) . count ( ) {
252+ lines
253+ . into_iter ( )
254+ . chain ( [ "..." ] )
255+ . collect :: < Vec < _ > > ( )
256+ . join ( "\n " )
257+ } else {
258+ lines. join ( "\n " )
259+ }
260+ } )
261+ . unwrap_or ( "#serde_error" . to_string ( ) ) ;
262+ format ! ( "{}({})" , self . kind, spec_str)
263+ }
289264 }
290265 }
291266}
292267
293- impl fmt:: Display for OpSpec {
294- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
295- write ! ( f, "{}" , self . format_concise( ) )
296- }
297- }
298-
299268#[ derive( Debug , Clone , Serialize , Deserialize , Default ) ]
300269pub struct SourceRefreshOptions {
301270 pub refresh_interval : Option < std:: time:: Duration > ,
@@ -319,19 +288,16 @@ pub struct ImportOpSpec {
319288 pub refresh_options : SourceRefreshOptions ,
320289}
321290
322- impl ImportOpSpec {
323- pub fn format ( & self , mode : SpecFormatMode ) -> String {
324- let source = match mode {
325- SpecFormatMode :: Concise => self . source . format_concise ( ) ,
326- SpecFormatMode :: Verbose => self . source . format_verbose ( ) ,
327- } ;
291+ impl SpecFormatter for ImportOpSpec {
292+ fn format ( & self , mode : OutputMode ) -> String {
293+ let source = self . source . format ( mode) ;
328294 format ! ( "source={}, refresh={}" , source, self . refresh_options)
329295 }
330296}
331297
332298impl fmt:: Display for ImportOpSpec {
333299 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
334- write ! ( f, "{}" , self . format( SpecFormatMode :: Concise ) )
300+ write ! ( f, "{}" , self . format( OutputMode :: Concise ) )
335301 }
336302}
337303
@@ -341,31 +307,22 @@ pub struct TransformOpSpec {
341307 pub op : OpSpec ,
342308}
343309
344- impl TransformOpSpec {
345- pub fn format ( & self , mode : SpecFormatMode ) -> String {
310+ impl SpecFormatter for TransformOpSpec {
311+ fn format ( & self , mode : OutputMode ) -> String {
346312 let inputs = self
347313 . inputs
348314 . iter ( )
349315 . map ( ToString :: to_string)
350316 . collect :: < Vec < _ > > ( )
351317 . join ( "," ) ;
352- let op_str = match mode {
353- SpecFormatMode :: Concise => self . op . format_concise ( ) ,
354- SpecFormatMode :: Verbose => self . op . format_verbose ( ) ,
355- } ;
318+ let op_str = self . op . format ( mode) ;
356319 match mode {
357- SpecFormatMode :: Concise => format ! ( "op={}, inputs={}" , op_str, inputs) ,
358- SpecFormatMode :: Verbose => format ! ( "op={}, inputs=[{}]" , op_str, inputs) ,
320+ OutputMode :: Concise => format ! ( "op={}, inputs={}" , op_str, inputs) ,
321+ OutputMode :: Verbose => format ! ( "op={}, inputs=[{}]" , op_str, inputs) ,
359322 }
360323 }
361324}
362325
363- impl fmt:: Display for TransformOpSpec {
364- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
365- write ! ( f, "{}" , self . format( SpecFormatMode :: Concise ) )
366- }
367- }
368-
369326#[ derive( Debug , Clone , Serialize , Deserialize ) ]
370327pub struct ForEachOpSpec {
371328 /// Mapping that provides a table to apply reactive operations to.
@@ -377,21 +334,17 @@ impl ForEachOpSpec {
377334 pub fn get_label ( & self ) -> String {
378335 format ! ( "Loop over {}" , self . field_path)
379336 }
337+ }
380338
381- pub fn format ( & self , mode : SpecFormatMode ) -> String {
339+ impl SpecFormatter for ForEachOpSpec {
340+ fn format ( & self , mode : OutputMode ) -> String {
382341 match mode {
383- SpecFormatMode :: Concise => self . get_label ( ) ,
384- SpecFormatMode :: Verbose => format ! ( "field={}" , self . field_path) ,
342+ OutputMode :: Concise => self . get_label ( ) ,
343+ OutputMode :: Verbose => format ! ( "field={}" , self . field_path) ,
385344 }
386345 }
387346}
388347
389- impl fmt:: Display for ForEachOpSpec {
390- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
391- write ! ( f, "field={}" , self . field_path)
392- }
393- }
394-
395348#[ derive( Debug , Clone , Serialize , Deserialize ) ]
396349pub struct CollectOpSpec {
397350 /// Field values to be collected.
@@ -405,17 +358,17 @@ pub struct CollectOpSpec {
405358 pub auto_uuid_field : Option < FieldName > ,
406359}
407360
408- impl CollectOpSpec {
409- pub fn format ( & self , mode : SpecFormatMode ) -> String {
361+ impl SpecFormatter for CollectOpSpec {
362+ fn format ( & self , mode : OutputMode ) -> String {
410363 let uuid = self . auto_uuid_field . as_deref ( ) . unwrap_or ( "none" ) ;
411364 match mode {
412- SpecFormatMode :: Concise => {
365+ OutputMode :: Concise => {
413366 format ! (
414367 "collector={}, input={}, uuid={}" ,
415368 self . collector_name, self . input, uuid
416369 )
417370 }
418- SpecFormatMode :: Verbose => {
371+ OutputMode :: Verbose => {
419372 format ! (
420373 "scope={}, collector={}, input=[{}], uuid={}" ,
421374 self . scope_name, self . collector_name, self . input, uuid
@@ -425,12 +378,6 @@ impl CollectOpSpec {
425378 }
426379}
427380
428- impl fmt:: Display for CollectOpSpec {
429- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
430- write ! ( f, "{}" , self . format( SpecFormatMode :: Concise ) )
431- }
432- }
433-
434381#[ derive( Debug , Clone , Copy , Serialize , Deserialize , PartialEq , Eq ) ]
435382pub enum VectorSimilarityMetric {
436383 CosineSimilarity ,
@@ -493,29 +440,20 @@ pub struct ExportOpSpec {
493440 pub setup_by_user : bool ,
494441}
495442
496- impl ExportOpSpec {
497- pub fn format ( & self , mode : SpecFormatMode ) -> String {
498- let target_str = match mode {
499- SpecFormatMode :: Concise => self . target . format_concise ( ) ,
500- SpecFormatMode :: Verbose => self . target . format_verbose ( ) ,
501- } ;
443+ impl SpecFormatter for ExportOpSpec {
444+ fn format ( & self , mode : OutputMode ) -> String {
445+ let target_str = self . target . format ( mode) ;
502446 let base = format ! (
503447 "collector={}, target={}, {}" ,
504448 self . collector_name, target_str, self . index_options
505449 ) ;
506450 match mode {
507- SpecFormatMode :: Concise => base,
508- SpecFormatMode :: Verbose => format ! ( "{}, setup_by_user={}" , base, self . setup_by_user) ,
451+ OutputMode :: Concise => base,
452+ OutputMode :: Verbose => format ! ( "{}, setup_by_user={}" , base, self . setup_by_user) ,
509453 }
510454 }
511455}
512456
513- impl fmt:: Display for ExportOpSpec {
514- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
515- write ! ( f, "{}" , self . format( SpecFormatMode :: Concise ) )
516- }
517- }
518-
519457#[ derive( Debug , Clone , Serialize , Deserialize ) ]
520458#[ serde( tag = "action" ) ]
521459pub enum ReactiveOpSpec {
@@ -524,25 +462,19 @@ pub enum ReactiveOpSpec {
524462 Collect ( CollectOpSpec ) ,
525463}
526464
527- impl ReactiveOpSpec {
528- pub fn format ( & self , mode : SpecFormatMode ) -> String {
465+ impl SpecFormatter for ReactiveOpSpec {
466+ fn format ( & self , mode : OutputMode ) -> String {
529467 match self {
530468 ReactiveOpSpec :: Transform ( t) => format ! ( "Transform: {}" , t. format( mode) ) ,
531469 ReactiveOpSpec :: ForEach ( fe) => match mode {
532- SpecFormatMode :: Concise => format ! ( "{}" , fe. get_label( ) ) ,
533- SpecFormatMode :: Verbose => format ! ( "ForEach: {}" , fe. format( mode) ) ,
470+ OutputMode :: Concise => format ! ( "{}" , fe. get_label( ) ) ,
471+ OutputMode :: Verbose => format ! ( "ForEach: {}" , fe. format( mode) ) ,
534472 } ,
535473 ReactiveOpSpec :: Collect ( c) => format ! ( "Collect: {}" , c. format( mode) ) ,
536474 }
537475 }
538476}
539477
540- impl fmt:: Display for ReactiveOpSpec {
541- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
542- write ! ( f, "{}" , self . format( SpecFormatMode :: Concise ) )
543- }
544- }
545-
546478#[ derive( Debug , Clone , Serialize , Deserialize ) ]
547479pub struct ReactiveOpScope {
548480 pub name : ScopeName ,
0 commit comments