grumlin 0.21.1 → 0.22.2

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: 95963424bb38728bb21c2d3746a93be60daf303b2c2897b24d99684fd1fb7bff
4
- data.tar.gz: 809b4b589b2bc5fd8687f0f63a6f73f17aab82060990b3a5942164c2ac92ef83
3
+ metadata.gz: 23a0ce8dacaf7c4add38674353e6aa69e51ebd9865ed83c3112f62ad96a5d213
4
+ data.tar.gz: 775c7c6009e6969d9a2b060772dc5d6caf9846267050509a5aeccf1bd5050e0c
5
5
  SHA512:
6
- metadata.gz: b095f3958ebf4b70577e607a0b10e27fc073055fe08d6fe55787c71fd104e77cf78cdcd0a54d06e7881c9183cab479ef6e92e6117a1c1b418945d1ebb417655c
7
- data.tar.gz: 0477a8ce8ccfc5ea1cc3b95b7b48501b05387207918478adc4eecb8e286e8495910b6bd718e1d5c00ab63e61e02ca6e89212913ec35d8df49b267cb75281e9eb
6
+ metadata.gz: 6b9a820912679a67ca1be3545130ee3affcf89bea1bd9085a47f18d4b0c2ed6583ebfe5e7c52c339d93efe672d7ec7d5e604a68681581a4c57f6b21d8dce9e21
7
+ data.tar.gz: a5d371995de61123f954361143f98427af0109831c189bb1ad60cdf722109c72749872478096aa60de22bc7d3139825fdf1ed07c8cce2330eca51cb5865fc6f9
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- grumlin (0.21.1)
4
+ grumlin (0.22.2)
5
5
  async-pool (~> 0.3)
6
6
  async-websocket (~> 0.19)
7
7
  oj (~> 3.13)
@@ -21,14 +21,14 @@ GEM
21
21
  console (~> 1.10)
22
22
  nio4r (~> 2.3)
23
23
  timers (~> 4.1)
24
- async-http (0.57.0)
24
+ async-http (0.58.0)
25
25
  async (>= 1.25)
26
26
  async-io (>= 1.28)
27
27
  async-pool (>= 0.2)
28
28
  protocol-http (~> 0.23.1)
29
29
  protocol-http1 (~> 0.14.0)
30
30
  protocol-http2 (~> 0.14.0)
31
- traces (~> 0.4.0)
31
+ traces (>= 0.4.0)
32
32
  async-io (1.33.0)
33
33
  async
34
34
  async-pool (0.3.10)
@@ -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.23.1)
84
+ protocol-http (0.23.4)
85
85
  protocol-http1 (0.14.4)
86
86
  protocol-http (~> 0.22)
87
87
  protocol-http2 (0.14.2)
@@ -157,7 +157,7 @@ GEM
157
157
  thor (1.2.1)
158
158
  tilt (2.0.10)
159
159
  timers (4.3.3)
160
- traces (0.4.1)
160
+ traces (0.6.0)
161
161
  tzinfo (2.0.4)
162
162
  concurrent-ruby (~> 1.0)
163
163
  unicode-display_width (2.1.0)
data/README.md CHANGED
@@ -64,8 +64,7 @@ explicitly specify the provider you use.
64
64
  #### Provider features
65
65
 
66
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.
67
+ some parts of it's functionality to comply provider's supported features.
69
68
 
70
69
  To check current providers supported features use
71
70
 
@@ -73,6 +72,12 @@ To check current providers supported features use
73
72
  Grumlin.features
74
73
  ```
75
74
 
75
+ Current differences between providers:
76
+
77
+ | Feature | TinkerGraph |AWS Neptune|
78
+ |--------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|
79
+ | Transactions | Transaction semantic is ignoroed, data is always writen, `tx.rollback` does nothing, an info is printed every time transactions are used with TinkerGraph |Full support
80
+
76
81
  ### Traversing graphs
77
82
 
78
83
  **Warning**: Not all steps and expressions defined in the reference documentation are supported.
@@ -240,21 +245,29 @@ Each `return_mode` is mapped to a particular termination step:
240
245
  - `:traversal` - do not execute the query and return the traversal as is
241
246
 
242
247
  `Grumlin::Repository` also provides a set of generic CRUD operations:
243
- - `add_vertex(label, id = nil, **properties)`
244
- - `add_edge(label, id = nil, from:, to:, **properties)`
245
- - `drop_vertex(id)`
246
- - `drop_edge(id = nil, from: nil, to: nil, label: nil)`
248
+ - `add_vertex(label, id = nil, start: g, **properties)`
249
+ - `add_edge(label, id = nil, from:, to:, start: g, **properties)`
250
+ - `drop_vertex(id, start: g)`
251
+ - `drop_edge(id = nil, from: nil, to: nil, label: nil, start: g)`
252
+ - `drop_in_batches(traversal, batch_size: 10_000)`
247
253
 
248
254
  and a few methods that emulate upserts:
249
- - `upsert_vertex(label, id, create_properties: {}, update_properties: {}, on_failure: :retry, **params)`
250
- - `upsert_edge(label, from:, to:, create_properties: {}, update_properties: {}, on_failure: :retry, **params)`
251
- - `upsert_edges(edges, batch_size: 100, on_failure: :retry, **params)`
252
- - `upsert_vertices(edges, batch_size: 100, on_failure: :retry, **params)`
255
+ - `upsert_vertex(label, id, create_properties: {}, update_properties: {}, on_failure: :retry, start: g, **params)`
256
+ - `upsert_edge(label, from:, to:, create_properties: {}, update_properties: {}, on_failure: :retry, start: g, **params)`
257
+ - `upsert_edges(edges, batch_size: 100, on_failure: :retry, start: g, **params)`
258
+ - `upsert_vertices(edges, batch_size: 100, on_failure: :retry, start: g, **params)`
253
259
 
254
260
  All of them support 3 different modes for error handling: `:retry`, `:ignore` and `:raise`. Retry mode is implemented
255
261
  with [retryable](https://github.com/nfedyashev/retryable). **params will be merged to the default config for upserts
256
262
  and passed to `Retryable.retryable`. In case if you want to modify retryable behaviour you are to do so.
257
263
 
264
+ If you want to use these methods inside a transaction simply pass your `gtx` as `start` parameter:
265
+ ```ruby
266
+ g.tx do |gtx|
267
+ add_vertex(:vertex, start: gtx)
268
+ end
269
+ ```
270
+
258
271
  If you don't want to define you own repository, simply use
259
272
 
260
273
  `Grumlin::Repository.new` returns an instance of an anonymous class extending `Grumlin::Repository`.
@@ -282,6 +295,24 @@ it may be useful for debugging. Note that one needs to call a termination step m
282
295
 
283
296
  method will return profiling data of the results.
284
297
 
298
+ #### Transactions
299
+
300
+ Since 0.22.0 `Grumlin` supports transactions when working with providers that supports them:
301
+ ```ruby
302
+ # Using Transaction directly
303
+ tx = g.tx
304
+ gtx = tx.begin
305
+ gtx.addV(:vertex).iterate
306
+ tx.commit # or tx.rollback
307
+
308
+ # Using with a block
309
+ g.tx do |gtx|
310
+ gtx.addV(:vertex).iterate
311
+ # raise Grumlin::Rollback to manually rollback
312
+ # any other exception will also rollback the transaction and will be reraised
313
+ end # commits automatically
314
+ ```
315
+
285
316
  #### IRB
286
317
 
287
318
  An example of how to start an IRB session with support for executing gremlin queries:
@@ -16,7 +16,7 @@ module Grumlin
16
16
  end
17
17
 
18
18
  def configuration_step?
19
- CONFIGURATION_STEPS.include?(@name)
19
+ CONFIGURATION_STEPS.include?(@name) || name.to_sym == :tx
20
20
  end
21
21
 
22
22
  def start_step?
@@ -30,12 +30,6 @@ module Grumlin
30
30
  @count += 1
31
31
  end
32
32
 
33
- def finalize_tx(action, session_id)
34
- @client.finalize_tx(action, session_id)
35
- ensure
36
- @count += 1
37
- end
38
-
39
33
  def viable?
40
34
  !closed?
41
35
  end
@@ -104,15 +98,15 @@ module Grumlin
104
98
  raise NotConnectedError unless connected?
105
99
 
106
100
  request = to_query(bytecode, session_id: session_id)
107
- submit_request(request)
108
- end
109
101
 
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)
102
+ channel = @request_dispatcher.add_request(request)
103
+ begin
104
+ @transport.write(request)
105
+ channel.dequeue.flat_map { |item| Typing.cast(item) }
106
+ rescue Async::Stop, Async::TimeoutError
107
+ close(check_requests: false)
108
+ raise
109
+ end
116
110
  end
117
111
 
118
112
  def inspect
@@ -125,18 +119,6 @@ module Grumlin
125
119
 
126
120
  private
127
121
 
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
-
140
122
  # This might be overridden in successors
141
123
  def build_transport
142
124
  Transport.new(@url, parent: @parent, **@client_options)
@@ -157,21 +139,5 @@ module Grumlin
157
139
  }.compact
158
140
  }
159
141
  end
160
-
161
- def finalize_tx_query(action, session_id)
162
- {
163
- requestId: SecureRandom.uuid,
164
- op: :bytecode,
165
- processor: session_id ? :session : :traversal,
166
- args: {
167
- gremlin: {
168
- :@type => "g:Bytecode",
169
- :@value => { source: [[:tx, action]] }
170
- },
171
- aliases: { g: :g },
172
- session: session_id
173
- }.compact
174
- }
175
- end
176
142
  end
177
143
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grumlin
4
+ class DummyTransaction < Transaction
5
+ attr_reader :uuid
6
+
7
+ include Console
8
+
9
+ def initialize(traversal_start_class, pool: Grumlin.default_pool) # rubocop:disable Lint/MissingSuper, Lint/UnusedMethodArgument
10
+ @traversal_start_class = traversal_start_class
11
+
12
+ logger.info(self) do
13
+ "#{Grumlin.config.provider} does not support transactions. commit and rollback are ignored, data will be saved"
14
+ end
15
+ end
16
+
17
+ def commit
18
+ nil
19
+ end
20
+
21
+ def rollback
22
+ nil
23
+ end
24
+ end
25
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Grumlin
4
4
  module Repository
5
- module InstanceMethods
5
+ module InstanceMethods # rubocop:disable Metrics/ModuleLength
6
6
  include Grumlin::Expressions
7
7
 
8
8
  extend Forwardable
@@ -22,51 +22,73 @@ module Grumlin
22
22
  self.class.shortcuts
23
23
  end
24
24
 
25
- def drop_vertex(id)
26
- g.V(id).drop.iterate
25
+ def drop_vertex(id, start: g)
26
+ start.V(id).drop.iterate
27
27
  end
28
28
 
29
- def drop_edge(id = nil, from: nil, to: nil, label: nil) # rubocop:disable Metrics/AbcSize
29
+ def drop_in_batches(traversal, batch_size: 10_000) # rubocop:disable Metrics/AbcSize
30
+ total_count = traversal.count.next
31
+
32
+ batches = (total_count / batch_size) + 1
33
+
34
+ Console.logger.info(self) do
35
+ "drop_in_batches: total_count: #{total_count}, batch_size: #{batch_size}, batches: #{batches}"
36
+ end
37
+
38
+ batches.times do |batch|
39
+ Console.logger.info(self) { "drop_in_batches: deleting batch #{batch + 1}/#{batches}..." }
40
+ traversal.limit(batch_size).drop.iterate
41
+ Console.logger.info(self) { "drop_in_batches: batch #{batch + 1}/#{batches} deleted" }
42
+ end
43
+
44
+ return if traversal.count.next.zero?
45
+
46
+ drop_in_batches(traversal, batch_size: batch_size)
47
+
48
+ Console.logger.info(self) { "drop_in_batches: finished." }
49
+ end
50
+
51
+ def drop_edge(id = nil, from: nil, to: nil, label: nil, start: g) # rubocop:disable Metrics/AbcSize
30
52
  raise ArgumentError, "either id or from:, to: and label: must be passed" if [id, from, to, label].all?(&:nil?)
31
- return g.E(id).drop.iterate unless id.nil?
53
+ return start.E(id).drop.iterate unless id.nil?
32
54
 
33
55
  raise ArgumentError, "from:, to: and label: must be passed" if [from, to, label].any?(&:nil?)
34
56
 
35
- g.V(from).outE(label).where(__.inV.hasId(to)).limit(1).drop.iterate
57
+ start.V(from).outE(label).where(__.inV.hasId(to)).limit(1).drop.iterate
36
58
  end
37
59
 
38
- def add_vertex(label, id = nil, **properties)
60
+ def add_vertex(label, id = nil, start: g, **properties)
39
61
  id ||= properties[T.id]
40
62
  properties = except(properties, T.id)
41
63
 
42
- t = g.addV(label)
64
+ t = start.addV(label)
43
65
  t = t.props(T.id => id) unless id.nil?
44
66
  t.props(**properties).next
45
67
  end
46
68
 
47
- def add_edge(label, id = nil, from:, to:, **properties)
69
+ def add_edge(label, id = nil, from:, to:, start: g, **properties)
48
70
  id ||= properties[T.id]
49
71
  properties = except(properties, T.label)
50
72
  properties[T.id] = id
51
73
 
52
- g.addE(label).from(__.V(from)).to(__.V(to)).props(**properties).next
74
+ start.addE(label).from(__.V(from)).to(__.V(to)).props(**properties).next
53
75
  end
54
76
 
55
- def upsert_vertex(label, id, create_properties: {}, update_properties: {}, on_failure: :retry, **params)
77
+ def upsert_vertex(label, id, create_properties: {}, update_properties: {}, on_failure: :retry, start: g, **params) # rubocop:disable Metrics/ParameterLists
56
78
  with_upsert_error_handling(on_failure, params) do
57
79
  create_properties, update_properties = cleanup_properties(create_properties, update_properties)
58
80
 
59
- g.upsertV(label, id, create_properties, update_properties).id.next
81
+ start.upsertV(label, id, create_properties, update_properties).id.next
60
82
  end
61
83
  end
62
84
 
63
85
  # vertices:
64
86
  # [["label", "id", {create: :properties}, {update: properties}]]
65
87
  # params can override Retryable config from UPSERT_RETRY_PARAMS
66
- def upsert_vertices(vertices, batch_size: 100, on_failure: :retry, **params)
88
+ def upsert_vertices(vertices, batch_size: 100, on_failure: :retry, start: g, **params)
67
89
  vertices.each_slice(batch_size) do |slice|
68
90
  with_upsert_error_handling(on_failure, params) do
69
- slice.reduce(g) do |t, (label, id, create_properties, update_properties)|
91
+ slice.reduce(start) do |t, (label, id, create_properties, update_properties)|
70
92
  create_properties, update_properties = cleanup_properties(create_properties, update_properties)
71
93
 
72
94
  t.upsertV(label, id, create_properties, update_properties)
@@ -77,20 +99,21 @@ module Grumlin
77
99
 
78
100
  # Only from and to are used to find the existing edge, if one wants to assign an id to a created edge,
79
101
  # it must be passed as T.id in create_properties.
80
- def upsert_edge(label, from:, to:, create_properties: {}, update_properties: {}, on_failure: :retry, **params) # rubocop:disable Metrics/ParameterLists
102
+ def upsert_edge(label, from:, to:, create_properties: {}, update_properties: {}, # rubocop:disable Metrics/ParameterLists
103
+ on_failure: :retry, start: g, **params)
81
104
  with_upsert_error_handling(on_failure, params) do
82
105
  create_properties, update_properties = cleanup_properties(create_properties, update_properties, T.label)
83
- g.upsertE(label, from, to, create_properties, update_properties).id.next
106
+ start.upsertE(label, from, to, create_properties, update_properties).id.next
84
107
  end
85
108
  end
86
109
 
87
110
  # edges:
88
111
  # [["label", "from", "to", {create: :properties}, {update: properties}]]
89
112
  # params can override Retryable config from UPSERT_RETRY_PARAMS
90
- def upsert_edges(edges, batch_size: 100, on_failure: :retry, **params)
113
+ def upsert_edges(edges, batch_size: 100, on_failure: :retry, start: g, **params)
91
114
  edges.each_slice(batch_size) do |slice|
92
115
  with_upsert_error_handling(on_failure, params) do
93
- slice.reduce(g) do |t, (label, from, to, create_properties, update_properties)|
116
+ slice.reduce(start) do |t, (label, from, to, create_properties, update_properties)|
94
117
  create_properties, update_properties = cleanup_properties(create_properties, update_properties, T.label)
95
118
 
96
119
  t.upsertE(label, from, to, create_properties, update_properties)
@@ -18,11 +18,19 @@ module Grumlin
18
18
  # {"detailedMessage":"",
19
19
  # "requestId":"UUID",
20
20
  # "code":"ConcurrentModificationException"}
21
- # Currencly we simply search for substings to identify the exact error
21
+ # Currently we simply search for substrings to identify the exact error
22
22
  # TODO: parse json and use `code` instead
23
+
23
24
  VERTEX_ALREADY_EXISTS = "Vertex with id already exists:"
24
25
  EDGE_ALREADY_EXISTS = "Edge with id already exists:"
26
+
25
27
  CONCURRENT_VERTEX_INSERT_FAILED = "Failed to complete Insert operation for a Vertex due to conflicting concurrent"
28
+
29
+ CONCURRENT_VERTEX_PROPERTY_INSERT_FAILED =
30
+ "Failed to complete Insert operation for a VertexProperty due to conflicting concurrent"
31
+ CONCURRENT_EDGE_PROPERTY_INSERT_FAILED =
32
+ "Failed to complete Insert operation for a EdgeProperty due to conflicting concurrent"
33
+
26
34
  CONCURRENT_EDGE_INSERT_FAILED = "Failed to complete Insert operation for an Edge due to conflicting concurrent"
27
35
  CONCURRENCT_MODIFICATION_FAILED = "Failed to complete operation due to conflicting concurrent"
28
36
 
@@ -49,9 +57,15 @@ module Grumlin
49
57
  return EdgeAlreadyExistsError if status[:message]&.include?(EDGE_ALREADY_EXISTS)
50
58
  end
51
59
 
52
- def concurrent_modification_error(status)
60
+ def concurrent_modification_error(status) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
53
61
  return ConcurrentVertexInsertFailedError if status[:message]&.include?(CONCURRENT_VERTEX_INSERT_FAILED)
62
+ if status[:message]&.include?(CONCURRENT_VERTEX_PROPERTY_INSERT_FAILED)
63
+ return ConcurrentVertexPropertyInsertFailedError
64
+ end
54
65
  return ConcurrentEdgeInsertFailedError if status[:message]&.include?(CONCURRENT_EDGE_INSERT_FAILED)
66
+ if status[:message]&.include?(CONCURRENT_EDGE_PROPERTY_INSERT_FAILED)
67
+ return ConcurrentEdgePropertyInsertFailedError
68
+ end
55
69
  return ConcurrentModificationError if status[:message]&.include?(CONCURRENCT_MODIFICATION_FAILED)
56
70
  end
57
71
  end
data/lib/grumlin/steps.rb CHANGED
@@ -32,7 +32,9 @@ module Grumlin
32
32
  end
33
33
 
34
34
  def add(name, args: [], params: {})
35
- return add_configuration_step(name, args: args, params: params) if CONFIGURATION_STEPS.include?(name)
35
+ if CONFIGURATION_STEPS.include?(name) || name.to_sym == :tx
36
+ return add_configuration_step(name, args: args, params: params)
37
+ end
36
38
 
37
39
  StepData.new(name, args: cast_arguments(args), params: params).tap do |step|
38
40
  @steps << step
@@ -10,17 +10,19 @@ module Grumlin
10
10
 
11
11
  def serialize
12
12
  steps = ShortcutsApplyer.call(@steps)
13
- no_return = @params[:no_return] || false
14
-
15
- {
16
- step: (steps.steps + (no_return ? [NONE_STEP] : [])).map { |s| serialize_step(s) }
17
- }.tap do |v|
18
- v.merge!(source: steps.configuration_steps.map { |s| serialize_step(s) }) if steps.configuration_steps.any?
13
+ no_return = @params.fetch(:no_return, false)
14
+ {}.tap do |result|
15
+ result[:step] = serialize_steps(steps.steps + (no_return ? [NONE_STEP] : [])) if steps.steps.any?
16
+ result[:source] = serialize_steps(steps.configuration_steps) if steps.configuration_steps.any?
19
17
  end
20
18
  end
21
19
 
22
20
  private
23
21
 
22
+ def serialize_steps(steps)
23
+ steps.map { |s| serialize_step(s) }
24
+ end
25
+
24
26
  def serialize_step(step)
25
27
  [step.name].tap do |result|
26
28
  step.args.each do |arg|
@@ -2,49 +2,37 @@
2
2
 
3
3
  module Grumlin
4
4
  class Transaction
5
- attr_reader :uuid
5
+ attr_reader :session_id
6
6
 
7
7
  include Console
8
8
 
9
+ COMMIT = Grumlin::Repository.new.g.step(:tx, :commit).bytecode
10
+ ROLLBACK = Grumlin::Repository.new.g.step(:tx, :rollback).bytecode
11
+
9
12
  def initialize(traversal_start_class, pool: Grumlin.default_pool)
10
13
  @traversal_start_class = traversal_start_class
11
14
  @pool = pool
12
15
 
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?
16
+ @session_id = SecureRandom.uuid
25
17
  end
26
18
 
27
19
  def begin
28
- @traversal_start_class.new(session_id: @uuid)
20
+ @traversal_start_class.new(session_id: @session_id)
29
21
  end
30
22
 
31
23
  def commit
32
- return unless supported?
33
-
34
- finalize(:commit)
24
+ finalize(COMMIT)
35
25
  end
36
26
 
37
27
  def rollback
38
- return unless supported?
39
-
40
- finalize(:rollback)
28
+ finalize(ROLLBACK)
41
29
  end
42
30
 
43
31
  private
44
32
 
45
33
  def finalize(action)
46
34
  @pool.acquire do |client|
47
- client.finalize_tx(action, @uuid)
35
+ client.write(action, session_id: @session_id)
48
36
  end
49
37
  end
50
38
  end
@@ -5,12 +5,24 @@ module Grumlin
5
5
  include WithExtension
6
6
 
7
7
  class TraversalError < Grumlin::Error; end
8
- class AlreadyBoundToTransationError < TraversalError; end
8
+ class AlreadyBoundToTransactionError < TraversalError; end
9
9
 
10
10
  def tx
11
- raise AlreadyBoundToTransationError if @session_id
11
+ raise AlreadyBoundToTransactionError if @session_id
12
12
 
13
- Transaction.new(self.class, pool: @pool)
13
+ transaction = tx_class.new(self.class, pool: @pool)
14
+ return transaction unless block_given?
15
+
16
+ begin
17
+ yield transaction.begin
18
+ rescue Grumlin::Rollback
19
+ transaction.rollback
20
+ rescue StandardError
21
+ transaction.rollback
22
+ raise
23
+ else
24
+ transaction.commit
25
+ end
14
26
  end
15
27
 
16
28
  def to_s(*)
@@ -20,5 +32,11 @@ module Grumlin
20
32
  def inspect
21
33
  self.class.inspect
22
34
  end
35
+
36
+ private
37
+
38
+ def tx_class
39
+ Grumlin.features.supports_transactions? ? Transaction : DummyTransaction
40
+ end
23
41
  end
24
42
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Grumlin
4
- VERSION = "0.21.1"
4
+ VERSION = "0.22.2"
5
5
  end
data/lib/grumlin.rb CHANGED
@@ -33,6 +33,9 @@ loader.do_not_eager_load(test_helpers)
33
33
  module Grumlin
34
34
  class Error < StandardError; end
35
35
 
36
+ class TransactionError < Error; end
37
+ class Rollback < TransactionError; end
38
+
36
39
  class UnknownError < Error; end
37
40
 
38
41
  class ConnectionError < Error; end
@@ -104,6 +107,9 @@ module Grumlin
104
107
  class ConcurrentVertexInsertFailedError < ConcurrentInsertFailedError; end
105
108
  class ConcurrentEdgeInsertFailedError < ConcurrentInsertFailedError; end
106
109
 
110
+ class ConcurrentVertexPropertyInsertFailedError < ConcurrentInsertFailedError; end
111
+ class ConcurrentEdgePropertyInsertFailedError < ConcurrentInsertFailedError; end
112
+
107
113
  class ServerSerializationError < ServerSideError; end
108
114
 
109
115
  class ServerTimeoutError < ServerSideError; end
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.1
4
+ version: 0.22.2
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-08-11 00:00:00.000000000 Z
11
+ date: 2022-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async-pool
@@ -117,6 +117,7 @@ files:
117
117
  - lib/grumlin/benchmark/repository.rb
118
118
  - lib/grumlin/client.rb
119
119
  - lib/grumlin/config.rb
120
+ - lib/grumlin/dummy_transaction.rb
120
121
  - lib/grumlin/edge.rb
121
122
  - lib/grumlin/expressions/cardinality.rb
122
123
  - lib/grumlin/expressions/column.rb