dse-driver 1.0.1

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.
@@ -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