From b70adc28cc4f43efcc29070c1613aa92f8fb36b7 Mon Sep 17 00:00:00 2001 From: delete44 Date: Fri, 31 Mar 2023 19:01:47 +0100 Subject: [PATCH 01/10] Added failing spec for incorrect SQL formatting --- spec/whoop_spec.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/spec/whoop_spec.rb b/spec/whoop_spec.rb index 61337b2..9019602 100644 --- a/spec/whoop_spec.rb +++ b/spec/whoop_spec.rb @@ -88,6 +88,24 @@ expect(logged_message).not_to include(context) end end + + context 'when parsing PostgreSQL jsonb column operators' do + it 'appropriately formats the SQL' do + io = setup_whoop + column_operator_examples = [ + "'[{\"a\":\"foo\"},{\"b\":\"bar\"},{\"c\":\"baz\"}]'::json -> 2", + ] + + column_operator_examples.each do |sql| + whoop(sql, format: :sql) + logged_message = io.string + + puts logged_message + + expect(logged_message).to include(sql) + end + end + end end private From 995dcfbc0677b324a8c165dbca7e69557fa9423d Mon Sep 17 00:00:00 2001 From: delete44 Date: Fri, 31 Mar 2023 19:06:59 +0100 Subject: [PATCH 02/10] Added exception to throw if format is unsupported --- lib/whoop.rb | 5 +++++ spec/whoop_spec.rb | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/lib/whoop.rb b/lib/whoop.rb index 086efc9..f32661a 100644 --- a/lib/whoop.rb +++ b/lib/whoop.rb @@ -12,6 +12,9 @@ # config.level = :debug # end +class FormatNotSupportedError < StandardError +end + module Whoop mattr_accessor :logger @@logger = ActiveSupport::Logger.new($stdout) @@ -53,6 +56,8 @@ def whoop( explain: false, context: nil ) + raise FormatNotSupportedError unless %i[plain json sql].include?(format) + logger_method = detect_logger_method color_method = detect_color_method(color) formatter_method = detect_formatter_method(format, colorize: color.present?, explain: explain) diff --git a/spec/whoop_spec.rb b/spec/whoop_spec.rb index 9019602..209affc 100644 --- a/spec/whoop_spec.rb +++ b/spec/whoop_spec.rb @@ -33,6 +33,16 @@ end end + context "when the format is invalid" do + it "throws a FormatNotSupportedError exception" do + io = setup_whoop + + expect do + whoop("Bad format", format: :invalid) + end.to raise_error(FormatNotSupportedError) + end + end + context "when the format is :json" do it "writes to the logger" do io = setup_whoop From e366a146ace96173536a4c4f71ebface1c9fa086 Mon Sep 17 00:00:00 2001 From: delete44 Date: Fri, 31 Mar 2023 21:29:23 +0100 Subject: [PATCH 03/10] Added clause to fix broken characters in formatter --- lib/whoop/formatters/sql_formatter.rb | 30 ++++++++++++++++++++++++++- spec/whoop_spec.rb | 15 +++++--------- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/lib/whoop/formatters/sql_formatter.rb b/lib/whoop/formatters/sql_formatter.rb index b5ccdaa..585b9dd 100644 --- a/lib/whoop/formatters/sql_formatter.rb +++ b/lib/whoop/formatters/sql_formatter.rb @@ -6,6 +6,8 @@ module Whoop module Formatters module SqlFormatter + TOKENS_TO_PRESERVE = ['::', '->>', '->' , '#>>', '#>'] + # Format the SQL query # @param [String] sql The SQL query # @param [Boolean] colorize - colorize the SQL query (default: false) @@ -39,8 +41,21 @@ def self.format(sql, colorize: false, explain: false) def self.generate_pretty_sql(sql) rule = AnbtSql::Rule.new rule.indent_string = " " + formatter = AnbtSql::Formatter.new(rule) - formatter.format(sql.dup) + formatted_string = formatter.format(sql.dup) + + # Anbt injects additional spaces into joined symbols. + # This removes them by generating the "broken" collection + # of symbols, and replacing them with the original. + TOKENS_TO_PRESERVE.each do |token| + token_with_whitespace = inject_whitespace_into(token) + next unless formatted_string.include?(token_with_whitespace) + + formatted_string.gsub!(token_with_whitespace, token) + end + + formatted_string end # Execute the `EXPLAIN` query @@ -58,6 +73,19 @@ def self.exec_explain(sql) pretty_explain.join("\n") end + + # Adds whitespace to tokens so they match the incorrect format + # @params [String] token The token to inject whitespace into, ie "->>" + # @return [String] The token with additional whitespace, ie "- > >" + def self.inject_whitespace_into(token) + # Inject whitespace to match the (broken) format + token_with_whitespace = token.chars.join(" ") + + # :: is a special case where it needs to strip surrounding whitespace too + return token_with_whitespace unless token == '::' + + " #{token_with_whitespace} " + end end end end diff --git a/spec/whoop_spec.rb b/spec/whoop_spec.rb index 209affc..8bde109 100644 --- a/spec/whoop_spec.rb +++ b/spec/whoop_spec.rb @@ -99,20 +99,15 @@ end end - context 'when parsing PostgreSQL jsonb column operators' do - it 'appropriately formats the SQL' do + context 'parsing PostgreSQL operators' do + it 'appropriately formats jsonb column operators' do io = setup_whoop - column_operator_examples = [ - "'[{\"a\":\"foo\"},{\"b\":\"bar\"},{\"c\":\"baz\"}]'::json -> 2", - ] - column_operator_examples.each do |sql| - whoop(sql, format: :sql) + ['->>', '->' , '#>>', '#>'].each do |token| + whoop(token, format: :sql) logged_message = io.string - puts logged_message - - expect(logged_message).to include(sql) + expect(logged_message.uncolorize).to include(token) end end end From 4b40829d275500874e62d1f976740c141779afb4 Mon Sep 17 00:00:00 2001 From: delete44 Date: Fri, 31 Mar 2023 21:47:21 +0100 Subject: [PATCH 04/10] Reusing constant --- lib/whoop.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/whoop.rb b/lib/whoop.rb index f32661a..68cec06 100644 --- a/lib/whoop.rb +++ b/lib/whoop.rb @@ -56,7 +56,7 @@ def whoop( explain: false, context: nil ) - raise FormatNotSupportedError unless %i[plain json sql].include?(format) + raise FormatNotSupportedError unless FORMATS.include?(format) logger_method = detect_logger_method color_method = detect_color_method(color) From a7e316caf155c9c7dc61199cb975880223e2897a Mon Sep 17 00:00:00 2001 From: delete44 Date: Sun, 2 Apr 2023 14:28:47 +0100 Subject: [PATCH 05/10] Using hash of patterns instead --- lib/whoop/formatters/sql_formatter.rb | 28 ++++++++++----------------- 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/lib/whoop/formatters/sql_formatter.rb b/lib/whoop/formatters/sql_formatter.rb index 585b9dd..4f74e7c 100644 --- a/lib/whoop/formatters/sql_formatter.rb +++ b/lib/whoop/formatters/sql_formatter.rb @@ -6,7 +6,13 @@ module Whoop module Formatters module SqlFormatter - TOKENS_TO_PRESERVE = ['::', '->>', '->' , '#>>', '#>'] + PATTERNS_TO_PRESERVE = { + '::': ' : : ', + '->>': '- > >', + '->': '- >', + '#>>': '# > >', + '#>': '# >' + } # Format the SQL query # @param [String] sql The SQL query @@ -48,11 +54,10 @@ def self.generate_pretty_sql(sql) # Anbt injects additional spaces into joined symbols. # This removes them by generating the "broken" collection # of symbols, and replacing them with the original. - TOKENS_TO_PRESERVE.each do |token| - token_with_whitespace = inject_whitespace_into(token) - next unless formatted_string.include?(token_with_whitespace) + PATTERNS_TO_PRESERVE.each do |token, pattern| + next unless formatted_string.include?(pattern) - formatted_string.gsub!(token_with_whitespace, token) + formatted_string.gsub!(pattern, token.to_s) end formatted_string @@ -73,19 +78,6 @@ def self.exec_explain(sql) pretty_explain.join("\n") end - - # Adds whitespace to tokens so they match the incorrect format - # @params [String] token The token to inject whitespace into, ie "->>" - # @return [String] The token with additional whitespace, ie "- > >" - def self.inject_whitespace_into(token) - # Inject whitespace to match the (broken) format - token_with_whitespace = token.chars.join(" ") - - # :: is a special case where it needs to strip surrounding whitespace too - return token_with_whitespace unless token == '::' - - " #{token_with_whitespace} " - end end end end From 04156863804d31cc0572115deb91df85501347a1 Mon Sep 17 00:00:00 2001 From: delete44 Date: Sun, 2 Apr 2023 14:30:43 +0100 Subject: [PATCH 06/10] Comment explaining hash --- lib/whoop/formatters/sql_formatter.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/whoop/formatters/sql_formatter.rb b/lib/whoop/formatters/sql_formatter.rb index 4f74e7c..e1f8206 100644 --- a/lib/whoop/formatters/sql_formatter.rb +++ b/lib/whoop/formatters/sql_formatter.rb @@ -6,6 +6,9 @@ module Whoop module Formatters module SqlFormatter + # Hash of patterns to preserve in the SQL. The key is the expected pattern, + # the value is the pattern after it has been "broken" by anbt formatting. + # Instances of the value are replaced by the key. PATTERNS_TO_PRESERVE = { '::': ' : : ', '->>': '- > >', From cc5f3cd19493f881c55002ce02e049f62e7ea4fa Mon Sep 17 00:00:00 2001 From: delete44 Date: Sun, 2 Apr 2023 20:47:01 +0100 Subject: [PATCH 07/10] SQL formatting PR feedback; using color: false to simplify test output --- lib/whoop/formatters/sql_formatter.rb | 17 +++++++++-------- spec/whoop_spec.rb | 11 +++++++++-- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/lib/whoop/formatters/sql_formatter.rb b/lib/whoop/formatters/sql_formatter.rb index e1f8206..59f67d6 100644 --- a/lib/whoop/formatters/sql_formatter.rb +++ b/lib/whoop/formatters/sql_formatter.rb @@ -9,12 +9,13 @@ module SqlFormatter # Hash of patterns to preserve in the SQL. The key is the expected pattern, # the value is the pattern after it has been "broken" by anbt formatting. # Instances of the value are replaced by the key. + # Patterns are jsonb column operators from https://www.postgresql.org/docs/15/functions-json.html PATTERNS_TO_PRESERVE = { - '::': ' : : ', - '->>': '- > >', - '->': '- >', - '#>>': '# > >', - '#>': '# >' + '::' => ' : : ', + '->>' => '- > >', + '->' => '- >', + '#>>' => '# > >', + '#>' => '# >' } # Format the SQL query @@ -57,10 +58,10 @@ def self.generate_pretty_sql(sql) # Anbt injects additional spaces into joined symbols. # This removes them by generating the "broken" collection # of symbols, and replacing them with the original. - PATTERNS_TO_PRESERVE.each do |token, pattern| - next unless formatted_string.include?(pattern) + PATTERNS_TO_PRESERVE.each do |correct_pattern, incorrect_pattern| + next unless formatted_string.include?(incorrect_pattern) - formatted_string.gsub!(pattern, token.to_s) + formatted_string.gsub!(incorrect_pattern, correct_pattern) end formatted_string diff --git a/spec/whoop_spec.rb b/spec/whoop_spec.rb index 8bde109..f4a2df8 100644 --- a/spec/whoop_spec.rb +++ b/spec/whoop_spec.rb @@ -103,8 +103,15 @@ it 'appropriately formats jsonb column operators' do io = setup_whoop - ['->>', '->' , '#>>', '#>'].each do |token| - whoop(token, format: :sql) + [ + %Q['{"a": {"b":"foo"}}'::json -> 'a'], + %Q['[1,2,3]'::json ->> 2], + %Q['{"a":1,"b":2}'::json ->> 'b'], + %Q['{"a": {"b":{"c": "foo"}}}'::json #> '{a,b}'], + %Q['{"a":[1,2,3],"b":[4,5,6]}'::json #>> '{a,2}'] + # ... all examples from https://www.postgresql.org/docs/9.5/functions-json.html + ].each do |token| + whoop(token, format: :sql, color: false) logged_message = io.string expect(logged_message.uncolorize).to include(token) From c49eb7f400513932d6b199de609da127b7940856 Mon Sep 17 00:00:00 2001 From: delete44 Date: Sun, 2 Apr 2023 21:10:27 +0100 Subject: [PATCH 08/10] Removed error for unsupported format, added warning message --- lib/whoop.rb | 14 +++++++++----- spec/whoop_spec.rb | 13 +++++++++---- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/lib/whoop.rb b/lib/whoop.rb index 68cec06..accfbbd 100644 --- a/lib/whoop.rb +++ b/lib/whoop.rb @@ -12,9 +12,6 @@ # config.level = :debug # end -class FormatNotSupportedError < StandardError -end - module Whoop mattr_accessor :logger @@logger = ActiveSupport::Logger.new($stdout) @@ -56,8 +53,6 @@ def whoop( explain: false, context: nil ) - raise FormatNotSupportedError unless FORMATS.include?(format) - logger_method = detect_logger_method color_method = detect_color_method(color) formatter_method = detect_formatter_method(format, colorize: color.present?, explain: explain) @@ -92,6 +87,7 @@ def whoop( logger_method.call "" logger_method.call formatter_method.call(result) logger_method.call "" + display_invalid_format_message(format, color_method, logger_method) logger_method.call color_method.call "#{BOTTOM_LINE_CHAR}#{line}\n\n" end else @@ -103,6 +99,7 @@ def whoop( logger_method.call "" logger_method.call formatter_method.call(label) logger_method.call "" + display_invalid_format_message(format, color_method, logger_method) logger_method.call color_method.call "#{BOTTOM_LINE_CHAR}#{line}\n\n" end end @@ -155,6 +152,13 @@ def detect_formatter_method(format, colorize: false, explain: false) end end + def display_invalid_format_message(format, color_method, logger_method) + return if FORMATS.include?(format) + + invalid_format_line = [color_method.call(INDENT), "note:".colorize(:blue).underline, "Unsupported format used. Available formats: #{FORMATS.to_sentence}"].join(" ") + logger_method.call invalid_format_line + end + # Return the line with the label centered in it # @param [String] label # @param [Integer] count diff --git a/spec/whoop_spec.rb b/spec/whoop_spec.rb index f4a2df8..f9db55e 100644 --- a/spec/whoop_spec.rb +++ b/spec/whoop_spec.rb @@ -34,12 +34,15 @@ end context "when the format is invalid" do - it "throws a FormatNotSupportedError exception" do + it "adds a note listing available formats" do io = setup_whoop + whoop("Bad format", format: :invalid, color: false) + logged_message = io.string + + puts logged_message - expect do - whoop("Bad format", format: :invalid) - end.to raise_error(FormatNotSupportedError) + expect(logged_message).to include('Bad format') + expect(logged_message).to include('Unsupported format used. Available formats: plain, json, and sql') end end @@ -52,6 +55,7 @@ puts logged_message expect(logged_message).to include('"hello": "world"') + expect(logged_message).not_to include('Unsupported format used.') end end @@ -65,6 +69,7 @@ puts logged_message expect(logged_message).to include("SELECT") + expect(logged_message).not_to include('Unsupported format used.') end end From 54ac0ff7627dfd2282f275acef87f7d78092a37f Mon Sep 17 00:00:00 2001 From: delete44 Date: Wed, 5 Apr 2023 18:24:39 +0100 Subject: [PATCH 09/10] Additional operators added; switched to regexes for more flexibility when substituting strings --- lib/whoop/formatters/sql_formatter.rb | 27 +++++++++++++++++++++------ spec/whoop_spec.rb | 21 +++++++++++++++------ 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/lib/whoop/formatters/sql_formatter.rb b/lib/whoop/formatters/sql_formatter.rb index 59f67d6..30efa7e 100644 --- a/lib/whoop/formatters/sql_formatter.rb +++ b/lib/whoop/formatters/sql_formatter.rb @@ -11,11 +11,26 @@ module SqlFormatter # Instances of the value are replaced by the key. # Patterns are jsonb column operators from https://www.postgresql.org/docs/15/functions-json.html PATTERNS_TO_PRESERVE = { - '::' => ' : : ', - '->>' => '- > >', - '->' => '- >', - '#>>' => '# > >', - '#>' => '# >' + # jsonb operators without surrounding spaces + # IE, the first one replaces " : : " with "::" + '::' => /\s?: :\s?/, + '->>' => /\s?- > >\s?/, + '->' => /\s?- >\s?/, + '#>>' => /\s?# > >\s?/, + '#>' => /\s?# >\s?/, + + # jsonb operators with surrounding spaces + # IE, the first one replaces " @ > " with " @> " + ' @> ' => /\s?@ >\s?/, + ' <@ ' => /\s?< @\s?/, + ' ?| ' => /\s?\? \|\s?/, + ' ?& ' => /\s?\? &\s?/, + ' || ' => /\s?\| \|\s?/, + ' #- ' => /\s?# -\s?/, + + # Additional broken patterns + '[' => /\[\s?/, + ']' => /\s?\]/, } # Format the SQL query @@ -59,7 +74,7 @@ def self.generate_pretty_sql(sql) # This removes them by generating the "broken" collection # of symbols, and replacing them with the original. PATTERNS_TO_PRESERVE.each do |correct_pattern, incorrect_pattern| - next unless formatted_string.include?(incorrect_pattern) + next unless incorrect_pattern.match?(formatted_string) formatted_string.gsub!(incorrect_pattern, correct_pattern) end diff --git a/spec/whoop_spec.rb b/spec/whoop_spec.rb index f9db55e..05ccd81 100644 --- a/spec/whoop_spec.rb +++ b/spec/whoop_spec.rb @@ -108,13 +108,22 @@ it 'appropriately formats jsonb column operators' do io = setup_whoop + # Examples from https://www.postgresql.org/docs/9.5/functions-json.html [ - %Q['{"a": {"b":"foo"}}'::json -> 'a'], - %Q['[1,2,3]'::json ->> 2], - %Q['{"a":1,"b":2}'::json ->> 'b'], - %Q['{"a": {"b":{"c": "foo"}}}'::json #> '{a,b}'], - %Q['{"a":[1,2,3],"b":[4,5,6]}'::json #>> '{a,2}'] - # ... all examples from https://www.postgresql.org/docs/9.5/functions-json.html + %Q['{"a": {"b":"foo"}}'::json->'a'], + %Q['[1,2,3]'::json->>2], + %Q['{"a":1,"b":2}'::json->>'b'], + %Q['{"a": {"b":{"c": "foo"}}}'::json#>'{a,b}'], + %Q['{"a":[1,2,3],"b":[4,5,6]}'::json#>>'{a,2}'], + %Q['{"a":1, "b":2}'::jsonb @> '{"b":2}'::jsonb], + %Q['{"b":2}'::jsonb <@ '{"a":1, "b":2}'::jsonb], + %Q['{"a":1, "b":2}'::jsonb ? 'b'], + %Q['{"a":1, "b":2, "c":3}'::jsonb ?| array['b']], + %Q['["a", "b"]'::jsonb ?& array['a']], + %Q['["a", "b"]'::jsonb || '["c"]'::jsonb], + %Q['{"a": "b"}'::jsonb - 'a'], + %Q['["a", "b"]'::jsonb - 1], + %Q['["a", {"b":1}]'::jsonb #- '{1,b}'] ].each do |token| whoop(token, format: :sql, color: false) logged_message = io.string From 4eacfdd898d8c5ec12579b2c8647f5b7582b8c7f Mon Sep 17 00:00:00 2001 From: Eric Berry Date: Mon, 10 Apr 2023 14:52:36 +0000 Subject: [PATCH 10/10] Run bin/standardize --- lib/whoop/formatters/sql_formatter.rb | 26 ++++++++--------- sig/whoop.rbs | 8 ++++++ spec/whoop_spec.rb | 40 +++++++++++++-------------- 3 files changed, 41 insertions(+), 33 deletions(-) diff --git a/lib/whoop/formatters/sql_formatter.rb b/lib/whoop/formatters/sql_formatter.rb index 30efa7e..6ab774f 100644 --- a/lib/whoop/formatters/sql_formatter.rb +++ b/lib/whoop/formatters/sql_formatter.rb @@ -13,24 +13,24 @@ module SqlFormatter PATTERNS_TO_PRESERVE = { # jsonb operators without surrounding spaces # IE, the first one replaces " : : " with "::" - '::' => /\s?: :\s?/, - '->>' => /\s?- > >\s?/, - '->' => /\s?- >\s?/, - '#>>' => /\s?# > >\s?/, - '#>' => /\s?# >\s?/, + "::" => /\s?: :\s?/, + "->>" => /\s?- > >\s?/, + "->" => /\s?- >\s?/, + "#>>" => /\s?# > >\s?/, + "#>" => /\s?# >\s?/, # jsonb operators with surrounding spaces # IE, the first one replaces " @ > " with " @> " - ' @> ' => /\s?@ >\s?/, - ' <@ ' => /\s?< @\s?/, - ' ?| ' => /\s?\? \|\s?/, - ' ?& ' => /\s?\? &\s?/, - ' || ' => /\s?\| \|\s?/, - ' #- ' => /\s?# -\s?/, + " @> " => /\s?@ >\s?/, + " <@ " => /\s?< @\s?/, + " ?| " => /\s?\? \|\s?/, + " ?& " => /\s?\? &\s?/, + " || " => /\s?\| \|\s?/, + " #- " => /\s?# -\s?/, # Additional broken patterns - '[' => /\[\s?/, - ']' => /\s?\]/, + "[" => /\[\s?/, + "]" => /\s?\]/ } # Format the SQL query diff --git a/sig/whoop.rbs b/sig/whoop.rbs index 66337a4..886c98e 100644 --- a/sig/whoop.rbs +++ b/sig/whoop.rbs @@ -73,6 +73,12 @@ module Whoop # _@return_ — format method def detect_formatter_method: (Symbol format, ?colorize: untyped, ?explain: untyped) -> Method + # sord omit - no YARD type given for "format", using untyped + # sord omit - no YARD type given for "color_method", using untyped + # sord omit - no YARD type given for "logger_method", using untyped + # sord omit - no YARD return type given, using untyped + def display_invalid_format_message: (untyped format, untyped color_method, untyped logger_method) -> untyped + # Return the line with the label centered in it # # _@param_ `label` @@ -85,6 +91,8 @@ module Whoop module Formatters module SqlFormatter + PATTERNS_TO_PRESERVE: untyped + # Format the SQL query # # _@param_ `sql` — The SQL query diff --git a/spec/whoop_spec.rb b/spec/whoop_spec.rb index 05ccd81..ef2b11c 100644 --- a/spec/whoop_spec.rb +++ b/spec/whoop_spec.rb @@ -41,8 +41,8 @@ puts logged_message - expect(logged_message).to include('Bad format') - expect(logged_message).to include('Unsupported format used. Available formats: plain, json, and sql') + expect(logged_message).to include("Bad format") + expect(logged_message).to include("Unsupported format used. Available formats: plain, json, and sql") end end @@ -55,7 +55,7 @@ puts logged_message expect(logged_message).to include('"hello": "world"') - expect(logged_message).not_to include('Unsupported format used.') + expect(logged_message).not_to include("Unsupported format used.") end end @@ -69,7 +69,7 @@ puts logged_message expect(logged_message).to include("SELECT") - expect(logged_message).not_to include('Unsupported format used.') + expect(logged_message).not_to include("Unsupported format used.") end end @@ -104,26 +104,26 @@ end end - context 'parsing PostgreSQL operators' do - it 'appropriately formats jsonb column operators' do + context "parsing PostgreSQL operators" do + it "appropriately formats jsonb column operators" do io = setup_whoop # Examples from https://www.postgresql.org/docs/9.5/functions-json.html [ - %Q['{"a": {"b":"foo"}}'::json->'a'], - %Q['[1,2,3]'::json->>2], - %Q['{"a":1,"b":2}'::json->>'b'], - %Q['{"a": {"b":{"c": "foo"}}}'::json#>'{a,b}'], - %Q['{"a":[1,2,3],"b":[4,5,6]}'::json#>>'{a,2}'], - %Q['{"a":1, "b":2}'::jsonb @> '{"b":2}'::jsonb], - %Q['{"b":2}'::jsonb <@ '{"a":1, "b":2}'::jsonb], - %Q['{"a":1, "b":2}'::jsonb ? 'b'], - %Q['{"a":1, "b":2, "c":3}'::jsonb ?| array['b']], - %Q['["a", "b"]'::jsonb ?& array['a']], - %Q['["a", "b"]'::jsonb || '["c"]'::jsonb], - %Q['{"a": "b"}'::jsonb - 'a'], - %Q['["a", "b"]'::jsonb - 1], - %Q['["a", {"b":1}]'::jsonb #- '{1,b}'] + %('{"a": {"b":"foo"}}'::json->'a'), + %('[1,2,3]'::json->>2), + %('{"a":1,"b":2}'::json->>'b'), + %('{"a": {"b":{"c": "foo"}}}'::json#>'{a,b}'), + %('{"a":[1,2,3],"b":[4,5,6]}'::json#>>'{a,2}'), + %('{"a":1, "b":2}'::jsonb @> '{"b":2}'::jsonb), + %('{"b":2}'::jsonb <@ '{"a":1, "b":2}'::jsonb), + %('{"a":1, "b":2}'::jsonb ? 'b'), + %('{"a":1, "b":2, "c":3}'::jsonb ?| array['b']), + %('["a", "b"]'::jsonb ?& array['a']), + %('["a", "b"]'::jsonb || '["c"]'::jsonb), + %('{"a": "b"}'::jsonb - 'a'), + %('["a", "b"]'::jsonb - 1), + %('["a", {"b":1}]'::jsonb #- '{1,b}') ].each do |token| whoop(token, format: :sql, color: false) logged_message = io.string