typesense 0.1.1 → 0.5.2

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.
@@ -4,12 +4,21 @@ module Typesense
4
4
  class Client
5
5
  attr_reader :configuration
6
6
  attr_reader :collections
7
+ attr_reader :aliases
8
+ attr_reader :keys
7
9
  attr_reader :debug
10
+ attr_reader :health
11
+ attr_reader :metrics
8
12
 
9
13
  def initialize(options = {})
10
- @configuration ||= Configuration.new(options)
11
- @collections = Collections.new(@configuration)
12
- @debug = Debug.new(@configuration)
14
+ @configuration = Configuration.new(options)
15
+ @api_call = ApiCall.new(@configuration)
16
+ @collections = Collections.new(@api_call)
17
+ @aliases = Aliases.new(@api_call)
18
+ @keys = Keys.new(@api_call)
19
+ @debug = Debug.new(@api_call)
20
+ @health = Health.new(@api_call)
21
+ @metrics = Metrics.new(@api_call)
13
22
  end
14
23
  end
15
24
  end
@@ -3,19 +3,21 @@
3
3
  module Typesense
4
4
  class Collection
5
5
  attr_reader :documents
6
+ attr_reader :overrides
6
7
 
7
- def initialize(configuration, name)
8
- @configuration = configuration
9
- @name = name
10
- @documents = Documents.new(@configuration, @name)
8
+ def initialize(name, api_call)
9
+ @name = name
10
+ @api_call = api_call
11
+ @documents = Documents.new(@name, @api_call)
12
+ @overrides = Overrides.new(@name, @api_call)
11
13
  end
12
14
 
13
15
  def retrieve
14
- ApiCall.new(@configuration).get(endpoint_path)
16
+ @api_call.get(endpoint_path)
15
17
  end
16
18
 
17
19
  def delete
18
- ApiCall.new(@configuration).delete(endpoint_path)
20
+ @api_call.delete(endpoint_path)
19
21
  end
20
22
 
21
23
  private
@@ -4,21 +4,21 @@ module Typesense
4
4
  class Collections
5
5
  RESOURCE_PATH = '/collections'
6
6
 
7
- def initialize(configuration)
8
- @configuration = configuration
9
- @collections = {}
7
+ def initialize(api_call)
8
+ @api_call = api_call
9
+ @collections = {}
10
10
  end
11
11
 
12
12
  def create(schema)
13
- ApiCall.new(@configuration).post(RESOURCE_PATH, schema)
13
+ @api_call.post(RESOURCE_PATH, schema)
14
14
  end
15
15
 
16
16
  def retrieve
17
- ApiCall.new(@configuration).get(RESOURCE_PATH)
17
+ @api_call.get(RESOURCE_PATH)
18
18
  end
19
19
 
20
20
  def [](collection_name)
21
- @collections[collection_name] ||= Collection.new(@configuration, collection_name)
21
+ @collections[collection_name] ||= Collection.new(collection_name, @api_call)
22
22
  end
23
23
  end
24
24
  end
@@ -2,37 +2,53 @@
2
2
 
3
3
  module Typesense
4
4
  class Configuration
5
- attr_accessor :master_node
6
- attr_accessor :read_replica_nodes
7
- attr_accessor :timeout_seconds
5
+ attr_accessor :nodes
6
+ attr_accessor :nearest_node
7
+ attr_accessor :connection_timeout_seconds
8
+ attr_accessor :healthcheck_interval_seconds
9
+ attr_accessor :num_retries
10
+ attr_accessor :retry_interval_seconds
11
+ attr_accessor :api_key
12
+ attr_accessor :logger
13
+ attr_accessor :log_level
8
14
 
9
15
  def initialize(options = {})
10
- @master_node = options[:master_node] || {
11
- host: 'localhost',
12
- port: '8108',
13
- protocol: 'http'
14
- }
15
-
16
- @read_replica_nodes = options[:read_replica_nodes] || []
17
- @timeout_seconds = options[:timeout_seconds] || 10
16
+ @nodes = options[:nodes] || []
17
+ @nearest_node = options[:nearest_node]
18
+ @connection_timeout_seconds = options[:connection_timeout_seconds] || options[:timeout_seconds] || 10
19
+ @healthcheck_interval_seconds = options[:healthcheck_interval_seconds] || 15
20
+ @num_retries = options[:num_retries] || @nodes.length + (@nearest_node.nil? ? 0 : 1) || 3
21
+ @retry_interval_seconds = options[:retry_interval_seconds] || 0.1
22
+ @api_key = options[:api_key]
23
+
24
+ @logger = options[:logger] || Logger.new(STDOUT)
25
+ @log_level = options[:log_level] || Logger::WARN
26
+ @logger.level = @log_level
27
+
28
+ show_deprecation_warnings(options)
29
+ validate!
18
30
  end
19
31
 
20
32
  def validate!
21
- if @master_node.nil? ||
22
- node_missing_parameters?(@master_node)
23
- raise Error::MissingConfiguration, 'Missing required configuration. Ensure that master_node[:protocol], master_node[:host], master_node[:port] and master_node[:api_key] are set.'
33
+ if @nodes.nil? ||
34
+ @nodes.empty? ||
35
+ @nodes.any? { |node| node_missing_parameters?(node) }
36
+ raise Error::MissingConfiguration, 'Missing required configuration. Ensure that nodes[][:protocol], nodes[][:host] and nodes[][:port] are set.'
24
37
  end
25
38
 
26
- if !@read_replica_nodes.nil? &&
27
- @read_replica_nodes.any? { |node| node_missing_parameters?(node) }
28
- raise Error::MissingConfiguration, 'Missing required configuration for read_replica_nodes. Ensure that read_replica_nodes[][:protocol], read_replica_nodes[][:host], read_replica_nodes[][:port] and read_replica_nodes[][:api_key] are set.'
29
- end
39
+ raise Error::MissingConfiguration, 'Missing required configuration. Ensure that api_key is set.' if @api_key.nil?
30
40
  end
31
41
 
32
42
  private
33
43
 
34
44
  def node_missing_parameters?(node)
35
- %i[protocol host port api_key].any? { |attr| node.send(:[], attr).nil? }
45
+ %i[protocol host port].any? { |attr| node.send(:[], attr).nil? }
46
+ end
47
+
48
+ def show_deprecation_warnings(options)
49
+ @logger.warn 'Deprecation warning: timeout_seconds is now renamed to connection_timeout_seconds' unless options[:timeout_seconds].nil?
50
+ @logger.warn 'Deprecation warning: master_node is now consolidated to nodes, starting with Typesense Server v0.12' unless options[:master_node].nil?
51
+ @logger.warn 'Deprecation warning: read_replica_nodes is now consolidated to nodes, starting with Typesense Server v0.12' unless options[:read_replica_nodes].nil?
36
52
  end
37
53
  end
38
54
  end
@@ -4,12 +4,12 @@ module Typesense
4
4
  class Debug
5
5
  RESOURCE_PATH = '/debug'
6
6
 
7
- def initialize(configuration)
8
- @configuration = configuration
7
+ def initialize(api_call)
8
+ @api_call = api_call
9
9
  end
10
10
 
11
11
  def retrieve
12
- ApiCall.new(@configuration).get(RESOURCE_PATH)
12
+ @api_call.get(RESOURCE_PATH)
13
13
  end
14
14
  end
15
15
  end
@@ -2,18 +2,18 @@
2
2
 
3
3
  module Typesense
4
4
  class Document
5
- def initialize(configuration, collection_name, document_id)
6
- @configuration = configuration
5
+ def initialize(collection_name, document_id, api_call)
7
6
  @collection_name = collection_name
8
7
  @document_id = document_id
8
+ @api_call = api_call
9
9
  end
10
10
 
11
11
  def retrieve
12
- ApiCall.new(@configuration).get(endpoint_path)
12
+ @api_call.get(endpoint_path)
13
13
  end
14
14
 
15
15
  def delete
16
- ApiCall.new(@configuration).delete(endpoint_path)
16
+ @api_call.delete(endpoint_path)
17
17
  end
18
18
 
19
19
  private
@@ -4,26 +4,31 @@ module Typesense
4
4
  class Documents
5
5
  RESOURCE_PATH = '/documents'
6
6
 
7
- def initialize(configuration, collection_name)
8
- @configuration = configuration
7
+ def initialize(collection_name, api_call)
9
8
  @collection_name = collection_name
9
+ @api_call = api_call
10
10
  @documents = {}
11
11
  end
12
12
 
13
13
  def create(document)
14
- ApiCall.new(@configuration).post(endpoint_path, document)
14
+ @api_call.post(endpoint_path, document)
15
+ end
16
+
17
+ def create_many(documents)
18
+ documents_in_jsonl_format = documents.map { |document| JSON.dump(document) }.join("\n")
19
+ @api_call.post(endpoint_path('import'), as_json: false, body: documents_in_jsonl_format)
15
20
  end
16
21
 
17
22
  def export
18
- ApiCall.new(@configuration).get_unparsed_response(endpoint_path('export')).split("\n")
23
+ (@api_call.get(endpoint_path('export')) || '').split("\n")
19
24
  end
20
25
 
21
26
  def search(search_parameters)
22
- ApiCall.new(@configuration).get(endpoint_path('search'), search_parameters)
27
+ @api_call.get(endpoint_path('search'), search_parameters)
23
28
  end
24
29
 
25
30
  def [](document_id)
26
- @documents[document_id] ||= Document.new(@configuration, @collection_name, document_id)
31
+ @documents[document_id] ||= Document.new(@collection_name, document_id, @api_call)
27
32
  end
28
33
 
29
34
  private
@@ -23,7 +23,13 @@ module Typesense
23
23
  class ServerError < Error
24
24
  end
25
25
 
26
+ class HTTPStatus0Error < Error
27
+ end
28
+
26
29
  class NoMethodError < ::NoMethodError
27
30
  end
31
+
32
+ class HTTPError < Error
33
+ end
28
34
  end
29
35
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Typesense
4
+ class Health
5
+ RESOURCE_PATH = '/health'
6
+
7
+ def initialize(api_call)
8
+ @api_call = api_call
9
+ end
10
+
11
+ def retrieve
12
+ @api_call.get(RESOURCE_PATH)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Typesense
4
+ class Key
5
+ def initialize(id, api_call)
6
+ @id = id
7
+ @api_call = api_call
8
+ end
9
+
10
+ def retrieve
11
+ @api_call.get(endpoint_path)
12
+ end
13
+
14
+ def delete
15
+ @api_call.delete(endpoint_path)
16
+ end
17
+
18
+ private
19
+
20
+ def endpoint_path
21
+ "#{Keys::RESOURCE_PATH}/#{@id}"
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+
5
+ module Typesense
6
+ class Keys
7
+ RESOURCE_PATH = '/keys'
8
+
9
+ def initialize(api_call)
10
+ @api_call = api_call
11
+ @keys = {}
12
+ end
13
+
14
+ def create(parameters)
15
+ @api_call.post(RESOURCE_PATH, parameters)
16
+ end
17
+
18
+ def retrieve
19
+ @api_call.get(RESOURCE_PATH)
20
+ end
21
+
22
+ def generate_scoped_search_key(search_key, parameters)
23
+ parameters_json = JSON.dump(parameters)
24
+ digest = Base64.encode64(OpenSSL::HMAC.digest('sha256', search_key, parameters_json)).gsub("\n", '')
25
+ key_prefix = search_key[0...4]
26
+ raw_scoped_key = "#{digest}#{key_prefix}#{parameters_json}"
27
+ Base64.encode64(raw_scoped_key).gsub("\n", '')
28
+ end
29
+
30
+ def [](id)
31
+ @keys[id] ||= Key.new(id, @api_call)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Typesense
4
+ class Metrics
5
+ RESOURCE_PATH = '/metrics.json'
6
+
7
+ def initialize(api_call)
8
+ @api_call = api_call
9
+ end
10
+
11
+ def retrieve
12
+ @api_call.get(RESOURCE_PATH)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Typesense
4
+ class Override
5
+ def initialize(collection_name, override_id, api_call)
6
+ @collection_name = collection_name
7
+ @override_id = override_id
8
+ @api_call = api_call
9
+ end
10
+
11
+ def retrieve
12
+ @api_call.get(endpoint_path)
13
+ end
14
+
15
+ def delete
16
+ @api_call.delete(endpoint_path)
17
+ end
18
+
19
+ private
20
+
21
+ def endpoint_path
22
+ "#{Collections::RESOURCE_PATH}/#{@collection_name}#{Overrides::RESOURCE_PATH}/#{@override_id}"
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Typesense
4
+ class Overrides
5
+ RESOURCE_PATH = '/overrides'
6
+
7
+ def initialize(collection_name, api_call)
8
+ @collection_name = collection_name
9
+ @api_call = api_call
10
+ @overrides = {}
11
+ end
12
+
13
+ def create(params)
14
+ @api_call.put(endpoint_path, params)
15
+ end
16
+
17
+ def retrieve
18
+ @api_call.get(endpoint_path)
19
+ end
20
+
21
+ def [](override_id)
22
+ @overrides[override_id] ||= Override.new(@collection_name, override_id, @api_call)
23
+ end
24
+
25
+ private
26
+
27
+ def endpoint_path(operation = nil)
28
+ "#{Collections::RESOURCE_PATH}/#{@collection_name}#{Overrides::RESOURCE_PATH}#{operation.nil? ? '' : '/' + operation}"
29
+ end
30
+ end
31
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Typesense
4
- VERSION = '0.1.1'
4
+ VERSION = '0.5.2'
5
5
  end
@@ -7,7 +7,7 @@ require 'typesense/version'
7
7
  Gem::Specification.new do |spec|
8
8
  spec.name = 'typesense'
9
9
  spec.version = Typesense::VERSION
10
- spec.authors = ['Wreally Studios']
10
+ spec.authors = ['Typesense, Inc.']
11
11
  spec.email = ['contact@typesense.org']
12
12
 
13
13
  spec.summary = 'Ruby Library for Typesense'
@@ -23,15 +23,18 @@ Gem::Specification.new do |spec|
23
23
  spec.require_paths = ['lib']
24
24
 
25
25
  spec.add_development_dependency 'awesome_print', '~> 1.8'
26
- spec.add_development_dependency 'bundler', '~> 1.16'
27
- spec.add_development_dependency 'pry-byebug', '~> 3.5'
28
- spec.add_development_dependency 'rake', '~> 10.0'
29
- spec.add_development_dependency 'rspec', '~> 3.0'
30
- spec.add_development_dependency 'rspec_junit_formatter', '~> 0.3'
31
- spec.add_development_dependency 'rubocop', '~> 0.53.0'
32
- spec.add_development_dependency 'rubocop-rspec', '~> 1.24'
33
- spec.add_development_dependency 'simplecov', '~> 0.15'
34
- spec.add_development_dependency 'webmock', '~> 3.2'
26
+ spec.add_development_dependency 'bundler', '~> 2.0'
27
+ spec.add_development_dependency 'codecov', '~> 0.1'
28
+ spec.add_development_dependency 'pry-byebug', '~> 3.9'
29
+ spec.add_development_dependency 'rake', '~> 13.0'
30
+ spec.add_development_dependency 'rspec', '~> 3.9'
31
+ spec.add_development_dependency 'rspec-legacy_formatters', '~> 1.0' # For codecov formatter
32
+ spec.add_development_dependency 'rspec_junit_formatter', '~> 0.4'
33
+ spec.add_development_dependency 'rubocop', '~> 0.83'
34
+ spec.add_development_dependency 'rubocop-rspec', '~> 1.39'
35
+ spec.add_development_dependency 'simplecov', '~> 0.18'
36
+ spec.add_development_dependency 'timecop', '~> 0.9'
37
+ spec.add_development_dependency 'webmock', '~> 3.8'
35
38
 
36
- spec.add_dependency 'httparty', '~> 0.15'
39
+ spec.add_dependency 'httparty', '~> 0.18'
37
40
  end