dse-driver 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/dse/graph.rb ADDED
@@ -0,0 +1,18 @@
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
+ require 'dse/graph/edge'
11
+ require 'dse/graph/options'
12
+ require 'dse/graph/path'
13
+ require 'dse/graph/result'
14
+ require 'dse/graph/result_set'
15
+ require 'dse/graph/statement'
16
+ require 'dse/graph/vertex'
17
+ require 'dse/graph/vertex_property'
18
+ require 'dse/graph/duration'
@@ -0,0 +1,131 @@
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
+ # Represents a duration of time, corresponding to the Duration datatype in DSE Graph. In DSE Graph,
13
+ # this type is represented by the
14
+ # {https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html Java 8 Duration} type.
15
+ class Duration
16
+ # Days in duration of time. May be negative. Is internally coerced to an integer,
17
+ # so a value being assigned need not be an `Integer` itself.
18
+ # @return [Integer] days in duration of time.
19
+ attr_reader :days
20
+
21
+ # Hours in duration of time. May be negative. Is internally coerced to an integer,
22
+ # so a value being assigned need not be an `Integer` itself.
23
+ # @return [Integer] hours in duration of time.
24
+ attr_reader :hours
25
+
26
+ # Minutes in duration of time. May be negative. Is internally coerced to an integer,
27
+ # so a value being assigned need not be an `Integer` itself.
28
+ # @return [Integer] minutes in duration of time.
29
+ attr_reader :minutes
30
+
31
+ # Seconds in duration of time. May be negative. Is internally coerced to an float,
32
+ # so a value being assigned need not be an `Float` itself.
33
+ # @return [Float] seconds in duration of time.
34
+ attr_reader :seconds
35
+
36
+ # @private
37
+ # We expect a string of the form PnDTnHnMn.nS, where n's are positive or negative integers, and where
38
+ # components may be missing (e.g. PT7.8S is valid)
39
+ PAT = /^P((?<days>-?\d+)D)?T((?<hours>-?\d+)H)?((?<minutes>-?\d+)M)?((?<seconds>-?[0-9.]+)S)?$/
40
+
41
+ # Create a {Duration} object. All arguments are internally coerced to desired types.
42
+ # @param days [Integer] number of days in the time-frame. May be negative.
43
+ # @param hours [Integer] number of hours in the time-frame. May be negative.
44
+ # @param minutes [Integer] number of minutes in the time-frame. May be negative.
45
+ # @param seconds [Float] number of seconds in the time-frame. May be negative.
46
+ def initialize(days, hours, minutes, seconds)
47
+ @days = days.to_i
48
+ @hours = hours.to_i
49
+ @minutes = minutes.to_i
50
+ @seconds = seconds.to_f
51
+ end
52
+
53
+ def days=(days)
54
+ @days = days.to_i
55
+ end
56
+
57
+ def hours=(hours)
58
+ @hours = hours.to_i
59
+ end
60
+
61
+ def minutes=(minutes)
62
+ @minutes = minutes.to_i
63
+ end
64
+
65
+ def seconds=(seconds)
66
+ @seconds = seconds.to_f
67
+ end
68
+
69
+ # Parse a duration string from DSE Graph and construct a {Duration} object
70
+ # @param duration [String] duration string from DSE Graph.
71
+ # @raise [ArgumentError] if the duration string fails to parse.
72
+ def self.parse(duration)
73
+ parse_result = PAT.match(duration.to_s)
74
+ raise(ArgumentError,
75
+ "Failed to parse '#{duration}': expected format PnDTnHnMn.nS with integer n" \
76
+ ' and optionally missing duration components') unless parse_result
77
+ Duration.new(parse_result[:days], parse_result[:hours], parse_result[:minutes], parse_result[:seconds])
78
+ end
79
+
80
+ # A string formatted as `PnDTnHnMn.nS`, where `n` is a number that goes with the character code following it.
81
+ #
82
+ # D - days<br>
83
+ # H - hours<br>
84
+ # M - minutes<br>
85
+ # S - seconds<br>
86
+ #
87
+ # @example a duration of 1 day, 2 hours, 3 minutes, 4.5 seconds
88
+ # P1DT2H3M4.5S
89
+ # @return [String] this {Duration} as a string formatted `PnDTnHnMn.nS`.
90
+ #
91
+ # @see https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html#parse-java.lang.CharSequence-
92
+ # Java 8 Duration#parse
93
+ def to_s
94
+ # Construct a string of the form PnDTnHnMn.nS
95
+ "P#{@days}DT#{@hours}H#{@minutes}M#{@seconds}S"
96
+ end
97
+
98
+ # @private
99
+ def eql?(other)
100
+ other.is_a?(Duration) && as_seconds == other.as_seconds
101
+ end
102
+ alias == eql?
103
+
104
+ # @return [Float] this {Duration} object converted to seconds
105
+ def as_seconds
106
+ @seconds + @minutes * 60 + @hours * 3600 + @days * 86400
107
+ end
108
+
109
+ # @private
110
+ def hash
111
+ @hash ||= begin
112
+ h = 17
113
+ h = 31 * h + @days.hash
114
+ h = 31 * h + @hours.hash
115
+ h = 31 * h + @minutes.hash
116
+ h = 31 * h + @seconds.hash
117
+ h
118
+ end
119
+ end
120
+
121
+ # @private
122
+ def inspect
123
+ "#<Duration:0x#{object_id.to_s(16)} " \
124
+ "@days=#{@days.inspect}, " \
125
+ "@hours=#{@hours.inspect}, " \
126
+ "@minutes=#{@minutes.inspect}, " \
127
+ "@seconds=#{@seconds.inspect}>"
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,74 @@
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
+ # Edge represents an edge in DSE graph. An edge connects two vertices.
13
+ class Edge
14
+ include Cassandra::Util
15
+
16
+ # @return [Hash] id of this edge
17
+ attr_reader :id
18
+ # @return [String] label of this edge
19
+ attr_reader :label
20
+ # @return [Hash<String, String>] properties of this edge
21
+ attr_reader :properties
22
+ # @return [String] id of the "to" vertex of the edge
23
+ attr_reader :in_v
24
+ # @return [String] label of the "to" vertex of the edge
25
+ attr_reader :in_v_label
26
+ # @return [String] id of the "from" vertex of the edge
27
+ attr_reader :out_v
28
+ # @return [String] label of the "from" vertex of the edge
29
+ attr_reader :out_v_label
30
+
31
+ # @private
32
+ def initialize(id, label, properties, in_v, in_v_label, out_v, out_v_label)
33
+ @id = id
34
+ @label = label
35
+ @properties = properties
36
+ @in_v = in_v
37
+ @in_v_label = in_v_label
38
+ @out_v = out_v
39
+ @out_v_label = out_v_label
40
+ end
41
+
42
+ # @private
43
+ def [](key)
44
+ @properties[key]
45
+ end
46
+
47
+ # @private
48
+ def eql?(other)
49
+ # id's are unique among graph objects, so we only need to compare id's to test for equality.
50
+ other.is_a?(Edge) && \
51
+ @id == other.id
52
+ end
53
+ alias == eql?
54
+
55
+ # @private
56
+ def hash
57
+ # id's are unique among graph objects, so we only need to hash on the id for safely adding to a hash/set.
58
+ @hash ||= 31 * 17 + @id.hash
59
+ end
60
+
61
+ # @private
62
+ def inspect
63
+ "#<Dse::Graph::Edge:0x#{object_id.to_s(16)} " \
64
+ "@id=#{@id.inspect}, " \
65
+ "@label=#{@label.inspect}, " \
66
+ "@properties=#{@properties.inspect}, " \
67
+ "@in_v=#{@in_v.inspect}, " \
68
+ "@in_v_label=#{@in_v_label.inspect}, " \
69
+ "@out_v=#{@out_v.inspect}, " \
70
+ "@out_v_label=#{@out_v_label.inspect}>"
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,194 @@
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
+ # @!parse
13
+ # class Options
14
+ # # @return [String] name of the targeted graph; required unless the statement is a system query.
15
+ # attr_accessor :graph_name
16
+ # # @return [String] graph traversal source (default "g")
17
+ # attr_accessor :graph_source
18
+ # # @return [String] language used in the graph statement (default "gremlin-groovy")
19
+ # attr_accessor :graph_language
20
+ # # @return [Cassandra::CONSISTENCIES] read consistency level for graph statement.
21
+ # # Overrides the standard statement consistency level. Defaults to ONE in the server,
22
+ # # but the default may be configured differently.
23
+ # attr_accessor :graph_read_consistency
24
+ # # @return [Cassandra::CONSISTENCIES] write consistency level for graph statement.
25
+ # # Overrides the standard statement consistency level. Defaults to QUORUM in the server,
26
+ # # but the default may be configured differently.
27
+ # attr_accessor :graph_write_consistency
28
+ # end
29
+
30
+ # Options for DSE Graph queries
31
+ class Options
32
+ # @return [Numeric] the timeout for graph requests
33
+ attr_reader :timeout
34
+
35
+ # @private
36
+ DEFAULT_GRAPH_OPTIONS = {
37
+ 'graph-source' => 'g',
38
+ 'graph-language' => 'gremlin-groovy'
39
+ }.freeze
40
+
41
+ # @private
42
+ OPTION_NAMES = [
43
+ :graph_name,
44
+ :graph_source,
45
+ :graph_language,
46
+ :graph_read_consistency,
47
+ :graph_write_consistency
48
+ ].freeze
49
+
50
+ # Create an Options object.
51
+ # @param options [Hash] optional hash containing graph options. Keys are option name symbols
52
+ # (e.g. `:graph_name`). Unset options will inherit from the defaults.
53
+ def initialize(options = {})
54
+ # Filter the given options to only those we care about.
55
+ @real_options = {}
56
+ return unless options
57
+
58
+ options.each do |k, v|
59
+ set(k, v) if OPTION_NAMES.include?(k)
60
+ end
61
+
62
+ set_timeout(options[:timeout])
63
+ end
64
+
65
+ OPTION_NAMES.each do |attr|
66
+ define_method(attr.to_s) do
67
+ @real_options[stringify(attr)]
68
+ end
69
+
70
+ define_method("#{attr}=") do |value|
71
+ @real_options[stringify(attr)] = value
72
+ end
73
+ end
74
+
75
+ # @private
76
+ def timeout=(val)
77
+ set_timeout(val)
78
+ val
79
+ end
80
+
81
+ # @private
82
+ # rubocop:disable Style/AccessorMethodName
83
+ def set_timeout(new_timeout)
84
+ @timeout = new_timeout
85
+ if @timeout
86
+ @real_options['request-timeout'] = [@timeout * 1000].pack('Q>')
87
+ else
88
+ @real_options.delete('request-timeout')
89
+ end
90
+ nil
91
+ end
92
+
93
+ # Set an option in this {Options} object. This is primarily used to set "expert" options that
94
+ # are not part of the public api and thus may change over time.
95
+ # @param key [String, Symbol] option to set.
96
+ # @param value [String] value to set for the option.
97
+ # @return [Options] self, thus allowing method chaining.
98
+ def set(key, value)
99
+ string_key = stringify(key)
100
+ if string_key == 'timeout'
101
+ set_timeout(value)
102
+ elsif value
103
+ @real_options[stringify(key)] = value
104
+ end
105
+ self
106
+ end
107
+
108
+ # Delete an option from this {Options} object.
109
+ # @param key [String, Symbol] option to delete.
110
+ # @return nil
111
+ def delete(key)
112
+ string_key = stringify(key)
113
+ if string_key == 'timeout'
114
+ @timeout = nil
115
+ @real_options.delete('request-timeout')
116
+ else
117
+ @real_options.delete(string_key)
118
+ end
119
+ nil
120
+ end
121
+
122
+ # Merge another {Options} object with this one to produce a new merged {Options} object.
123
+ # The "other" object's values take precedence over this one.
124
+ # @param other [Options] Options object to merge with this one.
125
+ # @return [Options] new Options object with the merged options.
126
+ def merge(other)
127
+ # Just return our-self (no need to copy) if we're merging in nothing.
128
+ return self if other.nil?
129
+
130
+ # This is fairly efficient, but manipulates the guts of an Options object.
131
+ result = Options.new
132
+ result.instance_variable_set(:@real_options,
133
+ @real_options.merge(other.instance_variable_get(:@real_options)))
134
+ other_timeout = other.instance_variable_get(:@timeout)
135
+ result.instance_variable_set(:@timeout,
136
+ other_timeout ? other_timeout : @timeout)
137
+ result
138
+ end
139
+
140
+ # Clear the options within this {Options} object.
141
+ def clear
142
+ @real_options.clear
143
+ @timeout = nil
144
+ end
145
+
146
+ # @private
147
+ def stringify(attr)
148
+ attr.to_s.tr('_', '-')
149
+ end
150
+
151
+ # @private
152
+ def merge!(other)
153
+ result = merge(other)
154
+ @real_options = result.instance_variable_get(:@real_options)
155
+ @timeout = result.instance_variable_get(:@timeout)
156
+ self
157
+ end
158
+
159
+ # @return whether or not this options object is configured for the analytics graph source.
160
+ def analytics?
161
+ @real_options['graph-source'] == 'a'
162
+ end
163
+
164
+ # @private
165
+ def as_payload
166
+ # Merge in real options with defaults to get a final payload
167
+ DEFAULT_GRAPH_OPTIONS.merge(@real_options)
168
+ end
169
+
170
+ # @private
171
+ def eql?(other)
172
+ other.is_a?(Options) && \
173
+ @real_options == other.instance_variable_get(:@real_options)
174
+ end
175
+ alias == eql?
176
+
177
+ # @private
178
+ def hash
179
+ @hash ||= 31 * 17 + @real_options.hash
180
+ end
181
+
182
+ # @private
183
+ def inspect
184
+ "#<Dse::Graph::Options:0x#{object_id.to_s(16)} " \
185
+ "@graph_name=#{@real_options['graph-name'].inspect}, " \
186
+ "@graph_source=#{@real_options['graph-source'].inspect}, " \
187
+ "@graph_language=#{@real_options['graph-language'].inspect}, " \
188
+ "@graph_read_consistency=#{@real_options['graph-read-consistency'].inspect}, " \
189
+ "@graph_write_consistency=#{@real_options['graph-write-consistency'].inspect}, " \
190
+ "@timeout=#{@timeout.inspect}>"
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,54 @@
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
+ # Path represents a path connecting a set of vertices.
13
+ class Path
14
+ # @return [Array<Array>] labels in the path
15
+ attr_reader :labels
16
+ # @return [Array<Vertex, Edge, Result>] objects in the path, coerced to domain objects that
17
+ # we recognize, or a {Result} otherwise
18
+ attr_reader :objects
19
+
20
+ # @private
21
+ def initialize(labels, objects)
22
+ @labels = labels
23
+ @objects = objects.map do |o|
24
+ Result.new(o).cast
25
+ end
26
+ end
27
+
28
+ # @private
29
+ def eql?(other)
30
+ other.is_a?(Path) && \
31
+ @labels == other.labels && \
32
+ @objects == other.objects
33
+ end
34
+ alias == eql?
35
+
36
+ # @private
37
+ def hash
38
+ @hash ||= begin
39
+ h = 17
40
+ h = 31 * h + @labels.hash
41
+ h = 31 * h + @objects.hash
42
+ h
43
+ end
44
+ end
45
+
46
+ # @private
47
+ def inspect
48
+ "#<Dse::Graph::Path:0x#{object_id.to_s(16)} " \
49
+ "@labels=#{@labels.inspect}, " \
50
+ "@objects=#{@objects.inspect}>"
51
+ end
52
+ end
53
+ end
54
+ end