@@ -95,6 +95,7 @@ pub enum QueryExpect<T: ColumnType> {
9595 types : Vec < T > ,
9696 sort_mode : Option < SortMode > ,
9797 result_mode : Option < ResultMode > ,
98+ label : Option < String > ,
9899 results : Vec < String > ,
99100 } ,
100101 /// Query should fail with the given error message.
@@ -108,6 +109,7 @@ impl<T: ColumnType> QueryExpect<T> {
108109 types : Vec :: new ( ) ,
109110 sort_mode : None ,
110111 result_mode : None ,
112+ label : None ,
111113 results : Vec :: new ( ) ,
112114 }
113115 }
@@ -255,12 +257,18 @@ impl<T: ColumnType> std::fmt::Display for Record<T> {
255257 write ! ( f, "query " ) ?;
256258 match expected {
257259 QueryExpect :: Results {
258- types, sort_mode, ..
260+ types,
261+ sort_mode,
262+ label,
263+ ..
259264 } => {
260265 write ! ( f, "{}" , types. iter( ) . map( |c| c. to_char( ) ) . join( "" ) ) ?;
261266 if let Some ( sort_mode) = sort_mode {
262267 write ! ( f, " {}" , sort_mode. as_str( ) ) ?;
263268 }
269+ if let Some ( label) = label {
270+ write ! ( f, " {label}" ) ?;
271+ }
264272 }
265273 QueryExpect :: Error ( err) => err. fmt_inline ( f) ?,
266274 }
@@ -281,6 +289,8 @@ impl<T: ColumnType> std::fmt::Display for Record<T> {
281289 for result in results {
282290 write ! ( f, "\n {result}" ) ?;
283291 }
292+
293+ // query always ends with a blank line
284294 writeln ! ( f) ?
285295 }
286296 QueryExpect :: Error ( err) => err. fmt_multiline ( f) ?,
@@ -807,24 +817,38 @@ fn parse_inner<T: ColumnType>(loc: &Location, script: &str) -> Result<Vec<Record
807817 ( QueryExpect :: Error ( error) , & [ ] [ ..] )
808818 }
809819 [ type_str, res @ ..] => {
820+ // query <type-string> [<sort-mode>] [<label>] [retry <attempts> backoff <backoff>]
810821 let types = type_str
811822 . chars ( )
812823 . map ( |ch| {
813824 T :: from_char ( ch)
814825 . ok_or_else ( || ParseErrorKind :: InvalidType ( ch) . at ( loc. clone ( ) ) )
815826 } )
816827 . try_collect ( ) ?;
817- let sort_mode = res. first ( ) . and_then ( |& s| SortMode :: try_from_str ( s) . ok ( ) ) ; // Could be `retry`
828+ let sort_mode = res. first ( ) . and_then ( |& s| SortMode :: try_from_str ( s) . ok ( ) ) ; // Could be `retry` or label
829+
830+ // To support `retry`, we assume the label must *not* be "retry"
831+ let label_start = if sort_mode. is_some ( ) { 1 } else { 0 } ;
832+ let res = & res[ label_start..] ;
833+ let label = res. first ( ) . and_then ( |& s| {
834+ if s != "retry" {
835+ Some ( s. to_owned ( ) )
836+ } else {
837+ None // `retry` is not a valid label
838+ }
839+ } ) ;
818840
819- let retry_start = if sort_mode. is_some ( ) { 1 } else { 0 } ;
841+ let retry_start = if label. is_some ( ) { 1 } else { 0 } ;
842+ let res = & res[ retry_start..] ;
820843 (
821844 QueryExpect :: Results {
822845 types,
823846 sort_mode,
824847 result_mode : None ,
848+ label,
825849 results : Vec :: new ( ) ,
826850 } ,
827- & res[ retry_start.. ] ,
851+ res,
828852 )
829853 }
830854 [ ] => ( QueryExpect :: empty_results ( ) , & [ ] [ ..] ) ,
0 commit comments