grumlin 0.1.1 → 0.4.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 +4 -4
- data/.github/workflows/main.yml +1 -1
- data/.overcommit.yml +8 -0
- data/.rubocop.yml +3 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +31 -22
- data/bin/console +6 -3
- data/bin/setup +1 -0
- data/grumlin.gemspec +4 -3
- data/lib/async/channel.rb +64 -0
- data/lib/grumlin.rb +49 -3
- data/lib/grumlin/anonymous_step.rb +44 -0
- data/lib/grumlin/client.rb +68 -132
- data/lib/grumlin/edge.rb +2 -2
- data/lib/grumlin/exceptions.rb +22 -2
- data/lib/grumlin/order.rb +22 -0
- data/lib/grumlin/p.rb +18 -0
- data/lib/grumlin/path.rb +15 -0
- data/lib/grumlin/pop.rb +32 -0
- data/lib/grumlin/request_dispatcher.rb +84 -0
- data/lib/grumlin/step.rb +18 -29
- data/lib/grumlin/sugar.rb +42 -0
- data/lib/grumlin/t.rb +22 -0
- data/lib/grumlin/test/rspec.rb +11 -0
- data/lib/grumlin/test/rspec/db_cleaner_context.rb +18 -0
- data/lib/grumlin/test/rspec/gremlin_context.rb +21 -0
- data/lib/grumlin/translator.rb +22 -21
- data/lib/grumlin/transport.rb +86 -0
- data/lib/grumlin/traversal.rb +4 -11
- data/lib/grumlin/typing.rb +25 -5
- data/lib/grumlin/u.rb +18 -0
- data/lib/grumlin/version.rb +1 -1
- data/lib/grumlin/vertex.rb +2 -2
- metadata +36 -9
- data/bin/stress +0 -51
- data/lib/grumlin/traversing_context.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11e434ab0f5cd463d357e69dd3cbf5083f85a1bdd32e4d2c96023ce262704020
|
4
|
+
data.tar.gz: f24dd70f8b0abe9b370f77587d590802b32aa3e7b8a20380b9518004868cc6c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5bfbd0d4db9ef46d35839b8ca5654cdc1f5038ee2c4ca004b678471380095d1fb587fa89a8df0c5a4769e3943ceb4e0b88734b701593ccf1047a05ab85baaaf5
|
7
|
+
data.tar.gz: a7d87e630e6b2076bedd079365e709018b3fc61f1577564c504593ffdeb4deab88f56d8785c30877489171b6c9d7fd245982475a75f4c639647c923e2ca296ef
|
data/.github/workflows/main.yml
CHANGED
data/.overcommit.yml
ADDED
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
@@ -4,6 +4,7 @@ source "https://rubygems.org"
|
|
4
4
|
|
5
5
|
gemspec
|
6
6
|
|
7
|
+
gem "nokogiri"
|
7
8
|
gem "rubocop"
|
8
9
|
gem "rubocop-performance"
|
9
10
|
gem "rubocop-rspec"
|
@@ -12,5 +13,6 @@ gem "solargraph"
|
|
12
13
|
|
13
14
|
gem "async-rspec"
|
14
15
|
gem "factory_bot"
|
16
|
+
gem "overcommit"
|
15
17
|
gem "rspec"
|
16
18
|
gem "simplecov"
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
grumlin (0.
|
5
|
-
async-
|
4
|
+
grumlin (0.4.0)
|
5
|
+
async-pool (~> 0.3)
|
6
|
+
async-websocket (~> 0.19)
|
6
7
|
|
7
8
|
GEM
|
8
9
|
remote: https://rubygems.org/
|
@@ -14,33 +15,34 @@ GEM
|
|
14
15
|
tzinfo (~> 2.0)
|
15
16
|
zeitwerk (~> 2.3)
|
16
17
|
ast (2.4.2)
|
17
|
-
async (1.
|
18
|
+
async (1.30.1)
|
18
19
|
console (~> 1.10)
|
19
20
|
nio4r (~> 2.3)
|
20
21
|
timers (~> 4.1)
|
21
|
-
async-http (0.56.
|
22
|
-
async (
|
23
|
-
async-io (
|
24
|
-
async-pool (
|
22
|
+
async-http (0.56.5)
|
23
|
+
async (>= 1.25)
|
24
|
+
async-io (>= 1.28)
|
25
|
+
async-pool (>= 0.2)
|
25
26
|
protocol-http (~> 0.22.0)
|
26
27
|
protocol-http1 (~> 0.14.0)
|
27
28
|
protocol-http2 (~> 0.14.0)
|
28
|
-
async-io (1.
|
29
|
-
async
|
30
|
-
async-pool (0.3.
|
31
|
-
async (
|
29
|
+
async-io (1.32.2)
|
30
|
+
async
|
31
|
+
async-pool (0.3.8)
|
32
|
+
async (>= 1.25)
|
32
33
|
async-rspec (1.16.0)
|
33
34
|
rspec (~> 3.0)
|
34
35
|
rspec-files (~> 1.0)
|
35
36
|
rspec-memory (~> 1.0)
|
36
|
-
async-websocket (0.
|
37
|
+
async-websocket (0.19.0)
|
37
38
|
async-http (~> 0.54)
|
38
39
|
async-io (~> 1.23)
|
39
40
|
protocol-websocket (~> 0.7.0)
|
40
|
-
backport (1.
|
41
|
+
backport (1.2.0)
|
41
42
|
benchmark (0.1.1)
|
43
|
+
childprocess (4.0.0)
|
42
44
|
concurrent-ruby (1.1.8)
|
43
|
-
console (1.
|
45
|
+
console (1.13.1)
|
44
46
|
fiber-local
|
45
47
|
diff-lcs (1.4.4)
|
46
48
|
docile (1.4.0)
|
@@ -50,20 +52,24 @@ GEM
|
|
50
52
|
fiber-local (1.0.0)
|
51
53
|
i18n (1.8.10)
|
52
54
|
concurrent-ruby (~> 1.0)
|
55
|
+
iniparse (1.5.0)
|
53
56
|
jaro_winkler (1.5.4)
|
54
57
|
kramdown (2.3.1)
|
55
58
|
rexml
|
56
59
|
kramdown-parser-gfm (1.1.0)
|
57
60
|
kramdown (~> 2.0)
|
58
61
|
minitest (5.14.4)
|
59
|
-
nio4r (2.5.
|
60
|
-
nokogiri (1.11.
|
62
|
+
nio4r (2.5.8)
|
63
|
+
nokogiri (1.11.7-x86_64-linux)
|
61
64
|
racc (~> 1.4)
|
65
|
+
overcommit (0.57.0)
|
66
|
+
childprocess (>= 0.6.3, < 5)
|
67
|
+
iniparse (~> 1.4)
|
62
68
|
parallel (1.20.1)
|
63
69
|
parser (3.0.1.1)
|
64
70
|
ast (~> 2.4.1)
|
65
71
|
protocol-hpack (1.4.2)
|
66
|
-
protocol-http (0.22.
|
72
|
+
protocol-http (0.22.5)
|
67
73
|
protocol-http1 (0.14.1)
|
68
74
|
protocol-http (~> 0.22)
|
69
75
|
protocol-http2 (0.14.2)
|
@@ -95,16 +101,16 @@ GEM
|
|
95
101
|
diff-lcs (>= 1.2.0, < 2.0)
|
96
102
|
rspec-support (~> 3.10.0)
|
97
103
|
rspec-support (3.10.2)
|
98
|
-
rubocop (1.
|
104
|
+
rubocop (1.16.1)
|
99
105
|
parallel (~> 1.10)
|
100
106
|
parser (>= 3.0.0.0)
|
101
107
|
rainbow (>= 2.2.2, < 4.0)
|
102
108
|
regexp_parser (>= 1.8, < 3.0)
|
103
109
|
rexml
|
104
|
-
rubocop-ast (>= 1.
|
110
|
+
rubocop-ast (>= 1.7.0, < 2.0)
|
105
111
|
ruby-progressbar (~> 1.7)
|
106
112
|
unicode-display_width (>= 1.4.0, < 3.0)
|
107
|
-
rubocop-ast (1.
|
113
|
+
rubocop-ast (1.7.0)
|
108
114
|
parser (>= 3.0.1.1)
|
109
115
|
rubocop-performance (1.11.3)
|
110
116
|
rubocop (>= 1.7.0, < 2.0)
|
@@ -119,10 +125,11 @@ GEM
|
|
119
125
|
simplecov_json_formatter (~> 0.1)
|
120
126
|
simplecov-html (0.12.3)
|
121
127
|
simplecov_json_formatter (0.1.3)
|
122
|
-
solargraph (0.
|
123
|
-
backport (~> 1.
|
128
|
+
solargraph (0.43.0)
|
129
|
+
backport (~> 1.2)
|
124
130
|
benchmark
|
125
131
|
bundler (>= 1.17.2)
|
132
|
+
diff-lcs (~> 1.4)
|
126
133
|
e2mmap
|
127
134
|
jaro_winkler (~> 1.5)
|
128
135
|
kramdown (~> 2.3)
|
@@ -149,6 +156,8 @@ DEPENDENCIES
|
|
149
156
|
async-rspec
|
150
157
|
factory_bot
|
151
158
|
grumlin!
|
159
|
+
nokogiri
|
160
|
+
overcommit
|
152
161
|
rspec
|
153
162
|
rubocop
|
154
163
|
rubocop-performance
|
data/bin/console
CHANGED
@@ -5,9 +5,12 @@ require "bundler/setup"
|
|
5
5
|
require "grumlin"
|
6
6
|
require "irb"
|
7
7
|
|
8
|
+
Grumlin.configure do |config|
|
9
|
+
config.url = ENV["GREMLIN_URL"] || "ws://localhost:8182/gremlin"
|
10
|
+
end
|
11
|
+
|
8
12
|
Async do
|
9
|
-
|
10
|
-
g = Grumlin::Traversal.new(client)
|
13
|
+
g = Grumlin::Traversal.new
|
11
14
|
|
12
15
|
IRB.setup(nil)
|
13
16
|
workspace = IRB::WorkSpace.new(binding)
|
@@ -16,5 +19,5 @@ Async do
|
|
16
19
|
rescue StandardError
|
17
20
|
raise
|
18
21
|
ensure
|
19
|
-
|
22
|
+
Grumlin.config.default_pool.close
|
20
23
|
end
|
data/bin/setup
CHANGED
data/grumlin.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.authors = ["Gleb Sinyavskiy"]
|
9
9
|
spec.email = ["zhulik.gleb@gmail.com"]
|
10
10
|
|
11
|
-
spec.summary = "
|
12
|
-
spec.description = "
|
11
|
+
spec.summary = "Gremlin query language DSL for Ruby."
|
12
|
+
spec.description = "Gremlin query language DSL for Ruby."
|
13
13
|
spec.homepage = "https://github.com/zhulik/grumlin"
|
14
14
|
spec.license = "MIT"
|
15
15
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
|
@@ -23,5 +23,6 @@ Gem::Specification.new do |spec|
|
|
23
23
|
end
|
24
24
|
spec.require_paths = ["lib"]
|
25
25
|
|
26
|
-
spec.add_dependency "async-
|
26
|
+
spec.add_dependency "async-pool", "~> 0.3"
|
27
|
+
spec.add_dependency "async-websocket", "~> 0.19"
|
27
28
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
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 with only 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
|
16
|
+
|
17
|
+
def closed?
|
18
|
+
@closed
|
19
|
+
end
|
20
|
+
|
21
|
+
# Methods for a publisher
|
22
|
+
def <<(payload)
|
23
|
+
raise(ChannelClosedError, "Cannot send to a closed channel") if @closed
|
24
|
+
|
25
|
+
@queue << [:payload, payload]
|
26
|
+
end
|
27
|
+
|
28
|
+
def exception(exception)
|
29
|
+
raise(ChannelClosedError, "Cannot send to a closed channel") if closed?
|
30
|
+
|
31
|
+
@queue << [:exception, exception]
|
32
|
+
end
|
33
|
+
|
34
|
+
def close
|
35
|
+
raise(ChannelClosedError, "Cannot close a closed channel") if closed?
|
36
|
+
|
37
|
+
@queue << [:close]
|
38
|
+
@closed = true
|
39
|
+
end
|
40
|
+
|
41
|
+
# Methods for a subscriber
|
42
|
+
def dequeue
|
43
|
+
each do |payload| # rubocop:disable Lint/UnreachableLoop this is intended
|
44
|
+
return payload
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def each # rubocop:disable Metrics/MethodLength
|
49
|
+
raise(ChannelClosedError, "Cannot receive from a closed channel") if closed?
|
50
|
+
|
51
|
+
@queue.each do |type, payload|
|
52
|
+
case type
|
53
|
+
when :exception
|
54
|
+
payload.set_backtrace(caller + (payload.backtrace || [])) # A hack to preserve full backtrace
|
55
|
+
raise payload
|
56
|
+
when :payload
|
57
|
+
yield payload
|
58
|
+
when :close
|
59
|
+
break
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/grumlin.rb
CHANGED
@@ -4,21 +4,67 @@ require "securerandom"
|
|
4
4
|
require "json"
|
5
5
|
|
6
6
|
require "async"
|
7
|
+
require "async/pool"
|
8
|
+
require "async/pool/resource"
|
9
|
+
require "async/pool/controller"
|
7
10
|
require "async/queue"
|
11
|
+
require "async/barrier"
|
8
12
|
require "async/http/endpoint"
|
9
13
|
require "async/websocket/client"
|
10
14
|
|
15
|
+
require_relative "async/channel"
|
16
|
+
|
11
17
|
require_relative "grumlin/version"
|
12
18
|
require_relative "grumlin/exceptions"
|
13
19
|
|
20
|
+
require_relative "grumlin/transport"
|
21
|
+
require_relative "grumlin/client"
|
22
|
+
|
14
23
|
require_relative "grumlin/vertex"
|
15
24
|
require_relative "grumlin/edge"
|
25
|
+
require_relative "grumlin/path"
|
16
26
|
require_relative "grumlin/typing"
|
17
|
-
require_relative "grumlin/client"
|
18
27
|
require_relative "grumlin/traversal"
|
19
|
-
require_relative "grumlin/
|
28
|
+
require_relative "grumlin/request_dispatcher"
|
20
29
|
require_relative "grumlin/translator"
|
21
|
-
|
30
|
+
|
31
|
+
require_relative "grumlin/anonymous_step"
|
32
|
+
require_relative "grumlin/step"
|
33
|
+
|
34
|
+
require_relative "grumlin/t"
|
35
|
+
require_relative "grumlin/order"
|
36
|
+
require_relative "grumlin/u"
|
37
|
+
require_relative "grumlin/p"
|
38
|
+
require_relative "grumlin/pop"
|
39
|
+
require_relative "grumlin/sugar"
|
22
40
|
|
23
41
|
module Grumlin
|
42
|
+
class Config
|
43
|
+
attr_accessor :url, :pool_size, :client_concurrency, :client_factory
|
44
|
+
|
45
|
+
# For some reason, client_concurrency must be greater than pool_size
|
46
|
+
def initialize
|
47
|
+
@pool_size = 10
|
48
|
+
@client_concurrency = 20
|
49
|
+
@client_factory = ->(url, parent) { Grumlin::Client.new(url, parent: parent) }
|
50
|
+
end
|
51
|
+
|
52
|
+
def default_pool
|
53
|
+
@default_pool ||= Async::Pool::Controller.new(Grumlin::Client::PoolResource, limit: pool_size)
|
54
|
+
end
|
55
|
+
|
56
|
+
def reset!
|
57
|
+
@default_pool = nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class << self
|
62
|
+
def configure
|
63
|
+
yield config
|
64
|
+
end
|
65
|
+
|
66
|
+
def config
|
67
|
+
@config ||= Config.new
|
68
|
+
end
|
69
|
+
end
|
24
70
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grumlin
|
4
|
+
class AnonymousStep
|
5
|
+
attr_reader :name, :args
|
6
|
+
|
7
|
+
def initialize(name, *args, previous_steps: [])
|
8
|
+
@name = name
|
9
|
+
@previous_steps = previous_steps
|
10
|
+
@args = args
|
11
|
+
end
|
12
|
+
|
13
|
+
%w[addV addE V E limit count drop property valueMap select from to as order by has hasLabel values hasNot
|
14
|
+
not outE groupCount label group in out fold unfold inV path dedup project coalesce repeat emit
|
15
|
+
elementMap where].each do |step|
|
16
|
+
define_method step do |*args|
|
17
|
+
add_step(step, args, previous_steps: steps)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
alias addVertex addV
|
22
|
+
alias addEdge addE
|
23
|
+
|
24
|
+
def inspect
|
25
|
+
@inspect ||= to_bytecode.to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
alias to_s inspect
|
29
|
+
|
30
|
+
def to_bytecode
|
31
|
+
@to_bytecode ||= (@previous_steps.last&.to_bytecode || []) + [Translator.to_bytecode(self)]
|
32
|
+
end
|
33
|
+
|
34
|
+
def steps
|
35
|
+
(@previous_steps + [self])
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def add_step(step_name, args, previous_steps:)
|
41
|
+
self.class.new(step_name, *args, previous_steps: previous_steps)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/grumlin/client.rb
CHANGED
@@ -1,172 +1,108 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Grumlin
|
4
|
-
class Client
|
5
|
-
|
6
|
-
|
7
|
-
PARTIAL_CONTENT_STATUS = 206
|
8
|
-
|
9
|
-
ERRORS = {
|
10
|
-
499 => InvalidRequestArgumentsError,
|
11
|
-
500 => ServerError,
|
12
|
-
597 => ScriptEvaluationError,
|
13
|
-
599 => ServerSerializationError,
|
14
|
-
598 => ServerTimeoutError,
|
15
|
-
|
16
|
-
401 => ClientSideError,
|
17
|
-
407 => ClientSideError,
|
18
|
-
498 => ClientSideError
|
19
|
-
}.freeze
|
20
|
-
|
21
|
-
def initialize(url, task: Async::Task.current, autoconnect: true, mode: :bytecode)
|
22
|
-
@task = task
|
23
|
-
@endpoint = Async::HTTP::Endpoint.parse(url)
|
24
|
-
@mode = mode
|
25
|
-
|
26
|
-
@requests = {}
|
27
|
-
@query_queue = Async::Queue.new
|
28
|
-
|
29
|
-
connect if autoconnect
|
30
|
-
end
|
31
|
-
|
32
|
-
def connect # rubocop:disable Metrics/MethodLength
|
33
|
-
raise AlreadyConnectedError unless @connection_task.nil?
|
4
|
+
class Client
|
5
|
+
class PoolResource < Async::Pool::Resource
|
6
|
+
attr_reader :client
|
34
7
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
response_task(connection)
|
39
|
-
end
|
40
|
-
rescue StandardError => e
|
41
|
-
@requests.each_value do |queue|
|
42
|
-
queue << [:error, e]
|
43
|
-
end
|
44
|
-
disconnect
|
8
|
+
def self.call
|
9
|
+
config = Grumlin.config
|
10
|
+
new(config.url, client_factory: config.client_factory, concurrency: config.client_concurrency)
|
45
11
|
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def disconnect
|
49
|
-
raise NotConnectedError if @connection_task.nil?
|
50
|
-
|
51
|
-
@connection_task&.stop
|
52
|
-
@connection_task&.wait
|
53
|
-
@connection_task = nil
|
54
|
-
@requests = {}
|
55
|
-
end
|
56
|
-
|
57
|
-
def query(*args) # rubocop:disable Metrics/MethodLength
|
58
|
-
response_queue, request_id = schedule_query(args)
|
59
|
-
result = []
|
60
12
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
if status[:code] == NO_CONTENT_STATUS
|
67
|
-
close_request(request_id)
|
68
|
-
return []
|
69
|
-
end
|
13
|
+
def initialize(url, client_factory:, concurrency: 1, parent: Async::Task.current)
|
14
|
+
super(concurrency)
|
15
|
+
@client = client_factory.call(url, parent).tap(&:connect)
|
16
|
+
end
|
70
17
|
|
71
|
-
|
18
|
+
def closed?
|
19
|
+
!@client.connected?
|
20
|
+
end
|
72
21
|
|
73
|
-
|
22
|
+
def close
|
23
|
+
@client.close
|
24
|
+
end
|
74
25
|
|
75
|
-
|
76
|
-
|
77
|
-
close_request(request_id)
|
78
|
-
return result + page
|
79
|
-
when PARTIAL_CONTENT_STATUS
|
80
|
-
result += page
|
81
|
-
else
|
82
|
-
raise UnknownResponseStatus, status
|
83
|
-
end
|
26
|
+
def write(*args)
|
27
|
+
@client.write(*args)
|
84
28
|
end
|
85
29
|
end
|
86
30
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
@requests[uuid] = queue
|
93
|
-
@query_queue << to_query(uuid, args)
|
94
|
-
|
95
|
-
[queue, uuid]
|
31
|
+
def initialize(url, parent: Async::Task.current, **client_options)
|
32
|
+
@url = url
|
33
|
+
@client_options = client_options
|
34
|
+
@parent = parent
|
35
|
+
reset!
|
96
36
|
end
|
97
37
|
|
98
|
-
def
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
38
|
+
def connect
|
39
|
+
@transport = build_transport
|
40
|
+
response_channel = @transport.connect
|
41
|
+
@request_dispatcher = RequestDispatcher.new
|
42
|
+
@parent.async do
|
43
|
+
response_channel.each do |response|
|
44
|
+
@request_dispatcher.add_response(response)
|
45
|
+
end
|
46
|
+
rescue StandardError
|
47
|
+
close
|
104
48
|
end
|
105
49
|
end
|
106
50
|
|
107
|
-
def
|
108
|
-
|
109
|
-
|
110
|
-
raise(error, status) if error
|
111
|
-
end
|
51
|
+
def close
|
52
|
+
@transport.close
|
53
|
+
raise ResourceLeakError, "Request list is not empty: #{requests}" if @request_dispatcher.requests.any?
|
112
54
|
|
113
|
-
|
114
|
-
@requests.delete(request_id)
|
55
|
+
reset!
|
115
56
|
end
|
116
57
|
|
117
|
-
def
|
118
|
-
|
119
|
-
rescue StandardError
|
120
|
-
raise ConnectionError
|
58
|
+
def connected?
|
59
|
+
@transport&.connected? || false
|
121
60
|
end
|
122
61
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
62
|
+
# TODO: support yielding
|
63
|
+
def write(*args) # rubocop:disable Metrics/MethodLength
|
64
|
+
raise NotConnectedError unless connected?
|
65
|
+
|
66
|
+
request_id = SecureRandom.uuid
|
67
|
+
request = to_query(request_id, args)
|
68
|
+
channel = @request_dispatcher.add_request(request)
|
69
|
+
@transport.write(request)
|
129
70
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
71
|
+
begin
|
72
|
+
channel.dequeue.flat_map { |item| Typing.cast(item) }
|
73
|
+
rescue Async::Stop
|
74
|
+
retry if @request_dispatcher.ongoing_request?(request_id)
|
75
|
+
raise Grumlin::UnknownRequestStoppedError, "#{request_id} is not in the ongoing requests list"
|
135
76
|
end
|
136
77
|
end
|
137
78
|
|
138
|
-
def
|
139
|
-
{
|
140
|
-
requestId: uuid,
|
141
|
-
op: "eval",
|
142
|
-
processor: "",
|
143
|
-
args: {
|
144
|
-
gremlin: query,
|
145
|
-
bindings: bindings,
|
146
|
-
language: "gremlin-groovy"
|
147
|
-
}
|
148
|
-
}
|
79
|
+
def inspect
|
80
|
+
"<#{self.class} url=#{@url} connected=#{connected?}>"
|
149
81
|
end
|
150
82
|
|
151
|
-
|
83
|
+
alias to_s inspect
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def to_query(request_id, message)
|
152
88
|
{
|
153
|
-
requestId:
|
89
|
+
requestId: request_id,
|
154
90
|
op: "bytecode",
|
155
91
|
processor: "traversal",
|
156
92
|
args: {
|
157
|
-
gremlin:
|
93
|
+
gremlin: Typing.to_bytecode(Translator.to_bytecode_query(message)),
|
158
94
|
aliases: { g: :g }
|
159
95
|
}
|
160
96
|
}
|
161
97
|
end
|
162
98
|
|
163
|
-
def
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
99
|
+
def reset!
|
100
|
+
@request_dispatcher = nil
|
101
|
+
@transport = nil
|
102
|
+
end
|
103
|
+
|
104
|
+
def build_transport
|
105
|
+
Transport.new(@url, parent: @parent, **@client_options)
|
170
106
|
end
|
171
107
|
end
|
172
108
|
end
|