@@ -80,6 +80,8 @@ class IndexSettings
8080 OPTIONS = [
8181 :multi_way_synonyms ,
8282 :one_way_synonyms ,
83+ :synonym_sets ,
84+ :curation_sets ,
8385 :predefined_fields ,
8486 :fields ,
8587 :default_sorting_field ,
@@ -271,11 +273,13 @@ def collection_name_with_timestamp(options)
271273 "#{ typesense_collection_name ( options ) } _#{ Time . now . to_i } "
272274 end
273275
274- def typesense_create_collection ( collection_name , settings = nil )
276+ def typesense_create_collection ( collection_name , settings = nil , existing_collection : nil )
275277 fields = settings . get_setting ( :predefined_fields ) || settings . get_setting ( :fields )
276278 default_sorting_field = settings . get_setting ( :default_sorting_field )
277279 multi_way_synonyms = settings . get_setting ( :multi_way_synonyms )
278280 one_way_synonyms = settings . get_setting ( :one_way_synonyms )
281+ synonym_sets = settings . get_setting ( :synonym_sets )
282+ curation_sets = settings . get_setting ( :curation_sets )
279283 symbols_to_index = settings . get_setting ( :symbols_to_index )
280284 token_separators = settings . get_setting ( :token_separators )
281285 enable_nested_fields = settings . get_setting ( :enable_nested_fields )
@@ -300,9 +304,14 @@ def typesense_create_collection(collection_name, settings = nil)
300304 )
301305 Typesense . log ( :debug , "Collection '#{ collection_name } ' created!" )
302306
303- typesense_multi_way_synonyms ( collection_name , multi_way_synonyms ) if multi_way_synonyms
304-
305- typesense_one_way_synonyms ( collection_name , one_way_synonyms ) if one_way_synonyms
307+ apply_typesense_collection_resources (
308+ collection_name ,
309+ multi_way_synonyms : multi_way_synonyms ,
310+ one_way_synonyms : one_way_synonyms ,
311+ synonym_sets : synonym_sets ,
312+ curation_sets : curation_sets ,
313+ existing_collection : existing_collection
314+ )
306315 end
307316
308317 def typesense_upsert_alias ( collection_name , alias_name )
@@ -385,6 +394,103 @@ def typesense_one_way_synonyms(collection, synonyms)
385394 end
386395 end
387396
397+ def apply_typesense_collection_resources ( collection_name , multi_way_synonyms : nil , one_way_synonyms : nil , synonym_sets : nil , curation_sets : nil , existing_collection : nil )
398+ if typesense_server_major_version >= 30
399+ apply_v30_collection_resources (
400+ collection_name ,
401+ multi_way_synonyms : multi_way_synonyms ,
402+ one_way_synonyms : one_way_synonyms ,
403+ synonym_sets : synonym_sets ,
404+ curation_sets : curation_sets ,
405+ existing_collection : existing_collection
406+ )
407+ else
408+ ensure_v30_resource_support! ( synonym_sets , curation_sets )
409+ typesense_multi_way_synonyms ( collection_name , multi_way_synonyms ) if multi_way_synonyms
410+ typesense_one_way_synonyms ( collection_name , one_way_synonyms ) if one_way_synonyms
411+ end
412+ end
413+
414+ def apply_v30_collection_resources ( collection_name , multi_way_synonyms : nil , one_way_synonyms : nil , synonym_sets : nil , curation_sets : nil , existing_collection : nil )
415+ inline_synonyms_present = multi_way_synonyms || one_way_synonyms
416+ attached_synonym_sets = Array ( existing_collection && existing_collection [ "synonym_sets" ] ) + Array ( synonym_sets )
417+ attached_curation_sets = Array ( existing_collection && existing_collection [ "curation_sets" ] ) + Array ( curation_sets )
418+
419+ if inline_synonyms_present
420+ synonym_set_name = default_synonym_set_name ( collection_name )
421+ ensure_synonym_set_exists ( synonym_set_name )
422+ upsert_synonym_set_items ( synonym_set_name , multi_way_synonyms , one_way_synonyms )
423+ attached_synonym_sets << synonym_set_name
424+ end
425+
426+ collection_patch = { }
427+ collection_patch [ "synonym_sets" ] = attached_synonym_sets . uniq if attached_synonym_sets . any?
428+ collection_patch [ "curation_sets" ] = attached_curation_sets . uniq if attached_curation_sets . any?
429+
430+ return if collection_patch . empty?
431+
432+ typesense_client . collections [ collection_name ] . update ( collection_patch )
433+ end
434+
435+ def ensure_v30_resource_support! ( synonym_sets , curation_sets )
436+ unsupported = [ ]
437+ unsupported << "synonym_sets" if synonym_sets
438+ unsupported << "curation_sets" if curation_sets
439+ return if unsupported . empty?
440+
441+ raise Typesense ::BadConfiguration , "#{ unsupported . join ( ' and ' ) } require Typesense v30.0 or newer"
442+ end
443+
444+ def default_synonym_set_name ( collection_name )
445+ "#{ collection_name } _synonyms_index"
446+ end
447+
448+ def ensure_synonym_set_exists ( synonym_set_name )
449+ typesense_client . synonym_sets . upsert ( synonym_set_name , { "items" => [ ] } )
450+ end
451+
452+ def upsert_synonym_set_items ( synonym_set_name , multi_way_synonyms , one_way_synonyms )
453+ items = [ ]
454+
455+ Array ( multi_way_synonyms ) . each do |synonym_hash |
456+ synonym_hash . each do |synonym_name , synonym |
457+ items << { "id" => synonym_name , "synonyms" => synonym }
458+ end
459+ end
460+
461+ Array ( one_way_synonyms ) . each do |synonym_hash |
462+ synonym_hash . each do |synonym_name , synonym |
463+ items << synonym . merge ( "id" => synonym_name )
464+ end
465+ end
466+
467+ typesense_client . synonym_sets . upsert ( synonym_set_name , { "items" => items } )
468+ end
469+
470+ def typesense_server_major_version
471+ Typesense . server_major_version
472+ end
473+
474+ def reset_typesense_server_major_version!
475+ Typesense . reset_server_version_cache!
476+ end
477+
478+ def typesense_debug_info
479+ Typesense . debug_info
480+ end
481+
482+ def typesense_collection_resources ( collection_name )
483+ return { } if typesense_server_major_version < 30
484+
485+ collection = typesense_get_collection ( collection_name )
486+ return { } unless collection
487+
488+ {
489+ "synonym_sets" => Array ( collection [ "synonym_sets" ] ) ,
490+ "curation_sets" => Array ( collection [ "curation_sets" ] )
491+ }
492+ end
493+
388494 def typesense ( options = { } , &block )
389495 self . typesense_settings = IndexSettings . new ( options , &block )
390496 self . typesense_options = { type : typesense_full_const_get ( model_name . to_s ) } . merge ( options ) # :per_page => typesense_settings.get_setting(:hitsPerPage) || 10, :page => 1
@@ -528,8 +634,10 @@ def typesense_reindex(batch_size = Typesense::IndexSettings::DEFAULT_BATCH_SIZE)
528634 typesense_configurations . each do |options , settings |
529635 next if typesense_indexing_disabled? ( options )
530636
637+ existing_collection_resources = { }
531638 begin
532639 master_index = typesense_ensure_init ( options , settings , false )
640+ existing_collection_resources = typesense_collection_resources ( master_index [ :alias_name ] )
533641 delete_collection ( master_index [ :alias_name ] )
534642 rescue ArgumentError
535643 @typesense_indexes [ settings ] = { collection_name : "" , alias_name : typesense_collection_name ( options ) }
@@ -542,7 +650,7 @@ def typesense_reindex(batch_size = Typesense::IndexSettings::DEFAULT_BATCH_SIZE)
542650 tmp_options . delete ( :per_environment ) # already included in the temporary index_name
543651 tmp_settings = settings . dup
544652
545- create_collection ( src_index_name , settings )
653+ create_collection ( src_index_name , settings , existing_collection : existing_collection_resources )
546654
547655 typesense_find_in_batches ( batch_size ) do |group |
548656 if typesense_conditional_index? ( options )
0 commit comments