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 +4 -4
- data/.rubocop.yml +21 -0
- data/.rubocop_todo.yml +1 -40
- data/README.md +2 -1
- data/examples/client_initialization.rb +4 -4
- data/examples/keys.rb +127 -0
- data/lib/typesense.rb +4 -0
- data/lib/typesense/api_call.rb +3 -2
- data/lib/typesense/client.rb +6 -0
- data/lib/typesense/health.rb +15 -0
- data/lib/typesense/key.rb +24 -0
- data/lib/typesense/keys.rb +34 -0
- data/lib/typesense/metrics.rb +15 -0
- data/lib/typesense/version.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: daf1095f05bf1b0a6a8dce800dcbd08d80c6711615dd96bd533bdff561bcfd4b
|
4
|
+
data.tar.gz: c3f22c5657cfbffd5eea14862f81cf32af19a699354f8f6cecd45850c7d22b26
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3933ca65c765545244d66c18e4c2a20b390ed7c3f9d3ef0134596f6f929826748eace3cfc14e9985e93bd091e5463d990d4173ba6b1f3e5e6a31a3681615822d
|
7
|
+
data.tar.gz: 704d5853d7c232d66d05aa037c26f3adfa9089599ae68c74c90af69e02bfc28cc5a87e51958cfb56acc7d64b75c7d53129bb514af736e299348abfa233b5fd0f
|
data/.rubocop.yml
CHANGED
@@ -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
|
data/.rubocop_todo.yml
CHANGED
@@ -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.
|
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.
|
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.
|
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.
|
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
|
|
data/examples/keys.rb
ADDED
@@ -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
|
data/lib/typesense.rb
CHANGED
@@ -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'
|
data/lib/typesense/api_call.rb
CHANGED
@@ -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
|
-
|
86
|
-
|
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,
|
data/lib/typesense/client.rb
CHANGED
@@ -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,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
|
data/lib/typesense/version.rb
CHANGED
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
|
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-
|
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
|