@@ -132,8 +132,24 @@ const compiler = Statement.makeCompiler({
132132 onCustom : ( ) => [ "" , [ ] ] ,
133133} )
134134
135+ // ClickHouse reads a scalar HTTP query parameter in the escaped (TabSeparated) format: a raw
136+ // newline fails to parse, and a backslash starts an escape sequence. An array parameter is
137+ // read as a literal instead, so only its quoted strings are escaped.
138+ const escapes : Record < string , string > = { "\\" : "\\\\" , "\0" : "\\0" , "\b" : "\\b" , "\f" : "\\f" , "\n" : "\\n" , "\r" : "\\r" , "\t" : "\\t" }
139+
140+ const dateValue = ( value : Date ) : string => value . toISOString ( ) . replace ( "T" , " " ) . replace ( "Z" , "" )
141+
142+ /** An array as a ClickHouse literal: strings single-quoted, since JSON's double quotes do not parse. */
143+ const arrayLiteral = ( value : ReadonlyArray < unknown > ) : string =>
144+ `[${ value . map ( ( item ) =>
145+ item === null || item === undefined ? "NULL"
146+ : Array . isArray ( item ) ? arrayLiteral ( item )
147+ : typeof item === "number" || typeof item === "bigint" || typeof item === "boolean" ? String ( item )
148+ : `'${ ( item instanceof Date ? dateValue ( item ) : String ( item ) ) . replace ( / [ \\ ' ] / g, ( c ) => `\\${ c } ` ) } '` ) . join ( "," ) } ]`
149+
135150const paramValue = ( value : unknown ) : string =>
136- value instanceof Date ? value . toISOString ( ) . replace ( "T" , " " ) . replace ( "Z" , "" ) : Array . isArray ( value ) ? JSON . stringify ( value ) : String ( value )
151+ Array . isArray ( value ) ? arrayLiteral ( value )
152+ : ( value instanceof Date ? dateValue ( value ) : String ( value ) ) . replace ( / [ \\ \0 \b \f \n \r \t ] / g, ( c ) => escapes [ c ] ! )
137153
138154export const make = (
139155 config : ClickhouseHttpClientConfig ,
0 commit comments