grumlin 0.16.1 → 0.18.1
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 +4 -4
- data/.rubocop.yml +1 -0
- data/Gemfile.lock +2 -2
- data/README.md +52 -14
- data/lib/grumlin/action.rb +0 -6
- data/lib/grumlin/repository.rb +126 -1
- data/lib/grumlin/shortcuts/properties.rb +3 -7
- data/lib/grumlin/shortcuts_applyer.rb +4 -4
- data/lib/grumlin/step_data.rb +6 -4
- data/lib/grumlin/steps.rb +7 -7
- data/lib/grumlin/steps_serializers/bytecode.rb +2 -2
- data/lib/grumlin/steps_serializers/human_readable_bytecode.rb +4 -10
- data/lib/grumlin/steps_serializers/string.rb +10 -9
- data/lib/grumlin/typing.rb +2 -2
- data/lib/grumlin/version.rb +1 -1
- data/lib/grumlin.rb +4 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 573e2c9cda13465c0560d36e9e10d8bcdda5e0ea01ea4bbf89cb8d6cb943f6de
|
4
|
+
data.tar.gz: 8dd6fa7264875f372c6117352f2e87c7984457ff3f94da57f8f19d91344c4dd2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2eea2219d92cd29ef311993dcd0bcd0e9d8906d39474d93733c8406952e93babf85d4468b6acd15ac1d114c940c49533603960fa496c8f757223d016b5619a03
|
7
|
+
data.tar.gz: 39c8821a89cb1194d973c7b2dee5e96ad90288e2a611ef42a080586987759949453a2c7bade5be56d500588a8655a485c6c415c075c1295534bbc8a419bf2d43
|
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
grumlin (0.
|
4
|
+
grumlin (0.18.1)
|
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.
|
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
@@ -77,8 +77,7 @@ end
|
|
77
77
|
|
78
78
|
**Shortcuts** is a way to share and organize gremlin code. They let developers define their own steps consisting of
|
79
79
|
sequences of standard gremlin steps, other shortcuts and even add new initially unsupported by Grumlin steps.
|
80
|
-
Remember ActiveRecord scopes? Shortcuts are very similar.
|
81
|
-
a proxy object that simply proxies all methods existing in the wrapped object to it and handles shortcuts.
|
80
|
+
Remember ActiveRecord scopes? Shortcuts are very similar.
|
82
81
|
|
83
82
|
**Important**: if a shortcut's name matches a name of a method defined on the wrapped object, this shortcut will be
|
84
83
|
be ignored because methods have higher priority. You cannot override supported by Grumlin steps with shortcuts,
|
@@ -128,17 +127,18 @@ class MyRepository
|
|
128
127
|
|
129
128
|
# Wrapping a traversal
|
130
129
|
def red_triangles
|
131
|
-
|
132
|
-
|
133
|
-
|
130
|
+
g(self.class.shortcuts).V.hasLabel(:triangle)
|
131
|
+
.hasColor("red")
|
132
|
+
.toList
|
134
133
|
end
|
135
134
|
|
136
135
|
# Wrapping _
|
137
136
|
def something_else
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
137
|
+
g(self.class.shortcuts).V.hasColor("red")
|
138
|
+
.repeat(__(self.class.shortcuts))
|
139
|
+
.out(:has)
|
140
|
+
.hasColor("blue")
|
141
|
+
.toList
|
142
142
|
end
|
143
143
|
end
|
144
144
|
```
|
@@ -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
|
-
**
|
153
|
+
**Definition**
|
154
154
|
|
155
155
|
```ruby
|
156
156
|
class MyRepository
|
@@ -167,15 +167,53 @@ class MyRepository
|
|
167
167
|
hasAll(T.label => :triangle, color: color)
|
168
168
|
end
|
169
169
|
|
170
|
-
# g and __ are already aware of shortcuts
|
171
|
-
|
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(
|
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
|
+
`Grumlin::Repository` also provides a set of generic CRUD operations:
|
187
|
+
- `add_vertex(label, id = nil, **properties)`
|
188
|
+
- `add_edge(label, id = nil, from:, to:, **properties)`
|
189
|
+
- `drop_vertex(id)`
|
190
|
+
- `drop_edge(id = nil, from: nil, to: nil, label: nil)`
|
191
|
+
- `upsert_vertex(label, id, create_properties: {}, update_properties: {})`
|
192
|
+
- `upsert_edge(label, from:, to:, create_properties: {}, update_properties: {})`
|
193
|
+
|
194
|
+
**Usage**
|
195
|
+
|
196
|
+
To execute the query defined in a query block one simply needs to call a method with the same name:
|
197
|
+
|
198
|
+
`MyRepository.new.triangles_with_color(:red)`
|
199
|
+
|
200
|
+
One can also override the `return_mode`:
|
201
|
+
|
202
|
+
`MyRepository.new.triangles_with_color(:red, query_params: { return_mode: :single })`
|
203
|
+
|
204
|
+
or even pass a block to the method and a raw traversal will be yielded:
|
205
|
+
```ruby
|
206
|
+
MyRepository.new.triangles_with_color(:red) do |t|
|
207
|
+
t.has(:other_property, :some_value).toList
|
208
|
+
end
|
209
|
+
```
|
210
|
+
it may be useful for debugging. Note that one needs to call a termination step manually in this case.
|
211
|
+
|
212
|
+
`query` also provides a helper for profiling requests:
|
213
|
+
`MyRepository.new.triangles_with_color(:red, query_params: { profile: true })`
|
214
|
+
|
215
|
+
method will return profiling data of the results.
|
216
|
+
|
179
217
|
#### IRB
|
180
218
|
|
181
219
|
An example of how to start an IRB session with support for executing gremlin queries:
|
data/lib/grumlin/action.rb
CHANGED
@@ -49,12 +49,6 @@ module Grumlin
|
|
49
49
|
@shortcuts.key?(@name)
|
50
50
|
end
|
51
51
|
|
52
|
-
def arguments
|
53
|
-
@arguments ||= [*@args].tap do |args|
|
54
|
-
args << @params if @params.any?
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
52
|
def method_missing(name, *args, **params)
|
59
53
|
return step(name, *args, **params) if @shortcuts.key?(name)
|
60
54
|
|
data/lib/grumlin/repository.rb
CHANGED
@@ -2,7 +2,16 @@
|
|
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
|
13
|
+
include Grumlin::Expressions
|
14
|
+
|
6
15
|
def __
|
7
16
|
TraversalStart.new(self.class.shortcuts)
|
8
17
|
end
|
@@ -10,14 +19,130 @@ module Grumlin
|
|
10
19
|
def g
|
11
20
|
TraversalStart.new(self.class.shortcuts)
|
12
21
|
end
|
22
|
+
|
23
|
+
def drop_vertex(id)
|
24
|
+
g.V(id).drop.iterate
|
25
|
+
end
|
26
|
+
|
27
|
+
def drop_edge(id = nil, from: nil, to: nil, label: nil) # rubocop:disable Metrics/AbcSize
|
28
|
+
raise ArgumentError, "either id or from:, to: and label: must be passed" if [id, from, to, label].all?(&:nil?)
|
29
|
+
return g.E(id).drop.iterate unless id.nil?
|
30
|
+
|
31
|
+
raise ArgumentError, "from:, to: and label: must be passed" if [from, to, label].any?(&:nil?)
|
32
|
+
|
33
|
+
g.V(from).outE(label).where(__.inV.hasId(to)).limit(1).drop.iterate
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_vertex(label, id = nil, **properties)
|
37
|
+
id ||= properties[T.id]
|
38
|
+
properties = except(properties, T.id)
|
39
|
+
|
40
|
+
t = g.addV(label)
|
41
|
+
t = t.props(T.id => id) unless id.nil?
|
42
|
+
t.props(**properties).next
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_edge(label, id = nil, from:, to:, **properties)
|
46
|
+
id ||= properties[T.id]
|
47
|
+
properties = except(properties, T.label)
|
48
|
+
properties[T.id] = id
|
49
|
+
|
50
|
+
g.addE(label).from(__.V(from)).to(__.V(to)).props(**properties).next
|
51
|
+
end
|
52
|
+
|
53
|
+
def upsert_vertex(label, id, create_properties: {}, update_properties: {}) # rubocop:disable Metrics/AbcSize
|
54
|
+
create_properties = except(create_properties, T.id, T.label)
|
55
|
+
update_properties = except(update_properties, T.id, T.label)
|
56
|
+
g.V(id)
|
57
|
+
.fold
|
58
|
+
.coalesce(
|
59
|
+
__.unfold,
|
60
|
+
__.addV(label).props(**create_properties.merge(T.id => id))
|
61
|
+
).props(**update_properties)
|
62
|
+
.next
|
63
|
+
end
|
64
|
+
|
65
|
+
# Only from and to are used to find the existing edge, if one wants to assign an id to a created edge,
|
66
|
+
# it must be passed as T.id in via create_properties.
|
67
|
+
def upsert_edge(label, from:, to:, create_properties: {}, update_properties: {}) # rubocop:disable Metrics/AbcSize
|
68
|
+
create_properties = except(create_properties, T.label)
|
69
|
+
update_properties = except(update_properties, T.id, T.label)
|
70
|
+
|
71
|
+
g.V(from)
|
72
|
+
.outE(label).where(__.inV.hasId(to))
|
73
|
+
.fold
|
74
|
+
.coalesce(
|
75
|
+
__.unfold,
|
76
|
+
__.addE(label).from(__.V(from)).to(__.V(to)).props(**create_properties)
|
77
|
+
).props(**update_properties).next
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
# A polyfill for Hash#except for ruby 2.x environments without ActiveSupport
|
83
|
+
# TODO: delete and use native Hash#except when after ruby 2.7 is deprecated.
|
84
|
+
def except(hash, *keys)
|
85
|
+
return hash.except(*keys) if hash.respond_to?(:except)
|
86
|
+
|
87
|
+
hash.each_with_object({}) do |(k, v), res|
|
88
|
+
res[k] = v unless keys.include?(k)
|
89
|
+
end
|
90
|
+
end
|
13
91
|
end
|
14
92
|
|
15
93
|
def self.extended(base)
|
16
94
|
base.extend(Grumlin::Shortcuts)
|
17
|
-
base.include(Grumlin::Expressions)
|
18
95
|
base.include(InstanceMethods)
|
19
96
|
|
20
97
|
base.shortcuts_from(Grumlin::Shortcuts::Properties)
|
21
98
|
end
|
99
|
+
|
100
|
+
def query(name, return_mode: :list, postprocess_with: nil, &query_block) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
101
|
+
return_mode = validate_return_mode!(return_mode)
|
102
|
+
postprocess_with = validate_postprocess_with!(postprocess_with)
|
103
|
+
|
104
|
+
define_method name do |*args, query_params: {}, **params, &block|
|
105
|
+
t = instance_exec(*args, **params, &query_block)
|
106
|
+
return t if self.class.empty_result?(t)
|
107
|
+
|
108
|
+
unless t.is_a?(Grumlin::Action)
|
109
|
+
raise WrongQueryResult,
|
110
|
+
"queries must return #{Grumlin::Action}, nil or an empty collection. Given: #{t.class}"
|
111
|
+
end
|
112
|
+
|
113
|
+
return block.call(t) unless block.nil?
|
114
|
+
|
115
|
+
return t.profile.next if query_params[:profile] == true
|
116
|
+
|
117
|
+
return_mode = self.class.validate_return_mode!(query_params[:return_mode] || return_mode)
|
118
|
+
|
119
|
+
return t if return_mode == :traversal
|
120
|
+
|
121
|
+
t.public_send(RETURN_MODES[return_mode]).tap do |result|
|
122
|
+
return postprocess_with.call(result) if postprocess_with.respond_to?(:call)
|
123
|
+
return send(postprocess_with, result) unless postprocess_with.nil?
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def validate_return_mode!(return_mode)
|
129
|
+
return return_mode if RETURN_MODES.key?(return_mode)
|
130
|
+
|
131
|
+
raise ArgumentError, "unsupported return mode #{return_mode}. Supported modes: #{RETURN_MODES.keys}"
|
132
|
+
end
|
133
|
+
|
134
|
+
def validate_postprocess_with!(postprocess_with)
|
135
|
+
if postprocess_with.nil? || postprocess_with.is_a?(Symbol) ||
|
136
|
+
postprocess_with.is_a?(String) || postprocess_with.respond_to?(:call)
|
137
|
+
return postprocess_with
|
138
|
+
end
|
139
|
+
|
140
|
+
raise ArgumentError,
|
141
|
+
"postprocess_with must be a String, Symbol or a callable object, given: #{postprocess_with.class}"
|
142
|
+
end
|
143
|
+
|
144
|
+
def empty_result?(result)
|
145
|
+
result.nil? || (result.respond_to?(:empty?) && result.empty?)
|
146
|
+
end
|
22
147
|
end
|
23
148
|
end
|
@@ -5,17 +5,13 @@ module Grumlin
|
|
5
5
|
module Properties
|
6
6
|
extend Grumlin::Shortcuts
|
7
7
|
|
8
|
-
shortcut :props do
|
9
|
-
|
10
|
-
|
11
|
-
props.reduce(self) do |tt, (prop, value)|
|
8
|
+
shortcut :props do |**props|
|
9
|
+
props.compact.reduce(self) do |tt, (prop, value)|
|
12
10
|
tt.property(prop, value)
|
13
11
|
end
|
14
12
|
end
|
15
13
|
|
16
|
-
shortcut :hasAll do
|
17
|
-
next if props.nil? # TODO: fixme, add proper support for **params
|
18
|
-
|
14
|
+
shortcut :hasAll do |**props|
|
19
15
|
props.reduce(self) do |tt, (prop, value)|
|
20
16
|
tt.has(prop, value)
|
21
17
|
end
|
@@ -18,7 +18,7 @@ module Grumlin
|
|
18
18
|
|
19
19
|
Steps.new(shortcuts).tap do |processed_steps|
|
20
20
|
(configuration_steps + regular_steps).each do |step|
|
21
|
-
processed_steps.add(step.name, step.
|
21
|
+
processed_steps.add(step.name, args: step.args, params: step.params)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -27,20 +27,20 @@ module Grumlin
|
|
27
27
|
|
28
28
|
def process_steps(steps, shortcuts) # rubocop:disable Metrics/AbcSize
|
29
29
|
steps.each_with_object([]) do |step, result|
|
30
|
-
|
30
|
+
args = step.args.map do |arg|
|
31
31
|
arg.is_a?(Steps) ? ShortcutsApplyer.call(arg) : arg
|
32
32
|
end
|
33
33
|
|
34
34
|
if shortcuts.include?(step.name)
|
35
35
|
t = TraversalStart.new(shortcuts)
|
36
|
-
action = shortcuts[step.name].apply(t, *
|
36
|
+
action = shortcuts[step.name].apply(t, *args, **step.params)
|
37
37
|
next if action.nil? || action == t # Shortcut did not add any steps
|
38
38
|
|
39
39
|
new_steps = ShortcutsApplyer.call(Steps.from(action))
|
40
40
|
result.concat(new_steps.configuration_steps)
|
41
41
|
result.concat(new_steps.steps)
|
42
42
|
else
|
43
|
-
result << StepData.new(step.name,
|
43
|
+
result << StepData.new(step.name, args: args, params: step.params)
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
data/lib/grumlin/step_data.rb
CHANGED
@@ -2,17 +2,19 @@
|
|
2
2
|
|
3
3
|
module Grumlin
|
4
4
|
class StepData
|
5
|
-
attr_reader :name, :
|
5
|
+
attr_reader :name, :args, :params
|
6
6
|
|
7
|
-
def initialize(name,
|
7
|
+
def initialize(name, args: [], params: {})
|
8
8
|
@name = name
|
9
|
-
@
|
9
|
+
@args = args
|
10
|
+
@params = params
|
10
11
|
end
|
11
12
|
|
12
13
|
def ==(other)
|
13
14
|
self.class == other.class &&
|
14
15
|
@name == other.name &&
|
15
|
-
@
|
16
|
+
@args == other.args &&
|
17
|
+
@params == other.params
|
16
18
|
end
|
17
19
|
end
|
18
20
|
end
|
data/lib/grumlin/steps.rb
CHANGED
@@ -18,7 +18,7 @@ module Grumlin
|
|
18
18
|
|
19
19
|
new(shortcuts).tap do |chain|
|
20
20
|
actions.each do |act|
|
21
|
-
chain.add(act.name, act.
|
21
|
+
chain.add(act.name, args: act.args, params: act.params)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -31,10 +31,10 @@ module Grumlin
|
|
31
31
|
@steps = steps
|
32
32
|
end
|
33
33
|
|
34
|
-
def add(name,
|
35
|
-
return add_configuration_step(name,
|
34
|
+
def add(name, args: [], params: {})
|
35
|
+
return add_configuration_step(name, args: args, params: params) if CONFIGURATION_STEPS.include?(name)
|
36
36
|
|
37
|
-
StepData.new(name, cast_arguments(
|
37
|
+
StepData.new(name, args: cast_arguments(args), params: params).tap do |step|
|
38
38
|
@steps << step
|
39
39
|
end
|
40
40
|
end
|
@@ -56,16 +56,16 @@ module Grumlin
|
|
56
56
|
|
57
57
|
def shortcuts?(steps_ary)
|
58
58
|
steps_ary.any? do |step|
|
59
|
-
@shortcuts.include?(step.name) || step.
|
59
|
+
@shortcuts.include?(step.name) || step.args.any? do |arg|
|
60
60
|
arg.is_a?(Steps) ? arg.uses_shortcuts? : false
|
61
61
|
end
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
def add_configuration_step(name,
|
65
|
+
def add_configuration_step(name, args: [], params: {})
|
66
66
|
raise ArgumentError, "cannot use configuration steps after start step was used" unless @steps.empty?
|
67
67
|
|
68
|
-
StepData.new(name, cast_arguments(
|
68
|
+
StepData.new(name, args: cast_arguments(args), params: params).tap do |step|
|
69
69
|
@configuration_steps << step
|
70
70
|
end
|
71
71
|
end
|
@@ -6,7 +6,7 @@ module Grumlin
|
|
6
6
|
# constructor params: no_return: true|false, default false
|
7
7
|
# TODO: add pretty
|
8
8
|
|
9
|
-
NONE_STEP = StepData.new("none"
|
9
|
+
NONE_STEP = StepData.new("none")
|
10
10
|
|
11
11
|
def serialize
|
12
12
|
steps = ShortcutsApplyer.call(@steps)
|
@@ -22,7 +22,7 @@ module Grumlin
|
|
22
22
|
private
|
23
23
|
|
24
24
|
def serialize_step(step)
|
25
|
-
[step.name, *step.
|
25
|
+
[step.name, *step.args.map { |arg| serialize_arg(arg) }, step.params.any? ? step.params : nil].compact
|
26
26
|
end
|
27
27
|
|
28
28
|
def serialize_arg(arg)
|
@@ -2,22 +2,16 @@
|
|
2
2
|
|
3
3
|
module Grumlin
|
4
4
|
module StepsSerializers
|
5
|
-
class HumanReadableBytecode <
|
5
|
+
class HumanReadableBytecode < Bytecode
|
6
6
|
def serialize
|
7
7
|
steps = ShortcutsApplyer.call(@steps)
|
8
|
-
[
|
9
|
-
|
10
|
-
|
11
|
-
def serialize_steps(steps)
|
12
|
-
steps.map { |s| serialize_step(s) }
|
8
|
+
[steps.configuration_steps, steps.steps].map do |stps|
|
9
|
+
stps.map { |s| serialize_step(s) }
|
10
|
+
end
|
13
11
|
end
|
14
12
|
|
15
13
|
private
|
16
14
|
|
17
|
-
def serialize_step(step)
|
18
|
-
[step.name, *step.arguments.map { |arg| serialize_arg(arg) }]
|
19
|
-
end
|
20
|
-
|
21
15
|
def serialize_arg(arg)
|
22
16
|
return arg.to_s if arg.is_a?(TypedValue)
|
23
17
|
return serialize_predicate(arg) if arg.is_a?(Expressions::P::Predicate)
|
@@ -10,14 +10,21 @@ module Grumlin
|
|
10
10
|
def serialize
|
11
11
|
steps = @params[:apply_shortcuts] ? ShortcutsApplyer.call(@steps) : @steps
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
steps = [steps.configuration_steps, steps.steps].map do |stps|
|
14
|
+
stps.map { |step| serialize_step(step) }
|
15
|
+
end
|
15
16
|
|
16
|
-
"#{prefix}.#{(
|
17
|
+
"#{prefix}.#{(steps[0] + steps[1]).join(".")}"
|
17
18
|
end
|
18
19
|
|
19
20
|
private
|
20
21
|
|
22
|
+
def serialize_step(step)
|
23
|
+
"#{step.name}(#{(step.args + [step.params.any? ? step.params : nil].compact).map do |a|
|
24
|
+
serialize_arg(a)
|
25
|
+
end.join(", ")})"
|
26
|
+
end
|
27
|
+
|
21
28
|
def prefix
|
22
29
|
@prefix ||= @params[:anonymous] ? "__" : "g"
|
23
30
|
end
|
@@ -31,12 +38,6 @@ module Grumlin
|
|
31
38
|
|
32
39
|
StepsSerializers::String.new(arg, anonymous: true, **@params).serialize
|
33
40
|
end
|
34
|
-
|
35
|
-
def serialize_steps(steps)
|
36
|
-
steps.map do |step|
|
37
|
-
"#{step.name}(#{step.arguments.map { |a| serialize_arg(a) }.join(", ")})"
|
38
|
-
end
|
39
|
-
end
|
40
41
|
end
|
41
42
|
end
|
42
43
|
end
|
data/lib/grumlin/typing.rb
CHANGED
@@ -18,7 +18,7 @@ module Grumlin
|
|
18
18
|
# "g:VertexProperty"=> ->(value) { value }, # TODO: implement me
|
19
19
|
"g:TraversalMetrics" => ->(value) { cast_map(value[:@value]) },
|
20
20
|
"g:Metrics" => ->(value) { cast_map(value[:@value]) },
|
21
|
-
"g:T" => ->(value) { value
|
21
|
+
"g:T" => ->(value) { Grumlin::Expressions::T.public_send(value) }
|
22
22
|
}.freeze
|
23
23
|
|
24
24
|
CASTABLE_TYPES = [Hash, String, Integer, TrueClass, FalseClass].freeze
|
@@ -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) }
|
data/lib/grumlin/version.rb
CHANGED
data/lib/grumlin.rb
CHANGED
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.
|
4
|
+
version: 0.18.1
|
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-
|
11
|
+
date: 2022-04-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async-pool
|
@@ -155,7 +155,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
155
|
- !ruby/object:Gem::Version
|
156
156
|
version: '0'
|
157
157
|
requirements: []
|
158
|
-
rubygems_version: 3.2.
|
158
|
+
rubygems_version: 3.2.33
|
159
159
|
signing_key:
|
160
160
|
specification_version: 4
|
161
161
|
summary: Gremlin graph traversal language DSL and client for Ruby.
|