grumlin 0.19.5 → 0.20.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: 80bbea20c7a9e194618b59cc128ae8e783af4d342ddd9ca56039f08013218a81
4
- data.tar.gz: baf7565f084501e8b4488bf5d7d8e09a5c786b91181dda46919b0668662ecfd0
3
+ metadata.gz: 0ab9e228cb2cd8ecc761136dab0e92a42aae268708aecf5784aac670a4404ecb
4
+ data.tar.gz: 984d2323e97056291370c37dadc2cf90d694f27caa753053a110165985dc067b
5
5
  SHA512:
6
- metadata.gz: 3c2760d46e3bada592f71da13bbbec31a970cde6c112a57d06f435eb673ba213573d98e82e65080c5453f521c27c27f6037472cd1db65046dfa31432f879d3e1
7
- data.tar.gz: e6a073136f3ebeaaf1cac78a6c6886a2e7a91beeaf18a61d340e18ab968018859861de64fc01a04f7ba708fea9ab8859706b6edb5f27c9432a2116717d323c55
6
+ metadata.gz: 27a73c8e77850b99e030c129f8df2e30fc6933ad4da29e5a205b7812c64c88f24d7aceb2128af6687fc4bf35056509421989d2cae5a51c5db6f53c18f735fe97
7
+ data.tar.gz: adf371f27c60f2c0e70feaafcfede32dc64beef09b098bf35f01270b37049ee5ce76a68c184bf80abe33c7069ca8b947bbd54ecdcab42fd461a8bb09c270b1b1
data/.rspec CHANGED
@@ -1,2 +1,3 @@
1
1
  --color
2
+ --require dead_end
2
3
  --require spec_helper
data/Gemfile CHANGED
@@ -13,6 +13,7 @@ gem "overcommit"
13
13
  gem "rake"
14
14
 
15
15
  gem "async-rspec"
16
+ gem "dead_end"
16
17
  gem "factory_bot"
17
18
  gem "rspec"
18
19
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- grumlin (0.19.5)
4
+ grumlin (0.20.0)
5
5
  async-pool (~> 0.3)
6
6
  async-websocket (~> 0.19)
7
7
  oj (~> 3.13)
@@ -17,7 +17,7 @@ GEM
17
17
  minitest (>= 5.1)
18
18
  tzinfo (~> 2.0)
19
19
  ast (2.4.2)
20
- async (1.30.2)
20
+ async (1.30.3)
21
21
  console (~> 1.10)
22
22
  nio4r (~> 2.3)
23
23
  timers (~> 4.1)
@@ -48,6 +48,7 @@ GEM
48
48
  concurrent-ruby (1.1.10)
49
49
  console (1.15.3)
50
50
  fiber-local
51
+ dead_end (4.0.0)
51
52
  diff-lcs (1.5.0)
52
53
  docile (1.4.0)
53
54
  e2mmap (0.1.0)
@@ -71,7 +72,7 @@ GEM
71
72
  racc (~> 1.4)
72
73
  nokogiri (1.13.6-x86_64-linux)
73
74
  racc (~> 1.4)
74
- oj (3.13.14)
75
+ oj (3.13.16)
75
76
  overcommit (0.59.1)
76
77
  childprocess (>= 0.6.3, < 5)
77
78
  iniparse (~> 1.4)
@@ -172,6 +173,7 @@ PLATFORMS
172
173
  DEPENDENCIES
173
174
  async-rspec
174
175
  benchmark-ips
176
+ dead_end
175
177
  factory_bot
176
178
  grumlin!
177
179
  memory_profiler
data/README.md CHANGED
@@ -143,6 +143,20 @@ class MyRepository
143
143
  end
144
144
  ```
145
145
 
146
+ ##### Overriding standard steps
147
+
148
+ Sometimes it may be useful to override standard steps. Grumlin does not allow it by default, but one
149
+ is still able to override standard steps if they know what they are doing:
150
+
151
+ ```ruby
152
+ shortcut :addV, override: true do |label|
153
+ super(label).property(:default, :value)
154
+ end
155
+ ```
156
+
157
+ This will create a new shortcut that overrides the standard step `addV` and adds default properties to all vertices
158
+ created by the repository that uses this shortcut.
159
+
146
160
  #### Grumlin::Repository
147
161
  `Grumlin::Repository` combines functionality of `Grumlin::Sugar` and `Grumlin::Shortcuts` as well as adds a few useful
148
162
  shortcuts to make gremlin code more rubyish. Can be used as a drop in replacement for `Grumlin::Sugar`. Remember that
@@ -167,6 +181,23 @@ class MyRepository
167
181
  hasAll(T.label => :triangle, color: color)
168
182
  end
169
183
 
184
+ # `default_vertex_properties` and `default_edge_properties`
185
+ # override `addV` and `addE` according and inject hashes returned from passed
186
+ # as properties for newly created vertices and edges.
187
+ # In case if a repository is inherited, newly defined default properties will be merged to
188
+ # default properties defined in the parent repository.
189
+ default_vertex_properties do |_label|
190
+ {
191
+ created_at: Time.now.to_i
192
+ }
193
+ end
194
+
195
+ default_edge_properties do |_label|
196
+ {
197
+ created_at: Time.now.to_i
198
+ }
199
+ end
200
+
170
201
  # g and __ are already aware of shortcuts
171
202
  query(:triangles_with_color, return_mode: :list) do |color| # :list is the default return mode, also possible: :none, :single, :traversal
172
203
  g.V.hasLabel(:triangle)
data/bin/console CHANGED
@@ -7,6 +7,8 @@ require "grumlin"
7
7
  require "irb"
8
8
  require "irb/completion"
9
9
 
10
+ require "dead_end"
11
+
10
12
  Grumlin.configure do |config|
11
13
  config.url = ENV.fetch("GREMLIN_URL", "ws://localhost:8182/gremlin")
12
14
  end
@@ -1,3 +1,7 @@
1
1
  FROM tinkerpop/gremlin-server
2
2
 
3
+ RUN rm -rf /opt/gremlin-server/ext/tinkergraph-gremlin
4
+
5
+ ADD tinkergraph-gremlin /opt/gremlin-server/ext/tinkergraph-gremlin
6
+
3
7
  ADD tinkergraph-empty.properties /opt/gremlin-server/conf/
data/grumlin.gemspec CHANGED
@@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
21
21
  spec.metadata["homepage_uri"] = spec.homepage
22
22
  spec.metadata["source_code_uri"] = "https://github.com/zhulik/grumlin"
23
23
  spec.metadata["changelog_uri"] = "https://github.com/zhulik/grumlin/blob/master/CHANGELOG.md"
24
+ spec.metadata["rubygems_mfa_required"] = "true"
24
25
 
25
26
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
26
27
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
@@ -32,7 +33,4 @@ Gem::Specification.new do |spec|
32
33
  spec.add_dependency "oj", "~> 3.13"
33
34
  spec.add_dependency "retryable", "~> 3.0"
34
35
  spec.add_dependency "zeitwerk", "~> 2.6"
35
- spec.metadata = {
36
- "rubygems_mfa_required" => "true"
37
- }
38
36
  end
data/lib/definitions.yml CHANGED
@@ -8,9 +8,11 @@ steps:
8
8
  - aggregate
9
9
  - and
10
10
  - as
11
+ - barrier
11
12
  - both
12
13
  - bothE
13
14
  - by
15
+ - cap
14
16
  - choose
15
17
  - coalesce
16
18
  - constant
@@ -19,6 +21,7 @@ steps:
19
21
  - drop
20
22
  - elementMap
21
23
  - emit
24
+ - filter
22
25
  - fold
23
26
  - from
24
27
  - group
@@ -37,6 +40,9 @@ steps:
37
40
  - label
38
41
  - limit
39
42
  - map
43
+ - match
44
+ - max
45
+ - min
40
46
  - none
41
47
  - not
42
48
  - option
@@ -77,9 +83,13 @@ steps:
77
83
  - withSack
78
84
  - withSideEffect
79
85
  expressions:
86
+ cardinality:
87
+ - list
88
+ - set
89
+ - single
80
90
  column:
81
- - keys
82
- - values
91
+ - keys
92
+ - values
83
93
  operator:
84
94
  - addAll
85
95
  - and
@@ -1,32 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Grumlin
4
- class Action
5
- START_STEPS = Grumlin.definitions.dig(:steps, :start).map(&:to_sym).freeze
6
- CONFIGURATION_STEPS = Grumlin.definitions.dig(:steps, :configuration).map(&:to_sym).freeze
7
- REGULAR_STEPS = Grumlin.definitions.dig(:steps, :regular).map(&:to_sym).freeze
4
+ class Action < Steppable
5
+ attr_reader :name, :args, :params, :next_step, :configuration_steps, :previous_step, :shortcut
8
6
 
9
- ALL_STEPS = START_STEPS + CONFIGURATION_STEPS + REGULAR_STEPS
10
-
11
- attr_reader :name, :args, :params, :shortcuts, :next_step, :configuration_steps, :previous_step
12
-
13
- def initialize(name, args: [], params: {}, previous_step: nil, shortcuts: {}, pool: Grumlin.default_pool)
7
+ def initialize(name, args: [], params: {}, previous_step: nil, pool: nil)
8
+ super()
14
9
  @name = name.to_sym
15
10
  @args = args # TODO: add recursive validation: only json types or Action
16
11
  @params = params # TODO: add recursive validation: only json types
17
12
  @previous_step = previous_step
18
- @shortcuts = shortcuts
19
- @pool = pool
20
- end
21
-
22
- ALL_STEPS.each do |step|
23
- define_method step do |*args, **params|
24
- step(step, *args, **params)
25
- end
26
- end
27
-
28
- def step(name, *args, **params)
29
- Action.new(name, args: args, params: params, previous_step: self, shortcuts: @shortcuts, pool: @pool)
13
+ @shortcut = shortcuts[@name]
14
+ @pool = pool || Grumlin.default_pool
30
15
  end
31
16
 
32
17
  def configuration_step?
@@ -45,23 +30,13 @@ module Grumlin
45
30
  ALL_STEPS.include?(@name)
46
31
  end
47
32
 
48
- def shortcut?
49
- @shortcuts.key?(@name)
50
- end
51
-
52
- def method_missing(name, *args, **params)
53
- return step(name, *args, **params) if @shortcuts.key?(name)
54
-
55
- super
56
- end
57
-
58
33
  def ==(other)
59
34
  self.class == other.class &&
60
35
  @name == other.name &&
61
36
  @args == other.args &&
62
37
  @params == other.params &&
63
38
  @previous_step == other.previous_step &&
64
- @shortcuts == other.shortcuts
39
+ shortcuts == other.shortcuts
65
40
  end
66
41
 
67
42
  def steps
@@ -108,11 +83,5 @@ module Grumlin
108
83
  client.write(bytecode(no_return: true))
109
84
  end
110
85
  end
111
-
112
- private
113
-
114
- def respond_to_missing?(name, _include_private = false)
115
- @shortcuts.key?(name)
116
- end
117
86
  end
118
87
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grumlin
4
+ module Expressions
5
+ module Cardinality
6
+ SUPPORTED_STEPS = Grumlin.definitions.dig(:expressions, :cardinality).map(&:to_sym).freeze
7
+
8
+ class << self
9
+ extend Expression
10
+
11
+ define_steps(SUPPORTED_STEPS, "Cardinality")
12
+ end
13
+ end
14
+ end
15
+ end
@@ -16,7 +16,7 @@ module Grumlin
16
16
 
17
17
  class << self
18
18
  # TODO: support more predicates
19
- %i[eq neq].each do |predicate|
19
+ %i[eq gt lt neq].each do |predicate|
20
20
  define_method predicate do |*args|
21
21
  Predicate.new("P", predicate, value: args[0])
22
22
  end
@@ -5,6 +5,8 @@ module Grumlin
5
5
  module InstanceMethods
6
6
  include Grumlin::Expressions
7
7
 
8
+ extend Forwardable
9
+
8
10
  UPSERT_RETRY_PARAMS = {
9
11
  on: [Grumlin::AlreadyExistsError, Grumlin::ConcurrentInsertFailedError],
10
12
  sleep_method: ->(n) { Async::Task.current.sleep(n) },
@@ -14,12 +16,10 @@ module Grumlin
14
16
 
15
17
  DEFAULT_ERROR_HANDLING_STRATEGY = ErrorHandlingStrategy.new(mode: :retry, **UPSERT_RETRY_PARAMS)
16
18
 
17
- def __
18
- @__ ||= TraversalStart.new(self.class.shortcuts)
19
- end
19
+ def_delegators :shortcuts, :g, :__
20
20
 
21
- def g
22
- @g ||= TraversalStart.new(self.class.shortcuts)
21
+ def shortcuts
22
+ self.class.shortcuts
23
23
  end
24
24
 
25
25
  def drop_vertex(id)
@@ -23,7 +23,7 @@ module Grumlin
23
23
 
24
24
  define_method name do |*args, query_params: {}, **params, &block|
25
25
  t = instance_exec(*args, **params, &query_block)
26
- return t if self.class.empty_result?(t)
26
+ return t if t.nil? || (t.respond_to?(:empty?) && t.empty?)
27
27
 
28
28
  unless t.is_a?(Grumlin::Action)
29
29
  raise WrongQueryResult,
@@ -45,8 +45,20 @@ module Grumlin
45
45
  end
46
46
  end
47
47
 
48
+ def default_vertex_properties(&block)
49
+ shortcut :addV, override: true do |*args|
50
+ super(*args).props(**block.call(*args)) # rubocop:disable Performance/RedundantBlockCall
51
+ end
52
+ end
53
+
54
+ def default_edge_properties(&block)
55
+ shortcut :addE, override: true do |*args|
56
+ super(*args).props(**block.call(*args)) # rubocop:disable Performance/RedundantBlockCall
57
+ end
58
+ end
59
+
48
60
  def validate_return_mode!(return_mode)
49
- return return_mode if RETURN_MODES.key?(return_mode)
61
+ return return_mode if RETURN_MODES.include?(return_mode)
50
62
 
51
63
  raise ArgumentError, "unsupported return mode #{return_mode}. Supported modes: #{RETURN_MODES.keys}"
52
64
  end
@@ -60,9 +72,5 @@ module Grumlin
60
72
  raise ArgumentError,
61
73
  "postprocess_with must be a String, Symbol or a callable object, given: #{postprocess_with.class}"
62
74
  end
63
-
64
- def empty_result?(result)
65
- result.nil? || (result.respond_to?(:empty?) && result.empty?)
66
- end
67
75
  end
68
76
  end
@@ -38,7 +38,7 @@ module Grumlin
38
38
  end
39
39
 
40
40
  def add_request(request)
41
- raise RequestAlreadyAddedError if @requests.key?(request[:requestId])
41
+ raise RequestAlreadyAddedError if @requests.include?(request[:requestId])
42
42
 
43
43
  Async::Channel.new.tap do |channel|
44
44
  @requests[request[:requestId]] = { request: request, result: [], channel: channel }
@@ -73,7 +73,7 @@ module Grumlin
73
73
  end
74
74
 
75
75
  def ongoing_request?(request_id)
76
- @requests.key?(request_id)
76
+ @requests.include?(request_id)
77
77
  end
78
78
 
79
79
  def clear
@@ -9,8 +9,9 @@ module Grumlin
9
9
  def_delegator :@block, :arity
10
10
  def_delegator :@block, :source_location
11
11
 
12
- def initialize(name, &block)
12
+ def initialize(name, lazy: true, &block)
13
13
  @name = name
14
+ @lazy = lazy
14
15
  @block = block
15
16
  end
16
17
 
@@ -18,6 +19,10 @@ module Grumlin
18
19
  @name == other.name && @block == other.block
19
20
  end
20
21
 
22
+ def lazy?
23
+ @lazy
24
+ end
25
+
21
26
  # TODO: to_s, inspect, preview
22
27
 
23
28
  def apply(object, *args, **params)
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grumlin
4
+ module Shortcuts
5
+ class Storage
6
+ extend Forwardable
7
+
8
+ class << self
9
+ def [](other)
10
+ new(other)
11
+ end
12
+
13
+ def empty
14
+ @empty ||= new
15
+ end
16
+ end
17
+
18
+ def initialize(storage = {})
19
+ @storage = storage
20
+ storage.each do |n, s|
21
+ add(n, s)
22
+ end
23
+ end
24
+
25
+ def_delegator :@storage, :[]
26
+ def_delegator :@storage, :include?, :known?
27
+ def_delegator :@storage, :keys, :names
28
+
29
+ def ==(other)
30
+ @storage == other.storage
31
+ end
32
+
33
+ def add(name, shortcut)
34
+ # not lazy shortcuts are allowed to be overridden
35
+ if known?(name) && @storage[name] != shortcut && shortcut.lazy?
36
+ raise ArgumentError,
37
+ "shortcut '#{name}' already exists"
38
+ end
39
+
40
+ @storage[name] = shortcut
41
+
42
+ ac = action_class
43
+
44
+ shortcut_methods_module.define_method(name) do |*args, **params|
45
+ next ac.new(name, args: args, params: params, previous_step: self)
46
+ end
47
+ extend_traversal_classes(shortcut) unless shortcut.lazy?
48
+ end
49
+
50
+ def add_from(other)
51
+ other.storage.each do |name, shortcut|
52
+ add(name, shortcut)
53
+ end
54
+ end
55
+
56
+ def g
57
+ __
58
+ end
59
+
60
+ def __
61
+ @__ ||= traversal_start_class.new
62
+ end
63
+
64
+ def traversal_start_class
65
+ @traversal_start_class ||= shortcut_aware_class(TraversalStart)
66
+ end
67
+
68
+ def action_class
69
+ @action_class ||= shortcut_aware_class(Action)
70
+ end
71
+
72
+ protected
73
+
74
+ attr_reader :storage
75
+
76
+ private
77
+
78
+ def shortcut_methods_module
79
+ @shortcut_methods_module ||= begin
80
+ shorts = self
81
+ Module.new do
82
+ define_method :shortcuts do
83
+ shorts
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ def shortcut_aware_class(base)
90
+ methods = shortcut_methods_module
91
+ Class.new(base) do
92
+ include methods
93
+ end
94
+ end
95
+
96
+ def extend_traversal_classes(shortcut)
97
+ m = Module.new do
98
+ define_method(shortcut.name, &shortcut.block)
99
+ end
100
+ action_class.include(m)
101
+ traversal_start_class.include(m)
102
+ end
103
+ end
104
+ end
105
+ end
@@ -5,16 +5,16 @@ module Grumlin
5
5
  module Upserts
6
6
  extend Grumlin::Shortcuts
7
7
 
8
- shortcut :upsertV do |label, id, create_properties, update_properties|
8
+ shortcut :upsertV do |label, id, create_properties = {}, update_properties = {}|
9
9
  self.V(id)
10
10
  .fold
11
- .coalesce( # TODO: extract upsert pattern to a shortcut
11
+ .coalesce(
12
12
  __.unfold,
13
13
  __.addV(label).props(**create_properties.merge(T.id => id))
14
14
  ).props(**update_properties)
15
15
  end
16
16
 
17
- shortcut :upsertE do |label, from, to, create_properties, update_properties|
17
+ shortcut :upsertE do |label, from, to, create_properties = {}, update_properties = {}|
18
18
  self.V(from)
19
19
  .outE(label).where(__.inV.hasId(to))
20
20
  .fold
@@ -11,33 +11,26 @@ module Grumlin
11
11
  subclass.shortcuts_from(self)
12
12
  end
13
13
 
14
- def shortcut(name, shortcut = nil, &block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
14
+ def shortcut(name, shortcut = nil, override: false, lazy: true, &block)
15
15
  name = name.to_sym
16
- # TODO: blocklist of names to avoid conflicts with standard methods?
17
- if Grumlin::Action::REGULAR_STEPS.include?(name)
18
- raise ArgumentError,
19
- "cannot use names of standard gremlin steps"
20
- end
16
+ lazy = false if override
21
17
 
22
- if (shortcut.nil? && block.nil?) || (shortcut && block)
23
- raise ArgumentError, "either shortcut or block must be passed"
18
+ if Grumlin::Action::REGULAR_STEPS.include?(name) && !override
19
+ raise ArgumentError,
20
+ "overriding standard gremlin steps is not allowed, if you know what you're doing, pass `override: true`"
24
21
  end
25
22
 
26
- shortcut ||= Shortcut.new(name, &block)
23
+ raise ArgumentError, "either shortcut or block must be passed" if [shortcut, block].count(&:nil?) != 1
27
24
 
28
- raise ArgumentError, "shortcut '#{name}' already exists" if shortcuts.key?(name) && shortcuts[name] != shortcut
29
-
30
- shortcuts[name] = shortcut
25
+ shortcuts.add(name, shortcut || Shortcut.new(name, lazy: lazy, &block))
31
26
  end
32
27
 
33
28
  def shortcuts_from(other_shortcuts)
34
- other_shortcuts.shortcuts.each do |name, shortcut|
35
- shortcut(name, shortcut)
36
- end
29
+ shortcuts.add_from(other_shortcuts.shortcuts)
37
30
  end
38
31
 
39
32
  def shortcuts
40
- @shortcuts ||= {}
33
+ @shortcuts ||= Storage.new
41
34
  end
42
35
  end
43
36
  end
@@ -4,15 +4,17 @@ module Grumlin
4
4
  class ShortcutsApplyer
5
5
  class << self
6
6
  def call(steps)
7
- return steps unless steps.uses_shortcuts?
7
+ return steps if !steps.is_a?(Steps) || !steps.uses_shortcuts?
8
8
 
9
9
  shortcuts = steps.shortcuts
10
10
 
11
- configuration_steps = process_steps(steps.configuration_steps, shortcuts)
12
- regular_steps = process_steps(steps.steps, shortcuts)
11
+ steps = [
12
+ *process_steps(steps.configuration_steps, shortcuts),
13
+ *process_steps(steps.steps, shortcuts)
14
+ ]
13
15
 
14
16
  Steps.new(shortcuts).tap do |processed_steps|
15
- (configuration_steps + regular_steps).each do |step|
17
+ steps.each do |step|
16
18
  processed_steps.add(step.name, args: step.args, params: step.params)
17
19
  end
18
20
  end
@@ -22,21 +24,17 @@ module Grumlin
22
24
 
23
25
  def process_steps(steps, shortcuts) # rubocop:disable Metrics/AbcSize
24
26
  steps.each_with_object([]) do |step, result|
25
- args = step.args.map do |arg|
26
- arg.is_a?(Steps) ? ShortcutsApplyer.call(arg) : arg
27
- end
27
+ args = step.args.map { |arg| call(arg) }
28
28
 
29
- if shortcuts.include?(step.name)
30
- t = TraversalStart.new(shortcuts)
31
- action = shortcuts[step.name].apply(t, *args, **step.params)
32
- next if action.nil? || action == t # Shortcut did not add any steps
29
+ shortcut = shortcuts[step.name]
30
+ next result << StepData.new(step.name, args: args, params: step.params) unless shortcut&.lazy?
33
31
 
34
- new_steps = ShortcutsApplyer.call(Steps.from(action))
35
- result.concat(new_steps.configuration_steps)
36
- result.concat(new_steps.steps)
37
- else
38
- result << StepData.new(step.name, args: args, params: step.params)
39
- end
32
+ t = shortcuts.__
33
+ action = shortcut.apply(t, *args, **step.params)
34
+ next if action.nil? || action == t # Shortcut did not add any steps
35
+
36
+ new_steps = call(Steps.from(action))
37
+ result.concat(new_steps.configuration_steps, new_steps.steps)
40
38
  end
41
39
  end
42
40
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grumlin
4
+ class Steppable
5
+ extend Forwardable
6
+
7
+ START_STEPS = Grumlin.definitions.dig(:steps, :start).map(&:to_sym).freeze
8
+ REGULAR_STEPS = Grumlin.definitions.dig(:steps, :regular).map(&:to_sym).freeze
9
+ CONFIGURATION_STEPS = Grumlin.definitions.dig(:steps, :configuration).map(&:to_sym).freeze
10
+
11
+ ALL_STEPS = START_STEPS + CONFIGURATION_STEPS + REGULAR_STEPS
12
+
13
+ def initialize
14
+ return if respond_to?(:shortcuts)
15
+
16
+ raise RuntimerError,
17
+ "steppable must not be initialized directly, use Grumlin::Shortcuts::Storage#g or #__ instead"
18
+ end
19
+
20
+ ALL_STEPS.each do |step|
21
+ define_method step do |*args, **params|
22
+ shortcuts.action_class.new(step, args: args, params: params, previous_step: self)
23
+ end
24
+ end
25
+
26
+ def step(name, *args, **params)
27
+ shortcuts.action_class.new(name, args: args, params: params, previous_step: self)
28
+ end
29
+
30
+ def_delegator :shortcuts, :__
31
+ end
32
+ end
data/lib/grumlin/steps.rb CHANGED
@@ -11,7 +11,7 @@ module Grumlin
11
11
  shortcuts = action.shortcuts
12
12
  actions = []
13
13
 
14
- until action.nil?
14
+ until action.nil? || action.is_a?(TraversalStart)
15
15
  actions.unshift(action)
16
16
  action = action.previous_step
17
17
  end
@@ -56,7 +56,7 @@ module Grumlin
56
56
 
57
57
  def shortcuts?(steps_ary)
58
58
  steps_ary.any? do |step|
59
- @shortcuts.include?(step.name) || step.args.any? do |arg|
59
+ @shortcuts.known?(step.name) || step.args.any? do |arg|
60
60
  arg.is_a?(Steps) ? arg.uses_shortcuts? : false
61
61
  end
62
62
  end
data/lib/grumlin/sugar.rb CHANGED
@@ -6,12 +6,10 @@ module Grumlin
6
6
  base.include(Grumlin::Expressions)
7
7
  end
8
8
 
9
- def __(shortcuts = {})
10
- Grumlin::TraversalStart.new(shortcuts) # TODO: allow only regular and start steps
11
- end
12
-
13
- def g(shortcuts = {})
14
- Grumlin::TraversalStart.new(shortcuts)
9
+ %i[__ g].each do |name|
10
+ define_method name do |cuts = Shortcuts::Storage.empty|
11
+ cuts.send(name)
12
+ end
15
13
  end
16
14
  end
17
15
  end
@@ -1,39 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Grumlin
4
- class TraversalStart
5
- START_STEPS = Grumlin.definitions.dig(:steps, :start).map(&:to_sym).freeze
6
- REGULAR_STEPS = Grumlin.definitions.dig(:steps, :regular).map(&:to_sym).freeze
7
- CONFIGURATION_STEPS = Grumlin.definitions.dig(:steps, :configuration).map(&:to_sym).freeze
8
-
9
- ALL_STEPS = START_STEPS + CONFIGURATION_STEPS + REGULAR_STEPS
10
-
11
- ALL_STEPS.each do |step|
12
- define_method step do |*args, **params|
13
- step(step, *args, **params)
14
- end
15
- end
16
-
17
- attr_reader :shortcuts
18
-
19
- def initialize(shortcuts)
20
- @shortcuts = shortcuts
21
- end
22
-
23
- def step(name, *args, **params)
24
- Action.new(name, args: args, params: params, shortcuts: @shortcuts)
25
- end
26
-
27
- def method_missing(name, *args, **params)
28
- return step(name, *args, **params) if @shortcuts.key?(name)
29
-
30
- super
31
- end
32
-
33
- def __
34
- @__ ||= TraversalStart.new(@shortcuts) # TODO: allow only regular and start steps
35
- end
36
-
4
+ class TraversalStart < Steppable
37
5
  def to_s(*)
38
6
  self.class.to_s
39
7
  end
@@ -41,11 +9,5 @@ module Grumlin
41
9
  def inspect
42
10
  self.class.inspect
43
11
  end
44
-
45
- private
46
-
47
- def respond_to_missing?(name, _include_private = false)
48
- @shortcuts.key?(name)
49
- end
50
12
  end
51
13
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Grumlin
4
- VERSION = "0.19.5"
4
+ VERSION = "0.20.0"
5
5
  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.19.5
4
+ version: 0.20.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-06-14 00:00:00.000000000 Z
11
+ date: 2022-07-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async-pool
@@ -108,6 +108,8 @@ files:
108
108
  - docker-compose.yml
109
109
  - gremlin_server/Dockerfile
110
110
  - gremlin_server/tinkergraph-empty.properties
111
+ - gremlin_server/tinkergraph-gremlin/lib/tinkergraph-gremlin-3.5.3.jar
112
+ - gremlin_server/tinkergraph-gremlin/plugin/tinkergraph-gremlin-3.5.3.jar
111
113
  - grumlin.gemspec
112
114
  - lib/async/channel.rb
113
115
  - lib/definitions.yml
@@ -116,6 +118,7 @@ files:
116
118
  - lib/grumlin/benchmark/repository.rb
117
119
  - lib/grumlin/client.rb
118
120
  - lib/grumlin/edge.rb
121
+ - lib/grumlin/expressions/cardinality.rb
119
122
  - lib/grumlin/expressions/column.rb
120
123
  - lib/grumlin/expressions/expression.rb
121
124
  - lib/grumlin/expressions/operator.rb
@@ -135,9 +138,11 @@ files:
135
138
  - lib/grumlin/shortcut.rb
136
139
  - lib/grumlin/shortcuts.rb
137
140
  - lib/grumlin/shortcuts/properties.rb
141
+ - lib/grumlin/shortcuts/storage.rb
138
142
  - lib/grumlin/shortcuts/upserts.rb
139
143
  - lib/grumlin/shortcuts_applyer.rb
140
144
  - lib/grumlin/step_data.rb
145
+ - lib/grumlin/steppable.rb
141
146
  - lib/grumlin/steps.rb
142
147
  - lib/grumlin/steps_serializers/bytecode.rb
143
148
  - lib/grumlin/steps_serializers/human_readable_bytecode.rb
@@ -159,6 +164,9 @@ homepage: https://github.com/zhulik/grumlin
159
164
  licenses:
160
165
  - MIT
161
166
  metadata:
167
+ homepage_uri: https://github.com/zhulik/grumlin
168
+ source_code_uri: https://github.com/zhulik/grumlin
169
+ changelog_uri: https://github.com/zhulik/grumlin/blob/master/CHANGELOG.md
162
170
  rubygems_mfa_required: 'true'
163
171
  post_install_message:
164
172
  rdoc_options: []