dse-driver 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,85 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright (C) 2016 DataStax Inc.
5
+ #
6
+ # This software can be used solely with DataStax Enterprise. Please consult the license at
7
+ # http://www.datastax.com/terms/datastax-dse-driver-license-terms
8
+ #++
9
+
10
+ module Dse
11
+ module Graph
12
+ # An individual result of running a graph query. It wraps the JSON result and provides
13
+ # access to it as a hash. It also supports casting the result into a known
14
+ # domain object type: {Vertex}, {Edge}, and {Path} currently.
15
+ #
16
+ # @see ResultSet
17
+ class Result
18
+ # @return hash representation of the JSON result of a graph query if it's a complex result. A simple value
19
+ # otherwise
20
+ attr_reader :value
21
+
22
+ # @private
23
+ def initialize(result)
24
+ @value = result
25
+ end
26
+
27
+ # Coerce this result into a domain object if possible.
28
+ # @return [Vertex, Edge, Result] a new wrapped object, or self if we can't cast it
29
+ def cast
30
+ type = @value['type'] if @value.is_a?(Hash)
31
+ case type
32
+ when 'vertex'
33
+ as_vertex
34
+ when 'edge'
35
+ as_edge
36
+ else
37
+ self
38
+ end
39
+ end
40
+
41
+ # Coerce this result into a {Vertex} object.
42
+ # @return [Vertex] a vertex domain object
43
+ # @raise [ArgumentError] if the result data does not represent a vertex
44
+ def as_vertex
45
+ Cassandra::Util.assert_instance_of(::Hash, @value)
46
+ Dse::Graph::Vertex.new(@value['id'], @value['label'], @value.fetch('properties', {}))
47
+ end
48
+
49
+ # Coerce this result into an {Edge} object.
50
+ # @return [Edge] an edge domain object.
51
+ # @raise [ArgumentError] if the result data does not represent an edge.
52
+ def as_edge
53
+ Cassandra::Util.assert_instance_of(::Hash, @value)
54
+ Dse::Graph::Edge.new(@value['id'], @value['label'], @value.fetch('properties', {}),
55
+ @value['inV'], @value['inVLabel'],
56
+ @value['outV'], @value['outVLabel'])
57
+ end
58
+
59
+ # Coerce this result into a {Path} object.
60
+ # @return [Path] a path domain object.
61
+ def as_path
62
+ Cassandra::Util.assert_instance_of(::Hash, @value)
63
+ Dse::Graph::Path.new(@value['labels'], @value['objects'])
64
+ end
65
+
66
+ # @private
67
+ def eql?(other)
68
+ other.is_a?(Result) && \
69
+ @value == other.value
70
+ end
71
+ alias == eql?
72
+
73
+ # @private
74
+ def hash
75
+ @hash ||= 31 * 17 + @value.hash
76
+ end
77
+
78
+ # @private
79
+ def inspect
80
+ "#<Dse::Graph::Result:0x#{object_id.to_s(16)} " \
81
+ "@value=#{@value.inspect}>"
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,77 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright (C) 2016 DataStax Inc.
5
+ #
6
+ # This software can be used solely with DataStax Enterprise. Please consult the license at
7
+ # http://www.datastax.com/terms/datastax-dse-driver-license-terms
8
+ #++
9
+
10
+ module Dse
11
+ module Graph
12
+ # Collection of results of running a graph query. It wraps a {Cassandra::Result}. When iterating
13
+ # over results, individual results may be well-known domain objects or a generic {Result}.
14
+ #
15
+ # @see Vertex
16
+ # @see Edge
17
+ # @see Path
18
+ # @see Result
19
+ class ResultSet
20
+ include Enumerable
21
+ extend Forwardable
22
+
23
+ # @private -- just for ==/eql?
24
+ attr_reader :parsed_results
25
+
26
+ # @!method execution_info
27
+ # Query execution information, such as number of retries and all tried hosts, etc.
28
+ # @return [Cassandra::Execution::Info]
29
+ #
30
+ # @!method empty?
31
+ # @return [Boolean] whether it has any result data
32
+ #
33
+ # @!method size
34
+ # @return [Integer] number of results
35
+ #
36
+ def_delegators :@results, :execution_info, :empty?, :size
37
+ alias length size
38
+
39
+ # @private
40
+ def initialize(results)
41
+ @results = results
42
+ @parsed_results = results.map do |r|
43
+ Result.new(JSON.parse(r.fetch('gremlin', {})).fetch('result', {})).cast
44
+ end
45
+ end
46
+
47
+ # @yieldparam result [Vertex, Edge, Path, Result] result object for a particular result
48
+ # @return [Enumerator, self] returns Enumerator if no block given
49
+ def each(&block)
50
+ @parsed_results.each(&block)
51
+ end
52
+
53
+ # Allow array indexing into the result-set.
54
+ # @param ind [Integer] index into the collection of query results.
55
+ def [](ind)
56
+ @parsed_results[ind]
57
+ end
58
+
59
+ # @private
60
+ def eql?(other)
61
+ other.is_a?(ResultSet) && \
62
+ @parsed_results == other.parsed_results
63
+ end
64
+ alias == eql?
65
+
66
+ # @private
67
+ def hash
68
+ @hash ||= 31 * 17 + @parsed_results.hash
69
+ end
70
+
71
+ # @private
72
+ def inspect
73
+ "#<Dse::ResultSet:0x#{object_id.to_s(16)} []=#{@parsed_results.inspect}>"
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,118 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright (C) 2016 DataStax Inc.
5
+ #
6
+ # This software can be used solely with DataStax Enterprise. Please consult the license at
7
+ # http://www.datastax.com/terms/datastax-dse-driver-license-terms
8
+ #++
9
+
10
+ module Dse
11
+ module Graph
12
+ # Encapsulates a graph statement, parameters, options, and idempotency. This is primarily useful for
13
+ # re-issuing the same statement multiple times the same way.
14
+ class Statement
15
+ include Cassandra::Statement
16
+
17
+ # @return [String] graph statement string
18
+ attr_reader :statement
19
+ # @return [Hash<String, String>] parameters to the statement
20
+ attr_reader :parameters
21
+ # @return [Options] graph options
22
+ attr_reader :options
23
+ # @private
24
+ attr_reader :simple_statement
25
+
26
+ # @param statement [String] graph statement
27
+ # @param parameters [Hash<String, String>] (nil) parameters to the statement
28
+ # @param options [Hash, Options] (nil) graph options
29
+ # @param idempotent [Boolean] (false) whether or not the statement is idempotent
30
+ def initialize(statement, parameters = nil, options = nil, idempotent = false)
31
+ # Save off statement and idempotent; easy stuff.
32
+ @statement = statement.freeze
33
+ @idempotent = idempotent.freeze
34
+ @parameters = parameters.freeze
35
+
36
+ # Convert the parameters into a one-element array with JSON; that's what we need to
37
+ # send to DSE over the wire. But if we have no params, nil is fine.
38
+ unless parameters.nil?
39
+ ::Cassandra::Util.assert_instance_of(::Hash, parameters, 'Graph parameters must be a hash')
40
+ # Some of our parameters may be geo-type values. Convert them to their wkt representation.
41
+ tweaked_params = {}
42
+ parameters.each do |name, value|
43
+ value = value.wkt if value.respond_to?(:wkt)
44
+ tweaked_params[name] = value
45
+ end
46
+ parameters = [tweaked_params.to_json]
47
+ end
48
+
49
+ # Graph options may be tricky. A few cases:
50
+ # 1. options is nil; then @options should be nil.
51
+ # 2. options is a Hash with a graph_options key; then @options is the referenced Options object.
52
+ # We must validate that the referenced object *is* an Options.
53
+ # 3. options is an Options object; then just assign to @options.
54
+
55
+ unless options.nil?
56
+ Cassandra::Util.assert_instance_of_one_of([Dse::Graph::Options, ::Hash], options)
57
+ @options = if options.is_a?(Options)
58
+ options
59
+ elsif !options[:graph_options].nil?
60
+ Cassandra::Util.assert_instance_of(Dse::Graph::Options, options[:graph_options])
61
+ options[:graph_options]
62
+ else
63
+ Dse::Graph::Options.new(options)
64
+ end
65
+ end
66
+
67
+ @simple_statement = Cassandra::Statements::Simple.new(@statement,
68
+ parameters,
69
+ parameters.nil? ? nil : [Cassandra::Types.varchar],
70
+ @idempotent)
71
+ end
72
+
73
+ # @private
74
+ def accept(client, options)
75
+ simple_statement.accept(client, options)
76
+ end
77
+
78
+ # @private
79
+ def eql?(other)
80
+ other.is_a?(Statement) && \
81
+ @statement == other.statement && \
82
+ @parameters == other.parameters && \
83
+ @options == other.options && \
84
+ @idempotent == other.idempotent?
85
+ end
86
+ alias == eql?
87
+
88
+ # @private
89
+ def hash
90
+ @hash ||= begin
91
+ h = 17
92
+ h = 31 * h + @statement.hash
93
+ h = 31 * h + @parameters.hash
94
+ h = 31 * h + @options.hash
95
+ h = 31 * h + @idempotent.hash
96
+ h
97
+ end
98
+ end
99
+
100
+ # @private
101
+ def inspect
102
+ "#<Dse::Graph::Statement:0x#{object_id.to_s(16)} " \
103
+ "@statement=#{@statement.inspect}, " \
104
+ "@parameters=#{@parameters.inspect}, " \
105
+ "@options=#{@options.inspect}, " \
106
+ "@idempotent=#{@idempotent.inspect}>"
107
+ end
108
+
109
+ protected
110
+
111
+ # @private
112
+ def method_missing(method, *args, &block)
113
+ # Delegate unrecognized method calls to our embedded statement.
114
+ @simple_statement.send(method, *args, &block)
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,107 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright (C) 2016 DataStax Inc.
5
+ #
6
+ # This software can be used solely with DataStax Enterprise. Please consult the license at
7
+ # http://www.datastax.com/terms/datastax-dse-driver-license-terms
8
+ #++
9
+
10
+ module Dse
11
+ module Graph
12
+ # Vertex represents a vertex in DSE graph. Vertices have sophisticated properties. A given property can have
13
+ # multiple values, and each value can have a collection of meta-properties. To access a property of a vertex, you'd
14
+ # reference the {#properties} hash, and then get the n'th value, which is a {VertexProperty}, and then get the
15
+ # actual value from there.
16
+ # @example To get the first value of the 'name' property:
17
+ # v.properties['name'][0].value
18
+ # @example Use array/hash dereference shortcut
19
+ # v['name'][0].value
20
+ # @example Get all of the values of the 'name' property
21
+ # values = v['name'].map do |vertex_prop|
22
+ # vertex_prop.value
23
+ # end
24
+ # @example Use the 'values' method on the array to do the heavy-lifting for you.
25
+ # values = v['name'].values
26
+ # @example VertexProperty exposes meta-properties for a value:
27
+ # meta1 = v['name'][0].properties['meta1']
28
+ # # Shortcut
29
+ # meta1 = v['name'][0]['meta1']
30
+ class Vertex
31
+ include Cassandra::Util
32
+
33
+ # @return [Hash] id of this vertex.
34
+ attr_reader :id
35
+ # @return [String] label of this vertex.
36
+ attr_reader :label
37
+ # @return [Hash<String, Array<VertexProperty>>] properties of this vertex.
38
+ attr_reader :properties
39
+
40
+ # @private
41
+ def initialize(id, label, properties)
42
+ @id = id
43
+ @label = label
44
+
45
+ # Vertex properties are structured like this:
46
+ # { 'name' => [
47
+ # { 'id' => {... }, 'value' => 'some_val', 'properties' => { 'key' => 'value' } },
48
+ # { 'id' => {... }, 'value' => 'some_val2', 'properties' => { 'key2' => 'value2' } }
49
+ # ], 'age' => [........], .... }
50
+ #
51
+ # When storing in @properties, we convert it to use VertexProperty's:
52
+ # { 'name' => [
53
+ # vertex_prop1,
54
+ # vertex_prop2
55
+ # ], 'age' => [........], .... }
56
+ #
57
+ # With that structure, we'll support syntactic sugar that lets users get to properties and meta-properties
58
+ # more easily:
59
+ #
60
+ # v['name'][0].value -- get the first value of the 'name' property.
61
+ # v['name'][0]['key'] -- get the value of the 'key' meta-property of the first name property.
62
+
63
+ @properties = {}
64
+ properties.each do |prop_name, values|
65
+ vertex_props = values.map do |v|
66
+ VertexProperty.new(v)
67
+ end
68
+
69
+ # Add a 'values' method to the array to get the values of each prop
70
+ # in one array.
71
+ def vertex_props.values
72
+ map(&:value)
73
+ end
74
+
75
+ @properties[prop_name] = vertex_props
76
+ end
77
+ end
78
+
79
+ # @private
80
+ def [](key)
81
+ @properties[key]
82
+ end
83
+
84
+ # @private
85
+ def eql?(other)
86
+ # id's are unique among graph objects, so we only need to compare id's to test for equality.
87
+ other.is_a?(Vertex) && \
88
+ @id == other.id
89
+ end
90
+ alias == eql?
91
+
92
+ # @private
93
+ def hash
94
+ # id's are unique among graph objects, so we only need to hash on the id for safely adding to a hash/set.
95
+ @hash ||= 31 * 17 + @id.hash
96
+ end
97
+
98
+ # @private
99
+ def inspect
100
+ "#<Dse::Graph::Vertex:0x#{object_id.to_s(16)} " \
101
+ "@id=#{@id.inspect}, " \
102
+ "@label=#{@label.inspect}, " \
103
+ "@properties=#{@properties.inspect}>"
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright (C) 2016 DataStax Inc.
5
+ #
6
+ # This software can be used solely with DataStax Enterprise. Please consult the license at
7
+ # http://www.datastax.com/terms/datastax-dse-driver-license-terms
8
+ #++
9
+
10
+ module Dse
11
+ module Graph
12
+ # Encapsulates a vertex-property complex value. The name of the property is stored in the owning
13
+ # {Vertex}. This object contains a simple property value and any meta-properties that go with it.
14
+ #
15
+ # VertexProperty's are created when creating a Vertex object out of a graph query result hash. Access
16
+ # to meta-properties is done via the {#properties} attribute, but there is also a short-cut using
17
+ # array/hash dereference syntax:
18
+ # @example
19
+ # val = vp.properties['meta1']
20
+ # # is the same as
21
+ # val = vp['meta1']
22
+ class VertexProperty
23
+ # @return [Hash] id of this property
24
+ attr_reader :id
25
+ # @return [String] value of this property
26
+ attr_reader :value
27
+ # @return [Hash<String, String>] meta-properties of this property
28
+ attr_reader :properties
29
+
30
+ # @private
31
+ def initialize(vertex_property_hash)
32
+ # Vertex properties have three attributes: id, value, properties. Pull those out of the hash.
33
+ @id = vertex_property_hash['id']
34
+ @value = vertex_property_hash['value']
35
+ @properties = vertex_property_hash.fetch('properties', {})
36
+ end
37
+
38
+ # @private
39
+ def [](key)
40
+ @properties[key]
41
+ end
42
+
43
+ # @private
44
+ def eql?(other)
45
+ # id's are unique among graph objects, so we only need to compare id's to test for equality.
46
+ other.is_a?(VertexProperty) && \
47
+ @id == other.id
48
+ end
49
+ alias == eql?
50
+
51
+ # @private
52
+ def hash
53
+ # id's are unique among graph objects, so we only need to hash on the id for safely adding to a hash/set.
54
+ @hash ||= 31 * 17 + @id.hash
55
+ end
56
+
57
+ # @private
58
+ def inspect
59
+ "#<Dse::Graph::VertexProperty:0x#{object_id.to_s(16)} " \
60
+ "@id=#{@id.inspect}, " \
61
+ "@value=#{@value.inspect}, " \
62
+ "@properties=#{@properties.inspect}>"
63
+ end
64
+ end
65
+ end
66
+ end