Module: ClickHouse::HTTPClient::ParameterSerializer
- Defined in:
- lib/clickhouse/http_client/parameter_serializer.rb
Overview
Serializes Ruby placeholder values into the text format ClickHouse expects for query parameters, for binding values into SQL.
ClickHouse parses a top-level parameter value in its escaped text
format, where an unquoted \N denotes NULL, while values nested inside
Array/Map literals are parsed as SQL-like literals, where NULL is
spelled NULL and strings must be quoted.
Constant Summary collapse
- ESCAPED_TEXT_REPLACEMENTS =
ClickHouse parses each top-level parameter value with the type's escaped-text deserialization: backslash sequences (\t, \n, \N, \xNN, ...) are decoded, and a literal TAB or LF byte terminates the value, failing the query. Escaping the backslash and terminator bytes makes String values round-trip byte-for-byte. Values serialized from other Ruby types cannot contain these bytes.
{ "\\" => "\\\\", "\t" => "\\t", "\n" => "\\n", "\r" => "\\r", }.freeze
Class Method Summary collapse
-
.escape_top_level_string(str) ⇒ String
Escapes a top-level String value for ClickHouse's escaped text format.
-
.quote_and_escape_string(str) ⇒ String
Escapes each single-quote and backslash by prefixing it with a backslash, and wraps the result in single quotes.
-
.serialize(input) ⇒ String
Serializes a value for the top/outer/root layer, where e.g.
-
.serialize_nested(input) ⇒ String
Serializes a value nested within a container e.g.
Class Method Details
.escape_top_level_string(str) ⇒ String
Escapes a top-level String value for ClickHouse's escaped text format.
107 108 109 |
# File 'lib/clickhouse/http_client/parameter_serializer.rb', line 107 def self.escape_top_level_string(str) str.gsub(/[\\\t\n\r]/, ESCAPED_TEXT_REPLACEMENTS) end |
.quote_and_escape_string(str) ⇒ String
Escapes each single-quote and backslash by prefixing it with a backslash, and wraps the result in single quotes.
116 117 118 119 120 121 122 123 124 |
# File 'lib/clickhouse/http_client/parameter_serializer.rb', line 116 def self.quote_and_escape_string(str) # Note the double-escaping in the replacement string: # - Ruby strings consume one backslash # - ruby syntax "\\" => ruby string "\" # - Regexp replacement consumes one backslash # - ruby literal syntax \\\\ => ruby string \\ => regexp replacement \ # - ruby literal syntax \\0 => ruby string \0 => regexp replacement match #0 "'#{str.gsub(/['\\]/, "\\\\\\0")}'" end |
.serialize(input) ⇒ String
Serializes a value for the top/outer/root layer, where e.g. strings don't need to be surrounded by quotes (whereas e.g. strings in an Array do need quotes).
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/clickhouse/http_client/parameter_serializer.rb', line 22 def self.serialize(input) case input when NilClass "\\N" when String escape_top_level_string(input) when Symbol escape_top_level_string(input.to_s) when Array elements = input.map { serialize_nested(_1) } "[#{elements.join(",")}]" when Hash elements = input.map { |k, v| serialize_nested(k) + ":" + serialize_nested(v) } "{#{elements.join(",")}}" when DateTime # DateTime is a Date subclass, so it must be matched first and # converted to a Time (preserving its offset) to render as UTC # wall-clock text like Time below, not as a date-only string. serialize(input.to_time) when Date input.to_s # Ruby and ClickHouse agree on YYYY-MM-DD when Time # ClickHouse interprets the rendered text in the placeholder's (or # server's) timezone, so only UTC wall-clock text is safe to send. # Sub-second precision is dropped; when precision matters, callers # pre-format the value as a String (as ClickHouse::SQL does for # DateTime64 placeholders). input.getutc.strftime("%Y-%m-%d %H:%M:%S") else input.to_s end end |
.serialize_nested(input) ⇒ String
Serializes a value nested within a container e.g. an Array or Hash/Map, where strings are surrounded by quotes and NULL is spelled out.
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/clickhouse/http_client/parameter_serializer.rb', line 70 def self.serialize_nested(input) case input when NilClass "NULL" when Symbol serialize_nested(input.to_s) when String quote_and_escape_string(input) when Date, Time quote_and_escape_string(serialize(input)) else serialize(input) end end |