typesense 0.4.0 → 0.5.4

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: 8c74454a48a4f170bbb99bb5e382199c8842e84ec5d2fbd6198106df89b45977
4
- data.tar.gz: ca4772c87e84fabe0cef3af42bfb6e1bb889e305b402d9a2e2f83b10bdbe6d1b
3
+ metadata.gz: daf1095f05bf1b0a6a8dce800dcbd08d80c6711615dd96bd533bdff561bcfd4b
4
+ data.tar.gz: c3f22c5657cfbffd5eea14862f81cf32af19a699354f8f6cecd45850c7d22b26
5
5
  SHA512:
6
- metadata.gz: d1ab99d6e52d15257c8e664d765b1debb063d151d364916b273cef1658537dadcd0241e76fffa5807be50b15c83891b76c2aaef7105c875be2c3bb70728b88e0
7
- data.tar.gz: db20bce0c42a7713a3c5fa25ca1c7a17bb6724bd8949b5dc16202d11538b348d806d960f0def0712e118d856184da8650a3b12ba861037754e20e172856d38c0
6
+ metadata.gz: 3933ca65c765545244d66c18e4c2a20b390ed7c3f9d3ef0134596f6f929826748eace3cfc14e9985e93bd091e5463d990d4173ba6b1f3e5e6a31a3681615822d
7
+ data.tar.gz: 704d5853d7c232d66d05aa037c26f3adfa9089599ae68c74c90af69e02bfc28cc5a87e51958cfb56acc7d64b75c7d53129bb514af736e299348abfa233b5fd0f
@@ -11,3 +11,24 @@ Metrics/BlockLength:
11
11
  - 'spec/**/*'
12
12
  - 'Gemfile'
13
13
  - 'typesense.gemspec'
14
+
15
+ Style/Documentation:
16
+ Enabled: false
17
+
18
+ RSpec/ExampleLength:
19
+ Enabled: false
20
+
21
+ Metrics/MethodLength:
22
+ Enabled: false
23
+
24
+ Metrics/AbcSize:
25
+ Enabled: false
26
+
27
+ Metrics/ClassLength:
28
+ Enabled: false
29
+
30
+ Metrics/CyclomaticComplexity:
31
+ Enabled: false
32
+
33
+ Metrics/PerceivedComplexity:
34
+ Enabled: false
@@ -17,46 +17,7 @@ Lint/SuppressedException:
17
17
  Exclude:
18
18
  - 'examples/collections_and_documents.rb'
19
19
  - 'examples/search.rb'
20
-
21
- # Offense count: 3
22
- # Configuration parameters: IgnoredMethods.
23
- Metrics/AbcSize:
24
- Max: 43
25
-
26
- # Offense count: 1
27
- # Configuration parameters: CountComments.
28
- Metrics/ClassLength:
29
- Max: 184
30
-
31
- # Offense count: 3
32
- # Configuration parameters: IgnoredMethods.
33
- Metrics/CyclomaticComplexity:
34
- Max: 11
35
-
36
- # Offense count: 5
37
- # Configuration parameters: CountComments, ExcludedMethods.
38
- Metrics/MethodLength:
39
- Max: 29
40
-
41
- # Offense count: 3
42
- # Configuration parameters: IgnoredMethods.
43
- Metrics/PerceivedComplexity:
44
- Max: 11
45
-
46
- # Offense count: 25
47
- # Configuration parameters: Max.
48
- RSpec/ExampleLength:
49
- Exclude:
50
- - 'spec/typesense/alias_spec.rb'
51
- - 'spec/typesense/aliases_spec.rb'
52
- - 'spec/typesense/api_call_spec.rb'
53
- - 'spec/typesense/collection_spec.rb'
54
- - 'spec/typesense/collections_spec.rb'
55
- - 'spec/typesense/debug_spec.rb'
56
- - 'spec/typesense/document_spec.rb'
57
- - 'spec/typesense/documents_spec.rb'
58
- - 'spec/typesense/override_spec.rb'
59
- - 'spec/typesense/overrides_spec.rb'
20
+ - 'examples/keys.rb'
60
21
 
61
22
  # Offense count: 10
62
23
  RSpec/MultipleExpectations:
data/README.md CHANGED
@@ -33,8 +33,9 @@ Tests are also a good place to know how the the library works internally: [spec]
33
33
 
34
34
  | Typesense Server | typesense-ruby |
35
35
  |------------------|----------------|
36
+ | \>= v0.12.1 | \>= v0.5.0 |
37
+ | \>= v0.12.0 | \>= v0.4.0 |
36
38
  | <= v0.11 | <= v0.3.0 |
37
- | \>= v0.12 | \>= v0.4.0 |
38
39
 
39
40
  ## Development
40
41
 
@@ -11,7 +11,7 @@ AwesomePrint.defaults = {
11
11
  ## Setup
12
12
  #
13
13
  ### Option 1: Start a single-node cluster
14
- # $ docker run -i -p 8108:8108 -v/tmp/typesense-server-data-1b/:/data -v`pwd`/typesense-server-peers:/typesense-server-peers typesense/typesense:0.12.rc9 --data-dir /data --api-key=xyz --search-only-api-key=abcd --listen-port 8108 --enable-cors
14
+ # $ docker run -i -p 8108:8108 -v/tmp/typesense-server-data-1b/:/data -v`pwd`/typesense-server-peers:/typesense-server-peers typesense/typesense:0.12.1.rc1 --data-dir /data --api-key=xyz --listen-port 8108 --enable-cors
15
15
  #
16
16
  ### Option 2: Start a 3-node cluster
17
17
  #
@@ -19,13 +19,13 @@ AwesomePrint.defaults = {
19
19
  # $ echo '172.17.0.2:8107:8108,172.17.0.3:7107:7108,172.17.0.4:9107:9108' > `pwd`/typesense-server-peers
20
20
  #
21
21
  # Start node 1:
22
- # $ docker run -i -p 8108:8108 -p 8107:8107 -v/tmp/typesense-server-data-1b/:/data -v`pwd`/typesense-server-peers:/typesense-server-peers typesense/typesense:0.12.rc9 --data-dir /data --api-key=xyz --search-only-api-key=abcd --listen-port 8108 --peering-port 8107 --enable-cors --nodes=/typesense-server-peers
22
+ # $ docker run -i -p 8108:8108 -p 8107:8107 -v/tmp/typesense-server-data-1b/:/data -v`pwd`/typesense-server-peers:/typesense-server-peers typesense/typesense:0.12.1.rc1 --data-dir /data --api-key=xyz --listen-port 8108 --peering-port 8107 --enable-cors --nodes=/typesense-server-peers
23
23
  #
24
24
  # Start node 2:
25
- # $ docker run -i -p 7108:7108 -p 7107:7107 -v/tmp/.typesense-server-data-2b/:/data -v`pwd`/typesense-server-peers:/typesense-server-peers typesense/typesense:0.12.rc9 --data-dir /data --api-key=xyz --search-only-api-key=abcd --listen-port 7108 --peering-port 7107 --enable-cors --nodes=/typesense-server-peers
25
+ # $ docker run -i -p 7108:7108 -p 7107:7107 -v/tmp/.typesense-server-data-2b/:/data -v`pwd`/typesense-server-peers:/typesense-server-peers typesense/typesense:0.12.1.rc1 --data-dir /data --api-key=xyz --listen-port 7108 --peering-port 7107 --enable-cors --nodes=/typesense-server-peers
26
26
  #
27
27
  # Start node 3:
28
- # $ docker run -i -p 9108:9108 -p 9107:9107 -v/tmp/.typesense-server-data-3b/:/data -v`pwd`/typesense-server-peers:/typesense-server-peers typesense/typesense:0.12.rc9 --data-dir /data --api-key=xyz --search-only-api-key=abcd --listen-port 9108 --peering-port 9107 --enable-cors --nodes=/typesense-server-peers
28
+ # $ docker run -i -p 9108:9108 -p 9107:9107 -v/tmp/.typesense-server-data-3b/:/data -v`pwd`/typesense-server-peers:/typesense-server-peers typesense/typesense:0.12.1.rc1 --data-dir /data --api-key=xyz --listen-port 9108 --peering-port 9107 --enable-cors --nodes=/typesense-server-peers
29
29
  #
30
30
  # Note: Be sure to add `--license-key=<>` at the end when starting a Typesense Premium server
31
31
 
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # These examples walk you through operations to manage API Keys
5
+
6
+ require_relative './client_initialization'
7
+
8
+ # Let's setup some test data for this example
9
+ schema = {
10
+ 'name' => 'users',
11
+ 'fields' => [
12
+ {
13
+ 'name' => 'company_id',
14
+ 'type' => 'int32',
15
+ 'facet' => false
16
+ },
17
+ {
18
+ 'name' => 'user_name',
19
+ 'type' => 'string',
20
+ 'facet' => false
21
+ },
22
+ {
23
+ 'name' => 'login_count',
24
+ 'type' => 'int32',
25
+ 'facet' => false
26
+ },
27
+ {
28
+ 'name' => 'country',
29
+ 'type' => 'string',
30
+ 'facet' => true
31
+ }
32
+ ],
33
+ 'default_sorting_field' => 'company_id'
34
+ }
35
+
36
+ # We have four users, belonging to two companies: 124 and 126
37
+ documents = [
38
+ {
39
+ 'company_id' => 124,
40
+ 'user_name' => 'Hilary Bradford',
41
+ 'login_count' => 10,
42
+ 'country' => 'USA'
43
+ },
44
+ {
45
+ 'company_id' => 124,
46
+ 'user_name' => 'Nile Carty',
47
+ 'login_count' => 100,
48
+ 'country' => 'USA'
49
+ },
50
+ {
51
+ 'company_id' => 126,
52
+ 'user_name' => 'Tahlia Maxwell',
53
+ 'login_count' => 1,
54
+ 'country' => 'France'
55
+ },
56
+ {
57
+ 'company_id' => 126,
58
+ 'user_name' => 'Karl Roy',
59
+ 'login_count' => 2,
60
+ 'country' => 'Germany'
61
+ }
62
+ ]
63
+
64
+ # Delete if the collection already exists from a previous example run
65
+ begin
66
+ @typesense.collections['users'].delete
67
+ rescue Typesense::Error::ObjectNotFound
68
+ end
69
+
70
+ # create a collection
71
+ @typesense.collections.create(schema)
72
+
73
+ # Index documents
74
+ documents.each do |document|
75
+ @typesense.collections['users'].documents.create(document)
76
+ end
77
+
78
+ # Generate an API key and restrict it to only allow searches
79
+ # You want to use this API Key in the browser instead of the master API Key
80
+ unscoped_search_only_api_key_response = @typesense.keys.create({
81
+ 'description' => 'Search-only key.',
82
+ 'actions' => ['documents:search'],
83
+ 'collections' => ['*']
84
+ })
85
+ ap unscoped_search_only_api_key_response
86
+
87
+ # Save the key returned, since this will be the only time the full API Key is returned, for security purposes
88
+ unscoped_search_only_api_key = unscoped_search_only_api_key_response['value']
89
+
90
+ # Side note: you can also retrieve metadata of API keys using the ID returned in the above response
91
+ unscoped_search_only_api_key_response = @typesense.keys[unscoped_search_only_api_key_response['id']].retrieve
92
+ ap unscoped_search_only_api_key_response
93
+
94
+ # We'll now use this search-only API key to generate a scoped search API key that can only access documents that have company_id:124
95
+ # This is useful when you store multi-tenant data in a single Typesense server, but you only want
96
+ # a particular tenant to access their own data. You'd generate one scoped search key per tenant.
97
+ # IMPORTANT: scoped search keys should only be generated *server-side*, so as to not leak the unscoped main search key to clients
98
+ scoped_search_only_api_key = @typesense.keys.generate_scoped_search_key(unscoped_search_only_api_key, { 'filter_by': 'company_id:124' })
99
+ ap "scoped_search_only_api_key: #{scoped_search_only_api_key}"
100
+
101
+ # Now let's search the data using the scoped API Key for company_id:124
102
+ # You can do searches with this scoped_search_only_api_key from the server-side or client-side
103
+ scoped_typesense_client = Typesense::Client.new({
104
+ 'nodes': [{
105
+ 'host': 'localhost',
106
+ 'port': '8108',
107
+ 'protocol': 'http'
108
+ }],
109
+ 'api_key': scoped_search_only_api_key
110
+ })
111
+
112
+ search_results = scoped_typesense_client.collections['users'].documents.search({
113
+ 'q' => 'Hilary',
114
+ 'query_by' => 'user_name'
115
+ })
116
+ ap search_results
117
+
118
+ # Search for a user that exists, but is outside the current key's scope
119
+ search_results = scoped_typesense_client.collections['users'].documents.search({
120
+ 'q': 'Maxwell',
121
+ 'query_by': 'user_name'
122
+ })
123
+ ap search_results # Will return empty result set
124
+
125
+ # Now let's delete the unscoped_search_only_api_key. You'd want to do this when you need to rotate keys for example.
126
+ results = @typesense.keys[unscoped_search_only_api_key_response['id']].delete
127
+ ap results
@@ -15,5 +15,9 @@ require_relative 'typesense/overrides'
15
15
  require_relative 'typesense/override'
16
16
  require_relative 'typesense/aliases'
17
17
  require_relative 'typesense/alias'
18
+ require_relative 'typesense/keys'
19
+ require_relative 'typesense/key'
18
20
  require_relative 'typesense/debug'
21
+ require_relative 'typesense/health'
22
+ require_relative 'typesense/metrics'
19
23
  require_relative 'typesense/error'
@@ -82,8 +82,9 @@ module Typesense
82
82
  # If response is 2xx return the object, else raise the response as an exception
83
83
  return response_object.parsed_response if response_object.response.code_type <= Net::HTTPSuccess # 2xx
84
84
 
85
- raise custom_exception_klass_for(response_object.response), response_object.parsed_response['message'] || 'Error message not available'
86
- rescue Net::ReadTimeout, Net::OpenTimeout,
85
+ exception_message = (response_object.parsed_response && response_object.parsed_response['message']) || 'Error'
86
+ raise custom_exception_klass_for(response_object.response), exception_message
87
+ rescue SocketError, Net::ReadTimeout, Net::OpenTimeout,
87
88
  EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError,
88
89
  Errno::EINVAL, Errno::ENETDOWN, Errno::ENETUNREACH, Errno::ENETRESET, Errno::ECONNABORTED, Errno::ECONNRESET,
89
90
  Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::EHOSTDOWN, Errno::EHOSTUNREACH,
@@ -5,14 +5,20 @@ module Typesense
5
5
  attr_reader :configuration
6
6
  attr_reader :collections
7
7
  attr_reader :aliases
8
+ attr_reader :keys
8
9
  attr_reader :debug
10
+ attr_reader :health
11
+ attr_reader :metrics
9
12
 
10
13
  def initialize(options = {})
11
14
  @configuration = Configuration.new(options)
12
15
  @api_call = ApiCall.new(@configuration)
13
16
  @collections = Collections.new(@api_call)
14
17
  @aliases = Aliases.new(@api_call)
18
+ @keys = Keys.new(@api_call)
15
19
  @debug = Debug.new(@api_call)
20
+ @health = Health.new(@api_call)
21
+ @metrics = Metrics.new(@api_call)
16
22
  end
17
23
  end
18
24
  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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Typesense
4
- VERSION = '0.4.0'
4
+ VERSION = '0.5.4'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: typesense
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Typesense, Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-23 00:00:00.000000000 Z
11
+ date: 2020-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: awesome_print
@@ -229,6 +229,7 @@ files:
229
229
  - examples/aliases.rb
230
230
  - examples/client_initialization.rb
231
231
  - examples/collections_and_documents.rb
232
+ - examples/keys.rb
232
233
  - examples/overrides.rb
233
234
  - examples/search.rb
234
235
  - lib/typesense.rb
@@ -243,6 +244,10 @@ files:
243
244
  - lib/typesense/document.rb
244
245
  - lib/typesense/documents.rb
245
246
  - lib/typesense/error.rb
247
+ - lib/typesense/health.rb
248
+ - lib/typesense/key.rb
249
+ - lib/typesense/keys.rb
250
+ - lib/typesense/metrics.rb
246
251
  - lib/typesense/override.rb
247
252
  - lib/typesense/overrides.rb
248
253
  - lib/typesense/version.rb