Module: Mysql2::NestedHashBind::QueryExtension

Defined in:
lib/mysql2/nested_hash_bind/query_extension.rb

Overview

Apply patches to Mysql2::Client#query and Mysql2::Client#xquery

Instance Method Summary collapse

Instance Method Details

#query(sql, **options) ⇒ Array<Hash>, ...

Parameters:

  • sql (String)
  • options (Hash)

Returns:

  • (Array<Hash>)

    Exists columns containing dots

  • (Mysql2::Result)

    No columns containing dots (This is the original behavior of Mysql2::Client#query)

  • (nil)

    No response was returned. (e.g. ROLLBACK)

See Also:



# File 'lib/mysql2/nested_hash_bind/query_extension.rb', line 7

#xquery(sql, *args, **options) ⇒ Array<Hash>, ...

Parameters:

  • sql (String)
  • args (Array)
  • options (Hash)

Returns:

  • (Array<Hash>)

    Exists columns containing dots

  • (Mysql2::Result)

    No columns containing dots (This is the original behavior of Mysql2::Client#xquery)

  • (nil)

    No response was returned. (e.g. ROLLBACK)

See Also:



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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/mysql2/nested_hash_bind/query_extension.rb', line 30

refine(Mysql2::Client) do
  # @param sql [String]
  # @param options [Hash]
  #
  # @return [Array<Hash>] Exists columns containing dots
  # @return [Mysql2::Result] No columns containing dots (This is the original behavior of `Mysql2::Client#query`)
  # @return [nil] No response was returned. (e.g. `ROLLBACK`)
  def query_with_bind(sql, **options)
    rows = query_without_bind(sql, **options)

    __transform_rows(rows)
  end

  alias_method :query_without_bind, :query
  alias_method :query, :query_with_bind

  # @param sql [String]
  # @param args [Array]
  # @param options [Hash]
  #
  # @return [Array<Hash>] Exists columns containing dots
  # @return [Mysql2::Result] No columns containing dots (This is the original behavior of `Mysql2::Client#xquery`)
  # @return [nil] No response was returned. (e.g. `ROLLBACK`)
  def xquery_with_bind(sql, *args, **options)
    rows = xquery_without_bind(sql, *args, **options)

    __transform_rows(rows)
  end

  alias_method :xquery_without_bind, :xquery
  alias_method :xquery, :xquery_with_bind

  private

  # @param [Mysql2::Result,nil] rows
  #
  # @return [Array<Hash>] Exists columns containing dots
  # @return [Mysql2::Result] No columns containing dots
  #                          (This is the original behavior of `Mysql2::Client#query` and `Mysql2::Client#xquery`)
  # @return [nil] No response was returned. (e.g. `ROLLBACK`)
  def __transform_rows(rows)
    column_names = rows&.first&.keys

    # No columns containing dots
    return rows unless column_names

    return rows unless column_names.any? { |column_name| __include_column_name_dot?(column_name) }

    # NOTE: Caching result of `column_name.split`
    columns_cache = __split_columns(column_names)

    rows.map { |row| __transform_row(row: row, columns_cache: columns_cache) }
  end

  # @param column_names [Array<String,Symbol>]
  # @return [Hash{String,Symbol=>Array<String,Symbol>}]
  def __split_columns(column_names)
    column_names.each_with_object({}) do |column_name, hash|
      str_key = column_name.respond_to?(:name) ? column_name.name : column_name
      parent_key, child_key = *str_key.split(".", 2)

      next unless child_key

      if query_options[:symbolize_keys]
        parent_key = parent_key.to_sym
        child_key = child_key.to_sym
      end

      hash[column_name] = { parent_key: parent_key, child_key: child_key }
    end
  end

  # @param column_name [String,Symbol]
  # @return [Boolean]
  def __include_column_name_dot?(column_name)
    # NOTE: Call Symbol#name if possible
    return column_name.name.include?(".") if column_name.respond_to?(:name)

    column_name.include?(".")
  end

  # @param row [Hash]
  # @param columns_cache [Hash{String,Symbol=>Array<String,Symbol>}]
  #
  # @return [Hash]
  def __transform_row(row:, columns_cache:)
    row.each_with_object({}) do |(k, v), new_row|
      if columns_cache[k]
        __update_for_nested_hash(row: new_row, key: k, value: v, columns_cache: columns_cache)
      else
        new_row[k] = v
      end
    end
  end

  # @param row [Hash]
  # @param key [String,Symbol]
  # @param value [Object]
  # @param columns_cache [Hash{String,Symbol=>Array<String,Symbol>}]
  def __update_for_nested_hash(row:, key:, value:, columns_cache:)
    parent_key = columns_cache[key][:parent_key]
    child_key = columns_cache[key][:child_key]

    row[parent_key] ||= {}
    row[parent_key][child_key] = value
  end
end