typesense 0.4.0 → 0.5.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 +4 -4
- data/.rubocop.yml +3 -0
- data/.rubocop_todo.yml +3 -0
- data/README.md +2 -1
- data/examples/client_initialization.rb +4 -4
- data/examples/keys.rb +127 -0
- data/lib/typesense.rb +2 -0
- data/lib/typesense/client.rb +2 -0
- data/lib/typesense/key.rb +24 -0
- data/lib/typesense/keys.rb +34 -0
- data/lib/typesense/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ec69deb240d0c343346d128161aa74fe12ab18e7f79007dfa24ac16738c46237
|
4
|
+
data.tar.gz: e681fcd5f9b1241054f3c786ee5e6eebad45c1ddc1705311bf7a45ea6551a23f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f6dd0dfd751499e1ec32cfd45935038df7ad219c498f433745fd8855439ef5136a7df7c47491f37fa9940d8bc1f1d02cfcc5aa77f6c4a154256f6ebe4dcb5c32
|
7
|
+
data.tar.gz: 7ef2d64aa701054a756222bc18dc19c9b3e282dbb6cc8789a47fe901d5716d67faaacf0c8fe1ed5b3de7cf1f06a1af11621e77ec633a4dfb6722e5bb0ed6908f
|
data/.rubocop.yml
CHANGED
data/.rubocop_todo.yml
CHANGED
@@ -17,6 +17,7 @@ Lint/SuppressedException:
|
|
17
17
|
Exclude:
|
18
18
|
- 'examples/collections_and_documents.rb'
|
19
19
|
- 'examples/search.rb'
|
20
|
+
- 'examples/keys.rb'
|
20
21
|
|
21
22
|
# Offense count: 3
|
22
23
|
# Configuration parameters: IgnoredMethods.
|
@@ -49,6 +50,8 @@ RSpec/ExampleLength:
|
|
49
50
|
Exclude:
|
50
51
|
- 'spec/typesense/alias_spec.rb'
|
51
52
|
- 'spec/typesense/aliases_spec.rb'
|
53
|
+
- 'spec/typesense/key_spec.rb'
|
54
|
+
- 'spec/typesense/keys_spec.rb'
|
52
55
|
- 'spec/typesense/api_call_spec.rb'
|
53
56
|
- 'spec/typesense/collection_spec.rb'
|
54
57
|
- 'spec/typesense/collections_spec.rb'
|
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,7 @@ 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'
|
19
21
|
require_relative 'typesense/error'
|
data/lib/typesense/client.rb
CHANGED
@@ -5,6 +5,7 @@ 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
|
9
10
|
|
10
11
|
def initialize(options = {})
|
@@ -12,6 +13,7 @@ module Typesense
|
|
12
13
|
@api_call = ApiCall.new(@configuration)
|
13
14
|
@collections = Collections.new(@api_call)
|
14
15
|
@aliases = Aliases.new(@api_call)
|
16
|
+
@keys = Keys.new(@api_call)
|
15
17
|
@debug = Debug.new(@api_call)
|
16
18
|
end
|
17
19
|
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
|
+
version: 0.5.0
|
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-
|
11
|
+
date: 2020-05-31 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,8 @@ files:
|
|
243
244
|
- lib/typesense/document.rb
|
244
245
|
- lib/typesense/documents.rb
|
245
246
|
- lib/typesense/error.rb
|
247
|
+
- lib/typesense/key.rb
|
248
|
+
- lib/typesense/keys.rb
|
246
249
|
- lib/typesense/override.rb
|
247
250
|
- lib/typesense/overrides.rb
|
248
251
|
- lib/typesense/version.rb
|