neo4j-core 3.1.1 → 4.0.0
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/Gemfile +7 -12
- data/README.md +7 -7
- data/lib/neo4j-core.rb +3 -2
- data/lib/neo4j-core/active_entity.rb +8 -10
- data/lib/neo4j-core/cypher_translator.rb +61 -59
- data/lib/neo4j-core/hash_with_indifferent_access.rb +31 -22
- data/lib/neo4j-core/helpers.rb +15 -17
- data/lib/neo4j-core/label.rb +7 -6
- data/lib/neo4j-core/query.rb +271 -268
- data/lib/neo4j-core/query_clauses.rb +371 -355
- data/lib/neo4j-core/query_find_in_batches.rb +26 -26
- data/lib/neo4j-core/version.rb +1 -1
- data/lib/neo4j-embedded.rb +2 -2
- data/lib/neo4j-embedded/cypher_response.rb +40 -41
- data/lib/neo4j-embedded/embedded_database.rb +21 -22
- data/lib/neo4j-embedded/embedded_ha_session.rb +13 -11
- data/lib/neo4j-embedded/embedded_impermanent_session.rb +9 -8
- data/lib/neo4j-embedded/embedded_label.rb +64 -70
- data/lib/neo4j-embedded/embedded_node.rb +68 -73
- data/lib/neo4j-embedded/embedded_relationship.rb +6 -13
- data/lib/neo4j-embedded/embedded_session.rb +128 -132
- data/lib/neo4j-embedded/embedded_transaction.rb +34 -33
- data/lib/neo4j-embedded/property.rb +84 -77
- data/lib/neo4j-embedded/to_java.rb +24 -23
- data/lib/neo4j-server.rb +1 -1
- data/lib/neo4j-server/cypher_authentication.rb +105 -103
- data/lib/neo4j-server/cypher_label.rb +25 -23
- data/lib/neo4j-server/cypher_node.rb +180 -177
- data/lib/neo4j-server/cypher_node_uncommited.rb +11 -9
- data/lib/neo4j-server/cypher_relationship.rb +101 -102
- data/lib/neo4j-server/cypher_response.rb +171 -170
- data/lib/neo4j-server/cypher_session.rb +209 -205
- data/lib/neo4j-server/cypher_transaction.rb +66 -48
- data/lib/neo4j-server/resource.rb +17 -22
- data/lib/neo4j/entity_equality.rb +3 -4
- data/lib/neo4j/label.rb +13 -16
- data/lib/neo4j/node.rb +30 -34
- data/lib/neo4j/property_container.rb +3 -3
- data/lib/neo4j/property_validator.rb +4 -5
- data/lib/neo4j/relationship.rb +17 -22
- data/lib/neo4j/session.rb +19 -21
- data/lib/neo4j/tasks/config_server.rb +2 -3
- data/lib/neo4j/tasks/neo4j_server.rake +82 -74
- data/lib/neo4j/transaction.rb +23 -22
- data/neo4j-core.gemspec +21 -16
- metadata +72 -2
@@ -1,12 +1,14 @@
|
|
1
|
-
module Neo4j
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
module Neo4j
|
2
|
+
module Server
|
3
|
+
class CypherNodeUncommited
|
4
|
+
def initialize(db, data)
|
5
|
+
@db = db
|
6
|
+
@data = data
|
7
|
+
end
|
7
8
|
|
8
|
-
|
9
|
-
|
9
|
+
def [](key)
|
10
|
+
@data[key.to_s]
|
11
|
+
end
|
10
12
|
end
|
11
13
|
end
|
12
|
-
end
|
14
|
+
end
|
@@ -1,131 +1,130 @@
|
|
1
|
-
module Neo4j
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
1
|
+
module Neo4j
|
2
|
+
module Server
|
3
|
+
class CypherRelationship < Neo4j::Relationship
|
4
|
+
include Neo4j::Server::Resource
|
5
|
+
include Neo4j::Core::CypherTranslator
|
6
|
+
include Neo4j::Core::ActiveEntity
|
7
|
+
|
8
|
+
def initialize(session, value)
|
9
|
+
@session = session
|
10
|
+
@response_hash = value
|
11
|
+
@rel_type = @response_hash['type']
|
12
|
+
@props = @response_hash['data']
|
13
|
+
@start_node_neo_id = @response_hash['start'].is_a?(Integer) ? @response_hash['start'] : @response_hash['start'].match(/\d+$/)[0].to_i
|
14
|
+
@end_node_neo_id = @response_hash['end'].is_a?(Integer) ? @response_hash['end'] : @response_hash['end'].match(/\d+$/)[0].to_i
|
15
|
+
@id = @response_hash['id']
|
16
|
+
end
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
def ==(other)
|
19
|
+
other.class == self.class && other.neo_id == neo_id
|
20
|
+
end
|
21
|
+
alias_method :eql?, :==
|
22
22
|
|
23
|
-
|
24
|
-
@id
|
25
|
-
end
|
23
|
+
attr_reader :id
|
26
24
|
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
def neo_id
|
26
|
+
id
|
27
|
+
end
|
30
28
|
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
def inspect
|
30
|
+
"CypherRelationship #{neo_id}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def load_resource
|
34
|
+
return if resource_data_present?
|
34
35
|
|
35
|
-
def load_resource
|
36
|
-
if resource_data.nil? || resource_data.empty?
|
37
36
|
@resource_data = @session._query_or_fail("#{match_start} RETURN n", true, neo_id: neo_id) # r.first_data
|
38
37
|
end
|
39
|
-
end
|
40
38
|
|
41
|
-
|
42
|
-
@start_node_neo_id
|
43
|
-
end
|
39
|
+
attr_reader :start_node_neo_id
|
44
40
|
|
45
|
-
|
46
|
-
@end_node_neo_id
|
47
|
-
end
|
41
|
+
attr_reader :end_node_neo_id
|
48
42
|
|
49
|
-
|
50
|
-
|
51
|
-
|
43
|
+
def _start_node_id
|
44
|
+
@start_node_neo_id ||= get_node_id(:start)
|
45
|
+
end
|
52
46
|
|
53
|
-
|
54
|
-
|
55
|
-
|
47
|
+
def _end_node_id
|
48
|
+
@end_node_neo_id ||= get_node_id(:end)
|
49
|
+
end
|
56
50
|
|
57
|
-
|
58
|
-
|
59
|
-
|
51
|
+
def _start_node
|
52
|
+
@_start_node ||= Neo4j::Node._load(start_node_neo_id)
|
53
|
+
end
|
60
54
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
55
|
+
def _end_node
|
56
|
+
load_resource
|
57
|
+
@_end_node ||= Neo4j::Node._load(end_node_neo_id)
|
58
|
+
end
|
65
59
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
60
|
+
def get_node_id(direction)
|
61
|
+
load_resource
|
62
|
+
resource_url_id(resource_url(direction))
|
63
|
+
end
|
70
64
|
|
71
|
-
|
72
|
-
|
73
|
-
|
65
|
+
def get_property(key)
|
66
|
+
@session._query_or_fail("#{match_start} RETURN n.`#{key}`", true, neo_id: neo_id)
|
67
|
+
end
|
74
68
|
|
75
|
-
|
76
|
-
|
77
|
-
|
69
|
+
def set_property(key, value)
|
70
|
+
@session._query_or_fail("#{match_start} SET n.`#{key}` = {value}", false, value: value, neo_id: neo_id)
|
71
|
+
end
|
78
72
|
|
79
|
-
|
80
|
-
|
81
|
-
|
73
|
+
def remove_property(key)
|
74
|
+
@session._query_or_fail("#{match_start} REMOVE n.`#{key}`", false, neo_id: neo_id)
|
75
|
+
end
|
82
76
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
77
|
+
# (see Neo4j::Relationship#props)
|
78
|
+
def props
|
79
|
+
if @props
|
80
|
+
@props
|
81
|
+
else
|
82
|
+
hash = @session._query_entity_data("#{match_start} RETURN n", nil, neo_id: neo_id)
|
83
|
+
@props = Hash[hash['data'].map { |k, v| [k.to_sym, v] }]
|
84
|
+
end
|
90
85
|
end
|
91
|
-
end
|
92
86
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
87
|
+
# (see Neo4j::Relationship#props=)
|
88
|
+
def props=(properties)
|
89
|
+
@session._query_or_fail("#{match_start} SET n = { props }", false, props: properties, neo_id: neo_id)
|
90
|
+
properties
|
91
|
+
end
|
98
92
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
93
|
+
# (see Neo4j::Relationship#update_props)
|
94
|
+
def update_props(properties)
|
95
|
+
return if properties.empty?
|
96
|
+
q = "#{match_start} SET " + properties.keys.map do |k|
|
97
|
+
"n.`#{k}`= #{escape_value(properties[k])}"
|
98
|
+
end.join(',')
|
99
|
+
@session._query_or_fail(q, false, neo_id: neo_id)
|
100
|
+
properties
|
101
|
+
end
|
108
102
|
|
109
|
-
|
110
|
-
|
111
|
-
|
103
|
+
def rel_type
|
104
|
+
@rel_type.to_sym
|
105
|
+
end
|
112
106
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
107
|
+
def del
|
108
|
+
@session._query("#{match_start} DELETE n", neo_id: neo_id)
|
109
|
+
end
|
110
|
+
alias_method :delete, :del
|
111
|
+
alias_method :destroy, :del
|
118
112
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
113
|
+
def exist?
|
114
|
+
response = @session._query("#{match_start} RETURN n", neo_id: neo_id)
|
115
|
+
# binding.pry
|
116
|
+
(response.data.nil? || response.data.empty?) ? false : true
|
117
|
+
end
|
124
118
|
|
125
|
-
|
119
|
+
private
|
126
120
|
|
127
|
-
|
128
|
-
|
121
|
+
def match_start(identifier = 'n')
|
122
|
+
"MATCH (node)-[#{identifier}]-() WHERE ID(#{identifier}) = {neo_id}"
|
123
|
+
end
|
124
|
+
|
125
|
+
def resource_data_present?
|
126
|
+
!resource_data.nil? && !resource_data.empty?
|
127
|
+
end
|
129
128
|
end
|
130
129
|
end
|
131
130
|
end
|
@@ -1,225 +1,226 @@
|
|
1
|
-
module Neo4j
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
1
|
+
module Neo4j
|
2
|
+
module Server
|
3
|
+
class CypherResponse
|
4
|
+
attr_reader :data, :columns, :error_msg, :error_status, :error_code, :response
|
5
|
+
|
6
|
+
class ResponseError < StandardError
|
7
|
+
attr_reader :status, :code
|
8
|
+
|
9
|
+
def initialize(msg, status, code)
|
10
|
+
super(msg)
|
11
|
+
@status = status
|
12
|
+
@code = code
|
13
|
+
end
|
12
14
|
end
|
13
|
-
end
|
14
15
|
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
17
|
+
class HashEnumeration
|
18
|
+
include Enumerable
|
19
|
+
extend Forwardable
|
20
|
+
def_delegator :@response, :error_msg
|
21
|
+
def_delegator :@response, :error_status
|
22
|
+
def_delegator :@response, :error_code
|
23
|
+
def_delegator :@response, :columns
|
24
|
+
def_delegator :@response, :struct
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
def initialize(response, query)
|
27
|
+
@response = response
|
28
|
+
@query = query
|
29
|
+
end
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
def to_s
|
32
|
+
@query
|
33
|
+
end
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
35
|
+
def inspect
|
36
|
+
"Enumerable query: '#{@query}'"
|
37
|
+
end
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
def each(&block)
|
40
|
+
@response.each_data_row do |row|
|
41
|
+
yield(row.each_with_index.each_with_object(struct.new) do |(value, i), result|
|
42
|
+
result[columns[i].to_sym] = value
|
43
|
+
end)
|
44
|
+
end
|
43
45
|
end
|
44
46
|
end
|
45
|
-
end
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
48
|
+
def to_struct_enumeration(cypher = '')
|
49
|
+
HashEnumeration.new(self, cypher)
|
50
|
+
end
|
50
51
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
52
|
+
def to_node_enumeration(cypher = '', session = Neo4j::Session.current)
|
53
|
+
Enumerator.new do |yielder|
|
54
|
+
@result_index = 0
|
55
|
+
to_struct_enumeration(cypher).each do |row|
|
56
|
+
@row_index = 0
|
57
|
+
yielder << row.each_pair.each_with_object(@struct.new) do |(column, value), result|
|
58
|
+
result[column] = map_row_value(value, session)
|
59
|
+
@row_index += 1
|
60
|
+
end
|
61
|
+
@result_index += 1
|
59
62
|
end
|
60
|
-
@result_index += 1
|
61
63
|
end
|
62
64
|
end
|
63
|
-
end
|
64
65
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
66
|
+
def map_row_value(value, session)
|
67
|
+
if value.is_a?(Hash)
|
68
|
+
hash_value_as_object(value, session)
|
69
|
+
elsif value.is_a?(Array)
|
70
|
+
value.map { |v| map_row_value(v, session) }
|
71
|
+
else
|
72
|
+
value
|
73
|
+
end
|
72
74
|
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def hash_value_as_object(value, session)
|
76
|
-
return value unless value['labels'] || value['type'] || is_transaction_response?
|
77
|
-
obj_type, data = if is_transaction_response?
|
78
|
-
add_transaction_entity_id
|
79
|
-
[(mapped_rest_data['start'] ? CypherRelationship : CypherNode), mapped_rest_data]
|
80
|
-
else value['labels'] || value['type']
|
81
|
-
add_entity_id(value)
|
82
|
-
[(value['labels'] ? CypherNode : CypherRelationship), value]
|
83
|
-
end
|
84
|
-
obj_type.new(session, data).wrapper
|
85
|
-
end
|
86
75
|
|
87
|
-
|
76
|
+
def hash_value_as_object(value, session)
|
77
|
+
return value unless value['labels'] || value['type'] || transaction_response?
|
78
|
+
|
79
|
+
is_node, data = if transaction_response?
|
80
|
+
add_transaction_entity_id
|
81
|
+
[!mapped_rest_data['start'], mapped_rest_data]
|
82
|
+
elsif value['labels'] || value['type']
|
83
|
+
add_entity_id(value)
|
84
|
+
[value['labels'], value]
|
85
|
+
end
|
86
|
+
(is_node ? CypherNode : CypherRelationship).new(session, data).wrapper
|
87
|
+
end
|
88
88
|
|
89
|
-
|
90
|
-
@response = response
|
91
|
-
@uncommited = uncommited
|
92
|
-
end
|
89
|
+
attr_reader :struct
|
93
90
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
data.is_a?(Hash) ? {'data' => data, 'id' => id} : data
|
98
|
-
else
|
99
|
-
data = @data[0][0]
|
100
|
-
data.is_a?(Hash) ? add_entity_id(data) : data
|
91
|
+
def initialize(response, uncommited = false)
|
92
|
+
@response = response
|
93
|
+
@uncommited = uncommited
|
101
94
|
end
|
102
|
-
end
|
103
95
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
96
|
+
def entity_data(id = nil)
|
97
|
+
if @uncommited
|
98
|
+
data = @data.first['row'].first
|
99
|
+
data.is_a?(Hash) ? {'data' => data, 'id' => id} : data
|
100
|
+
else
|
101
|
+
data = @data[0][0]
|
102
|
+
data.is_a?(Hash) ? add_entity_id(data) : data
|
103
|
+
end
|
111
104
|
end
|
112
|
-
end
|
113
105
|
|
114
|
-
|
115
|
-
|
116
|
-
|
106
|
+
def first_data(id = nil)
|
107
|
+
if @uncommited
|
108
|
+
data = @data.first['row'].first
|
109
|
+
# data.is_a?(Hash) ? {'data' => data, 'id' => id} : data
|
110
|
+
else
|
111
|
+
data = @data[0][0]
|
112
|
+
data.is_a?(Hash) ? add_entity_id(data) : data
|
113
|
+
end
|
114
|
+
end
|
117
115
|
|
118
|
-
|
119
|
-
|
120
|
-
|
116
|
+
def add_entity_id(data)
|
117
|
+
data.merge!('id' => self.class.id_from_url(data['self']))
|
118
|
+
end
|
121
119
|
|
122
|
-
|
123
|
-
|
124
|
-
|
120
|
+
def add_transaction_entity_id
|
121
|
+
mapped_rest_data.merge!('id' => mapped_rest_data['self'].split('/').last.to_i)
|
122
|
+
end
|
125
123
|
|
126
|
-
|
127
|
-
|
128
|
-
|
124
|
+
def error?
|
125
|
+
!!@error
|
126
|
+
end
|
129
127
|
|
130
|
-
|
131
|
-
|
132
|
-
|
128
|
+
def data?
|
129
|
+
!response.body['data'].nil?
|
130
|
+
end
|
133
131
|
|
134
|
-
|
135
|
-
|
136
|
-
|
132
|
+
def raise_unless_response_code(code)
|
133
|
+
fail "Response code #{response.status}, expected #{code} for #{response.headers['location']}, #{response.body}" unless response.status == code
|
134
|
+
end
|
137
135
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
136
|
+
def each_data_row
|
137
|
+
if @uncommited
|
138
|
+
data.each { |r| yield r['row'] }
|
139
|
+
else
|
140
|
+
data.each { |r| yield r }
|
141
|
+
end
|
143
142
|
end
|
144
|
-
end
|
145
143
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
144
|
+
def set_data(data, columns)
|
145
|
+
@data = data
|
146
|
+
@columns = columns
|
147
|
+
@struct = columns.empty? ? Object.new : Struct.new(*columns.map(&:to_sym))
|
148
|
+
self
|
149
|
+
end
|
152
150
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
151
|
+
def set_error(error_msg, error_status, error_core)
|
152
|
+
@error = true
|
153
|
+
@error_msg = error_msg
|
154
|
+
@error_status = error_status
|
155
|
+
@error_code = error_core
|
156
|
+
self
|
157
|
+
end
|
160
158
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
159
|
+
def raise_error
|
160
|
+
fail 'Tried to raise error without an error' unless @error
|
161
|
+
fail ResponseError.new(@error_msg, @error_status, @error_code)
|
162
|
+
end
|
165
163
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
164
|
+
def raise_cypher_error
|
165
|
+
fail 'Tried to raise error without an error' unless @error
|
166
|
+
fail Neo4j::Session::CypherError.new(@error_msg, @error_code, @error_status)
|
167
|
+
end
|
170
168
|
|
171
169
|
|
172
|
-
|
173
|
-
|
170
|
+
def self.create_with_no_tx(response)
|
171
|
+
case response.status
|
174
172
|
when 200
|
175
173
|
CypherResponse.new(response).set_data(response.body['data'], response.body['columns'])
|
176
174
|
when 400
|
177
175
|
CypherResponse.new(response).set_error(response.body['message'], response.body['exception'], response.body['fullname'])
|
178
176
|
else
|
179
|
-
|
177
|
+
fail "Unknown response code #{response.status} for #{response.env[:url]}"
|
178
|
+
end
|
180
179
|
end
|
181
|
-
end
|
182
180
|
|
183
|
-
|
184
|
-
|
181
|
+
def self.create_with_tx(response)
|
182
|
+
fail "Unknown response code #{response.status} for #{response.request_uri}" unless response.status == 200
|
185
183
|
|
186
|
-
|
187
|
-
|
184
|
+
first_result = response.body['results'][0]
|
185
|
+
cr = CypherResponse.new(response, true)
|
188
186
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
187
|
+
if response.body['errors'].empty?
|
188
|
+
cr.set_data(first_result['data'], first_result['columns'])
|
189
|
+
else
|
190
|
+
first_error = response.body['errors'].first
|
191
|
+
cr.set_error(first_error['message'], first_error['status'], first_error['code'])
|
192
|
+
end
|
193
|
+
cr
|
194
194
|
end
|
195
|
-
cr
|
196
|
-
end
|
197
195
|
|
198
|
-
|
199
|
-
|
200
|
-
|
196
|
+
def transaction_response?
|
197
|
+
response.respond_to?('body') && !response.body['commit'].nil?
|
198
|
+
end
|
201
199
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
200
|
+
def rest_data
|
201
|
+
@result_index = @row_index = 0
|
202
|
+
mapped_rest_data
|
203
|
+
end
|
206
204
|
|
207
|
-
|
208
|
-
|
209
|
-
|
205
|
+
def rest_data_with_id
|
206
|
+
rest_data.merge!('id' => mapped_rest_data['self'].split('/').last.to_i)
|
207
|
+
end
|
208
|
+
|
209
|
+
class << self
|
210
|
+
def id_from_url(url)
|
211
|
+
url.split('/')[-1].to_i
|
212
|
+
end
|
213
|
+
end
|
210
214
|
|
211
|
-
|
215
|
+
private
|
212
216
|
|
213
|
-
|
214
|
-
@row_index
|
215
|
-
end
|
217
|
+
attr_reader :row_index
|
216
218
|
|
217
|
-
|
218
|
-
@result_index
|
219
|
-
end
|
219
|
+
attr_reader :result_index
|
220
220
|
|
221
|
-
|
222
|
-
|
221
|
+
def mapped_rest_data
|
222
|
+
response.body['results'][0]['data'][result_index]['rest'][row_index]
|
223
|
+
end
|
223
224
|
end
|
224
225
|
end
|
225
|
-
end
|
226
|
+
end
|