grumlin 0.3.0 → 0.6.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: e532964db5d5afd11d89978a132a5f4f7d1a4d98c740f639acadac260c93be89
4
- data.tar.gz: 9015cb71bbab17895d8809dc7ff514b90e9d1ceb81ed6a9eec446a0db7ec0994
3
+ metadata.gz: a847514be85565126dc453b6f088ad5c9a388464e74f6744e34427f09a07ec9c
4
+ data.tar.gz: ea6b1241c611222aa7866b8c3a7b4b798d5a68ba09f79f030196758d4f2dd7f0
5
5
  SHA512:
6
- metadata.gz: a4295b9e6041726c36c05cc0aed94a645e8d7103c99351dfadef7077f14037b81daf87a4ffb1fd48105d8c1fa888e96ce173aa3be42c9b35ec58de3e289c01ed
7
- data.tar.gz: 51824ca159be63be91fc798b40777a25d55f0ce423b07a9ce4ce9880002e94b4e4196bc0d92b4ca84bee86356f17fd90f3cc2dd9daa594f906fc2e93f11be422
6
+ metadata.gz: 2aa5546c4b0139b1fd81cf2c2d5b32886a0c54ee958ddf3d9684ff9a38a19c8401fb2ef89a6767840f2dc0a12fbc86ea0b4821477f0721d767fc4c4f3a6cd7c1
7
+ data.tar.gz: 38da748bde5febd21a8d94a8ae00768fa8b25bb544dd9b9895a9dd544136faa489a8591d01386afcbb8ed103e5f909c7c4dfff2af9a69f2c42a77fa963be7438
@@ -1,6 +1,6 @@
1
1
  name: Ruby
2
2
 
3
- on: [push, pull_request]
3
+ on: [push]
4
4
 
5
5
  jobs:
6
6
  lint:
data/.rubocop.yml CHANGED
@@ -7,24 +7,44 @@ require:
7
7
  - rubocop-performance
8
8
  - rubocop-rspec
9
9
 
10
- Style/StringLiterals:
11
- Enabled: true
12
- EnforcedStyle: double_quotes
13
-
14
- Style/StringLiteralsInInterpolation:
15
- Enabled: true
16
- EnforcedStyle: double_quotes
17
-
18
- Style/Documentation:
19
- Enabled: false
20
-
21
10
  Layout/LineLength:
22
11
  Max: 120
12
+ Exclude:
13
+ - spec/**/*_spec.rb
23
14
 
24
15
  Metrics/BlockLength:
25
16
  Exclude:
26
17
  - spec/**/*_spec.rb
27
18
 
19
+ Metrics/MethodLength:
20
+ Max: 20
21
+
22
+ Metrics/ParameterLists:
23
+ Max: 6
24
+
25
+ Naming/MethodName:
26
+ IgnoredPatterns:
27
+ - toList
28
+ - inVLabel
29
+ - outVLabel
30
+ - inV
31
+ - outV
32
+
33
+ Naming/VariableName:
34
+ AllowedIdentifiers:
35
+ - inV
36
+ - outV
37
+ - inVLabel
38
+ - outVLabel
39
+
40
+ Naming/MethodParameterName:
41
+ AllowedNames:
42
+ - id
43
+ - inV
44
+ - outV
45
+ - inVLabel
46
+ - outVLabel
47
+
28
48
  RSpec/NamedSubject:
29
49
  Enabled: false
30
50
 
@@ -34,5 +54,26 @@ RSpec/NestedGroups:
34
54
  RSpec/ExampleLength:
35
55
  Enabled: false
36
56
 
57
+ RSpec/MultipleExpectations:
58
+ Enabled: false
59
+
60
+ RSpec/DescribeClass:
61
+ Enabled: false
62
+
63
+ Style/WordArray:
64
+ Exclude:
65
+ - spec/**/*_spec.rb
66
+
67
+ Style/StringLiterals:
68
+ Enabled: true
69
+ EnforcedStyle: double_quotes
70
+
71
+ Style/StringLiteralsInInterpolation:
72
+ Enabled: true
73
+ EnforcedStyle: double_quotes
74
+
75
+ Style/Documentation:
76
+ Enabled: false
77
+
37
78
  Style/MultilineBlockChain:
38
- Enabled: false
79
+ Enabled: false
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 2.6.6
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- grumlin (0.3.0)
4
+ grumlin (0.6.0)
5
5
  async-pool (~> 0.3)
6
6
  async-websocket (~> 0.19)
7
7
 
@@ -59,7 +59,7 @@ GEM
59
59
  kramdown-parser-gfm (1.1.0)
60
60
  kramdown (~> 2.0)
61
61
  minitest (5.14.4)
62
- nio4r (2.5.7)
62
+ nio4r (2.5.8)
63
63
  nokogiri (1.11.7-x86_64-linux)
64
64
  racc (~> 1.4)
65
65
  overcommit (0.57.0)
@@ -70,7 +70,7 @@ GEM
70
70
  ast (~> 2.4.1)
71
71
  protocol-hpack (1.4.2)
72
72
  protocol-http (0.22.5)
73
- protocol-http1 (0.14.1)
73
+ protocol-http1 (0.14.2)
74
74
  protocol-http (~> 0.22)
75
75
  protocol-http2 (0.14.2)
76
76
  protocol-hpack (~> 1.4)
@@ -166,4 +166,4 @@ DEPENDENCIES
166
166
  solargraph
167
167
 
168
168
  BUNDLED WITH
169
- 2.2.15
169
+ 2.2.26
data/bin/console CHANGED
@@ -10,7 +10,7 @@ Grumlin.configure do |config|
10
10
  end
11
11
 
12
12
  Async do
13
- g = Grumlin::Traversal.new
13
+ include Grumlin::Sugar
14
14
 
15
15
  IRB.setup(nil)
16
16
  workspace = IRB::WorkSpace.new(binding)
@@ -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
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
@@ -4,23 +4,23 @@ module Grumlin
4
4
  class AnonymousStep
5
5
  attr_reader :name, :args
6
6
 
7
+ # TODO: add other steps
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
11
+
7
12
  def initialize(name, *args, previous_steps: [])
8
13
  @name = name
9
14
  @previous_steps = previous_steps
10
15
  @args = args
11
16
  end
12
17
 
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|
18
+ SUPPORTED_STEPS.each do |step|
16
19
  define_method step do |*args|
17
20
  add_step(step, args, previous_steps: steps)
18
21
  end
19
22
  end
20
23
 
21
- alias addVertex addV
22
- alias addEdge addE
23
-
24
24
  def inspect
25
25
  @inspect ||= to_bytecode.to_s
26
26
  end
@@ -2,45 +2,49 @@
2
2
 
3
3
  module Grumlin
4
4
  class Client
5
- class PoolResource < self
6
- attr :concurrency, :count
5
+ class PoolResource < Async::Pool::Resource
6
+ attr_reader :client
7
7
 
8
8
  def self.call
9
- new(Grumlin.config.url, concurrency: Grumlin.config.client_concurrency).tap(&:connect)
9
+ config = Grumlin.config
10
+ new(config.url, client_factory: config.client_factory, concurrency: config.client_concurrency)
10
11
  end
11
12
 
12
- def initialize(url, concurrency: 1, parent: Async::Task.current)
13
- super(url, parent: parent)
14
- @concurrency = concurrency
15
- @count = 0
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
16
  end
17
17
 
18
- def viable?
19
- connected?
18
+ def closed?
19
+ !@client.connected?
20
20
  end
21
21
 
22
- def closed?
23
- connected?
22
+ def close
23
+ @client.close
24
24
  end
25
25
 
26
- def reusable?
27
- true
26
+ def write(*args)
27
+ @client.write(*args)
28
28
  end
29
29
  end
30
30
 
31
- def initialize(url, parent: Async::Task.current)
31
+ def initialize(url, parent: Async::Task.current, **client_options)
32
+ @url = url
33
+ @client_options = client_options
32
34
  @parent = parent
33
- @transport = Transport.new(url)
34
35
  reset!
35
36
  end
36
37
 
37
38
  def connect
38
- response_queue = @transport.connect
39
+ @transport = build_transport
40
+ response_channel = @transport.connect
39
41
  @request_dispatcher = RequestDispatcher.new
40
42
  @parent.async do
41
- response_queue.each do |response|
43
+ response_channel.each do |response|
42
44
  @request_dispatcher.add_response(response)
43
45
  end
46
+ rescue StandardError
47
+ close
44
48
  end
45
49
  end
46
50
 
@@ -52,31 +56,28 @@ module Grumlin
52
56
  end
53
57
 
54
58
  def connected?
55
- @transport.connected?
59
+ @transport&.connected? || false
56
60
  end
57
61
 
58
62
  # TODO: support yielding
59
- def write(*args) # rubocop:disable Metrics/MethodLength
63
+ def write(*args)
64
+ raise NotConnectedError unless connected?
65
+
60
66
  request_id = SecureRandom.uuid
61
67
  request = to_query(request_id, args)
62
- queue = @request_dispatcher.add_request(request)
68
+ channel = @request_dispatcher.add_request(request)
63
69
  @transport.write(request)
64
70
 
65
71
  begin
66
- msg, response = queue.dequeue
67
- raise response if msg == :error
68
-
69
- return response.flat_map { |item| Typing.cast(item) } if msg == :result
70
-
71
- raise "ERROR"
72
+ channel.dequeue.flat_map { |item| Typing.cast(item) }
72
73
  rescue Async::Stop
73
74
  retry if @request_dispatcher.ongoing_request?(request_id)
74
- raise UnknownRequestStopped, "#{request_id} is not in the ongoing requests list"
75
+ raise Grumlin::UnknownRequestStoppedError, "#{request_id} is not in the ongoing requests list"
75
76
  end
76
77
  end
77
78
 
78
79
  def inspect
79
- "<#{self.class} url=#{@transport.url}>"
80
+ "<#{self.class} url=#{@url} connected=#{connected?}>"
80
81
  end
81
82
 
82
83
  alias to_s inspect
@@ -97,6 +98,11 @@ module Grumlin
97
98
 
98
99
  def reset!
99
100
  @request_dispatcher = nil
101
+ @transport = nil
102
+ end
103
+
104
+ def build_transport
105
+ Transport.new(@url, parent: @parent, **@client_options)
100
106
  end
101
107
  end
102
108
  end
data/lib/grumlin/edge.rb CHANGED
@@ -1,11 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # rubocop:disable Naming/VariableName,Naming/MethodParameterName,Naming/MethodName
4
3
  module Grumlin
5
4
  class Edge
6
5
  attr_reader :label, :id, :inVLabel, :outVLabel, :inV, :outV
7
6
 
8
- def initialize(label:, id:, inVLabel:, outVLabel:, inV:, outV:) # rubocop:disable Metrics/ParameterLists
7
+ def initialize(label:, id:, inVLabel:, outVLabel:, inV:, outV:)
9
8
  @label = label
10
9
  @id = Typing.cast(id)
11
10
  @inVLabel = inVLabel
@@ -24,4 +23,3 @@ module Grumlin
24
23
  alias to_s inspect
25
24
  end
26
25
  end
27
- # rubocop:enable Naming/MethodParameterName,Naming/VariableName,Naming/MethodName
data/lib/grumlin/order.rb CHANGED
@@ -2,21 +2,16 @@
2
2
 
3
3
  module Grumlin
4
4
  module Order
5
- module Order
6
- DESC = { "@type": "g:Order", "@value": "desc" }.freeze
7
- ASC = { "@type": "g:Order", "@value": "desc" }.freeze
5
+ # TODO: share the code?
6
+ class << self
7
+ %i[asc desc].each do |step|
8
+ define_method step do
9
+ name = "@#{step}"
10
+ return instance_variable_get(name) if instance_variable_defined?(name)
8
11
 
9
- extend self # rubocop:disable Style/ModuleFunction
10
-
11
- def asc
12
- ASC
13
- end
14
-
15
- def desc
16
- DESC
12
+ instance_variable_set(name, TypedValue.new("Order", step))
13
+ end
17
14
  end
18
15
  end
19
-
20
- extend Order
21
16
  end
22
17
  end
data/lib/grumlin/p.rb CHANGED
@@ -5,7 +5,7 @@ module Grumlin
5
5
  module P
6
6
  %w[within].each do |step|
7
7
  define_method step do |*args|
8
- { # TODO: replace with a class?
8
+ { # TODO: replace with a TypedValue?
9
9
  "@type": "g:P",
10
10
  "@value": { predicate: "within", value: { "@type": "g:List", "@value": args } }
11
11
  }
data/lib/grumlin/pop.rb CHANGED
@@ -2,31 +2,16 @@
2
2
 
3
3
  module Grumlin
4
4
  module Pop
5
- module Pop
6
- extend self # rubocop:disable Style/ModuleFunction
5
+ # TODO: share the code?
6
+ class << self
7
+ %i[first last all mixed].each do |step|
8
+ define_method step do
9
+ name = "@#{step}"
10
+ return instance_variable_get(name) if instance_variable_defined?(name)
7
11
 
8
- FIRST = { "@type": "g:Pop", "@value": "first" }.freeze
9
- LAST = { "@type": "g:Pop", "@value": "last" }.freeze
10
- ALL = { "@type": "g:Pop", "@value": "all" }.freeze
11
- MIXED = { "@type": "g:Pop", "@value": "mixed" }.freeze
12
-
13
- def first
14
- FIRST
15
- end
16
-
17
- def last
18
- LAST
19
- end
20
-
21
- def all
22
- ALL
23
- end
24
-
25
- def mixed
26
- MIXED
12
+ instance_variable_set(name, TypedValue.new("Pop", step))
13
+ end
27
14
  end
28
15
  end
29
-
30
- extend Pop
31
16
  end
32
17
  end
@@ -29,14 +29,14 @@ module Grumlin
29
29
  def add_request(request)
30
30
  raise "ERROR" if @requests.key?(request[:requestId])
31
31
 
32
- Async::Queue.new.tap do |queue|
33
- @requests[request[:requestId]] = { request: request, result: [], queue: queue }
32
+ Async::Channel.new.tap do |channel|
33
+ @requests[request[:requestId]] = { request: request, result: [], channel: channel }
34
34
  end
35
35
  end
36
36
 
37
- # builds a response object, when it's ready sends it to the client via a queue
37
+ # builds a response object, when it's ready sends it to the client via a channel
38
38
  # TODO: sometimes response does not include requestID, no idea how to handle it so far.
39
- def add_response(response) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
39
+ def add_response(response) # rubocop:disable Metrics/AbcSize
40
40
  request_id = response[:requestId]
41
41
  raise "ERROR" unless ongoing_request?(request_id)
42
42
 
@@ -46,15 +46,15 @@ module Grumlin
46
46
 
47
47
  case SUCCESS[response.dig(:status, :code)]
48
48
  when :success
49
- request[:queue] << [:result, request[:result] + [response.dig(:result, :data)]]
49
+ request[:channel] << request[:result] + [response.dig(:result, :data)]
50
50
  close_request(request_id)
51
51
  when :partial_content then request[:result] << response.dig(:result, :data)
52
52
  when :no_content
53
- request[:queue] << [:result, []]
53
+ request[:channel] << []
54
54
  close_request(request_id)
55
55
  end
56
56
  rescue StandardError => e
57
- request[:queue] << [:error, e]
57
+ request[:channel].exception(e)
58
58
  close_request(request_id)
59
59
  end
60
60
 
@@ -62,7 +62,7 @@ module Grumlin
62
62
  raise "ERROR" unless ongoing_request?(request_id)
63
63
 
64
64
  request = @requests.delete(request_id)
65
- request[:queue] << nil
65
+ request[:channel].close
66
66
  end
67
67
 
68
68
  def ongoing_request?(request_id)
data/lib/grumlin/step.rb CHANGED
@@ -14,7 +14,7 @@ module Grumlin
14
14
  @enum.next
15
15
  end
16
16
 
17
- def toList # rubocop:disable Naming/MethodName
17
+ def toList
18
18
  @pool.acquire do |client|
19
19
  client.write(*steps)
20
20
  end
data/lib/grumlin/sugar.rb CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  module Grumlin
4
4
  module Sugar
5
- # TODO: how to use it in specs?
6
5
  HELPERS = [
7
6
  Grumlin::U,
8
7
  Grumlin::T,
@@ -12,25 +11,12 @@ module Grumlin
12
11
  ].freeze
13
12
 
14
13
  def self.included(base)
15
- base.extend ClassMethods
16
- end
17
-
18
- module ClassMethods
19
- def const_missing(name)
20
- helper = HELPERS.find { |h| h.const_defined?(name) }
21
- super if helper.nil?
22
-
23
- const_set(name, helper)
14
+ HELPERS.each do |helper|
15
+ name = helper.name.split("::").last
16
+ base.const_set(name, helper)
24
17
  end
25
18
  end
26
19
 
27
- def const_missing(name)
28
- helper = HELPERS.find { |h| h.const_defined?(name) }
29
- super if helper.nil?
30
-
31
- const_set(name, helper)
32
- end
33
-
34
20
  def __
35
21
  Grumlin::U
36
22
  end
data/lib/grumlin/t.rb CHANGED
@@ -2,21 +2,16 @@
2
2
 
3
3
  module Grumlin
4
4
  module T
5
- module T
6
- T_ID = { :@type => "g:T", :@value => "id" }.freeze # TODO: replace with a class?
7
- T_LABEL = { :@type => "g:T", :@value => "label" }.freeze # TODO: replace with a class?
5
+ # TODO: share the code?
6
+ class << self
7
+ %i[id label].each do |step|
8
+ define_method step do
9
+ name = "@#{step}"
10
+ return instance_variable_get(name) if instance_variable_defined?(name)
8
11
 
9
- extend self # rubocop:disable Style/ModuleFunction
10
-
11
- def id
12
- T_ID
13
- end
14
-
15
- def label
16
- T_LABEL
12
+ instance_variable_set(name, TypedValue.new("T", step))
13
+ end
17
14
  end
18
15
  end
19
-
20
- extend T
21
16
  end
22
17
  end
@@ -8,8 +8,14 @@ module Grumlin
8
8
 
9
9
  ::RSpec.shared_context GremlinContext do
10
10
  include GremlinContext
11
+ include Grumlin::Sugar
11
12
 
12
- let(:g) { Grumlin::Traversal.new }
13
+ before do
14
+ Grumlin::Sugar::HELPERS.each do |helper|
15
+ name = helper.name.split("::").last
16
+ stub_const(name, helper)
17
+ end
18
+ end
13
19
 
14
20
  after do
15
21
  Grumlin.config.default_pool.close
@@ -20,6 +20,7 @@ module Grumlin
20
20
  private
21
21
 
22
22
  def arg_to_bytecode(arg)
23
+ return arg.to_bytecode if arg.is_a?(TypedValue)
23
24
  return arg unless arg.is_a?(AnonymousStep)
24
25
 
25
26
  args = arg.args.flatten.map do |a|
@@ -30,8 +31,11 @@ module Grumlin
30
31
 
31
32
  def arg_to_query_bytecode(arg)
32
33
  return ["none"] if arg.nil?
34
+ return arg.to_bytecode if arg.is_a?(TypedValue)
33
35
  return arg unless arg.is_a?(AnonymousStep)
34
36
 
37
+ # return arg.to_bytecode if arg.is_a?(TypedValue)
38
+
35
39
  args = arg.args.flatten.map do |a|
36
40
  a.instance_of?(AnonymousStep) ? Typing.to_bytecode(to_bytecode(a.steps)) : arg_to_query_bytecode(a)
37
41
  end
@@ -4,64 +4,72 @@ module Grumlin
4
4
  class Transport
5
5
  # A transport based on https://github.com/socketry/async
6
6
  # and https://github.com/socketry/async-websocket
7
- def initialize(url, parent: Async::Task.current)
8
- @endpoint = Async::HTTP::Endpoint.parse(url)
7
+
8
+ attr_reader :url
9
+
10
+ def initialize(url, parent: Async::Task.current, **client_options)
11
+ @url = url
9
12
  @parent = parent
10
- @request_queue = Async::Queue.new
11
- @response_queue = Async::Queue.new
13
+ @client_options = client_options
14
+ @request_channel = Async::Channel.new
15
+ @response_channel = Async::Channel.new
12
16
  reset!
13
17
  end
14
18
 
15
- def url
16
- @endpoint.url
17
- end
18
-
19
19
  def connected?
20
20
  @connected
21
21
  end
22
22
 
23
- def connect # rubocop:disable Metrics/MethodLength
23
+ def connect # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
24
24
  raise AlreadyConnectedError if connected?
25
25
 
26
- @connection = Async::WebSocket::Client.connect(@endpoint)
26
+ @connection = Async::WebSocket::Client.connect(Async::HTTP::Endpoint.parse(@url), **@client_options)
27
27
 
28
28
  @response_task = @parent.async do
29
29
  loop do
30
30
  data = @connection.read
31
- @response_queue << data
31
+ @response_channel << data
32
32
  end
33
33
  rescue Async::Stop
34
- @response_queue << nil
34
+ @response_channel.close
35
+ rescue StandardError => e
36
+ @response_channel.exception(e)
35
37
  end
36
38
 
37
39
  @request_task = @parent.async do
38
- @request_queue.each do |message|
40
+ @request_channel.each do |message|
39
41
  @connection.write(message)
40
42
  @connection.flush
41
43
  end
44
+ rescue StandardError => e
45
+ @response_channel.exception(e)
42
46
  end
43
47
 
44
48
  @connected = true
45
49
 
46
- @response_queue
50
+ @response_channel
47
51
  end
48
52
 
49
53
  def write(message)
50
54
  raise NotConnectedError unless connected?
51
55
 
52
- @request_queue << message
56
+ @request_channel << message
53
57
  end
54
58
 
55
59
  def close
56
- raise NotConnectedError unless connected?
60
+ return unless connected?
57
61
 
58
- @request_queue << nil
62
+ @request_channel.close
59
63
  @request_task.wait
60
64
 
61
65
  @response_task.stop
62
66
  @response_task.wait
63
67
 
64
- @connection.close
68
+ begin
69
+ @connection.close
70
+ rescue Errno::EPIPE
71
+ nil
72
+ end
65
73
 
66
74
  reset!
67
75
  end
@@ -4,18 +4,17 @@ module Grumlin
4
4
  class Traversal
5
5
  attr_reader :connection
6
6
 
7
+ # TODO: add other start steps
8
+ SUPPORTED_START_STEPS = %w[E V addE addV].freeze
9
+
7
10
  def initialize(pool = Grumlin.config.default_pool)
8
11
  @pool = pool
9
12
  end
10
13
 
11
- # TODO: add other start steps
12
- %w[addV addE V E].each do |step|
14
+ SUPPORTED_START_STEPS.each do |step|
13
15
  define_method step do |*args|
14
16
  Step.new(@pool, step, *args)
15
17
  end
16
18
  end
17
-
18
- alias addVertex addV
19
- alias addEdge addE
20
19
  end
21
20
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grumlin
4
+ # TODO: find a better name
5
+ class TypedValue
6
+ def initialize(type, value)
7
+ @type = type
8
+ @value = value
9
+ end
10
+
11
+ def inspect(*)
12
+ "#{@type}.#{@value}"
13
+ end
14
+
15
+ def to_bytecode
16
+ @to_bytecode ||= { "@type": "g:#{@type}", "@value": @value }
17
+ end
18
+ end
19
+ end
data/lib/grumlin/u.rb CHANGED
@@ -2,17 +2,15 @@
2
2
 
3
3
  module Grumlin
4
4
  module U
5
- module U
6
- extend self # rubocop:disable Style/ModuleFunction
5
+ # TODO: add other start steps
6
+ SUPPORTED_START_STEPS = %w[V addV count has out unfold values].freeze
7
7
 
8
- %w[addV V has count out values unfold].each do |step|
8
+ class << self
9
+ SUPPORTED_START_STEPS.each do |step|
9
10
  define_method step do |*args|
10
11
  AnonymousStep.new(step, *args)
11
12
  end
12
13
  end
13
14
  end
14
-
15
- # TODO: add alias __
16
- extend U
17
15
  end
18
16
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Grumlin
4
- VERSION = "0.3.0"
4
+ VERSION = "0.6.0"
5
5
  end
data/lib/grumlin.rb CHANGED
@@ -12,11 +12,14 @@ require "async/barrier"
12
12
  require "async/http/endpoint"
13
13
  require "async/websocket/client"
14
14
 
15
+ require_relative "async/channel"
16
+
15
17
  require_relative "grumlin/version"
16
18
  require_relative "grumlin/exceptions"
17
19
 
18
20
  require_relative "grumlin/transport"
19
21
  require_relative "grumlin/client"
22
+ require_relative "grumlin/typed_value"
20
23
 
21
24
  require_relative "grumlin/vertex"
22
25
  require_relative "grumlin/edge"
@@ -38,12 +41,13 @@ require_relative "grumlin/sugar"
38
41
 
39
42
  module Grumlin
40
43
  class Config
41
- attr_accessor :url, :pool_size, :client_concurrency
44
+ attr_accessor :url, :pool_size, :client_concurrency, :client_factory
42
45
 
43
- # For some reason, client_concurrency must be greather pool_size
46
+ # For some reason, client_concurrency must be greater than pool_size
44
47
  def initialize
45
48
  @pool_size = 10
46
49
  @client_concurrency = 20
50
+ @client_factory = ->(url, parent) { Grumlin::Client.new(url, parent: parent) }
47
51
  end
48
52
 
49
53
  def default_pool
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.3.0
4
+ version: 0.6.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-07-29 00:00:00.000000000 Z
11
+ date: 2021-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async-pool
@@ -50,6 +50,7 @@ files:
50
50
  - ".overcommit.yml"
51
51
  - ".rspec"
52
52
  - ".rubocop.yml"
53
+ - ".tool-versions"
53
54
  - CHANGELOG.md
54
55
  - CODE_OF_CONDUCT.md
55
56
  - Gemfile
@@ -62,6 +63,7 @@ files:
62
63
  - gremlin_server/Dockerfile
63
64
  - gremlin_server/tinkergraph-empty.properties
64
65
  - grumlin.gemspec
66
+ - lib/async/channel.rb
65
67
  - lib/grumlin.rb
66
68
  - lib/grumlin/anonymous_step.rb
67
69
  - lib/grumlin/client.rb
@@ -81,6 +83,7 @@ files:
81
83
  - lib/grumlin/translator.rb
82
84
  - lib/grumlin/transport.rb
83
85
  - lib/grumlin/traversal.rb
86
+ - lib/grumlin/typed_value.rb
84
87
  - lib/grumlin/typing.rb
85
88
  - lib/grumlin/u.rb
86
89
  - lib/grumlin/version.rb