vertica 0.12.0 → 1.0.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +18 -20
- data/lib/vertica.rb +15 -8
- data/lib/vertica/column.rb +32 -13
- data/lib/vertica/connection.rb +143 -119
- data/lib/vertica/{messages/backend_messages → protocol/backend}/authentication.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/backend_key_data.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/bind_complete.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/close_complete.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/command_complete.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/copy_in_response.rb +2 -2
- data/lib/vertica/{messages/backend_messages → protocol/backend}/data_row.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/empty_query_response.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/error_response.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/no_data.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/notice_response.rb +6 -6
- data/lib/vertica/{messages/backend_messages → protocol/backend}/parameter_description.rb +2 -2
- data/lib/vertica/{messages/backend_messages → protocol/backend}/parameter_status.rb +3 -3
- data/lib/vertica/{messages/backend_messages → protocol/backend}/parse_complete.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/portal_suspended.rb +1 -1
- data/lib/vertica/{messages/backend_messages → protocol/backend}/ready_for_query.rb +2 -2
- data/lib/vertica/{messages/backend_messages → protocol/backend}/row_description.rb +9 -9
- data/lib/vertica/{messages/backend_messages → protocol/backend}/unknown.rb +1 -1
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/bind.rb +2 -3
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/cancel_request.rb +3 -4
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/close.rb +3 -3
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/copy_data.rb +6 -6
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/copy_done.rb +1 -1
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/copy_fail.rb +5 -5
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/describe.rb +3 -3
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/execute.rb +3 -3
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/flush.rb +1 -1
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/parse.rb +3 -3
- data/lib/vertica/protocol/frontend/password.rb +32 -0
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/query.rb +3 -4
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/ssl_request.rb +2 -2
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/startup.rb +2 -3
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/sync.rb +1 -1
- data/lib/vertica/{messages/frontend_messages → protocol/frontend}/terminate.rb +1 -1
- data/lib/vertica/protocol/message.rb +86 -0
- data/lib/vertica/query.rb +63 -44
- data/lib/vertica/result.rb +25 -47
- data/lib/vertica/row.rb +44 -0
- data/lib/vertica/row_description.rb +102 -0
- data/lib/vertica/version.rb +1 -1
- data/test/connection.yml.example +8 -8
- data/test/functional/functional_connection_test.rb +178 -0
- data/test/functional/{query_test.rb → functional_query_test.rb} +64 -67
- data/test/functional/functional_value_conversion_test.rb +117 -0
- data/test/test_helper.rb +1 -1
- data/test/unit/backend_message_test.rb +57 -57
- data/test/unit/column_test.rb +23 -23
- data/test/unit/frontend_message_test.rb +5 -5
- data/test/unit/quoting_test.rb +16 -5
- data/test/unit/result_test.rb +61 -0
- data/test/unit/row_description_test.rb +56 -0
- data/test/unit/row_test.rb +31 -0
- data/vertica.gemspec +1 -0
- metadata +67 -45
- data/lib/vertica/messages/frontend_messages/password.rb +0 -34
- data/lib/vertica/messages/message.rb +0 -79
- data/test/functional/connection_test.rb +0 -128
- data/test/functional/value_conversion_test.rb +0 -88
@@ -1,5 +1,5 @@
|
|
1
1
|
module Vertica
|
2
|
-
module
|
2
|
+
module Protocol
|
3
3
|
|
4
4
|
class Startup < FrontendMessage
|
5
5
|
message_id nil
|
@@ -10,13 +10,12 @@ module Vertica
|
|
10
10
|
@options = options
|
11
11
|
end
|
12
12
|
|
13
|
-
def
|
13
|
+
def message_body
|
14
14
|
str = [Vertica::PROTOCOL_VERSION].pack('N')
|
15
15
|
str << ["user", @user].pack('Z*Z*') if @user
|
16
16
|
str << ["database", @database].pack('Z*Z*') if @database
|
17
17
|
str << ["options", @options].pack('Z*Z*') if @options
|
18
18
|
str << [].pack('x')
|
19
|
-
message_string str
|
20
19
|
end
|
21
20
|
end
|
22
21
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Vertica
|
2
|
+
module Protocol
|
3
|
+
|
4
|
+
class Message
|
5
|
+
def self.message_id(message_id)
|
6
|
+
self.send(:define_method, :message_id) { message_id }
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class BackendMessage < Message
|
11
|
+
MessageIdMap = {}
|
12
|
+
|
13
|
+
def self.factory(type, data)
|
14
|
+
if klass = MessageIdMap[type]
|
15
|
+
klass.new(data)
|
16
|
+
else
|
17
|
+
Protocol::Unknown.new(type, data)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.message_id(message_id)
|
22
|
+
super
|
23
|
+
MessageIdMap[message_id] = self
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(_data)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class FrontendMessage < Message
|
31
|
+
def to_bytes
|
32
|
+
prepend_message_header(message_body)
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def message_body
|
38
|
+
''
|
39
|
+
end
|
40
|
+
|
41
|
+
def prepend_message_header(msg)
|
42
|
+
if message_id
|
43
|
+
[message_id, 4 + msg.bytesize, msg].pack('aNa*')
|
44
|
+
else
|
45
|
+
[4 + msg.bytesize, msg].pack('Na*')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
require 'vertica/protocol/backend/authentication'
|
53
|
+
require 'vertica/protocol/backend/backend_key_data'
|
54
|
+
require 'vertica/protocol/backend/bind_complete'
|
55
|
+
require 'vertica/protocol/backend/close_complete'
|
56
|
+
require 'vertica/protocol/backend/command_complete'
|
57
|
+
require 'vertica/protocol/backend/data_row'
|
58
|
+
require 'vertica/protocol/backend/empty_query_response'
|
59
|
+
require 'vertica/protocol/backend/notice_response'
|
60
|
+
require 'vertica/protocol/backend/error_response'
|
61
|
+
require 'vertica/protocol/backend/no_data'
|
62
|
+
require 'vertica/protocol/backend/parameter_description'
|
63
|
+
require 'vertica/protocol/backend/parameter_status'
|
64
|
+
require 'vertica/protocol/backend/parse_complete'
|
65
|
+
require 'vertica/protocol/backend/portal_suspended'
|
66
|
+
require 'vertica/protocol/backend/ready_for_query'
|
67
|
+
require 'vertica/protocol/backend/row_description'
|
68
|
+
require 'vertica/protocol/backend/copy_in_response'
|
69
|
+
require 'vertica/protocol/backend/unknown'
|
70
|
+
|
71
|
+
require 'vertica/protocol/frontend/bind'
|
72
|
+
require 'vertica/protocol/frontend/cancel_request'
|
73
|
+
require 'vertica/protocol/frontend/close'
|
74
|
+
require 'vertica/protocol/frontend/describe'
|
75
|
+
require 'vertica/protocol/frontend/execute'
|
76
|
+
require 'vertica/protocol/frontend/flush'
|
77
|
+
require 'vertica/protocol/frontend/parse'
|
78
|
+
require 'vertica/protocol/frontend/password'
|
79
|
+
require 'vertica/protocol/frontend/query'
|
80
|
+
require 'vertica/protocol/frontend/ssl_request'
|
81
|
+
require 'vertica/protocol/frontend/startup'
|
82
|
+
require 'vertica/protocol/frontend/sync'
|
83
|
+
require 'vertica/protocol/frontend/terminate'
|
84
|
+
require 'vertica/protocol/frontend/copy_done'
|
85
|
+
require 'vertica/protocol/frontend/copy_fail'
|
86
|
+
require 'vertica/protocol/frontend/copy_data'
|
data/lib/vertica/query.rb
CHANGED
@@ -1,85 +1,104 @@
|
|
1
1
|
class Vertica::Query
|
2
2
|
|
3
|
-
attr_reader :connection, :sql, :
|
4
|
-
attr_accessor :row_handler, :copy_handler, :row_style
|
3
|
+
attr_reader :connection, :sql, :error, :result
|
5
4
|
|
6
|
-
def initialize(connection, sql,
|
5
|
+
def initialize(connection, sql, row_handler: nil, copy_handler: nil)
|
7
6
|
@connection, @sql = connection, sql
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
@
|
7
|
+
if row_handler.nil?
|
8
|
+
@buffer = []
|
9
|
+
@row_handler = lambda { |row| buffer_row(row) }
|
10
|
+
else
|
11
|
+
@row_handler = row_handler
|
12
|
+
end
|
13
|
+
@copy_handler = copy_handler
|
14
|
+
@error = nil
|
15
15
|
end
|
16
16
|
|
17
17
|
def run
|
18
|
-
@connection.write_message(Vertica::
|
18
|
+
@connection.write_message(Vertica::Protocol::Query.new(sql))
|
19
19
|
|
20
20
|
begin
|
21
21
|
process_message(message = @connection.read_message)
|
22
|
-
end until message.kind_of?(Vertica::
|
22
|
+
end until message.kind_of?(Vertica::Protocol::ReadyForQuery)
|
23
23
|
|
24
24
|
raise error unless error.nil?
|
25
25
|
return result
|
26
26
|
end
|
27
27
|
|
28
|
-
def write(data)
|
29
|
-
@connection.write_message(Vertica::Messages::CopyData.new(data))
|
30
|
-
return self
|
31
|
-
end
|
32
|
-
|
33
|
-
alias_method :<<, :write
|
34
|
-
|
35
28
|
def to_s
|
36
29
|
@sql
|
37
30
|
end
|
38
31
|
|
39
32
|
protected
|
40
33
|
|
34
|
+
def buffer_rows?
|
35
|
+
!!@buffer
|
36
|
+
end
|
37
|
+
|
41
38
|
def process_message(message)
|
42
39
|
case message
|
43
|
-
when Vertica::
|
40
|
+
when Vertica::Protocol::ErrorResponse
|
44
41
|
@error = Vertica::Error::QueryError.from_error_response(message, @sql)
|
45
|
-
when Vertica::
|
42
|
+
when Vertica::Protocol::EmptyQueryResponse
|
46
43
|
@error = Vertica::Error::EmptyQueryError.new("A SQL string was expected, but the given string was blank or only contained SQL comments.")
|
47
|
-
when Vertica::
|
48
|
-
|
49
|
-
when Vertica::
|
50
|
-
|
51
|
-
when Vertica::
|
52
|
-
|
53
|
-
when Vertica::
|
54
|
-
|
44
|
+
when Vertica::Protocol::CopyInResponse
|
45
|
+
handle_copy_in_response(message)
|
46
|
+
when Vertica::Protocol::RowDescription
|
47
|
+
handle_row_description(message)
|
48
|
+
when Vertica::Protocol::DataRow
|
49
|
+
handle_data_row(message)
|
50
|
+
when Vertica::Protocol::CommandComplete
|
51
|
+
handle_command_complete(message)
|
55
52
|
else
|
56
53
|
@connection.process_message(message)
|
57
54
|
end
|
58
55
|
end
|
59
56
|
|
60
|
-
def
|
61
|
-
|
62
|
-
|
57
|
+
def handle_row_description(message)
|
58
|
+
@row_description = Vertica::RowDescription.build(message)
|
59
|
+
end
|
60
|
+
|
61
|
+
def handle_data_row(message)
|
62
|
+
@row_handler.call(@row_description.build_row(message))
|
63
|
+
end
|
64
|
+
|
65
|
+
def handle_command_complete(message)
|
66
|
+
if buffer_rows?
|
67
|
+
@result = Vertica::Result.build(row_description: @row_description, rows: @buffer, tag: message.tag)
|
68
|
+
@row_description, @buffer = nil, nil
|
69
|
+
else
|
70
|
+
@result = message.tag
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def handle_copy_in_response(_message)
|
75
|
+
if @copy_handler.nil?
|
76
|
+
@connection.write_message(Vertica::Protocol::CopyFail.new('no handler provided'))
|
63
77
|
else
|
64
78
|
begin
|
65
|
-
|
66
|
-
|
67
|
-
else
|
68
|
-
@connection.write_message(Vertica::Messages::CopyDone.new)
|
69
|
-
end
|
79
|
+
@copy_handler.call(CopyFromStdinWriter.new(connection))
|
80
|
+
@connection.write_message(Vertica::Protocol::CopyDone.new)
|
70
81
|
rescue => e
|
71
|
-
@connection.write_message(Vertica::
|
82
|
+
@connection.write_message(Vertica::Protocol::CopyFail.new(e.message))
|
72
83
|
end
|
73
84
|
end
|
74
85
|
end
|
75
86
|
|
76
|
-
def
|
77
|
-
|
78
|
-
result.add_row(record) if buffer_rows?
|
79
|
-
row_handler.call(record) if row_handler
|
87
|
+
def buffer_row(row)
|
88
|
+
@buffer << row
|
80
89
|
end
|
81
90
|
|
82
|
-
|
83
|
-
|
91
|
+
class CopyFromStdinWriter
|
92
|
+
def initialize(connection)
|
93
|
+
@connection = connection
|
94
|
+
end
|
95
|
+
|
96
|
+
def write(data)
|
97
|
+
@connection.write_message(Vertica::Protocol::CopyData.new(data))
|
98
|
+
return self
|
99
|
+
end
|
100
|
+
|
101
|
+
alias_method :<<, :write
|
84
102
|
end
|
103
|
+
private_constant :CopyFromStdinWriter
|
85
104
|
end
|
data/lib/vertica/result.rb
CHANGED
@@ -1,70 +1,48 @@
|
|
1
1
|
class Vertica::Result
|
2
2
|
include Enumerable
|
3
3
|
|
4
|
-
attr_reader :
|
4
|
+
attr_reader :row_description
|
5
5
|
attr_reader :rows
|
6
|
-
|
6
|
+
attr_reader :tag
|
7
7
|
|
8
|
-
def initialize(
|
9
|
-
@
|
10
|
-
@rows = []
|
8
|
+
def initialize(row_description: nil, rows: nil, tag: nil)
|
9
|
+
@row_description, @rows, @tag = row_description, rows, tag
|
11
10
|
end
|
12
11
|
|
13
|
-
def
|
14
|
-
@
|
15
|
-
end
|
16
|
-
|
17
|
-
def format_row_as_hash(row_data)
|
18
|
-
row = {}
|
19
|
-
row_data.values.each_with_index do |value, idx|
|
20
|
-
col = columns.fetch(idx)
|
21
|
-
row[col.name] = col.convert(value)
|
22
|
-
end
|
23
|
-
row
|
12
|
+
def each(&block)
|
13
|
+
@rows.each(&block)
|
24
14
|
end
|
25
15
|
|
26
|
-
def
|
27
|
-
|
16
|
+
def empty?
|
17
|
+
@rows.empty?
|
28
18
|
end
|
29
19
|
|
30
|
-
def
|
31
|
-
|
32
|
-
row_data.values.each_with_index do |value, idx|
|
33
|
-
row << columns.fetch(idx).convert(value)
|
34
|
-
end
|
35
|
-
row
|
20
|
+
def size
|
21
|
+
@rows.length
|
36
22
|
end
|
37
23
|
|
38
|
-
|
39
|
-
|
40
|
-
end
|
24
|
+
alias_method :count, :size
|
25
|
+
alias_method :length, :size
|
41
26
|
|
42
|
-
def
|
43
|
-
|
27
|
+
def fetch(row_index, col = nil)
|
28
|
+
row = rows.fetch(row_index)
|
29
|
+
return row if col.nil?
|
30
|
+
row.fetch(col)
|
44
31
|
end
|
45
32
|
|
46
|
-
|
47
|
-
@rows.empty?
|
48
|
-
end
|
33
|
+
alias_method :[], :fetch
|
49
34
|
|
50
|
-
def
|
51
|
-
|
52
|
-
nil
|
53
|
-
else
|
54
|
-
@row_style == :array ? rows[0][0] : rows[0][columns[0].name]
|
55
|
-
end
|
35
|
+
def value
|
36
|
+
fetch(0, 0)
|
56
37
|
end
|
57
38
|
|
58
|
-
|
59
|
-
col.nil? ? row[row] : rows[row][col]
|
60
|
-
end
|
39
|
+
alias_method :the_value, :value
|
61
40
|
|
62
|
-
alias_method :
|
41
|
+
alias_method :columns, :row_description
|
63
42
|
|
64
|
-
def
|
65
|
-
|
43
|
+
def self.build(row_description: nil, rows: [], tag: nil)
|
44
|
+
row_description = Vertica::RowDescription.build(row_description)
|
45
|
+
rows = rows.map { |values| row_description.build_row(values) }
|
46
|
+
new(row_description: row_description, rows: rows, tag: tag)
|
66
47
|
end
|
67
|
-
|
68
|
-
alias_method :size, :row_count
|
69
|
-
alias_method :length, :row_count
|
70
48
|
end
|
data/lib/vertica/row.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
class Vertica::Row
|
2
|
+
include Enumerable
|
3
|
+
|
4
|
+
def initialize(row_description, values)
|
5
|
+
@row_description, @values = row_description, values
|
6
|
+
end
|
7
|
+
|
8
|
+
def each(&block)
|
9
|
+
@values.each(&block)
|
10
|
+
end
|
11
|
+
|
12
|
+
def fetch(name_or_index)
|
13
|
+
@values.fetch(column_index(name_or_index))
|
14
|
+
end
|
15
|
+
|
16
|
+
def inspect
|
17
|
+
"<Vertica::Row#{@values.inspect}>"
|
18
|
+
end
|
19
|
+
|
20
|
+
alias_method :[], :fetch
|
21
|
+
|
22
|
+
def to_a
|
23
|
+
@values.to_a
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_h(symbolize_keys: false)
|
27
|
+
@row_description.inject({}) do |carry, column|
|
28
|
+
key = symbolize_keys ? column.name.to_sym : column.name
|
29
|
+
carry.merge(key => fetch(column.name))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def column(name_or_index)
|
34
|
+
column_with_index(name_or_index).fetch(0)
|
35
|
+
end
|
36
|
+
|
37
|
+
def column_index(name_or_index)
|
38
|
+
column_with_index(name_or_index).fetch(1)
|
39
|
+
end
|
40
|
+
|
41
|
+
def column_with_index(name_or_index)
|
42
|
+
@row_description.column_with_index(name_or_index)
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
class Vertica::RowDescription
|
2
|
+
include Enumerable
|
3
|
+
|
4
|
+
def self.build(columns)
|
5
|
+
case columns
|
6
|
+
when Vertica::Protocol::RowDescription
|
7
|
+
new(columns.fields.map { |fd| Vertica::Column.new(fd) })
|
8
|
+
when Vertica::RowDescription
|
9
|
+
columns
|
10
|
+
when Array
|
11
|
+
new(columns)
|
12
|
+
when nil
|
13
|
+
nil
|
14
|
+
else
|
15
|
+
raise ArgumentError, "Invalid list of columns: #{columns.inspect}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(columns)
|
20
|
+
@columns = columns
|
21
|
+
end
|
22
|
+
|
23
|
+
def column(name_or_index)
|
24
|
+
column_with_index(name_or_index).first
|
25
|
+
end
|
26
|
+
|
27
|
+
alias_method :[], :column
|
28
|
+
|
29
|
+
def column_with_index(name_or_index)
|
30
|
+
columns_index.fetch(name_or_index)
|
31
|
+
end
|
32
|
+
|
33
|
+
def each(&block)
|
34
|
+
@columns.each(&block)
|
35
|
+
end
|
36
|
+
|
37
|
+
def size
|
38
|
+
@columns.size
|
39
|
+
end
|
40
|
+
|
41
|
+
alias_method :length, :size
|
42
|
+
|
43
|
+
def to_a
|
44
|
+
@columns.clone
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_h(symbolize_keys: false)
|
48
|
+
@columns.inject({}) do |carry, column|
|
49
|
+
key = symbolize_keys ? column.name.to_sym : column.name
|
50
|
+
carry.merge(key => column)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def build_row(values)
|
55
|
+
case values
|
56
|
+
when Vertica::Row
|
57
|
+
values
|
58
|
+
|
59
|
+
when Vertica::Protocol::DataRow
|
60
|
+
converted_values = @columns.map.with_index do |column, index|
|
61
|
+
column.convert(values.values.fetch(index))
|
62
|
+
end
|
63
|
+
Vertica::Row.new(self, converted_values)
|
64
|
+
|
65
|
+
when Array
|
66
|
+
raise ArgumentError, "Number of values does not match row description" if values.size != size
|
67
|
+
Vertica::Row.new(self, values)
|
68
|
+
|
69
|
+
when Hash
|
70
|
+
raise ArgumentError, "Number of values does not match row description" if values.size != size
|
71
|
+
values_as_array = @columns.map { |column| values[column.name] || values[column.name.to_sym] }
|
72
|
+
Vertica::Row.new(self, values_as_array)
|
73
|
+
|
74
|
+
else
|
75
|
+
raise ArgumentError, "Don't know how to build a row from a #{values.class.name} instance"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def eql?(other)
|
80
|
+
self.class === other && other.to_a == self.to_a
|
81
|
+
end
|
82
|
+
|
83
|
+
alias_method :==, :eql?
|
84
|
+
|
85
|
+
def hash
|
86
|
+
@columns.hash
|
87
|
+
end
|
88
|
+
|
89
|
+
protected
|
90
|
+
|
91
|
+
def columns_index
|
92
|
+
@columns_index ||= begin
|
93
|
+
result = {}
|
94
|
+
@columns.each_with_index do |column, index|
|
95
|
+
result[index] = [column, index]
|
96
|
+
result[column.name.to_s] = [column, index]
|
97
|
+
result[column.name.to_sym] = [column, index]
|
98
|
+
end
|
99
|
+
result
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|