@@ -585,6 +585,8 @@ pub enum ParseErrorKind {
585585 UnexpectedEOF ,
586586 #[ error( "invalid sort mode: {0:?}" ) ]
587587 InvalidSortMode ( String ) ,
588+ #[ error( "invalid column: {0:?}" ) ]
589+ InvalidColumn ( String ) ,
588590 #[ error( "invalid line: {0:?}" ) ]
589591 InvalidLine ( String ) ,
590592 #[ error( "invalid type character: {0:?} in type string" ) ]
@@ -747,8 +749,8 @@ fn parse_inner<T: ColumnType>(loc: &Location, script: &str) -> Result<Vec<Record
747749 . map_err ( |e| e. at ( loc. clone ( ) ) ) ?;
748750 QueryExpect :: Error ( error)
749751 }
750- [ type_str , res @ ..] => {
751- let cols = parse_cols ( & loc , type_str ) ?;
752+ [ col_str , res @ ..] => {
753+ let cols = parse_cols ( col_str , & loc ) ?;
752754 let sort_mode = res
753755 . first ( )
754756 . map ( |& s| SortMode :: try_from_str ( s) )
@@ -840,43 +842,36 @@ fn parse_inner<T: ColumnType>(loc: &Location, script: &str) -> Result<Vec<Record
840842 Ok ( records)
841843}
842844
843- fn parse_cols < T : ColumnType > (
844- loc : & Location ,
845- type_str : & & str ,
846- ) -> Result < Vec < Column < T > > , ParseError > {
847- // Check if contains ':' or ',' to determine format
848- if type_str. contains ( ':' ) {
849- // Parse "c1:I,name:I" format
850- type_str
845+ fn parse_cols < T : ColumnType > ( col_str : & & str , loc : & Location ) -> Result < Vec < Column < T > > , ParseError > {
846+ fn parse_type_char < T : ColumnType > (
847+ part : & str ,
848+ name : String ,
849+ loc : & Location ,
850+ ) -> Result < Column < T > , ParseError > {
851+ let type_char = part
852+ . trim ( )
853+ . chars ( )
854+ . next ( )
855+ . ok_or_else ( || ParseErrorKind :: InvalidSortMode ( part. into ( ) ) . at ( loc. clone ( ) ) ) ?;
856+
857+ T :: from_char ( type_char)
858+ . map ( |t| Column { name, r#type : t } )
859+ . ok_or_else ( || ParseErrorKind :: InvalidType ( type_char) . at ( loc. clone ( ) ) )
860+ }
861+ if col_str. contains ( ':' ) {
862+ col_str
851863 . split ( ',' )
852- . map ( |part| {
853- let ( name, type_char) = part
854- . split_once ( ':' )
855- . ok_or_else ( || ParseErrorKind :: InvalidSortMode ( part. into ( ) ) . at ( loc. clone ( ) ) ) ?;
856-
857- let type_char =
858- type_char. trim ( ) . chars ( ) . next ( ) . ok_or_else ( || {
859- ParseErrorKind :: InvalidSortMode ( part. into ( ) ) . at ( loc. clone ( ) )
860- } ) ?;
861-
862- T :: from_char ( type_char)
863- . map ( |t| Column {
864- name : name. trim ( ) . to_string ( ) ,
865- r#type : t,
866- } )
867- . ok_or_else ( || ParseErrorKind :: InvalidType ( type_char) . at ( loc. clone ( ) ) )
864+ . map ( |part| match part. split_once ( ':' ) {
865+ Some ( ( name, type_str) ) => parse_type_char ( type_str, name. trim ( ) . to_string ( ) , loc) ,
866+ None => parse_type_char ( part, "?" . into ( ) , loc) ,
868867 } )
869868 . try_collect ( )
870869 } else {
871- // Original "III" format
872- type_str
870+ col_str
873871 . chars ( )
874872 . map ( |ch| {
875873 T :: from_char ( ch)
876- . map ( |t| Column {
877- name : "?" . into ( ) ,
878- r#type : t,
879- } )
874+ . map ( |t| Column :: anon ( t) )
880875 . ok_or_else ( || ParseErrorKind :: InvalidType ( ch) . at ( loc. clone ( ) ) )
881876 } )
882877 . try_collect ( )
@@ -992,6 +987,20 @@ mod tests {
992987 use super :: * ;
993988 use crate :: DefaultColumnType ;
994989
990+ #[ test]
991+ fn test_mixed_col_name_and_types ( ) {
992+ let script = r#"
993+ query NAME:I,B
994+ select * from t
995+ ----
996+ 1 true
997+
998+ "# ;
999+
1000+ let result = parse :: < CustomColumnType > ( script) ;
1001+ assert ! ( result. is_ok( ) )
1002+ }
1003+
9951004 #[ test]
9961005 fn test_trailing_comment ( ) {
9971006 let script = "\
0 commit comments