grumlin 0.16.1 → 0.17.0

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: ce713ebd08c676dfe38124e0286963ea18ee8d5d51f678096fd5f2ae8c28c51c
4
- data.tar.gz: 6cd25c9ac701a2276fdb470b55b4ebaf123323521c6cd8d4d87365b68d604426
3
+ metadata.gz: 2d63d3923f895d20e89fd1647495d99bb3a97888689c8f25c34973355d7c80e1
4
+ data.tar.gz: 878546a65736522f3c1f00f42741b6b207e992a1983321205d05406e0a74ed6b
5
5
  SHA512:
6
- metadata.gz: 81b5b522b5d183240d27cb36285f448e4918386cd267ea84fcffb2cc763d156d272844a4ffab2e00999d5c5be129930d905220506e07702ff150c49ac7388d1b
7
- data.tar.gz: f4d56b0a66d91f8f454964a8d42de46fa0b6b85595c48e67e09875e01bfdb96eb131e0c6cb5ec395ebeb7dda59c45ff67c445f88e75a12a03436689d9ba14279
6
+ metadata.gz: 60bf726b74019b36bb0437c78b97ea1ba78703058ba2a619805e0081d49158f30bb67cc7918b959cf0375c37a5600632a1df805563edccb0266b71c9ab70f1de
7
+ data.tar.gz: cc7dc9ecfd45c67b28301593d3ba60e471e7a9993460ce39dcb912bbed5fb0aa01ed25bcf52f49634f704d6732ba563d849fb8d492276f19fe83e5e8531a8181
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- grumlin (0.16.1)
4
+ grumlin (0.17.0)
5
5
  async-pool (~> 0.3)
6
6
  async-websocket (~> 0.19)
7
7
  oj (~> 3.12)
@@ -44,7 +44,7 @@ GEM
44
44
  benchmark (0.1.1)
45
45
  childprocess (4.0.0)
46
46
  concurrent-ruby (1.1.8)
47
- console (1.14.0)
47
+ console (1.15.0)
48
48
  fiber-local
49
49
  diff-lcs (1.4.4)
50
50
  docile (1.4.0)
data/README.md CHANGED
@@ -150,7 +150,7 @@ shortcuts to make gremlin code more rubyish. Can be used as a drop in replacemen
150
150
  or `Grumlin::Shortcuts` can be inherited**, successors don't need to extend them again and have access to shortcuts
151
151
  defined in the ancestor.
152
152
 
153
- **Using**:
153
+ **Definition**
154
154
 
155
155
  ```ruby
156
156
  class MyRepository
@@ -167,15 +167,45 @@ class MyRepository
167
167
  hasAll(T.label => :triangle, color: color)
168
168
  end
169
169
 
170
- # g and __ are already aware of shortcuts
171
- def red_triangles
170
+ # g and __ are already aware of shortcuts
171
+ query(:triangles_with_color, return_mode: :list) do |color| # :list is the default return mode, also possible: :none, :single, :traversal
172
172
  g.V.hasLabel(:triangle)
173
- .hasColor("red")
174
- .toList
173
+ .hasColor(color)
175
174
  end
175
+ # Note that when using the `query` one does not need to call a termination step like `next` or `toList`,
176
+ # repository does it automatically in according to the `return_mode` parameter.
176
177
  end
177
178
  ```
178
179
 
180
+ Each `return_mode` is mapped to a particular termination step:
181
+ - `:list` - `toList`
182
+ - `:single` - `next`
183
+ - `:none` - `iterate`
184
+ - `:traversal` - do not execute the query and return the traversal as is
185
+
186
+ **Usage**
187
+
188
+ To execute the query defined in a query block one simply needs to call a method with the same name:
189
+
190
+ `MyRepository.new.triangles_with_color(:red)`
191
+
192
+ One can also override the `return_mode`:
193
+
194
+ `MyRepository.new.triangles_with_color(:red, query_params: { return_mode: :single })`
195
+
196
+ or even pass a block to the method and a raw traversal will be yielded:
197
+ ```ruby
198
+ MyRepository.new.triangles_with_color(:red) do |t|
199
+ t.has(:other_property, :some_value).toList
200
+ end
201
+ ```
202
+ it may be useful for debugging. Note that one needs to call a termination step manually in this case.
203
+
204
+ `query` also provides a helper for profiling requests:
205
+ `MyRepository.new.triangles_with_color(:red, query_params: { profile: true })`
206
+
207
+ method will return profiling data of the results.
208
+
179
209
  #### IRB
180
210
 
181
211
  An example of how to start an IRB session with support for executing gremlin queries:
@@ -2,6 +2,13 @@
2
2
 
3
3
  module Grumlin
4
4
  module Repository
5
+ RETURN_MODES = {
6
+ list: :toList,
7
+ none: :iterate,
8
+ single: :next,
9
+ traversal: :nil
10
+ }.freeze
11
+
5
12
  module InstanceMethods
6
13
  def __
7
14
  TraversalStart.new(self.class.shortcuts)
@@ -19,5 +26,53 @@ module Grumlin
19
26
 
20
27
  base.shortcuts_from(Grumlin::Shortcuts::Properties)
21
28
  end
29
+
30
+ def query(name, return_mode: :list, postprocess_with: nil, &query_block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
31
+ return_mode = validate_return_mode!(return_mode)
32
+ postprocess_with = validate_postprocess_with!(postprocess_with)
33
+
34
+ define_method name do |*args, query_params: {}, **params, &block|
35
+ t = instance_exec(*args, **params, &query_block)
36
+ return t if self.class.empty_result?(t)
37
+
38
+ unless t.is_a?(Grumlin::Action)
39
+ raise WrongQueryResult,
40
+ "queries must return #{Grumlin::Action}, nil or an empty collection. Given: #{t.class}"
41
+ end
42
+
43
+ return block.call(t) unless block.nil?
44
+
45
+ return t.profile.next if query_params[:profile] == true
46
+
47
+ return_mode = self.class.validate_return_mode!(query_params[:return_mode] || return_mode)
48
+
49
+ return t if return_mode == :traversal
50
+
51
+ t.public_send(RETURN_MODES[return_mode]).tap do |result|
52
+ return postprocess_with.call(result) if postprocess_with.respond_to?(:call)
53
+ return send(postprocess_with, result) unless postprocess_with.nil?
54
+ end
55
+ end
56
+ end
57
+
58
+ def validate_return_mode!(return_mode)
59
+ return return_mode if RETURN_MODES.key?(return_mode)
60
+
61
+ raise ArgumentError, "unsupported return mode #{return_mode}. Supported modes: #{RETURN_MODES.keys}"
62
+ end
63
+
64
+ def validate_postprocess_with!(postprocess_with)
65
+ if postprocess_with.nil? || postprocess_with.is_a?(Symbol) ||
66
+ postprocess_with.is_a?(String) || postprocess_with.respond_to?(:call)
67
+ return postprocess_with
68
+ end
69
+
70
+ raise ArgumentError,
71
+ "postprocess_with must be a String, Symbol or a callable object, given: #{postprocess_with.class}"
72
+ end
73
+
74
+ def empty_result?(result)
75
+ result.nil? || (result.respond_to?(:empty?) && result.empty?)
76
+ end
22
77
  end
23
78
  end
@@ -69,7 +69,7 @@ module Grumlin
69
69
  def cast_map(value)
70
70
  Hash[*value].transform_keys do |key|
71
71
  next key.to_sym if key.respond_to?(:to_sym)
72
- next cast(key) if key[:@type]
72
+ next cast(key) if key[:@type] # TODO: g.V.group.by(:none_existing_property).next
73
73
 
74
74
  raise UnknownMapKey, key, value
75
75
  end.transform_values { |v| cast(v) }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Grumlin
4
- VERSION = "0.16.1"
4
+ VERSION = "0.17.0"
5
5
  end
data/lib/grumlin.rb CHANGED
@@ -100,6 +100,10 @@ module Grumlin
100
100
  end
101
101
  end
102
102
 
103
+ class RepositoryError < Error; end
104
+
105
+ class WrongQueryResult < RepositoryError; end
106
+
103
107
  class Config
104
108
  attr_accessor :url, :pool_size, :client_concurrency, :client_factory
105
109
 
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.16.1
4
+ version: 0.17.0
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-03-15 00:00:00.000000000 Z
11
+ date: 2022-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async-pool