grumlin 0.21.0 → 0.21.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bb67bbe2eff3a7fd02cce19c6052fa70e3f54f3ec2cb06102667f69e43d07e8d
4
- data.tar.gz: 1ecf0285f60fab6fd93bd0b36bfe58c39b94eebf0ead055f6f3cc4f2e9f8b19d
3
+ metadata.gz: 95963424bb38728bb21c2d3746a93be60daf303b2c2897b24d99684fd1fb7bff
4
+ data.tar.gz: 809b4b589b2bc5fd8687f0f63a6f73f17aab82060990b3a5942164c2ac92ef83
5
5
  SHA512:
6
- metadata.gz: '05263993fc271810fd493ae3d5fdd8d84b6b698a8d9a4e4a4c336b09858571b156971b6f3def4bdb2d9c3743b07bebeb40eb1c426e4c316a8aa4a87b264f15b5'
7
- data.tar.gz: 78fc706c4694146ff2b5fedc75b1d0186dca152fc9f2731c1b6936ea906e6410077c95871fba8b4c302f375cc8b28afffa37ccb59097a88470e266c4f26e6c51
6
+ metadata.gz: b095f3958ebf4b70577e607a0b10e27fc073055fe08d6fe55787c71fd104e77cf78cdcd0a54d06e7881c9183cab479ef6e92e6117a1c1b418945d1ebb417655c
7
+ data.tar.gz: 0477a8ce8ccfc5ea1cc3b95b7b48501b05387207918478adc4eecb8e286e8495910b6bd718e1d5c00ab63e61e02ca6e89212913ec35d8df49b267cb75281e9eb
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- grumlin (0.21.0)
4
+ grumlin (0.21.1)
5
5
  async-pool (~> 0.3)
6
6
  async-websocket (~> 0.19)
7
7
  oj (~> 3.13)
@@ -21,11 +21,11 @@ GEM
21
21
  console (~> 1.10)
22
22
  nio4r (~> 2.3)
23
23
  timers (~> 4.1)
24
- async-http (0.56.6)
24
+ async-http (0.57.0)
25
25
  async (>= 1.25)
26
26
  async-io (>= 1.28)
27
27
  async-pool (>= 0.2)
28
- protocol-http (~> 0.22.0)
28
+ protocol-http (~> 0.23.1)
29
29
  protocol-http1 (~> 0.14.0)
30
30
  protocol-http2 (~> 0.14.0)
31
31
  traces (~> 0.4.0)
@@ -37,7 +37,7 @@ GEM
37
37
  rspec (~> 3.0)
38
38
  rspec-files (~> 1.0)
39
39
  rspec-memory (~> 1.0)
40
- async-websocket (0.19.0)
40
+ async-websocket (0.19.2)
41
41
  async-http (~> 0.54)
42
42
  async-io (~> 1.23)
43
43
  protocol-websocket (~> 0.7.0)
@@ -72,7 +72,7 @@ GEM
72
72
  racc (~> 1.4)
73
73
  nokogiri (1.13.6-x86_64-linux)
74
74
  racc (~> 1.4)
75
- oj (3.13.18)
75
+ oj (3.13.20)
76
76
  overcommit (0.59.1)
77
77
  childprocess (>= 0.6.3, < 5)
78
78
  iniparse (~> 1.4)
@@ -81,7 +81,7 @@ GEM
81
81
  parser (3.1.2.0)
82
82
  ast (~> 2.4.1)
83
83
  protocol-hpack (1.4.2)
84
- protocol-http (0.22.6)
84
+ protocol-http (0.23.1)
85
85
  protocol-http1 (0.14.4)
86
86
  protocol-http (~> 0.22)
87
87
  protocol-http2 (0.14.2)
data/README.md CHANGED
@@ -46,9 +46,33 @@ Or install it yourself as:
46
46
  ```ruby
47
47
  Grumlin.configure do |config|
48
48
  config.url = "ws://localhost:8182/gremlin"
49
+
50
+ # make sure you select right provider for better compatibility
51
+ config.provider = :tinkergraph
49
52
  end
50
53
  ```
51
54
 
55
+ #### Providers
56
+
57
+ Currently `Grumlin` supports 2 providers:
58
+ - tinkergraph (default)
59
+ - neptune
60
+
61
+ As different providers may have or may have not support for specific features it's recommended to
62
+ explicitly specify the provider you use.
63
+
64
+ #### Provider features
65
+
66
+ Every provider is described by a set of features. In the future `Grumlin` may decide to disable or enable
67
+ some parts of it's functionality to comply provider's supported features. Currently there is no difference
68
+ in behaviour when working with different providers.
69
+
70
+ To check current providers supported features use
71
+
72
+ ```ruby
73
+ Grumlin.features
74
+ ```
75
+
52
76
  ### Traversing graphs
53
77
 
54
78
  **Warning**: Not all steps and expressions defined in the reference documentation are supported.
@@ -4,14 +4,15 @@ module Grumlin
4
4
  class Action < Steppable
5
5
  attr_reader :name, :args, :params, :next_step, :configuration_steps, :previous_step, :shortcut
6
6
 
7
- def initialize(name, args: [], params: {}, previous_step: nil, pool: nil)
8
- super()
7
+ # client is only used when a traversal is a part of transaction
8
+ def initialize(name, args: [], params: {}, previous_step: nil, pool: Grumlin.default_pool, session_id: nil)
9
+ super(pool: pool, session_id: session_id)
10
+
9
11
  @name = name.to_sym
10
12
  @args = args # TODO: add recursive validation: only json types or Action
11
13
  @params = params # TODO: add recursive validation: only json types
12
14
  @previous_step = previous_step
13
15
  @shortcut = shortcuts[@name]
14
- @pool = pool || Grumlin.default_pool
15
16
  end
16
17
 
17
18
  def configuration_step?
@@ -73,14 +74,18 @@ module Grumlin
73
74
  end
74
75
 
75
76
  def toList
76
- @pool.acquire do |client|
77
- client.write(bytecode)
78
- end
77
+ client_write(bytecode)
79
78
  end
80
79
 
81
80
  def iterate
81
+ client_write(bytecode(no_return: true))
82
+ end
83
+
84
+ private
85
+
86
+ def client_write(payload)
82
87
  @pool.acquire do |client|
83
- client.write(bytecode(no_return: true))
88
+ client.write(payload, session_id: @session_id)
84
89
  end
85
90
  end
86
91
  end
@@ -24,8 +24,14 @@ module Grumlin
24
24
  @client.close
25
25
  end
26
26
 
27
- def write(bytecode)
28
- @client.write(bytecode)
27
+ def write(bytecode, session_id: nil)
28
+ @client.write(bytecode, session_id: session_id)
29
+ ensure
30
+ @count += 1
31
+ end
32
+
33
+ def finalize_tx(action, session_id)
34
+ @client.finalize_tx(action, session_id)
29
35
  ensure
30
36
  @count += 1
31
37
  end
@@ -94,19 +100,19 @@ module Grumlin
94
100
  end
95
101
 
96
102
  # TODO: support yielding
97
- def write(bytecode)
103
+ def write(bytecode, session_id: nil)
98
104
  raise NotConnectedError unless connected?
99
105
 
100
- request = to_query(bytecode)
101
- channel = @request_dispatcher.add_request(request)
102
- @transport.write(request)
106
+ request = to_query(bytecode, session_id: session_id)
107
+ submit_request(request)
108
+ end
103
109
 
104
- begin
105
- channel.dequeue.flat_map { |item| Typing.cast(item) }
106
- rescue Async::Stop, Async::TimeoutError
107
- close(check_requests: false)
108
- raise
109
- end
110
+ def finalize_tx(action, session_id)
111
+ raise NotConnectedError unless connected?
112
+ raise ArgumentError, "session_id cannot be nil" if session_id.nil?
113
+
114
+ request = finalize_tx_query(action, session_id)
115
+ submit_request(request)
110
116
  end
111
117
 
112
118
  def inspect
@@ -119,20 +125,52 @@ module Grumlin
119
125
 
120
126
  private
121
127
 
128
+ def submit_request(request)
129
+ channel = @request_dispatcher.add_request(request)
130
+ @transport.write(request)
131
+
132
+ begin
133
+ channel.dequeue.flat_map { |item| Typing.cast(item) }
134
+ rescue Async::Stop, Async::TimeoutError
135
+ close(check_requests: false)
136
+ raise
137
+ end
138
+ end
139
+
122
140
  # This might be overridden in successors
123
141
  def build_transport
124
142
  Transport.new(@url, parent: @parent, **@client_options)
125
143
  end
126
144
 
127
- def to_query(bytecode)
145
+ def to_query(bytecode, session_id:)
146
+ {
147
+ requestId: SecureRandom.uuid,
148
+ op: :bytecode,
149
+ processor: session_id ? :session : :traversal,
150
+ args: {
151
+ gremlin: {
152
+ :@type => "g:Bytecode",
153
+ :@value => bytecode.serialize
154
+ },
155
+ aliases: { g: :g },
156
+ session: session_id
157
+ }.compact
158
+ }
159
+ end
160
+
161
+ def finalize_tx_query(action, session_id)
128
162
  {
129
163
  requestId: SecureRandom.uuid,
130
- op: "bytecode",
131
- processor: "traversal",
164
+ op: :bytecode,
165
+ processor: session_id ? :session : :traversal,
132
166
  args: {
133
- gremlin: { :@type => "g:Bytecode", :@value => bytecode.serialize },
134
- aliases: { g: :g }
135
- }
167
+ gremlin: {
168
+ :@type => "g:Bytecode",
169
+ :@value => { source: [[:tx, action]] }
170
+ },
171
+ aliases: { g: :g },
172
+ session: session_id
173
+ }.compact
136
174
  }
137
175
  end
138
176
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grumlin
4
+ class Config
5
+ attr_accessor :url, :pool_size, :client_concurrency, :client_factory, :provider
6
+
7
+ SUPPORTED_PROVIDERS = %i[neptune tinkergraph].freeze
8
+
9
+ class ConfigurationError < Grumlin::Error; end
10
+
11
+ class UnknownProviderError < ConfigurationError; end
12
+
13
+ def initialize
14
+ @pool_size = 10
15
+ @client_concurrency = 5
16
+ @provider = :tinkergraph
17
+ @client_factory = ->(url, parent) { Grumlin::Client.new(url, parent: parent) }
18
+ end
19
+
20
+ def validate!
21
+ return if SUPPORTED_PROVIDERS.include?(provider.to_sym)
22
+
23
+ raise UnknownProviderError, "provider '#{provider}' is unknown. Supported providers: #{SUPPORTED_PROVIDERS}"
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grumlin
4
+ module Features
5
+ class FeatureList
6
+ def user_supplied_ids?
7
+ raise(NotImplementedError) if @user_supplied_ids.nil?
8
+
9
+ @user_supplied_ids
10
+ end
11
+
12
+ def supports_transactions?
13
+ raise(NotImplementedError) if @supports_transactions.nil?
14
+
15
+ @supports_transactions
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grumlin
4
+ module Features
5
+ class NeptuneFeatures < FeatureList
6
+ def initialize
7
+ super
8
+ @user_supplied_ids = true
9
+ @supports_transactions = true
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grumlin
4
+ module Features
5
+ class TinkergraphFeatures < FeatureList
6
+ def initialize
7
+ super
8
+ @user_supplied_ids = true
9
+ @supports_transactions = false
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grumlin
4
+ module Features
5
+ class << self
6
+ FEATURES = {
7
+ neptune: NeptuneFeatures.new,
8
+ tinkergraph: TinkergraphFeatures.new
9
+ }.freeze
10
+
11
+ def for(provider)
12
+ FEATURES[provider]
13
+ end
14
+ end
15
+ end
16
+ end
@@ -8,7 +8,7 @@ module Grumlin
8
8
  extend Forwardable
9
9
 
10
10
  UPSERT_RETRY_PARAMS = {
11
- on: [Grumlin::AlreadyExistsError, Grumlin::ConcurrentInsertFailedError],
11
+ on: [Grumlin::AlreadyExistsError, Grumlin::ConcurrentModificationError],
12
12
  sleep_method: ->(n) { Async::Task.current.sleep(n) },
13
13
  tries: 3,
14
14
  sleep: ->(n) { (n**2) + 1 + rand }
@@ -10,23 +10,6 @@ module Grumlin
10
10
  206 => :partial_content
11
11
  }.freeze
12
12
 
13
- ERRORS = {
14
- 499 => InvalidRequestArgumentsError,
15
- 500 => ServerError,
16
- 597 => ScriptEvaluationError,
17
- 599 => ServerSerializationError,
18
- 598 => ServerTimeoutError,
19
-
20
- 401 => ClientSideError,
21
- 407 => ClientSideError,
22
- 498 => ClientSideError
23
- }.freeze
24
-
25
- VERTEX_ALREADY_EXISTS = "Vertex with id already exists:"
26
- EDGE_ALREADY_EXISTS = "Edge with id already exists:"
27
- CONCURRENT_VERTEX_INSERT_FAILED = "Failed to complete Insert operation for a Vertex due to conflicting concurrent"
28
- CONCURRENT_EDGE_INSERT_FAILED = "Failed to complete Insert operation for an Edge due to conflicting concurrent"
29
-
30
13
  class DispatcherError < Grumlin::Error; end
31
14
 
32
15
  class RequestAlreadyAddedError < DispatcherError; end
@@ -47,14 +30,16 @@ module Grumlin
47
30
 
48
31
  # builds a response object, when it's ready sends it to the client via a channel
49
32
  # TODO: sometimes response does not include requestID, no idea how to handle it so far.
50
- def add_response(response) # rubocop:disable Metrics/AbcSize
33
+ def add_response(response) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
51
34
  request_id = response[:requestId]
52
35
  raise UnknownRequestError unless ongoing_request?(request_id)
53
36
 
54
37
  begin
55
38
  request = @requests[request_id]
56
39
 
57
- check_errors!(response[:status], request[:request])
40
+ RequestErrorFactory.build(request, response).tap do |err|
41
+ raise err unless err.nil?
42
+ end
58
43
 
59
44
  case SUCCESS[response.dig(:status, :code)]
60
45
  when :success
@@ -91,29 +76,5 @@ module Grumlin
91
76
  request = @requests.delete(request_id)
92
77
  request[:channel].close
93
78
  end
94
-
95
- def check_errors!(status, query)
96
- if (error = ERRORS[status[:code]])
97
- raise (
98
- already_exists_error(status) ||
99
- concurrent_insert_error(status) ||
100
- error
101
- ).new(status, query)
102
- end
103
-
104
- return unless SUCCESS[status[:code]].nil?
105
-
106
- raise(UnknownResponseStatus, status)
107
- end
108
-
109
- def already_exists_error(status)
110
- return VertexAlreadyExistsError if status[:message]&.include?(VERTEX_ALREADY_EXISTS)
111
- return EdgeAlreadyExistsError if status[:message]&.include?(EDGE_ALREADY_EXISTS)
112
- end
113
-
114
- def concurrent_insert_error(status)
115
- return ConcurrentVertexInsertFailedError if status[:message]&.include?(CONCURRENT_VERTEX_INSERT_FAILED)
116
- return ConcurrentEdgeInsertFailedError if status[:message]&.include?(CONCURRENT_EDGE_INSERT_FAILED)
117
- end
118
79
  end
119
80
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grumlin
4
+ class RequestErrorFactory
5
+ ERRORS = {
6
+ 499 => InvalidRequestArgumentsError,
7
+ 500 => ServerError,
8
+ 597 => ScriptEvaluationError,
9
+ 599 => ServerSerializationError,
10
+ 598 => ServerTimeoutError,
11
+
12
+ 401 => ClientSideError,
13
+ 407 => ClientSideError,
14
+ 498 => ClientSideError
15
+ }.freeze
16
+
17
+ # Neptune presumably returns message as a JSON string of format
18
+ # {"detailedMessage":"",
19
+ # "requestId":"UUID",
20
+ # "code":"ConcurrentModificationException"}
21
+ # Currencly we simply search for substings to identify the exact error
22
+ # TODO: parse json and use `code` instead
23
+ VERTEX_ALREADY_EXISTS = "Vertex with id already exists:"
24
+ EDGE_ALREADY_EXISTS = "Edge with id already exists:"
25
+ CONCURRENT_VERTEX_INSERT_FAILED = "Failed to complete Insert operation for a Vertex due to conflicting concurrent"
26
+ CONCURRENT_EDGE_INSERT_FAILED = "Failed to complete Insert operation for an Edge due to conflicting concurrent"
27
+ CONCURRENCT_MODIFICATION_FAILED = "Failed to complete operation due to conflicting concurrent"
28
+
29
+ class << self
30
+ def build(request, response)
31
+ status = response[:status]
32
+ query = request[:request]
33
+
34
+ if (error = ERRORS[status[:code]])
35
+ return (
36
+ already_exists_error(status) ||
37
+ concurrent_modification_error(status) ||
38
+ error
39
+ ).new(status, query)
40
+ end
41
+
42
+ return unless RequestDispatcher::SUCCESS[status[:code]].nil?
43
+
44
+ UnknownResponseStatus.new(status)
45
+ end
46
+
47
+ def already_exists_error(status)
48
+ return VertexAlreadyExistsError if status[:message]&.include?(VERTEX_ALREADY_EXISTS)
49
+ return EdgeAlreadyExistsError if status[:message]&.include?(EDGE_ALREADY_EXISTS)
50
+ end
51
+
52
+ def concurrent_modification_error(status)
53
+ return ConcurrentVertexInsertFailedError if status[:message]&.include?(CONCURRENT_VERTEX_INSERT_FAILED)
54
+ return ConcurrentEdgeInsertFailedError if status[:message]&.include?(CONCURRENT_EDGE_INSERT_FAILED)
55
+ return ConcurrentModificationError if status[:message]&.include?(CONCURRENCT_MODIFICATION_FAILED)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -4,13 +4,18 @@ module Grumlin
4
4
  class Steppable
5
5
  extend Forwardable
6
6
 
7
+ attr_reader :session_id
8
+
7
9
  START_STEPS = Grumlin.definitions.dig(:steps, :start).map(&:to_sym).freeze
8
10
  REGULAR_STEPS = Grumlin.definitions.dig(:steps, :regular).map(&:to_sym).freeze
9
11
  CONFIGURATION_STEPS = Grumlin.definitions.dig(:steps, :configuration).map(&:to_sym).freeze
10
12
 
11
13
  ALL_STEPS = START_STEPS + CONFIGURATION_STEPS + REGULAR_STEPS
12
14
 
13
- def initialize
15
+ def initialize(pool: Grumlin.default_pool, session_id: nil)
16
+ @pool = pool
17
+ @session_id = session_id
18
+
14
19
  return if respond_to?(:shortcuts)
15
20
 
16
21
  raise "steppable must not be initialized directly, use Grumlin::Shortcuts::Storage#g or #__ instead"
@@ -18,12 +23,12 @@ module Grumlin
18
23
 
19
24
  ALL_STEPS.each do |step|
20
25
  define_method step do |*args, **params|
21
- shortcuts.action_class.new(step, args: args, params: params, previous_step: self)
26
+ shortcuts.action_class.new(step, args: args, params: params, previous_step: self, session_id: @session_id)
22
27
  end
23
28
  end
24
29
 
25
30
  def step(name, *args, **params)
26
- shortcuts.action_class.new(name, args: args, params: params, previous_step: self)
31
+ shortcuts.action_class.new(name, args: args, params: params, previous_step: self, session_id: @session_id)
27
32
  end
28
33
 
29
34
  def_delegator :shortcuts, :__
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grumlin
4
+ class Transaction
5
+ attr_reader :uuid
6
+
7
+ include Console
8
+
9
+ def initialize(traversal_start_class, pool: Grumlin.default_pool)
10
+ @traversal_start_class = traversal_start_class
11
+ @pool = pool
12
+
13
+ if supported?
14
+ @uuid = SecureRandom.uuid
15
+ return
16
+ end
17
+
18
+ logger.info(self) do
19
+ "#{Grumlin.config.provider} does not support transactions. commit and rollback are ignored, data will be saved"
20
+ end
21
+ end
22
+
23
+ def supported?
24
+ Grumlin.features.supports_transactions?
25
+ end
26
+
27
+ def begin
28
+ @traversal_start_class.new(session_id: @uuid)
29
+ end
30
+
31
+ def commit
32
+ return unless supported?
33
+
34
+ finalize(:commit)
35
+ end
36
+
37
+ def rollback
38
+ return unless supported?
39
+
40
+ finalize(:rollback)
41
+ end
42
+
43
+ private
44
+
45
+ def finalize(action)
46
+ @pool.acquire do |client|
47
+ client.finalize_tx(action, @uuid)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -4,6 +4,15 @@ module Grumlin
4
4
  class TraversalStart < Steppable
5
5
  include WithExtension
6
6
 
7
+ class TraversalError < Grumlin::Error; end
8
+ class AlreadyBoundToTransationError < TraversalError; end
9
+
10
+ def tx
11
+ raise AlreadyBoundToTransationError if @session_id
12
+
13
+ Transaction.new(self.class, pool: @pool)
14
+ end
15
+
7
16
  def to_s(*)
8
17
  self.class.to_s
9
18
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Grumlin
4
- VERSION = "0.21.0"
4
+ VERSION = "0.21.1"
5
5
  end
data/lib/grumlin.rb CHANGED
@@ -98,7 +98,8 @@ module Grumlin
98
98
  class VertexAlreadyExistsError < AlreadyExistsError; end
99
99
  class EdgeAlreadyExistsError < AlreadyExistsError; end
100
100
 
101
- class ConcurrentInsertFailedError < ServerError; end
101
+ class ConcurrentModificationError < ServerError; end
102
+ class ConcurrentInsertFailedError < ConcurrentModificationError; end
102
103
 
103
104
  class ConcurrentVertexInsertFailedError < ConcurrentInsertFailedError; end
104
105
  class ConcurrentEdgeInsertFailedError < ConcurrentInsertFailedError; end
@@ -127,27 +128,26 @@ module Grumlin
127
128
 
128
129
  class WrongQueryResult < RepositoryError; end
129
130
 
130
- class Config
131
- attr_accessor :url, :pool_size, :client_concurrency, :client_factory
132
-
133
- def initialize
134
- @pool_size = 10
135
- @client_concurrency = 5
136
- @client_factory = ->(url, parent) { Grumlin::Client.new(url, parent: parent) }
137
- end
138
- end
139
-
140
131
  @pool_mutex = Mutex.new
141
132
 
142
133
  class << self
143
134
  def configure
144
135
  yield config
136
+
137
+ config.validate!
145
138
  end
146
139
 
147
140
  def config
148
141
  @config ||= Config.new
149
142
  end
150
143
 
144
+ # returns a subset of features for currently configured backend.
145
+ # The features lists are hardcoded as there is no way to get them
146
+ # from the remote server.
147
+ def features
148
+ Features.for(config.provider) # no memoization as provider may be changed
149
+ end
150
+
151
151
  def default_pool
152
152
  if Thread.current.thread_variable_get(:grumlin_default_pool)
153
153
  return Thread.current.thread_variable_get(:grumlin_default_pool)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grumlin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.21.0
4
+ version: 0.21.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gleb Sinyavskiy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-07-28 00:00:00.000000000 Z
11
+ date: 2022-08-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async-pool
@@ -116,6 +116,7 @@ files:
116
116
  - lib/grumlin/action.rb
117
117
  - lib/grumlin/benchmark/repository.rb
118
118
  - lib/grumlin/client.rb
119
+ - lib/grumlin/config.rb
119
120
  - lib/grumlin/edge.rb
120
121
  - lib/grumlin/expressions/cardinality.rb
121
122
  - lib/grumlin/expressions/column.rb
@@ -128,12 +129,17 @@ files:
128
129
  - lib/grumlin/expressions/t.rb
129
130
  - lib/grumlin/expressions/text_p.rb
130
131
  - lib/grumlin/expressions/with_options.rb
132
+ - lib/grumlin/features.rb
133
+ - lib/grumlin/features/feature_list.rb
134
+ - lib/grumlin/features/neptune_features.rb
135
+ - lib/grumlin/features/tinkergraph_features.rb
131
136
  - lib/grumlin/path.rb
132
137
  - lib/grumlin/property.rb
133
138
  - lib/grumlin/repository.rb
134
139
  - lib/grumlin/repository/error_handling_strategy.rb
135
140
  - lib/grumlin/repository/instance_methods.rb
136
141
  - lib/grumlin/request_dispatcher.rb
142
+ - lib/grumlin/request_error_factory.rb
137
143
  - lib/grumlin/shortcut.rb
138
144
  - lib/grumlin/shortcuts.rb
139
145
  - lib/grumlin/shortcuts/properties.rb
@@ -151,6 +157,7 @@ files:
151
157
  - lib/grumlin/test/rspec.rb
152
158
  - lib/grumlin/test/rspec/db_cleaner_context.rb
153
159
  - lib/grumlin/test/rspec/gremlin_context.rb
160
+ - lib/grumlin/transaction.rb
154
161
  - lib/grumlin/transport.rb
155
162
  - lib/grumlin/traversal_start.rb
156
163
  - lib/grumlin/traversal_strategies/options_strategy.rb