Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
ruby-version: ['2.7', '3.0', '3.2']
ruby-version: ['3.0', '3.2', '3.3']
services:
typesense:
image: typesense/typesense:27.1
image: typesense/typesense:28.0.rc36
ports:
- 8108:8108
volumes:
Expand All @@ -37,8 +37,8 @@ jobs:
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- run: bundle exec rubocop
- run: bundle exec rspec --format documentation
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
with:
name: coverage
name: coverage-ruby-${{ matrix.ruby-version }}
path: coverage/
retention-days: 1
3 changes: 3 additions & 0 deletions lib/typesense.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,6 @@ module Typesense
require_relative 'typesense/stats'
require_relative 'typesense/operations'
require_relative 'typesense/error'
require_relative 'typesense/stemming'
require_relative 'typesense/stemming_dictionaries'
require_relative 'typesense/stemming_dictionary'
3 changes: 2 additions & 1 deletion lib/typesense/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
module Typesense
class Client
attr_reader :configuration, :collections, :aliases, :keys, :debug, :health, :metrics, :stats, :operations,
:multi_search, :analytics, :presets
:multi_search, :analytics, :presets, :stemming

def initialize(options = {})
@configuration = Configuration.new(options)
Expand All @@ -18,6 +18,7 @@ def initialize(options = {})
@stats = Stats.new(@api_call)
@operations = Operations.new(@api_call)
@analytics = Analytics.new(@api_call)
@stemming = Stemming.new(@api_call)
@presets = Presets.new(@api_call)
end
end
Expand Down
15 changes: 15 additions & 0 deletions lib/typesense/stemming.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

module Typesense
class Stemming
RESOURCE_PATH = '/stemming'

def initialize(api_call)
@api_call = api_call
end

def dictionaries
@dictionaries ||= StemmingDictionaries.new(@api_call)
end
end
end
49 changes: 49 additions & 0 deletions lib/typesense/stemming_dictionaries.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# frozen_string_literal: true

module Typesense
class StemmingDictionaries
RESOURCE_PATH = '/stemming/dictionaries'

def initialize(api_call)
@api_call = api_call
@dictionaries = {}
end

def upsert(dict_id, words_and_roots_combinations)
words_and_roots_combinations_in_jsonl = if words_and_roots_combinations.is_a?(Array)
words_and_roots_combinations.map { |combo| Oj.dump(combo, mode: :compat) }.join("\n")
else
words_and_roots_combinations
end

result_in_jsonl = @api_call.perform_request(
'post',
endpoint_path('import'),
query_parameters: { id: dict_id },
body_parameters: words_and_roots_combinations_in_jsonl,
additional_headers: { 'Content-Type' => 'text/plain' }
)

if words_and_roots_combinations.is_a?(Array)
result_in_jsonl.split("\n").map { |r| Oj.load(r) }
else
result_in_jsonl
end
end

def retrieve
response = @api_call.get(endpoint_path)
response || { 'dictionaries' => [] }
end

def [](dict_id)
@dictionaries[dict_id] ||= StemmingDictionary.new(dict_id, @api_call)
end

private

def endpoint_path(operation = nil)
"#{StemmingDictionaries::RESOURCE_PATH}#{operation.nil? ? '' : "/#{URI.encode_www_form_component(operation)}"}"
end
end
end
20 changes: 20 additions & 0 deletions lib/typesense/stemming_dictionary.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

module Typesense
class StemmingDictionary
def initialize(id, api_call)
@dict_id = id
@api_call = api_call
end

def retrieve
@api_call.get(endpoint_path)
end

private

def endpoint_path
"#{StemmingDictionaries::RESOURCE_PATH}/#{URI.encode_www_form_component(@dict_id)}"
end
end
end
3 changes: 3 additions & 0 deletions spec/typesense/collections_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
'optional' => false,
'sort' => false,
'stem' => false,
'stem_dictionary' => '',
'store' => true
},
{
Expand All @@ -112,6 +113,7 @@
'optional' => false,
'sort' => true,
'stem' => false,
'stem_dictionary' => '',
'store' => true
},
{
Expand All @@ -124,6 +126,7 @@
'optional' => false,
'sort' => false,
'stem' => false,
'stem_dictionary' => '',
'store' => true
}
]
Expand Down
48 changes: 48 additions & 0 deletions spec/typesense/stemming_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# frozen_string_literal: true

require_relative '../spec_helper'

describe 'StemmingDictionaries' do
let(:client) do
Typesense::Client.new(
nodes: [{ host: 'localhost', port: '8108', protocol: 'http' }],
api_key: 'xyz',
connection_timeout_seconds: 10
)
end

let(:dictionary_id) { 'test_dictionary' }
let(:dictionary) do
[
{ 'root' => 'exampleRoot1', 'word' => 'exampleWord1' },
{ 'root' => 'exampleRoot2', 'word' => 'exampleWord2' }
]
end

before do
WebMock.disable!
# Create the dictionary at the start of each test
client.stemming.dictionaries.upsert(dictionary_id, dictionary)
end

after do
WebMock.enable!
end

it 'can upsert a dictionary' do
response = client.stemming.dictionaries.upsert(dictionary_id, dictionary)
expect(response).to eq(dictionary)
end

it 'can retrieve a dictionary' do
response = client.stemming.dictionaries[dictionary_id].retrieve
expect(response['id']).to eq(dictionary_id)
expect(response['words']).to eq(dictionary)
end

it 'can retrieve all dictionaries' do
response = client.stemming.dictionaries.retrieve
expect(response['dictionaries'].length).to eq(1)
expect(response['dictionaries'][0]).to eq(dictionary_id)
end
end
1 change: 1 addition & 0 deletions typesense.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ['lib']

spec.add_dependency 'base64', '~> 0.2.0'
spec.add_dependency 'faraday', '~> 2.8'
spec.add_dependency 'oj', '~> 3.16'
spec.metadata['rubygems_mfa_required'] = 'true'
Expand Down