Skip to content

Commit dc69428

Browse files
authored
Merge pull request #39 from tharropoulos/v28-changes
V28 changes
2 parents 015274e + fb2029f commit dc69428

File tree

9 files changed

+145
-5
lines changed

9 files changed

+145
-5
lines changed

.github/workflows/tests.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ jobs:
1010
runs-on: ubuntu-latest
1111
strategy:
1212
matrix:
13-
ruby-version: ['2.7', '3.0', '3.2']
13+
ruby-version: ['3.0', '3.2', '3.3']
1414
services:
1515
typesense:
16-
image: typesense/typesense:27.1
16+
image: typesense/typesense:28.0.rc36
1717
ports:
1818
- 8108:8108
1919
volumes:
@@ -37,8 +37,8 @@ jobs:
3737
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
3838
- run: bundle exec rubocop
3939
- run: bundle exec rspec --format documentation
40-
- uses: actions/upload-artifact@v3
40+
- uses: actions/upload-artifact@v4
4141
with:
42-
name: coverage
42+
name: coverage-ruby-${{ matrix.ruby-version }}
4343
path: coverage/
4444
retention-days: 1

lib/typesense.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,6 @@ module Typesense
3232
require_relative 'typesense/stats'
3333
require_relative 'typesense/operations'
3434
require_relative 'typesense/error'
35+
require_relative 'typesense/stemming'
36+
require_relative 'typesense/stemming_dictionaries'
37+
require_relative 'typesense/stemming_dictionary'

lib/typesense/client.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
module Typesense
44
class Client
55
attr_reader :configuration, :collections, :aliases, :keys, :debug, :health, :metrics, :stats, :operations,
6-
:multi_search, :analytics, :presets
6+
:multi_search, :analytics, :presets, :stemming
77

88
def initialize(options = {})
99
@configuration = Configuration.new(options)
@@ -18,6 +18,7 @@ def initialize(options = {})
1818
@stats = Stats.new(@api_call)
1919
@operations = Operations.new(@api_call)
2020
@analytics = Analytics.new(@api_call)
21+
@stemming = Stemming.new(@api_call)
2122
@presets = Presets.new(@api_call)
2223
end
2324
end

lib/typesense/stemming.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# frozen_string_literal: true
2+
3+
module Typesense
4+
class Stemming
5+
RESOURCE_PATH = '/stemming'
6+
7+
def initialize(api_call)
8+
@api_call = api_call
9+
end
10+
11+
def dictionaries
12+
@dictionaries ||= StemmingDictionaries.new(@api_call)
13+
end
14+
end
15+
end
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# frozen_string_literal: true
2+
3+
module Typesense
4+
class StemmingDictionaries
5+
RESOURCE_PATH = '/stemming/dictionaries'
6+
7+
def initialize(api_call)
8+
@api_call = api_call
9+
@dictionaries = {}
10+
end
11+
12+
def upsert(dict_id, words_and_roots_combinations)
13+
words_and_roots_combinations_in_jsonl = if words_and_roots_combinations.is_a?(Array)
14+
words_and_roots_combinations.map { |combo| Oj.dump(combo, mode: :compat) }.join("\n")
15+
else
16+
words_and_roots_combinations
17+
end
18+
19+
result_in_jsonl = @api_call.perform_request(
20+
'post',
21+
endpoint_path('import'),
22+
query_parameters: { id: dict_id },
23+
body_parameters: words_and_roots_combinations_in_jsonl,
24+
additional_headers: { 'Content-Type' => 'text/plain' }
25+
)
26+
27+
if words_and_roots_combinations.is_a?(Array)
28+
result_in_jsonl.split("\n").map { |r| Oj.load(r) }
29+
else
30+
result_in_jsonl
31+
end
32+
end
33+
34+
def retrieve
35+
response = @api_call.get(endpoint_path)
36+
response || { 'dictionaries' => [] }
37+
end
38+
39+
def [](dict_id)
40+
@dictionaries[dict_id] ||= StemmingDictionary.new(dict_id, @api_call)
41+
end
42+
43+
private
44+
45+
def endpoint_path(operation = nil)
46+
"#{StemmingDictionaries::RESOURCE_PATH}#{operation.nil? ? '' : "/#{URI.encode_www_form_component(operation)}"}"
47+
end
48+
end
49+
end

lib/typesense/stemming_dictionary.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# frozen_string_literal: true
2+
3+
module Typesense
4+
class StemmingDictionary
5+
def initialize(id, api_call)
6+
@dict_id = id
7+
@api_call = api_call
8+
end
9+
10+
def retrieve
11+
@api_call.get(endpoint_path)
12+
end
13+
14+
private
15+
16+
def endpoint_path
17+
"#{StemmingDictionaries::RESOURCE_PATH}/#{URI.encode_www_form_component(@dict_id)}"
18+
end
19+
end
20+
end

spec/typesense/collections_spec.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
'optional' => false,
101101
'sort' => false,
102102
'stem' => false,
103+
'stem_dictionary' => '',
103104
'store' => true
104105
},
105106
{
@@ -112,6 +113,7 @@
112113
'optional' => false,
113114
'sort' => true,
114115
'stem' => false,
116+
'stem_dictionary' => '',
115117
'store' => true
116118
},
117119
{
@@ -124,6 +126,7 @@
124126
'optional' => false,
125127
'sort' => false,
126128
'stem' => false,
129+
'stem_dictionary' => '',
127130
'store' => true
128131
}
129132
]

spec/typesense/stemming_spec.rb

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# frozen_string_literal: true
2+
3+
require_relative '../spec_helper'
4+
5+
describe 'StemmingDictionaries' do
6+
let(:client) do
7+
Typesense::Client.new(
8+
nodes: [{ host: 'localhost', port: '8108', protocol: 'http' }],
9+
api_key: 'xyz',
10+
connection_timeout_seconds: 10
11+
)
12+
end
13+
14+
let(:dictionary_id) { 'test_dictionary' }
15+
let(:dictionary) do
16+
[
17+
{ 'root' => 'exampleRoot1', 'word' => 'exampleWord1' },
18+
{ 'root' => 'exampleRoot2', 'word' => 'exampleWord2' }
19+
]
20+
end
21+
22+
before do
23+
WebMock.disable!
24+
# Create the dictionary at the start of each test
25+
client.stemming.dictionaries.upsert(dictionary_id, dictionary)
26+
end
27+
28+
after do
29+
WebMock.enable!
30+
end
31+
32+
it 'can upsert a dictionary' do
33+
response = client.stemming.dictionaries.upsert(dictionary_id, dictionary)
34+
expect(response).to eq(dictionary)
35+
end
36+
37+
it 'can retrieve a dictionary' do
38+
response = client.stemming.dictionaries[dictionary_id].retrieve
39+
expect(response['id']).to eq(dictionary_id)
40+
expect(response['words']).to eq(dictionary)
41+
end
42+
43+
it 'can retrieve all dictionaries' do
44+
response = client.stemming.dictionaries.retrieve
45+
expect(response['dictionaries'].length).to eq(1)
46+
expect(response['dictionaries'][0]).to eq(dictionary_id)
47+
end
48+
end

typesense.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Gem::Specification.new do |spec|
2626
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
2727
spec.require_paths = ['lib']
2828

29+
spec.add_dependency 'base64', '~> 0.2.0'
2930
spec.add_dependency 'faraday', '~> 2.8'
3031
spec.add_dependency 'oj', '~> 3.16'
3132
spec.metadata['rubygems_mfa_required'] = 'true'

0 commit comments

Comments
 (0)