grumlin 0.6.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a847514be85565126dc453b6f088ad5c9a388464e74f6744e34427f09a07ec9c
4
- data.tar.gz: ea6b1241c611222aa7866b8c3a7b4b798d5a68ba09f79f030196758d4f2dd7f0
3
+ metadata.gz: 22dad640b5ac86f86381b9bc9fab03989e7b8c42c4b19234efc6b3a223d07055
4
+ data.tar.gz: c0cea0f26f1e5a5a9ef1c6ab96335bf24e7f642968030b2b1f1c0a74210898d7
5
5
  SHA512:
6
- metadata.gz: 2aa5546c4b0139b1fd81cf2c2d5b32886a0c54ee958ddf3d9684ff9a38a19c8401fb2ef89a6767840f2dc0a12fbc86ea0b4821477f0721d767fc4c4f3a6cd7c1
7
- data.tar.gz: 38da748bde5febd21a8d94a8ae00768fa8b25bb544dd9b9895a9dd544136faa489a8591d01386afcbb8ed103e5f909c7c4dfff2af9a69f2c42a77fa963be7438
6
+ metadata.gz: 71b7e970733edc7db87736c449008389b47431d41c12382c426b0db348e106047343d279e3d8901d76dd44175478279b4c2e22cd896b690c9d63eedbf605b6ec
7
+ data.tar.gz: 82f71e74fb61435de9d6a86fa8cceb4cea32cd8a87f91c6a941bbfbd622a21b67b434f3ccbe298f94265edb9999faa33ea4f80148a56a1e39c6491a575df1ae6
data/.overcommit.yml CHANGED
@@ -3,6 +3,3 @@ PreCommit:
3
3
  enabled: true
4
4
  on_warn: fail # Treat all warnings as failures
5
5
 
6
- PrePush:
7
- RSpec:
8
- enabled: true
data/Gemfile.lock CHANGED
@@ -1,9 +1,11 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- grumlin (0.6.0)
4
+ grumlin (0.8.0)
5
5
  async-pool (~> 0.3)
6
6
  async-websocket (~> 0.19)
7
+ oj (~> 3.12)
8
+ zeitwerk (~> 2.4)
7
9
 
8
10
  GEM
9
11
  remote: https://rubygems.org/
@@ -62,6 +64,7 @@ GEM
62
64
  nio4r (2.5.8)
63
65
  nokogiri (1.11.7-x86_64-linux)
64
66
  racc (~> 1.4)
67
+ oj (3.13.4)
65
68
  overcommit (0.57.0)
66
69
  childprocess (>= 0.6.3, < 5)
67
70
  iniparse (~> 1.4)
data/grumlin.gemspec CHANGED
@@ -25,4 +25,6 @@ Gem::Specification.new do |spec|
25
25
 
26
26
  spec.add_dependency "async-pool", "~> 0.3"
27
27
  spec.add_dependency "async-websocket", "~> 0.19"
28
+ spec.add_dependency "oj", "~> 3.12"
29
+ spec.add_dependency "zeitwerk", "~> 2.4"
28
30
  end
data/lib/async/channel.rb CHANGED
@@ -32,7 +32,7 @@ module Async
32
32
  end
33
33
 
34
34
  def close
35
- raise(ChannelClosedError, "Cannot close a closed channel") if closed?
35
+ return if closed?
36
36
 
37
37
  @queue << [:close]
38
38
  @closed = true
@@ -2,43 +2,39 @@
2
2
 
3
3
  module Grumlin
4
4
  class AnonymousStep
5
- attr_reader :name, :args
5
+ attr_reader :name, :args, :previous_step
6
6
 
7
7
  # TODO: add other steps
8
8
  SUPPORTED_STEPS = %w[E V addE addV as by coalesce count dedup drop elementMap emit fold from group groupCount has
9
- hasLabel hasNot in inV label limit not order out outE path project property repeat select to
10
- unfold valueMap values where].freeze
9
+ hasId hasLabel hasNot in inV label limit not order out outE path project property repeat select
10
+ to unfold valueMap values where].freeze
11
11
 
12
- def initialize(name, *args, previous_steps: [])
12
+ def initialize(name, *args, previous_step: nil)
13
13
  @name = name
14
- @previous_steps = previous_steps
14
+ @previous_step = previous_step
15
15
  @args = args
16
16
  end
17
17
 
18
18
  SUPPORTED_STEPS.each do |step|
19
- define_method step do |*args|
20
- add_step(step, args, previous_steps: steps)
19
+ define_method(step) do |*args|
20
+ add_step(step, args)
21
21
  end
22
22
  end
23
23
 
24
24
  def inspect
25
- @inspect ||= to_bytecode.to_s
25
+ bytecode.inspect
26
26
  end
27
27
 
28
28
  alias to_s inspect
29
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])
30
+ def bytecode(no_return: false)
31
+ @bytecode ||= Bytecode.new(self, no_return: no_return)
36
32
  end
37
33
 
38
34
  private
39
35
 
40
- def add_step(step_name, args, previous_steps:)
41
- self.class.new(step_name, *args, previous_steps: previous_steps)
36
+ def add_step(step_name, args)
37
+ self.class.new(step_name, *args, previous_step: self)
42
38
  end
43
39
  end
44
40
  end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grumlin
4
+ # Incapsulates logic of converting step chains and step arguments to queries that can be sent to the server
5
+ # and to human readable strings.
6
+ class Bytecode
7
+ class NoneStep
8
+ def to_bytecode
9
+ ["none"]
10
+ end
11
+ end
12
+
13
+ NONE_STEP = NoneStep.new
14
+
15
+ def initialize(step, no_return: false)
16
+ @step = step
17
+ @no_return = no_return
18
+ end
19
+
20
+ def inspect
21
+ to_readable_bytecode.to_s
22
+ end
23
+ alias to_s inspect
24
+
25
+ def to_query
26
+ {
27
+ requestId: SecureRandom.uuid,
28
+ op: "bytecode",
29
+ processor: "traversal",
30
+ args: {
31
+ gremlin: to_bytecode,
32
+ aliases: { g: :g }
33
+ }
34
+ }
35
+ end
36
+
37
+ def to_readable_bytecode
38
+ @to_readable_bytecode ||= steps.map { |s| serialize_arg(s, serialization_method: :to_readable_bytecode) }
39
+ end
40
+
41
+ def to_bytecode
42
+ @to_bytecode ||= {
43
+ "@type": "g:Bytecode",
44
+ "@value": { step: (steps + (@no_return ? [NONE_STEP] : [])).map { |s| serialize_arg(s) } }
45
+ }
46
+ end
47
+
48
+ private
49
+
50
+ # Serializes step or a step argument to either an executable query or a human readable string representation
51
+ # depending on the `serialization_method` parameter. I should be either `:to_readable_bytecode` for human readable
52
+ # representation or `:to_bytecode` for query.
53
+ def serialize_arg(arg, serialization_method: :to_bytecode)
54
+ return arg.send(serialization_method) if arg.respond_to?(:to_bytecode)
55
+ return arg unless arg.is_a?(AnonymousStep)
56
+
57
+ arg.args.flatten.each.with_object([arg.name]) do |a, res|
58
+ res << if a.instance_of?(AnonymousStep)
59
+ a.bytecode.send(serialization_method)
60
+ else
61
+ serialize_arg(a, serialization_method: serialization_method)
62
+ end
63
+ end
64
+ end
65
+
66
+ def steps
67
+ @steps ||= [].tap do |result|
68
+ step = @step
69
+ until step.nil?
70
+ result.unshift(step)
71
+ step = step.previous_step
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -13,6 +13,7 @@ module Grumlin
13
13
  def initialize(url, client_factory:, concurrency: 1, parent: Async::Task.current)
14
14
  super(concurrency)
15
15
  @client = client_factory.call(url, parent).tap(&:connect)
16
+ @parent = parent
16
17
  end
17
18
 
18
19
  def closed?
@@ -23,36 +24,69 @@ module Grumlin
23
24
  @client.close
24
25
  end
25
26
 
26
- def write(*args)
27
- @client.write(*args)
27
+ def write(bytecode)
28
+ @client.write(bytecode)
29
+ ensure
30
+ @count += 1
31
+ end
32
+
33
+ def viable?
34
+ !closed?
35
+ end
36
+
37
+ def reusable?
38
+ !closed?
28
39
  end
29
40
  end
30
41
 
42
+ include Console
43
+
44
+ # Client is not reusable. Once closed should be recreated.
31
45
  def initialize(url, parent: Async::Task.current, **client_options)
32
46
  @url = url
33
47
  @client_options = client_options
34
48
  @parent = parent
35
- reset!
49
+ @request_dispatcher = nil
50
+ @transport = nil
36
51
  end
37
52
 
38
53
  def connect
54
+ raise "ClientClosed" if @closed
55
+
39
56
  @transport = build_transport
40
57
  response_channel = @transport.connect
41
58
  @request_dispatcher = RequestDispatcher.new
42
- @parent.async do
59
+ @response_task = @parent.async do
43
60
  response_channel.each do |response|
44
61
  @request_dispatcher.add_response(response)
45
62
  end
46
- rescue StandardError
47
- close
63
+ rescue Async::Stop, Async::TimeoutError, StandardError
64
+ close(check_requests: false)
48
65
  end
66
+ logger.debug(self, "Connected")
49
67
  end
50
68
 
51
- def close
52
- @transport.close
53
- raise ResourceLeakError, "Request list is not empty: #{requests}" if @request_dispatcher.requests.any?
69
+ # Before calling close the user must ensure that:
70
+ # 1) There are no ongoing requests
71
+ # 2) There will be no new writes after
72
+ def close(check_requests: true) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
73
+ return if @closed
74
+
75
+ @closed = true
76
+
77
+ @transport&.close
78
+ @transport&.wait
54
79
 
55
- reset!
80
+ @response_task&.stop
81
+ @response_task&.wait
82
+
83
+ return if @request_dispatcher&.requests&.empty?
84
+
85
+ @request_dispatcher.clear unless check_requests
86
+
87
+ raise ResourceLeakError, "Request list is not empty: #{@request_dispatcher.requests}" if check_requests
88
+ ensure
89
+ logger.debug(self, "Closed")
56
90
  end
57
91
 
58
92
  def connected?
@@ -60,19 +94,18 @@ module Grumlin
60
94
  end
61
95
 
62
96
  # TODO: support yielding
63
- def write(*args)
97
+ def write(bytecode)
64
98
  raise NotConnectedError unless connected?
65
99
 
66
- request_id = SecureRandom.uuid
67
- request = to_query(request_id, args)
100
+ request = bytecode.to_query
68
101
  channel = @request_dispatcher.add_request(request)
69
102
  @transport.write(request)
70
103
 
71
104
  begin
72
105
  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"
106
+ rescue Async::Stop, Async::TimeoutError
107
+ close(check_requests: false)
108
+ raise
76
109
  end
77
110
  end
78
111
 
@@ -84,23 +117,6 @@ module Grumlin
84
117
 
85
118
  private
86
119
 
87
- def to_query(request_id, message)
88
- {
89
- requestId: request_id,
90
- op: "bytecode",
91
- processor: "traversal",
92
- args: {
93
- gremlin: Typing.to_bytecode(Translator.to_bytecode_query(message)),
94
- aliases: { g: :g }
95
- }
96
- }
97
- end
98
-
99
- def reset!
100
- @request_dispatcher = nil
101
- @transport = nil
102
- end
103
-
104
120
  def build_transport
105
121
  Transport.new(@url, parent: @parent, **@client_options)
106
122
  end
@@ -22,6 +22,8 @@ module Grumlin
22
22
  498 => ClientSideError
23
23
  }.freeze
24
24
 
25
+ include Console
26
+
25
27
  def initialize
26
28
  @requests = {}
27
29
  end
@@ -46,7 +48,7 @@ module Grumlin
46
48
 
47
49
  case SUCCESS[response.dig(:status, :code)]
48
50
  when :success
49
- request[:channel] << request[:result] + [response.dig(:result, :data)]
51
+ request[:channel] << [*request[:result], response.dig(:result, :data)]
50
52
  close_request(request_id)
51
53
  when :partial_content then request[:result] << response.dig(:result, :data)
52
54
  when :no_content
@@ -69,6 +71,10 @@ module Grumlin
69
71
  @requests.key?(request_id)
70
72
  end
71
73
 
74
+ def clear
75
+ @requests.clear
76
+ end
77
+
72
78
  private
73
79
 
74
80
  def check_errors!(status)
data/lib/grumlin/step.rb CHANGED
@@ -4,8 +4,8 @@ module Grumlin
4
4
  class Step < AnonymousStep
5
5
  attr_reader :client
6
6
 
7
- def initialize(pool, name, *args, previous_steps: [])
8
- super(name, *args, previous_steps: previous_steps)
7
+ def initialize(pool, name, *args, previous_step: nil)
8
+ super(name, *args, previous_step: previous_step)
9
9
  @pool = pool
10
10
  end
11
11
 
@@ -16,20 +16,20 @@ module Grumlin
16
16
 
17
17
  def toList
18
18
  @pool.acquire do |client|
19
- client.write(*steps)
19
+ client.write(bytecode)
20
20
  end
21
21
  end
22
22
 
23
23
  def iterate
24
24
  @pool.acquire do |client|
25
- client.write(*(steps + [nil]))
25
+ client.write(bytecode(no_return: true))
26
26
  end
27
27
  end
28
28
 
29
29
  private
30
30
 
31
- def add_step(step_name, args, previous_steps:)
32
- self.class.new(@pool, step_name, *args, previous_steps: previous_steps)
31
+ def add_step(step_name, args)
32
+ self.class.new(@pool, step_name, *args, previous_step: self)
33
33
  end
34
34
  end
35
35
  end
@@ -18,8 +18,7 @@ module Grumlin
18
18
  end
19
19
 
20
20
  after do
21
- Grumlin.config.default_pool.close
22
- Grumlin.config.reset!
21
+ Grumlin.close
23
22
  end
24
23
  end
25
24
  end
@@ -5,47 +5,33 @@ module Grumlin
5
5
  # A transport based on https://github.com/socketry/async
6
6
  # and https://github.com/socketry/async-websocket
7
7
 
8
+ include Console
9
+
8
10
  attr_reader :url
9
11
 
12
+ # Transport is not reusable. Once closed should be recreated.
10
13
  def initialize(url, parent: Async::Task.current, **client_options)
11
14
  @url = url
12
15
  @parent = parent
13
16
  @client_options = client_options
14
17
  @request_channel = Async::Channel.new
15
18
  @response_channel = Async::Channel.new
16
- reset!
17
19
  end
18
20
 
19
21
  def connected?
20
- @connected
22
+ !@connection.nil?
21
23
  end
22
24
 
23
- def connect # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
25
+ def connect
26
+ raise "ClientClosed" if @closed
24
27
  raise AlreadyConnectedError if connected?
25
28
 
26
29
  @connection = Async::WebSocket::Client.connect(Async::HTTP::Endpoint.parse(@url), **@client_options)
30
+ logger.debug(self) { "Connected to #{@url}." }
27
31
 
28
- @response_task = @parent.async do
29
- loop do
30
- data = @connection.read
31
- @response_channel << data
32
- end
33
- rescue Async::Stop
34
- @response_channel.close
35
- rescue StandardError => e
36
- @response_channel.exception(e)
37
- end
32
+ @response_task = @parent.async { run_response_task }
38
33
 
39
- @request_task = @parent.async do
40
- @request_channel.each do |message|
41
- @connection.write(message)
42
- @connection.flush
43
- end
44
- rescue StandardError => e
45
- @response_channel.exception(e)
46
- end
47
-
48
- @connected = true
34
+ @request_task = @parent.async { run_request_task }
49
35
 
50
36
  @response_channel
51
37
  end
@@ -57,30 +43,59 @@ module Grumlin
57
43
  end
58
44
 
59
45
  def close
60
- return unless connected?
46
+ return if @closed
61
47
 
62
- @request_channel.close
63
- @request_task.wait
48
+ @closed = true
64
49
 
65
- @response_task.stop
66
- @response_task.wait
50
+ @request_channel.close
51
+ @response_channel.close
67
52
 
68
53
  begin
69
54
  @connection.close
70
- rescue Errno::EPIPE
55
+ rescue StandardError
71
56
  nil
72
57
  end
58
+ @connection = nil
59
+
60
+ @request_task&.stop(true)
61
+ @response_task&.stop(true)
62
+ end
73
63
 
74
- reset!
64
+ def wait
65
+ @request_task.wait
66
+ @response_task.wait
75
67
  end
76
68
 
77
69
  private
78
70
 
79
- def reset!
80
- @connected = false
81
- @connection = nil
82
- @response_task = nil
83
- @request_task = nil
71
+ def run_response_task
72
+ with_guard do
73
+ loop do
74
+ data = @connection.read
75
+ @response_channel << data
76
+ end
77
+ end
78
+ end
79
+
80
+ def run_request_task
81
+ with_guard do
82
+ @request_channel.each do |message|
83
+ @connection.write(message)
84
+ @connection.flush
85
+ end
86
+ end
87
+ end
88
+
89
+ def with_guard
90
+ yield
91
+ rescue Async::Stop, Async::TimeoutError, StandardError => e
92
+ logger.debug(self) { "Guard error, closing." }
93
+ begin
94
+ @response_channel.exception(e)
95
+ rescue Async::Channel::ChannelClosedError
96
+ nil
97
+ end
98
+ close
84
99
  end
85
100
  end
86
101
  end
@@ -7,7 +7,7 @@ module Grumlin
7
7
  # TODO: add other start steps
8
8
  SUPPORTED_START_STEPS = %w[E V addE addV].freeze
9
9
 
10
- def initialize(pool = Grumlin.config.default_pool)
10
+ def initialize(pool = Grumlin.default_pool)
11
11
  @pool = pool
12
12
  end
13
13
 
@@ -8,12 +8,14 @@ module Grumlin
8
8
  @value = value
9
9
  end
10
10
 
11
- def inspect(*)
12
- "#{@type}.#{@value}"
13
- end
14
-
15
11
  def to_bytecode
16
12
  @to_bytecode ||= { "@type": "g:#{@type}", "@value": @value }
17
13
  end
14
+
15
+ def inspect
16
+ "<#{@type}.#{@value}>"
17
+ end
18
+ alias to_s inspect
19
+ alias to_readable_bytecode inspect
18
20
  end
19
21
  end
@@ -31,19 +31,10 @@ module Grumlin
31
31
  type.call(value[:@value])
32
32
  end
33
33
 
34
- def to_bytecode(step)
35
- {
36
- "@type": "g:Bytecode",
37
- "@value": { step: step }
38
- }
39
- end
40
-
41
34
  private
42
35
 
43
- def castable_type?(value); end
44
-
45
36
  def verify_type!(value)
46
- raise TypeError, "#{value.inspect} cannot be casted" unless CASTABLE_TYPES.any? { |t| value.is_a?(t) }
37
+ raise TypeError, "#{value.inspect} cannot be casted" unless CASTABLE_TYPES.include?(value.class)
47
38
  end
48
39
 
49
40
  def verify_castable_hash!(value, type)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Grumlin
4
- VERSION = "0.6.0"
4
+ VERSION = "0.8.0"
5
5
  end
data/lib/grumlin.rb CHANGED
@@ -1,7 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "securerandom"
4
- require "json"
4
+ require "oj"
5
+
6
+ Oj.mimic_JSON
7
+ Oj.add_to_json
5
8
 
6
9
  require "async"
7
10
  require "async/pool"
@@ -12,41 +15,92 @@ require "async/barrier"
12
15
  require "async/http/endpoint"
13
16
  require "async/websocket/client"
14
17
 
15
- require_relative "async/channel"
18
+ require "zeitwerk"
16
19
 
17
- require_relative "grumlin/version"
18
- require_relative "grumlin/exceptions"
20
+ loader = Zeitwerk::Loader.for_gem
21
+ loader.inflector.inflect(
22
+ "rspec" => "RSpec",
23
+ "db_cleaner_context" => "DBCleanerContext"
24
+ )
19
25
 
20
- require_relative "grumlin/transport"
21
- require_relative "grumlin/client"
22
- require_relative "grumlin/typed_value"
26
+ db_adapters = "#{__dir__}/grumlin/test"
27
+ loader.do_not_eager_load(db_adapters)
23
28
 
24
- require_relative "grumlin/vertex"
25
- require_relative "grumlin/edge"
26
- require_relative "grumlin/path"
27
- require_relative "grumlin/typing"
28
- require_relative "grumlin/traversal"
29
- require_relative "grumlin/request_dispatcher"
30
- require_relative "grumlin/translator"
29
+ module Grumlin
30
+ class Error < StandardError; end
31
31
 
32
- require_relative "grumlin/anonymous_step"
33
- require_relative "grumlin/step"
32
+ class UnknownError < Error; end
34
33
 
35
- require_relative "grumlin/t"
36
- require_relative "grumlin/order"
37
- require_relative "grumlin/u"
38
- require_relative "grumlin/p"
39
- require_relative "grumlin/pop"
40
- require_relative "grumlin/sugar"
34
+ class ConnectionError < Error; end
35
+
36
+ class CannotConnectError < ConnectionError; end
37
+
38
+ class DisconnectError < ConnectionError; end
39
+
40
+ class ConnectionStatusError < Error; end
41
+
42
+ class NotConnectedError < ConnectionStatusError; end
43
+
44
+ class AlreadyConnectedError < ConnectionStatusError; end
45
+
46
+ class ProtocolError < Error; end
47
+
48
+ class UnknownResponseStatus < ProtocolError
49
+ attr_reader :status
50
+
51
+ def initialize(status)
52
+ super("unknown response status code #{status[:code]}")
53
+ @status = status
54
+ end
55
+ end
56
+
57
+ class UnknownTypeError < ProtocolError; end
58
+
59
+ class StatusError < Error
60
+ attr_reader :status
61
+
62
+ def initialize(status)
63
+ super(status[:message])
64
+ @status = status
65
+ end
66
+ end
67
+
68
+ class ClientSideError < StatusError; end
69
+
70
+ class ServerSideError < StatusError; end
71
+
72
+ class ScriptEvaluationError < ServerSideError; end
73
+
74
+ class InvalidRequestArgumentsError < ServerSideError; end
75
+
76
+ class ServerError < ServerSideError; end
77
+
78
+ class ServerSerializationError < ServerSideError; end
79
+
80
+ class ServerTimeoutError < ServerSideError; end
81
+
82
+ class InternalClientError < Error; end
83
+
84
+ class UnknownRequestStoppedError < InternalClientError; end
85
+
86
+ class ResourceLeakError < InternalClientError; end
87
+
88
+ class UnknownMapKey < InternalClientError
89
+ attr_reader :key, :map
90
+
91
+ def initialize(key, map)
92
+ @key = key
93
+ @map = map
94
+ super("Cannot cast key #{key} in map #{map}")
95
+ end
96
+ end
41
97
 
42
- module Grumlin
43
98
  class Config
44
99
  attr_accessor :url, :pool_size, :client_concurrency, :client_factory
45
100
 
46
- # For some reason, client_concurrency must be greater than pool_size
47
101
  def initialize
48
102
  @pool_size = 10
49
- @client_concurrency = 20
103
+ @client_concurrency = 5
50
104
  @client_factory = ->(url, parent) { Grumlin::Client.new(url, parent: parent) }
51
105
  end
52
106
 
@@ -67,5 +121,19 @@ module Grumlin
67
121
  def config
68
122
  @config ||= Config.new
69
123
  end
124
+
125
+ def default_pool
126
+ config.default_pool
127
+ end
128
+
129
+ def close
130
+ default_pool.wait while default_pool.busy?
131
+
132
+ default_pool.close
133
+ config.reset!
134
+ end
70
135
  end
71
136
  end
137
+
138
+ loader.setup
139
+ loader.eager_load
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.6.0
4
+ version: 0.8.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: 2021-08-30 00:00:00.000000000 Z
11
+ date: 2021-09-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async-pool
@@ -38,6 +38,34 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.19'
41
+ - !ruby/object:Gem::Dependency
42
+ name: oj
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.12'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.12'
55
+ - !ruby/object:Gem::Dependency
56
+ name: zeitwerk
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.4'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.4'
41
69
  description: Gremlin query language DSL for Ruby.
42
70
  email:
43
71
  - zhulik.gleb@gmail.com
@@ -66,9 +94,9 @@ files:
66
94
  - lib/async/channel.rb
67
95
  - lib/grumlin.rb
68
96
  - lib/grumlin/anonymous_step.rb
97
+ - lib/grumlin/bytecode.rb
69
98
  - lib/grumlin/client.rb
70
99
  - lib/grumlin/edge.rb
71
- - lib/grumlin/exceptions.rb
72
100
  - lib/grumlin/order.rb
73
101
  - lib/grumlin/p.rb
74
102
  - lib/grumlin/path.rb
@@ -80,7 +108,6 @@ files:
80
108
  - lib/grumlin/test/rspec.rb
81
109
  - lib/grumlin/test/rspec/db_cleaner_context.rb
82
110
  - lib/grumlin/test/rspec/gremlin_context.rb
83
- - lib/grumlin/translator.rb
84
111
  - lib/grumlin/transport.rb
85
112
  - lib/grumlin/traversal.rb
86
113
  - lib/grumlin/typed_value.rb
@@ -1,71 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Grumlin
4
- class Error < StandardError; end
5
-
6
- class UnknownError < Error; end
7
-
8
- class ConnectionError < Error; end
9
-
10
- class CannotConnectError < ConnectionError; end
11
-
12
- class DisconnectError < ConnectionError; end
13
-
14
- class ConnectionStatusError < Error; end
15
-
16
- class NotConnectedError < ConnectionStatusError; end
17
-
18
- class AlreadyConnectedError < ConnectionStatusError; end
19
-
20
- class ProtocolError < Error; end
21
-
22
- class UnknownResponseStatus < ProtocolError
23
- attr_reader :status
24
-
25
- def initialize(status)
26
- super("unknown response status code #{status[:code]}")
27
- @status = status
28
- end
29
- end
30
-
31
- class UnknownTypeError < ProtocolError; end
32
-
33
- class StatusError < Error
34
- attr_reader :status
35
-
36
- def initialize(status)
37
- super(status[:message])
38
- @status = status
39
- end
40
- end
41
-
42
- class ClientSideError < StatusError; end
43
-
44
- class ServerSideError < StatusError; end
45
-
46
- class ScriptEvaluationError < ServerSideError; end
47
-
48
- class InvalidRequestArgumentsError < ServerSideError; end
49
-
50
- class ServerError < ServerSideError; end
51
-
52
- class ServerSerializationError < ServerSideError; end
53
-
54
- class ServerTimeoutError < ServerSideError; end
55
-
56
- class InternalClientError < Error; end
57
-
58
- class UnknownRequestStoppedError < InternalClientError; end
59
-
60
- class ResourceLeakError < InternalClientError; end
61
-
62
- class UnknownMapKey < InternalClientError
63
- attr_reader :key, :map
64
-
65
- def initialize(key, map)
66
- @key = key
67
- @map = map
68
- super("Cannot cast key #{key} in map #{map}")
69
- end
70
- end
71
- end
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Grumlin
4
- module Translator
5
- class << self
6
- def to_bytecode(steps)
7
- return arg_to_bytecode(steps) if steps.is_a?(AnonymousStep)
8
-
9
- steps.map do |step|
10
- arg_to_bytecode(step)
11
- end
12
- end
13
-
14
- def to_bytecode_query(steps)
15
- steps.map do |step|
16
- arg_to_query_bytecode(step)
17
- end
18
- end
19
-
20
- private
21
-
22
- def arg_to_bytecode(arg)
23
- return arg.to_bytecode if arg.is_a?(TypedValue)
24
- return arg unless arg.is_a?(AnonymousStep)
25
-
26
- args = arg.args.flatten.map do |a|
27
- a.instance_of?(AnonymousStep) ? to_bytecode(a.steps) : arg_to_bytecode(a)
28
- end
29
- [arg.name, *args]
30
- end
31
-
32
- def arg_to_query_bytecode(arg)
33
- return ["none"] if arg.nil?
34
- return arg.to_bytecode if arg.is_a?(TypedValue)
35
- return arg unless arg.is_a?(AnonymousStep)
36
-
37
- # return arg.to_bytecode if arg.is_a?(TypedValue)
38
-
39
- args = arg.args.flatten.map do |a|
40
- a.instance_of?(AnonymousStep) ? Typing.to_bytecode(to_bytecode(a.steps)) : arg_to_query_bytecode(a)
41
- end
42
- [arg.name, *args]
43
- end
44
- end
45
- end
46
- end