grumlin 0.21.1 → 0.22.2

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