grumlin 0.23.0 → 1.0.0.rc2

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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +9 -9
  3. data/Gemfile.lock +1 -1
  4. data/README.md +100 -142
  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 +19 -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. data/lib/grumlin.rb +13 -0
  77. metadata +9 -6
  78. data/lib/grumlin/middlewares/frozen_builder.rb +0 -18
  79. 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: 1321ed876a7cc42db4e40d16fe7a7c7baa4cd0d955ad58901ecfd07051700e7b
4
+ data.tar.gz: 1b66499966537dff77767ddc5936222a7129b29004f05a60d4f578ede6c08a9f
5
5
  SHA512:
6
- metadata.gz: f87b6a69c71ebd867f227b35e13a50c499d054c6688747465e05a41426167ee3ffea5afbfb1875ca5c49e6a0c2a97f42ea20b93f9cf32cd5966942ba844f839c
7
- data.tar.gz: 4b5262eacf5e57f4ad95e6cc5f450d924858b1e238e2bf3943b9b127da53db36c76078b22d8ba5d244aa35e5d0ddfc4db45516481bd41c58bbe2123ac262dd5f
6
+ metadata.gz: d6158025426480ae13930848e370014e2fc77325d650d5540c11a516b4ed982ee5b3526049d7f8e1b669d9b2ddffe2370e4dc5e8ce4cda55755e69f3b72750d3
7
+ data.tar.gz: 33c02aca842d77dbe1284504b9c00195a72301bbcf23ba69cbeeffa5ca75d4d95aa71791e3d7228e863c62d1048739c70f3df90515f0339698741c1938e49484
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.rc2)
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,18 @@ 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)`
151
+ - `upsert_vertices(edges, batch_size: 100, on_failure: :retry, start: g, **params)`
256
152
  - `upsert_edge(label, from:, to:, create_properties: {}, update_properties: {}, on_failure: :retry, start: g, **params)`
257
153
  - `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)`
154
+
155
+ **Note**: all upsert methods expect your provider has support for user supplied string ids for nodes and edges
156
+ respectively. For edges and if `create_properties[T.id]` if nil, grumlin will generate a uuid-like id out of `from` and
157
+ `to` vertex ids and edge's label to ensure uniqueness of the edge. If you manually provide an id, it's your
158
+ responsibility to ensure it's uniquely identifies the edge using it's `from`, `to` and `label`.
259
159
 
260
160
  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
161
+ with [retryable](https://github.com/nfedyashev/retryable). **params will be merged to the default config for upserts
262
162
  and passed to `Retryable.retryable`. In case if you want to modify retryable behaviour you are to do so.
263
163
 
264
164
  If you want to use these methods inside a transaction simply pass your `gtx` as `start` parameter:
@@ -270,7 +170,7 @@ end
270
170
 
271
171
  If you don't want to define you own repository, simply use
272
172
 
273
- `Grumlin::Repository.new` returns an instance of an anonymous class extending `Grumlin::Repository`.
173
+ `Grumlin::Repository.new` returns an instance of an anonymous class extending `Grumlin::Repository`.
274
174
 
275
175
  **Usage**
276
176
 
@@ -295,6 +195,62 @@ it may be useful for debugging. Note that one needs to call a termination step m
295
195
 
296
196
  method will return profiling data of the results.
297
197
 
198
+ #### Shortcuts
199
+
200
+ **Shortcuts** is a way to share and organize gremlin code. They let developers define their own steps consisting of
201
+ sequences of standard gremlin steps, other shortcuts and even add new initially unsupported by Grumlin steps.
202
+ Remember ActiveRecord scopes? Shortcuts are very similar.
203
+
204
+ **Important**: if a shortcut's name matches a name of a method defined on the wrapped object, this shortcut will be
205
+ be ignored because methods have higher priority.
206
+
207
+ **Defining**:
208
+ ```ruby
209
+
210
+ # Defining shortcuts
211
+ class ColorShortcut
212
+ extend Grumlin::Shortcuts
213
+
214
+ # Custom step
215
+ shortcut :hasColor do |color|
216
+ has(:color, color)
217
+ end
218
+ end
219
+
220
+ class ChooseShortcut
221
+ extend Grumlin::Shortcuts
222
+
223
+ # Standard Gremlin step
224
+ shortcut :choose do |*args|
225
+ step(:choose, *args)
226
+ end
227
+ end
228
+
229
+ class AllShortcuts
230
+ extend Grumlin::Shortcuts
231
+
232
+ # Adding shortcuts from other modules
233
+ shortcuts_from ColorShortcut
234
+ shortcuts_from ChooseShortcut
235
+ end
236
+ ```
237
+
238
+ ##### Overriding standard steps and shortcuts
239
+
240
+ Sometimes it may be useful to override standard steps. Grumlin does not allow it by default, but one
241
+ is still able to override standard steps if they know what they are doing:
242
+
243
+ ```ruby
244
+ shortcut :addV, override: true do |label|
245
+ super(label).property(:default, :value)
246
+ end
247
+ ```
248
+
249
+ This will create a new shortcut that overrides the standard step `addV` and adds default properties to all vertices
250
+ created by the repository that uses this shortcut.
251
+
252
+ Shortcuts also can be overridden, but super() is not available.
253
+
298
254
  ##### Middlewares
299
255
 
300
256
  Middlewares can be used to perform certain actions before and after every query made by `Grumlin`. It can be useful for
@@ -323,41 +279,43 @@ end # commits automatically
323
279
 
324
280
  #### IRB
325
281
 
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.
282
+ Please check out [bin/console](bin/console) for inspiration. A similar trick may be applied to PRY.
339
283
 
340
284
  #### Rails console
341
285
 
342
286
  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
287
+ a custom console class. It should look somewhat like
344
288
 
345
289
  ```ruby
346
- class MyRailsConsole
347
- def self.start
290
+ class Async::RailsConsole
291
+ extend Grumlin::Repository
292
+
293
+ def start
294
+ self.class.shortcuts_from Shortcuts::Content
295
+
348
296
  IRB::WorkSpace.prepend(Rails::Console::BacktraceCleaner)
349
297
  IRB::ExtendCommandBundle.include(Rails::ConsoleMethods)
350
298
 
351
- Async do
352
- include Grumlin::Sugar
299
+ IRB.setup(binding.source_location[0], argv: [])
300
+ workspace = IRB::WorkSpace.new(binding)
301
+
302
+ begin
303
+ Async do
304
+ IRB::Irb.new(workspace).run(IRB.conf)
305
+ ensure
306
+ Grumlin.close
307
+ end
308
+ rescue StandardError, Interrupt, Async::Stop, IRB::Abort
309
+ retry
310
+ end
311
+ end
353
312
 
354
- IRB.setup(binding.source_location[0], argv: [])
355
- workspace = IRB::WorkSpace.new(binding)
313
+ def inspect
314
+ 'main'
315
+ end
356
316
 
357
- IRB::Irb.new(workspace).run(IRB.conf)
358
- ensure
359
- Grumlin.close
360
- end
317
+ def to_s
318
+ inspect
361
319
  end
362
320
  end
363
321
  ```
@@ -381,13 +339,13 @@ require 'async/rspec'
381
339
  require require "grumlin/test/rspec"
382
340
  ...
383
341
  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
342
+ config.include_context(Grumlin::Test::RSpec::GremlinContext) # Injects `g`, `__` and expressions, makes sure client is closed after every test
385
343
  config.include_context(Grumlin::Test::RSpec::DBCleanerContext) # Cleans the database before every test
386
344
  ...
387
345
  ```
388
346
 
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.
347
+ It is highly recommended to use `Grumlin::Repository` and not trying to use lower level APIs as they are subject to
348
+ change.
391
349
 
392
350
  ## Development
393
351
 
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