grumlin 0.23.0 → 1.0.0.rc1

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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +9 -9
  3. data/Gemfile.lock +1 -1
  4. data/README.md +94 -141
  5. data/Rakefile +1 -1
  6. data/bin/console +18 -3
  7. data/doc/middlewares.md +49 -10
  8. data/lib/async/channel.rb +54 -56
  9. data/lib/grumlin/benchmark/repository.rb +10 -14
  10. data/lib/grumlin/client.rb +93 -95
  11. data/lib/grumlin/config.rb +33 -33
  12. data/lib/grumlin/dummy_transaction.rb +13 -15
  13. data/lib/grumlin/edge.rb +18 -20
  14. data/lib/grumlin/expressions/cardinality.rb +5 -9
  15. data/lib/grumlin/expressions/column.rb +5 -9
  16. data/lib/grumlin/expressions/expression.rb +7 -11
  17. data/lib/grumlin/expressions/operator.rb +5 -9
  18. data/lib/grumlin/expressions/order.rb +5 -9
  19. data/lib/grumlin/expressions/p.rb +27 -31
  20. data/lib/grumlin/expressions/pop.rb +5 -9
  21. data/lib/grumlin/expressions/scope.rb +5 -9
  22. data/lib/grumlin/expressions/t.rb +5 -9
  23. data/lib/grumlin/expressions/text_p.rb +5 -9
  24. data/lib/grumlin/expressions/with_options.rb +17 -21
  25. data/lib/grumlin/features/feature_list.rb +8 -12
  26. data/lib/grumlin/features/neptune_features.rb +5 -9
  27. data/lib/grumlin/features/tinkergraph_features.rb +5 -9
  28. data/lib/grumlin/features.rb +8 -10
  29. data/lib/grumlin/middlewares/apply_shortcuts.rb +4 -8
  30. data/lib/grumlin/middlewares/build_query.rb +16 -20
  31. data/lib/grumlin/middlewares/builder.rb +15 -0
  32. data/lib/grumlin/middlewares/cast_results.rb +3 -7
  33. data/lib/grumlin/middlewares/find_blocklisted_steps.rb +14 -0
  34. data/lib/grumlin/middlewares/find_mutating_steps.rb +9 -0
  35. data/lib/grumlin/middlewares/middleware.rb +6 -10
  36. data/lib/grumlin/middlewares/run_query.rb +3 -7
  37. data/lib/grumlin/middlewares/serialize_to_bytecode.rb +5 -9
  38. data/lib/grumlin/middlewares/serialize_to_steps.rb +4 -8
  39. data/lib/grumlin/path.rb +11 -13
  40. data/lib/grumlin/property.rb +14 -16
  41. data/lib/grumlin/query_validators/blocklisted_steps_validator.rb +22 -0
  42. data/lib/grumlin/query_validators/validator.rb +36 -0
  43. data/lib/grumlin/repository/error_handling_strategy.rb +36 -40
  44. data/lib/grumlin/repository/instance_methods.rb +115 -118
  45. data/lib/grumlin/repository.rb +82 -58
  46. data/lib/grumlin/request_dispatcher.rb +55 -57
  47. data/lib/grumlin/request_error_factory.rb +53 -55
  48. data/lib/grumlin/shortcut.rb +19 -21
  49. data/lib/grumlin/shortcuts/properties.rb +12 -16
  50. data/lib/grumlin/shortcuts/storage.rb +67 -74
  51. data/lib/grumlin/shortcuts/upserts.rb +18 -22
  52. data/lib/grumlin/shortcuts.rb +23 -25
  53. data/lib/grumlin/shortcuts_applyer.rb +27 -29
  54. data/lib/grumlin/step.rb +88 -90
  55. data/lib/grumlin/step_data.rb +12 -14
  56. data/lib/grumlin/steppable.rb +23 -25
  57. data/lib/grumlin/steps.rb +52 -54
  58. data/lib/grumlin/steps_serializers/bytecode.rb +53 -56
  59. data/lib/grumlin/steps_serializers/human_readable_bytecode.rb +17 -21
  60. data/lib/grumlin/steps_serializers/serializer.rb +7 -11
  61. data/lib/grumlin/steps_serializers/string.rb +26 -30
  62. data/lib/grumlin/test/rspec/db_cleaner_context.rb +8 -12
  63. data/lib/grumlin/test/rspec/gremlin_context.rb +18 -16
  64. data/lib/grumlin/test/rspec.rb +1 -5
  65. data/lib/grumlin/transaction.rb +34 -36
  66. data/lib/grumlin/transport.rb +71 -73
  67. data/lib/grumlin/traversal_start.rb +31 -33
  68. data/lib/grumlin/traversal_strategies/options_strategy.rb +3 -7
  69. data/lib/grumlin/traverser.rb +5 -7
  70. data/lib/grumlin/typed_value.rb +11 -13
  71. data/lib/grumlin/typing.rb +70 -72
  72. data/lib/grumlin/version.rb +1 -1
  73. data/lib/grumlin/vertex.rb +14 -16
  74. data/lib/grumlin/vertex_property.rb +14 -16
  75. data/lib/grumlin/with_extension.rb +17 -19
  76. metadata +9 -6
  77. data/lib/grumlin/middlewares/frozen_builder.rb +0 -18
  78. data/lib/grumlin/sugar.rb +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0560f7bf90bba9601628d6042ac1286076f9a8e9039b6f8e755b6f4beedb3e1a
4
- data.tar.gz: 83b7b4409198a6cbb5520b003e2dcdacfe8623b9aa8c057b0e9df1e29692a4f3
3
+ metadata.gz: e5a4223c6fde72d3f4ce23f3da0081a816f395a070d8737d9915f15b166c9721
4
+ data.tar.gz: 8c95dcb15d4f55741cc370298e1e763427858908abebaec33f945e404d3a6fa3
5
5
  SHA512:
6
- metadata.gz: f87b6a69c71ebd867f227b35e13a50c499d054c6688747465e05a41426167ee3ffea5afbfb1875ca5c49e6a0c2a97f42ea20b93f9cf32cd5966942ba844f839c
7
- data.tar.gz: 4b5262eacf5e57f4ad95e6cc5f450d924858b1e238e2bf3943b9b127da53db36c76078b22d8ba5d244aa35e5d0ddfc4db45516481bd41c58bbe2123ac262dd5f
6
+ metadata.gz: 69162f44551c45c0898ffa0c3650cee448a155d1950de5ea0a2a4b570c1b2b41612f3b97bd063f88f683af5fad3c18d4b874b96392a30334c77ab0e1fb1fd226
7
+ data.tar.gz: 1fdb7d10a84da7d8c8173e2b0edb0f5b0f913fb0418fce59bb92d28de9c2e9a1743b89eca1f0ed8495b4d0519d2068c2314e9f17f23b77a4297e080512ace082
data/.rubocop.yml CHANGED
@@ -65,10 +65,6 @@ RSpec/DescribeClass:
65
65
  RSpec/MultipleMemoizedHelpers:
66
66
  Max: 7
67
67
 
68
- Style/WordArray:
69
- Exclude:
70
- - spec/**/*_spec.rb
71
-
72
68
  Style/StringLiterals:
73
69
  Enabled: true
74
70
  EnforcedStyle: double_quotes
@@ -83,9 +79,13 @@ Style/Documentation:
83
79
  Style/MultilineBlockChain:
84
80
  Enabled: false
85
81
 
82
+ Style/SymbolArray:
83
+ EnforcedStyle: brackets
84
+
85
+ Style/WordArray:
86
+ EnforcedStyle: brackets
87
+ Exclude:
88
+ - spec/**/*_spec.rb
86
89
 
87
- # TODO:
88
- # Style/SymbolArray:
89
- # EnforcedStyle: brackets
90
- # Style/WordArray:
91
- # EnforcedStyle: brackets
90
+ Style/ClassAndModuleChildren:
91
+ EnforcedStyle: compact
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- grumlin (0.23.0)
4
+ grumlin (1.0.0.rc1)
5
5
  async-pool (~> 0.3)
6
6
  async-websocket (>= 0.19, < 0.20)
7
7
  ibsciss-middleware (~> 0.4.0)
data/README.md CHANGED
@@ -82,116 +82,11 @@ Current differences between providers:
82
82
 
83
83
  **Warning**: Not all steps and expressions defined in the reference documentation are supported.
84
84
 
85
- #### Sugar
86
-
87
- Grumlin provides an easy to use module called `Grumlin::Sugar`. Once included in your class it injects some useful
88
- constants and methods turning your class into an entrypoint for traversals with pure gremlin experience.
89
-
90
- ```ruby
91
- class MyRepository
92
- include Grumlin::Sugar
93
-
94
- def nodes(property1:, property2:)
95
- g.V()
96
- .has(T.label, "node")
97
- .has(:property1, property1)
98
- .has(:property2, property2)
99
- .order.by(:property3, Order.asc).limit(10)
100
- .toList
101
- end
102
- end
103
- ```
104
-
105
- #### Shortcuts
106
-
107
- **Shortcuts** is a way to share and organize gremlin code. They let developers define their own steps consisting of
108
- sequences of standard gremlin steps, other shortcuts and even add new initially unsupported by Grumlin steps.
109
- Remember ActiveRecord scopes? Shortcuts are very similar.
110
-
111
- **Important**: if a shortcut's name matches a name of a method defined on the wrapped object, this shortcut will be
112
- be ignored because methods have higher priority.
113
-
114
- Shortcuts are designed to be used with `Grumlin::Repository` but still can be used separately, with `Grumlin::Sugar`
115
- for example.
116
-
117
- **Defining**:
118
- ```ruby
119
-
120
- # Defining shortcuts
121
- class ColorShortcut
122
- extend Grumlin::Shortcuts
123
-
124
- # Custom step
125
- shortcut :hasColor do |color|
126
- has(:color, color)
127
- end
128
- end
129
-
130
- class ChooseShortcut
131
- extend Grumlin::Shortcuts
132
-
133
- # Standard Gremlin step
134
- shortcut :choose do |*args|
135
- step(:choose, *args)
136
- end
137
- end
138
-
139
- class AllShortcuts
140
- extend Grumlin::Shortcuts
141
-
142
- # Adding shortcuts from other modules
143
- shortcuts_from ColorShortcut
144
- shortcuts_from ChooseShortcut
145
- end
146
- ```
147
-
148
- **Using with Grumlin::Sugar**:
149
- ```ruby
150
- class MyRepository
151
- include Grumlin::Sugar
152
- extend Grumlin::Shortcuts
153
-
154
- shortcuts_from AllShortcuts
155
-
156
- # Wrapping a traversal
157
- def red_triangles
158
- g(self.class.shortcuts).V.hasLabel(:triangle)
159
- .hasColor("red")
160
- .toList
161
- end
162
-
163
- # Wrapping _
164
- def something_else
165
- g(self.class.shortcuts).V.hasColor("red")
166
- .repeat(__(self.class.shortcuts))
167
- .out(:has)
168
- .hasColor("blue")
169
- .toList
170
- end
171
- end
172
- ```
173
-
174
- ##### Overriding standard steps and shortcuts
175
-
176
- Sometimes it may be useful to override standard steps. Grumlin does not allow it by default, but one
177
- is still able to override standard steps if they know what they are doing:
178
-
179
- ```ruby
180
- shortcut :addV, override: true do |label|
181
- super(label).property(:default, :value)
182
- end
183
- ```
184
-
185
- This will create a new shortcut that overrides the standard step `addV` and adds default properties to all vertices
186
- created by the repository that uses this shortcut.
187
-
188
- Shortcuts also can be overridden, but super() is not available.
189
-
190
85
  #### Grumlin::Repository
191
- `Grumlin::Repository` combines functionality of `Grumlin::Sugar` and `Grumlin::Shortcuts` as well as adds a few useful
192
- shortcuts to make gremlin code more rubyish. Can be used as a drop in replacement for `Grumlin::Sugar`. Remember that
193
- `Grumlin::Sugar` needs to be included, but `Grumlin::Repository` - extended. **Classes extending `Grumlin::Repository`
194
- or `Grumlin::Shortcuts` can be inherited**, successors don't need to extend them again and have access to shortcuts
86
+ `Grumlin::Repository` - is a starting point for all traversals. It provides easy access to `g`, `__` and usual gremlin
87
+ expressions for you class. It has support for defining your own shortcuts and is even shipped with a couple of useful
88
+ shortcuts to make gremlin code more rubyish. **Classes extending `Grumlin::Repository`
89
+ or `Grumlin::Shortcuts` can be inherited**, successors don't need to extend them again and have access to shortcuts
195
90
  defined in the ancestor.
196
91
 
197
92
  **Definition**
@@ -199,8 +94,8 @@ defined in the ancestor.
199
94
  ```ruby
200
95
  class MyRepository
201
96
  extend Grumlin::Repository
202
-
203
- # Repository supports all Grumlin::Shortcut and Grumlin::Sugar features.
97
+ # read_only! - forbids mutating queries for this repository. May be useful for separation reads and writes
98
+
204
99
  # It can add shortcuts from another repository or a shortcuts module
205
100
  shortcuts_from ChooseShortcut
206
101
 
@@ -252,13 +147,13 @@ Each `return_mode` is mapped to a particular termination step:
252
147
  - `drop_in_batches(traversal, batch_size: 10_000)`
253
148
 
254
149
  and a few methods that emulate upserts:
255
- - `upsert_vertex(label, id, create_properties: {}, update_properties: {}, on_failure: :retry, start: g, **params)`
150
+ - `upsert_vertex(label, id, create_properties: {}, update_properties: {}, on_failure: :retry, start: g, **params)`
256
151
  - `upsert_edge(label, from:, to:, create_properties: {}, update_properties: {}, on_failure: :retry, start: g, **params)`
257
152
  - `upsert_edges(edges, batch_size: 100, on_failure: :retry, start: g, **params)`
258
153
  - `upsert_vertices(edges, batch_size: 100, on_failure: :retry, start: g, **params)`
259
154
 
260
155
  All of them support 3 different modes for error handling: `:retry`, `:ignore` and `:raise`. Retry mode is implemented
261
- with [retryable](https://github.com/nfedyashev/retryable). **params will be merged to the default config for upserts
156
+ with [retryable](https://github.com/nfedyashev/retryable). **params will be merged to the default config for upserts
262
157
  and passed to `Retryable.retryable`. In case if you want to modify retryable behaviour you are to do so.
263
158
 
264
159
  If you want to use these methods inside a transaction simply pass your `gtx` as `start` parameter:
@@ -270,7 +165,7 @@ end
270
165
 
271
166
  If you don't want to define you own repository, simply use
272
167
 
273
- `Grumlin::Repository.new` returns an instance of an anonymous class extending `Grumlin::Repository`.
168
+ `Grumlin::Repository.new` returns an instance of an anonymous class extending `Grumlin::Repository`.
274
169
 
275
170
  **Usage**
276
171
 
@@ -295,6 +190,62 @@ it may be useful for debugging. Note that one needs to call a termination step m
295
190
 
296
191
  method will return profiling data of the results.
297
192
 
193
+ #### Shortcuts
194
+
195
+ **Shortcuts** is a way to share and organize gremlin code. They let developers define their own steps consisting of
196
+ sequences of standard gremlin steps, other shortcuts and even add new initially unsupported by Grumlin steps.
197
+ Remember ActiveRecord scopes? Shortcuts are very similar.
198
+
199
+ **Important**: if a shortcut's name matches a name of a method defined on the wrapped object, this shortcut will be
200
+ be ignored because methods have higher priority.
201
+
202
+ **Defining**:
203
+ ```ruby
204
+
205
+ # Defining shortcuts
206
+ class ColorShortcut
207
+ extend Grumlin::Shortcuts
208
+
209
+ # Custom step
210
+ shortcut :hasColor do |color|
211
+ has(:color, color)
212
+ end
213
+ end
214
+
215
+ class ChooseShortcut
216
+ extend Grumlin::Shortcuts
217
+
218
+ # Standard Gremlin step
219
+ shortcut :choose do |*args|
220
+ step(:choose, *args)
221
+ end
222
+ end
223
+
224
+ class AllShortcuts
225
+ extend Grumlin::Shortcuts
226
+
227
+ # Adding shortcuts from other modules
228
+ shortcuts_from ColorShortcut
229
+ shortcuts_from ChooseShortcut
230
+ end
231
+ ```
232
+
233
+ ##### Overriding standard steps and shortcuts
234
+
235
+ Sometimes it may be useful to override standard steps. Grumlin does not allow it by default, but one
236
+ is still able to override standard steps if they know what they are doing:
237
+
238
+ ```ruby
239
+ shortcut :addV, override: true do |label|
240
+ super(label).property(:default, :value)
241
+ end
242
+ ```
243
+
244
+ This will create a new shortcut that overrides the standard step `addV` and adds default properties to all vertices
245
+ created by the repository that uses this shortcut.
246
+
247
+ Shortcuts also can be overridden, but super() is not available.
248
+
298
249
  ##### Middlewares
299
250
 
300
251
  Middlewares can be used to perform certain actions before and after every query made by `Grumlin`. It can be useful for
@@ -323,41 +274,43 @@ end # commits automatically
323
274
 
324
275
  #### IRB
325
276
 
326
- An example of how to start an IRB session with support for executing gremlin queries:
327
-
328
- ```ruby
329
- Async do
330
- include Grumlin::Sugar
331
-
332
- IRB.start
333
- ensure
334
- Grumlin.close
335
- end
336
- ```
337
-
338
- Please check out [bin/console](bin/console) for full source. A similar trick may be applied to PRY.
277
+ Please check out [bin/console](bin/console) for inspiration. A similar trick may be applied to PRY.
339
278
 
340
279
  #### Rails console
341
280
 
342
281
  In order to make it possible to execute gremlin queries from the rails console you need to define
343
- a custom console class. It should look somehow like
282
+ a custom console class. It should look somewhat like
344
283
 
345
284
  ```ruby
346
- class MyRailsConsole
347
- def self.start
285
+ class Async::RailsConsole
286
+ extend Grumlin::Repository
287
+
288
+ def start
289
+ self.class.shortcuts_from Shortcuts::Content
290
+
348
291
  IRB::WorkSpace.prepend(Rails::Console::BacktraceCleaner)
349
292
  IRB::ExtendCommandBundle.include(Rails::ConsoleMethods)
350
293
 
351
- Async do
352
- include Grumlin::Sugar
294
+ IRB.setup(binding.source_location[0], argv: [])
295
+ workspace = IRB::WorkSpace.new(binding)
296
+
297
+ begin
298
+ Async do
299
+ IRB::Irb.new(workspace).run(IRB.conf)
300
+ ensure
301
+ Grumlin.close
302
+ end
303
+ rescue StandardError, Interrupt, Async::Stop, IRB::Abort
304
+ retry
305
+ end
306
+ end
353
307
 
354
- IRB.setup(binding.source_location[0], argv: [])
355
- workspace = IRB::WorkSpace.new(binding)
308
+ def inspect
309
+ 'main'
310
+ end
356
311
 
357
- IRB::Irb.new(workspace).run(IRB.conf)
358
- ensure
359
- Grumlin.close
360
- end
312
+ def to_s
313
+ inspect
361
314
  end
362
315
  end
363
316
  ```
@@ -381,13 +334,13 @@ require 'async/rspec'
381
334
  require require "grumlin/test/rspec"
382
335
  ...
383
336
  config.include_context(Async::RSpec::Reactor) # Runs async reactor
384
- config.include_context(Grumlin::Test::RSpec::GremlinContext) # Injects sugar and makes sure client is closed after every test
337
+ config.include_context(Grumlin::Test::RSpec::GremlinContext) # Injects `g`, `__` and expressions, makes sure client is closed after every test
385
338
  config.include_context(Grumlin::Test::RSpec::DBCleanerContext) # Cleans the database before every test
386
339
  ...
387
340
  ```
388
341
 
389
- It is highly recommended to use `Grumlin::Sugar` or `Grumlin::Repository` and not trying to use lower level APIs
390
- as they are subject to change.
342
+ It is highly recommended to use `Grumlin::Repository` and not trying to use lower level APIs as they are subject to
343
+ change.
391
344
 
392
345
  ## Development
393
346
 
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ require "rubocop/rake_task"
9
9
  RSpec::Core::RakeTask.new(:spec)
10
10
  RuboCop::RakeTask.new
11
11
 
12
- task default: %i[rubocop spec]
12
+ task default: [:rubocop, :spec]
13
13
 
14
14
  namespace :definitions do
15
15
  desc "Format definitions.yml"
data/bin/console CHANGED
@@ -13,10 +13,25 @@ Grumlin.configure do |config|
13
13
  config.url = ENV.fetch("GREMLIN_URL", "ws://localhost:8182/gremlin")
14
14
  end
15
15
 
16
- Async do
17
- include Grumlin::Sugar
16
+ class Repository
17
+ extend Grumlin::Repository
18
+
19
+ def start_irb
20
+ IRB.setup(nil)
21
+ IRB.conf[:PROMPT][:DEFAULT] = { PROMPT_I: "%N(main):%03n:%i> ",
22
+ PROMPT_N: "%N(main):%03n:%i> ",
23
+ PROMPT_S: "%N(main):%03n:%i%l ",
24
+ PROMPT_C: "%N(main):%03n:%i* ",
25
+ RETURN: "=> %s\n" }
26
+ workspace = IRB::WorkSpace.new(binding)
27
+ irb = IRB::Irb.new(workspace)
28
+ IRB.conf[:MAIN_CONTEXT] = irb.context
29
+ irb.eval_input
30
+ end
31
+ end
18
32
 
19
- IRB.start
33
+ Async do
34
+ Repository.new.start_irb
20
35
  ensure
21
36
  Grumlin.close
22
37
  end
data/doc/middlewares.md CHANGED
@@ -14,10 +14,11 @@ execution process:
14
14
  Normally these middlewares must never be rearranged or removed from the stack. Middlewares added after
15
15
  `Middlewares::RunQuery` will not be executed.
16
16
 
17
- # Writing a middleware for Grumlin
17
+ ## Writing a middleware for Grumlin
18
18
 
19
- This entire feature is built on top of [ibsciss-middleware](https://github.com/Ibsciss/ruby-middleware).
20
- Please refer to it's docs if you want to implement a middleware.
19
+ This entire feature is built on top of [ibsciss-middleware](https://github.com/Ibsciss/ruby-middleware) but uses a
20
+ slightly modified `Builder` which caches the chain for better performance.
21
+ Please refer to ibsciss-middleware docs if you want to implement a middleware.
21
22
 
22
23
 
23
24
  A minimal middleware that measures query execution time and puts it back to `env`:
@@ -31,13 +32,6 @@ class MeasureExecutionTime < Grumlin::Middlewares::Middleware # Middleware provi
31
32
  result
32
33
  end
33
34
  end
34
-
35
- Grumlin.configure do |cfg|
36
- cfg.url = ENV.fetch("GREMLIN_URL", "ws://localhost:8182/gremlin")
37
- cfg.provider = :tinkergraph
38
-
39
- cfg.middlewares.insert_before Grumlin::Middlewares::CastResults, MeasureExecutionTime
40
- end
41
35
  ```
42
36
 
43
37
  When placed right before `Grumlin::Middlewares::CastResults` your middleware will have access to every intermediate result
@@ -56,3 +50,48 @@ Other useful parts of `env`:
56
50
  - `env[:session_id]` - id of the session when executed inside a transaction, otherwise `nil`
57
51
  - `env[:pool]` - connection pool that will be used to interact with the server
58
52
  - `env[:need_results]` - flag stating whether the client needs the query execution results(`toList`, `next`) or not(`iterate`)
53
+
54
+ ## Adding your middleware to the stack
55
+
56
+ There are two ways of adding middlewares to your queries:
57
+ - `global` - add the middleware to every single query from every single repository
58
+ - `per repository` - add the middleware to queries performed by particular repositories
59
+
60
+ Grumlin has one global middleware stack and every repository defines it's which is by default is a
61
+ copy of the global stack. This means one can easily modify repository's stack without worrying about the global one.
62
+
63
+ When inherited a class extending `Grumlin::Repository` will copy it's middlewares to the subclass, they can also be
64
+ modified independently from the parent's middlewares.
65
+
66
+ ### Adding a middleware globally
67
+ ```ruby
68
+ Grumlin.configure do |cfg|
69
+ cfg.url = ENV.fetch("GREMLIN_URL", "ws://localhost:8182/gremlin")
70
+ cfg.provider = :tinkergraph
71
+
72
+ cfg.middlewares do |b|
73
+ b.insert_before Grumlin::Middlewares::CastResults, MeasureExecutionTime
74
+ end
75
+ end
76
+ ```
77
+
78
+ ### Adding a middleware to a repository
79
+ ```ruby
80
+ class MyRepository
81
+ # MyRepository inherits a copy of global middlewares
82
+ extend Grumlin::Repository
83
+
84
+ # SomeOtherMiddleware will be added to MyRepository's middlewares only
85
+ middlewares do |b|
86
+ b.insert_before Grumlin::Middlewares::CastResults, MeasureExecutionTime
87
+ end
88
+ end
89
+
90
+ class AnotherRepository < MyRepository
91
+ # AnotherRepository inherits parent's middlewares
92
+ middlewares do |b|
93
+ # SomeOtherMiddleware will be added to AnotherRepository's middlewares only
94
+ b.insert_before Grumlin::Middlewares::CastResults, SomeOtherMiddleware
95
+ end
96
+ end
97
+ ```
data/lib/async/channel.rb CHANGED
@@ -1,74 +1,72 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Async
4
- # Channel is a wrapper around Async::Queue that provides
5
- # a protocol and handy tools for passing data, exceptions and closing.
6
- # It is designed to be used only with one publisher and one subscriber
7
- class Channel
8
- class ChannelError < StandardError; end
9
-
10
- class ChannelClosedError < ChannelError; end
11
-
12
- def initialize
13
- @queue = Async::Queue.new
14
- @closed = false
15
- end
3
+ # Channel is a wrapper around Async::Queue that provides
4
+ # a protocol and handy tools for passing data, exceptions and closing.
5
+ # It is designed to be used only with one publisher and one subscriber
6
+ class Async::Channel
7
+ class ChannelError < StandardError; end
16
8
 
17
- def closed?
18
- @closed
19
- end
9
+ class ChannelClosedError < ChannelError; end
20
10
 
21
- def open?
22
- !@closed
23
- end
11
+ def initialize
12
+ @queue = Async::Queue.new
13
+ @closed = false
14
+ end
24
15
 
25
- # Methods for a publisher
26
- def <<(payload)
27
- raise(ChannelClosedError, "Cannot send to a closed channel") if @closed
16
+ def closed?
17
+ @closed
18
+ end
28
19
 
29
- @queue << [:payload, payload]
30
- end
20
+ def open?
21
+ !@closed
22
+ end
31
23
 
32
- def exception(exception)
33
- raise(ChannelClosedError, "Cannot send to a closed channel") if closed?
24
+ # Methods for a publisher
25
+ def <<(payload)
26
+ raise(ChannelClosedError, "Cannot send to a closed channel") if @closed
34
27
 
35
- @queue << [:exception, exception]
36
- end
28
+ @queue << [:payload, payload]
29
+ end
37
30
 
38
- def close
39
- return if closed?
31
+ def exception(exception)
32
+ raise(ChannelClosedError, "Cannot send to a closed channel") if closed?
40
33
 
41
- @queue << [:close]
42
- @closed = true
43
- end
34
+ @queue << [:exception, exception]
35
+ end
44
36
 
45
- def close!
46
- return if closed?
37
+ def close
38
+ return if closed?
47
39
 
48
- exception(ChannelClosedError.new("Channel was forcefully closed"))
49
- close
50
- end
40
+ @queue << [:close]
41
+ @closed = true
42
+ end
51
43
 
52
- # Methods for a subscriber
53
- def dequeue
54
- each do |payload| # rubocop:disable Lint/UnreachableLoop this is intended
55
- return payload
56
- end
44
+ def close!
45
+ return if closed?
46
+
47
+ exception(ChannelClosedError.new("Channel was forcefully closed"))
48
+ close
49
+ end
50
+
51
+ # Methods for a subscriber
52
+ def dequeue
53
+ each do |payload| # rubocop:disable Lint/UnreachableLoop this is intended
54
+ return payload
57
55
  end
56
+ end
58
57
 
59
- def each
60
- raise(ChannelClosedError, "Cannot receive from a closed channel") if closed?
61
-
62
- @queue.each do |type, payload|
63
- case type
64
- when :exception
65
- payload.set_backtrace(caller + (payload.backtrace || [])) # A hack to preserve full backtrace
66
- raise payload
67
- when :payload
68
- yield payload
69
- when :close
70
- break
71
- end
58
+ def each
59
+ raise(ChannelClosedError, "Cannot receive from a closed channel") if closed?
60
+
61
+ @queue.each do |type, payload|
62
+ case type
63
+ when :exception
64
+ payload.set_backtrace(caller + (payload.backtrace || [])) # A hack to preserve full backtrace
65
+ raise payload
66
+ when :payload
67
+ yield payload
68
+ when :close
69
+ break
72
70
  end
73
71
  end
74
72
  end
@@ -1,21 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Grumlin
4
- module Benchmark
5
- class Repository
6
- extend Grumlin::Repository
3
+ class Grumlin::Benchmark::Repository
4
+ extend Grumlin::Repository
7
5
 
8
- shortcut :simple_test do
9
- self.V
10
- end
6
+ shortcut :simple_test do
7
+ self.V
8
+ end
11
9
 
12
- def simple_test
13
- g.V.bytecode.serialize
14
- end
10
+ def simple_test
11
+ g.V.bytecode.serialize
12
+ end
15
13
 
16
- def simple_test_with_shortcut
17
- g.simple_test.bytecode.serialize
18
- end
19
- end
14
+ def simple_test_with_shortcut
15
+ g.simple_test.bytecode.serialize
20
16
  end
21
17
  end