search-engine-for-typesense 30.1.0 → 30.1.1
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/README.md +5 -5
- data/app/search_engine/search_engine/index_partition_job.rb +7 -26
- data/lib/generators/search_engine/install/install_generator.rb +1 -1
- data/lib/generators/search_engine/install/templates/initializer.rb.tt +11 -11
- data/lib/generators/search_engine/model/model_generator.rb +2 -2
- data/lib/generators/search_engine/model/templates/model.rb.tt +2 -2
- data/lib/search_engine/admin/stopwords.rb +1 -1
- data/lib/search_engine/admin/synonyms.rb +1 -1
- data/lib/search_engine/ast/node.rb +1 -1
- data/lib/search_engine/ast.rb +1 -1
- data/lib/search_engine/base/creation.rb +4 -4
- data/lib/search_engine/cli/doctor.rb +6 -6
- data/lib/search_engine/client/request_builder.rb +2 -2
- data/lib/search_engine/client.rb +19 -19
- data/lib/search_engine/collection_resolver.rb +7 -2
- data/lib/search_engine/config/presets.rb +7 -7
- data/lib/search_engine/config.rb +5 -5
- data/lib/search_engine/console_helpers.rb +4 -4
- data/lib/search_engine/dispatcher.rb +2 -2
- data/lib/search_engine/dsl/parser.rb +9 -9
- data/lib/search_engine/errors.rb +6 -6
- data/lib/search_engine/filters/sanitizer.rb +24 -44
- data/lib/search_engine/hydration/materializers.rb +13 -7
- data/lib/search_engine/indexer/batch_planner.rb +3 -8
- data/lib/search_engine/indexer/import_dispatcher.rb +1 -1
- data/lib/search_engine/indexer/retry_policy.rb +9 -6
- data/lib/search_engine/indexer.rb +3 -176
- data/lib/search_engine/instrumentation.rb +1 -1
- data/lib/search_engine/joins/guard.rb +4 -4
- data/lib/search_engine/joins/resolver.rb +2 -2
- data/lib/search_engine/logging_subscriber.rb +4 -4
- data/lib/search_engine/mapper.rb +13 -21
- data/lib/search_engine/multi.rb +2 -2
- data/lib/search_engine/multi_result.rb +1 -1
- data/lib/search_engine/notifications/compact_logger.rb +3 -3
- data/lib/search_engine/otel.rb +5 -5
- data/lib/search_engine/partitioner.rb +5 -5
- data/lib/search_engine/ranking_plan.rb +4 -4
- data/lib/search_engine/relation/compiler.rb +11 -6
- data/lib/search_engine/relation/dsl/filters.rb +9 -9
- data/lib/search_engine/relation/dsl/selection.rb +3 -3
- data/lib/search_engine/relation/dsl.rb +17 -17
- data/lib/search_engine/relation/dx.rb +4 -4
- data/lib/search_engine/relation/materializers.rb +1 -1
- data/lib/search_engine/relation/options.rb +1 -1
- data/lib/search_engine/relation.rb +1 -1
- data/lib/search_engine/result.rb +1 -1
- data/lib/search_engine/schema.rb +4 -4
- data/lib/search_engine/sources/active_record_source.rb +0 -1
- data/lib/search_engine/sources/lambda_source.rb +1 -1
- data/lib/search_engine/sources/sql_source.rb +1 -1
- data/lib/search_engine/sources.rb +3 -3
- data/lib/search_engine/test/stub_client.rb +8 -8
- data/lib/search_engine/test.rb +2 -2
- data/lib/search_engine/version.rb +1 -1
- metadata +2 -2
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'set'
|
|
4
|
+
|
|
3
5
|
module SearchEngine
|
|
4
6
|
class Relation
|
|
5
7
|
# Compile immutable relation state and options into Typesense body params.
|
|
@@ -11,7 +13,7 @@ module SearchEngine
|
|
|
11
13
|
# redaction-aware instrumentation events for DX surfaces.
|
|
12
14
|
#
|
|
13
15
|
# @return [SearchEngine::CompiledParams] deterministic, deeply frozen params
|
|
14
|
-
# @see `https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/query-dsl`
|
|
16
|
+
# @see `https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/query-dsl`
|
|
15
17
|
# @see `https://typesense.org/docs/latest/api/documents.html#search-document`
|
|
16
18
|
def to_typesense_params
|
|
17
19
|
cfg = SearchEngine.config
|
|
@@ -80,7 +82,7 @@ module SearchEngine
|
|
|
80
82
|
# Compile filter_by string from AST nodes or legacy fragments.
|
|
81
83
|
# @param ast_nodes [Array<SearchEngine::AST::Node>]
|
|
82
84
|
# @return [String, nil] a Typesense filter string or nil when absent
|
|
83
|
-
# @see `https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/compiler`
|
|
85
|
+
# @see `https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/compiler`
|
|
84
86
|
def compiled_filter_by(ast_nodes)
|
|
85
87
|
unless ast_nodes.empty?
|
|
86
88
|
compiled = SearchEngine::Compiler.compile(ast_nodes, klass: @klass)
|
|
@@ -184,8 +186,9 @@ module SearchEngine
|
|
|
184
186
|
applied = Array(@state[:joins])
|
|
185
187
|
return {} if applied.empty?
|
|
186
188
|
|
|
189
|
+
seen = Set.new
|
|
187
190
|
assocs = []
|
|
188
|
-
applied.each { |a| assocs << a
|
|
191
|
+
applied.each { |a| assocs << a if seen.add?(a) }
|
|
189
192
|
|
|
190
193
|
nested_map = @state[:select_nested] || {}
|
|
191
194
|
nested_order = Array(@state[:select_nested_order])
|
|
@@ -219,6 +222,7 @@ module SearchEngine
|
|
|
219
222
|
list = Array(nodes).flatten.compact
|
|
220
223
|
return [] if list.empty?
|
|
221
224
|
|
|
225
|
+
seen_set = Set.new
|
|
222
226
|
seen = []
|
|
223
227
|
walker = lambda do |node|
|
|
224
228
|
return unless node.is_a?(SearchEngine::AST::Node)
|
|
@@ -229,7 +233,7 @@ module SearchEngine
|
|
|
229
233
|
m = field.match(/^\$(\w+)\./)
|
|
230
234
|
if m
|
|
231
235
|
name = m[1].to_sym
|
|
232
|
-
seen << name
|
|
236
|
+
seen << name if seen_set.add?(name)
|
|
233
237
|
end
|
|
234
238
|
end
|
|
235
239
|
end
|
|
@@ -248,6 +252,7 @@ module SearchEngine
|
|
|
248
252
|
list = Array(orders).flatten.compact
|
|
249
253
|
return [] if list.empty?
|
|
250
254
|
|
|
255
|
+
seen_set = Set.new
|
|
251
256
|
seen = []
|
|
252
257
|
list.each do |entry|
|
|
253
258
|
field, _dir = entry.to_s.split(':', 2)
|
|
@@ -257,7 +262,7 @@ module SearchEngine
|
|
|
257
262
|
next unless m
|
|
258
263
|
|
|
259
264
|
name = m[1].to_sym
|
|
260
|
-
seen << name
|
|
265
|
+
seen << name if seen_set.add?(name)
|
|
261
266
|
end
|
|
262
267
|
seen
|
|
263
268
|
end
|
|
@@ -600,7 +605,7 @@ module SearchEngine
|
|
|
600
605
|
rescue StandardError => error
|
|
601
606
|
raise SearchEngine::Errors::InvalidOption.new(
|
|
602
607
|
"InvalidOption: ranking options could not be compiled (#{error.class}: #{error.message})",
|
|
603
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/ranking#options'
|
|
608
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/ranking#options'
|
|
604
609
|
)
|
|
605
610
|
end
|
|
606
611
|
|
|
@@ -169,7 +169,7 @@ module SearchEngine
|
|
|
169
169
|
raise SearchEngine::Errors::InvalidParams.new(
|
|
170
170
|
"merge: cannot infer association for #{other.klass}",
|
|
171
171
|
hint: 'Declare a collection on the joined model or pass assoc: :name',
|
|
172
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/joins#troubleshooting'
|
|
172
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/joins#troubleshooting'
|
|
173
173
|
)
|
|
174
174
|
end
|
|
175
175
|
|
|
@@ -180,7 +180,7 @@ module SearchEngine
|
|
|
180
180
|
raise SearchEngine::Errors::InvalidParams.new(
|
|
181
181
|
"merge: no join association for #{collection_name} on #{klass_name_for_inspect}",
|
|
182
182
|
hint: "#{hint} Pass assoc: :name to disambiguate.",
|
|
183
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/joins#troubleshooting',
|
|
183
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/joins#troubleshooting',
|
|
184
184
|
details: { target_collection: collection_name, available: cfgs.keys }
|
|
185
185
|
)
|
|
186
186
|
end
|
|
@@ -190,7 +190,7 @@ module SearchEngine
|
|
|
190
190
|
raise SearchEngine::Errors::InvalidParams.new(
|
|
191
191
|
"merge: ambiguous association for #{collection_name} on #{klass_name_for_inspect}",
|
|
192
192
|
hint: "Pass assoc: :#{names.first} (available: #{names.map(&:inspect).join(', ')})",
|
|
193
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/joins#troubleshooting',
|
|
193
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/joins#troubleshooting',
|
|
194
194
|
details: { target_collection: collection_name, matches: names }
|
|
195
195
|
)
|
|
196
196
|
end
|
|
@@ -207,7 +207,7 @@ module SearchEngine
|
|
|
207
207
|
raise SearchEngine::Errors::InvalidParams.new(
|
|
208
208
|
"merge: expected a join scope Symbol or Array<Symbol> for #{assoc.inspect}",
|
|
209
209
|
hint: 'Use merge(assoc: :scope) or merge(assoc: [:scope1, :scope2])',
|
|
210
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/query-dsl#join-scope',
|
|
210
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/query-dsl#join-scope',
|
|
211
211
|
details: { assoc: assoc, value: scope_value }
|
|
212
212
|
)
|
|
213
213
|
end
|
|
@@ -350,7 +350,7 @@ module SearchEngine
|
|
|
350
350
|
unless target_klass.respond_to?(sym)
|
|
351
351
|
raise SearchEngine::Errors::InvalidParams.new(
|
|
352
352
|
%(Unknown join-scope :#{sym} on association :#{assoc} for #{target_klass}),
|
|
353
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/query-dsl#join-scope'
|
|
353
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/query-dsl#join-scope'
|
|
354
354
|
)
|
|
355
355
|
end
|
|
356
356
|
|
|
@@ -358,7 +358,7 @@ module SearchEngine
|
|
|
358
358
|
unless rel.is_a?(SearchEngine::Relation)
|
|
359
359
|
raise SearchEngine::Errors::InvalidParams.new(
|
|
360
360
|
%(join-scope :#{sym} on :#{assoc} must return a SearchEngine::Relation (got #{rel.class})),
|
|
361
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/query-dsl#join-scope'
|
|
361
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/query-dsl#join-scope'
|
|
362
362
|
)
|
|
363
363
|
end
|
|
364
364
|
|
|
@@ -397,7 +397,7 @@ module SearchEngine
|
|
|
397
397
|
if fragment.include?('$')
|
|
398
398
|
raise SearchEngine::Errors::InvalidParams.new(
|
|
399
399
|
'join-scope raw fragments must use base fields only (no nested join paths)',
|
|
400
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/query-dsl#join-scope',
|
|
400
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/query-dsl#join-scope',
|
|
401
401
|
details: { fragment: fragment, assoc: assoc_sym }
|
|
402
402
|
)
|
|
403
403
|
end
|
|
@@ -416,7 +416,7 @@ module SearchEngine
|
|
|
416
416
|
if lhs.start_with?('$') || lhs.include?('.')
|
|
417
417
|
raise SearchEngine::Errors::InvalidParams.new(
|
|
418
418
|
%(join-scope cannot reference nested join field #{lhs.inspect}; use base fields only),
|
|
419
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/query-dsl#join-scope',
|
|
419
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/query-dsl#join-scope',
|
|
420
420
|
details: { field: lhs, assoc: assoc_sym }
|
|
421
421
|
)
|
|
422
422
|
end
|
|
@@ -553,7 +553,7 @@ module SearchEngine
|
|
|
553
553
|
def raise_empty_array_type!(field_sym)
|
|
554
554
|
raise SearchEngine::Errors::InvalidType.new(
|
|
555
555
|
%(expected #{field_sym.inspect} to be a non-empty Array),
|
|
556
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/query-dsl#troubleshooting',
|
|
556
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/query-dsl#troubleshooting',
|
|
557
557
|
details: { field: field_sym }
|
|
558
558
|
)
|
|
559
559
|
end
|
|
@@ -9,7 +9,7 @@ module SearchEngine
|
|
|
9
9
|
# Select a subset of fields for Typesense `include_fields`.
|
|
10
10
|
# @param fields [Array<Symbol,String,Hash,Array>]
|
|
11
11
|
# @return [SearchEngine::Relation]
|
|
12
|
-
# @see `https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/field-selection`
|
|
12
|
+
# @see `https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/field-selection`
|
|
13
13
|
def select(*fields)
|
|
14
14
|
normalized = normalize_select_input(fields)
|
|
15
15
|
spawn do |s|
|
|
@@ -46,7 +46,7 @@ module SearchEngine
|
|
|
46
46
|
# Exclude a subset of fields from the final selection.
|
|
47
47
|
# @param fields [Array<Symbol,String,Hash,Array>]
|
|
48
48
|
# @return [SearchEngine::Relation]
|
|
49
|
-
# @see `https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/field-selection`
|
|
49
|
+
# @see `https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/field-selection`
|
|
50
50
|
#
|
|
51
51
|
# When excluding, you may also pass a joined association name (after calling
|
|
52
52
|
# `joins(:assoc)`) to exclude the entire joined payload from the response.
|
|
@@ -88,7 +88,7 @@ module SearchEngine
|
|
|
88
88
|
# Replace the selected fields list (Typesense `include_fields`).
|
|
89
89
|
# @param fields [Array<#to_sym,#to_s>]
|
|
90
90
|
# @return [SearchEngine::Relation]
|
|
91
|
-
# @see `https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/field-selection`
|
|
91
|
+
# @see `https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/field-selection`
|
|
92
92
|
def reselect(*fields)
|
|
93
93
|
normalized = normalize_select_input(fields)
|
|
94
94
|
|
|
@@ -98,7 +98,7 @@ module SearchEngine
|
|
|
98
98
|
raise SearchEngine::Errors::InvalidOption.new(
|
|
99
99
|
"InvalidOption: unknown prefix mode #{mode.inspect}",
|
|
100
100
|
hint: 'Use :disabled, :fallback, or :always',
|
|
101
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/ranking#prefix',
|
|
101
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/ranking#prefix',
|
|
102
102
|
details: { provided: mode, allowed: valid.keys }
|
|
103
103
|
)
|
|
104
104
|
end
|
|
@@ -571,7 +571,7 @@ module SearchEngine
|
|
|
571
571
|
if field_str.start_with?('$') || field_str.include?('.')
|
|
572
572
|
raise SearchEngine::Errors::UnsupportedGroupField.new(
|
|
573
573
|
%(UnsupportedGroupField: grouping supports base fields only (got #{field_str.inspect})),
|
|
574
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/grouping#troubleshooting',
|
|
574
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/grouping#troubleshooting',
|
|
575
575
|
details: { field: field_str }
|
|
576
576
|
)
|
|
577
577
|
end
|
|
@@ -583,7 +583,7 @@ module SearchEngine
|
|
|
583
583
|
msg = build_invalid_group_unknown_field_message(sym)
|
|
584
584
|
raise SearchEngine::Errors::InvalidGroup.new(
|
|
585
585
|
msg,
|
|
586
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/grouping#troubleshooting',
|
|
586
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/grouping#troubleshooting',
|
|
587
587
|
details: { field: sym }
|
|
588
588
|
)
|
|
589
589
|
end
|
|
@@ -593,7 +593,7 @@ module SearchEngine
|
|
|
593
593
|
got = limit.nil? ? 'nil' : limit.inspect
|
|
594
594
|
raise SearchEngine::Errors::InvalidGroup.new(
|
|
595
595
|
"InvalidGroup: limit must be a positive integer (got #{got})",
|
|
596
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/grouping#troubleshooting',
|
|
596
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/grouping#troubleshooting',
|
|
597
597
|
details: { limit: limit }
|
|
598
598
|
)
|
|
599
599
|
end
|
|
@@ -601,7 +601,7 @@ module SearchEngine
|
|
|
601
601
|
unless [true, false].include?(missing_values)
|
|
602
602
|
raise SearchEngine::Errors::InvalidGroup.new(
|
|
603
603
|
"InvalidGroup: missing_values must be boolean (got #{missing_values.inspect})",
|
|
604
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/grouping#troubleshooting',
|
|
604
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/grouping#troubleshooting',
|
|
605
605
|
details: { missing_values: missing_values }
|
|
606
606
|
)
|
|
607
607
|
end
|
|
@@ -702,7 +702,7 @@ module SearchEngine
|
|
|
702
702
|
'InvalidOption: ranking expects a Hash of options',
|
|
703
703
|
hint: 'Use ranking(num_typos: 1, drop_tokens_threshold: 0.2,'\
|
|
704
704
|
'prioritize_exact_match: true, query_by_weights: { name: 2 })',
|
|
705
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/ranking#options'
|
|
705
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/ranking#options'
|
|
706
706
|
)
|
|
707
707
|
end
|
|
708
708
|
|
|
@@ -729,14 +729,14 @@ module SearchEngine
|
|
|
729
729
|
unless [0, 1, 2].include?(iv)
|
|
730
730
|
raise SearchEngine::Errors::InvalidOption.new(
|
|
731
731
|
"InvalidOption: num_typos must be 0, 1, or 2 (got #{raw.inspect})",
|
|
732
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/ranking#options'
|
|
732
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/ranking#options'
|
|
733
733
|
)
|
|
734
734
|
end
|
|
735
735
|
out[:num_typos] = iv
|
|
736
736
|
rescue ArgumentError, TypeError
|
|
737
737
|
raise SearchEngine::Errors::InvalidOption.new(
|
|
738
738
|
"InvalidOption: num_typos must be an Integer in {0,1,2} (got #{raw.inspect})",
|
|
739
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/ranking#options'
|
|
739
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/ranking#options'
|
|
740
740
|
)
|
|
741
741
|
end
|
|
742
742
|
end
|
|
@@ -752,14 +752,14 @@ module SearchEngine
|
|
|
752
752
|
unless fv >= 0.0 && fv <= 1.0 && fv.finite?
|
|
753
753
|
raise SearchEngine::Errors::InvalidOption.new(
|
|
754
754
|
"InvalidOption: drop_tokens_threshold must be a float between 0.0 and 1.0 (got #{raw.inspect})",
|
|
755
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/ranking#options'
|
|
755
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/ranking#options'
|
|
756
756
|
)
|
|
757
757
|
end
|
|
758
758
|
out[:drop_tokens_threshold] = fv
|
|
759
759
|
rescue ArgumentError, TypeError
|
|
760
760
|
raise SearchEngine::Errors::InvalidOption.new(
|
|
761
761
|
"InvalidOption: drop_tokens_threshold must be a float between 0.0 and 1.0 (got #{raw.inspect})",
|
|
762
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/ranking#options'
|
|
762
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/ranking#options'
|
|
763
763
|
)
|
|
764
764
|
end
|
|
765
765
|
end
|
|
@@ -780,7 +780,7 @@ module SearchEngine
|
|
|
780
780
|
unless raw.is_a?(Hash)
|
|
781
781
|
raise SearchEngine::Errors::InvalidOption.new(
|
|
782
782
|
'InvalidOption: query_by_weights must be a Hash of { field => Integer }',
|
|
783
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/ranking#weights'
|
|
783
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/ranking#weights'
|
|
784
784
|
)
|
|
785
785
|
end
|
|
786
786
|
normalized = {}
|
|
@@ -793,14 +793,14 @@ module SearchEngine
|
|
|
793
793
|
rescue ArgumentError, TypeError
|
|
794
794
|
raise SearchEngine::Errors::InvalidOption.new(
|
|
795
795
|
"InvalidOption: weight for #{k.inspect} must be an Integer >= 0",
|
|
796
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/ranking#weights',
|
|
796
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/ranking#weights',
|
|
797
797
|
details: { field: k, weight: v }
|
|
798
798
|
)
|
|
799
799
|
end
|
|
800
800
|
if w.negative?
|
|
801
801
|
raise SearchEngine::Errors::InvalidOption.new(
|
|
802
802
|
"InvalidOption: weight for #{k.inspect} must be >= 0",
|
|
803
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/ranking#weights',
|
|
803
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/ranking#weights',
|
|
804
804
|
details: { field: k, weight: v }
|
|
805
805
|
)
|
|
806
806
|
end
|
|
@@ -844,7 +844,7 @@ module SearchEngine
|
|
|
844
844
|
|
|
845
845
|
raise SearchEngine::Errors::InvalidParams.new(
|
|
846
846
|
%(#{context}: supports base fields only (got #{name.inspect})),
|
|
847
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/faceting#supported-options',
|
|
847
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/faceting#supported-options',
|
|
848
848
|
details: { field: name }
|
|
849
849
|
)
|
|
850
850
|
end
|
|
@@ -873,7 +873,7 @@ module SearchEngine
|
|
|
873
873
|
raise SearchEngine::Errors::InvalidParams.new(
|
|
874
874
|
"facet_by: option :sort is not supported by Typesense facets (got #{sort.inspect})",
|
|
875
875
|
hint: 'Supported: default count-desc only at present.',
|
|
876
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/faceting#supported-options',
|
|
876
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/faceting#supported-options',
|
|
877
877
|
details: { sort: sort }
|
|
878
878
|
)
|
|
879
879
|
end
|
|
@@ -883,7 +883,7 @@ module SearchEngine
|
|
|
883
883
|
|
|
884
884
|
raise SearchEngine::Errors::InvalidParams.new(
|
|
885
885
|
'facet_by: option :stats is not supported at present',
|
|
886
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/faceting#supported-options',
|
|
886
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/faceting#supported-options',
|
|
887
887
|
details: { stats: stats }
|
|
888
888
|
)
|
|
889
889
|
end
|
|
@@ -905,7 +905,7 @@ module SearchEngine
|
|
|
905
905
|
raise SearchEngine::Errors::InvalidParams.new(
|
|
906
906
|
%(facet_query: invalid range syntax #{expr.inspect} (unbalanced brackets)),
|
|
907
907
|
hint: 'Use shapes like "[0..9]", "[10..19]"',
|
|
908
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/faceting#facet-query-expressions',
|
|
908
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/faceting#facet-query-expressions',
|
|
909
909
|
details: { expr: expr }
|
|
910
910
|
)
|
|
911
911
|
end
|
|
@@ -15,7 +15,7 @@ module SearchEngine
|
|
|
15
15
|
# @param pretty [Boolean] pretty-print with stable key ordering when true
|
|
16
16
|
# @return [String]
|
|
17
17
|
# @since M8
|
|
18
|
-
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/dx
|
|
18
|
+
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/dx
|
|
19
19
|
def to_params_json(pretty: true)
|
|
20
20
|
params = SearchEngine::CompiledParams.from(to_typesense_params)
|
|
21
21
|
redacted = SearchEngine::Relation::Dx::DryRun.redact_params(params.to_h)
|
|
@@ -25,7 +25,7 @@ module SearchEngine
|
|
|
25
25
|
# Return a single-line curl command with redacted API key and JSON body.
|
|
26
26
|
# @return [String]
|
|
27
27
|
# @since M8
|
|
28
|
-
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/dx
|
|
28
|
+
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/dx
|
|
29
29
|
def to_curl
|
|
30
30
|
url = compiled_url
|
|
31
31
|
params = SearchEngine::CompiledParams.from(to_typesense_params).to_h
|
|
@@ -37,7 +37,7 @@ module SearchEngine
|
|
|
37
37
|
# @return [Hash] { url:, body:, url_opts: }
|
|
38
38
|
# @raise [SearchEngine::Errors::*] same validation errors as runtime path
|
|
39
39
|
# @since M8
|
|
40
|
-
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/dx
|
|
40
|
+
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/dx
|
|
41
41
|
def dry_run!
|
|
42
42
|
params = SearchEngine::CompiledParams.from(to_typesense_params).to_h
|
|
43
43
|
SearchEngine::Relation::Dx::DryRun.payload(url: compiled_url, params: params, url_opts: compiled_url_opts)
|
|
@@ -48,7 +48,7 @@ module SearchEngine
|
|
|
48
48
|
# @param to [Symbol, nil]
|
|
49
49
|
# @return [String]
|
|
50
50
|
# @since M8
|
|
51
|
-
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/dx#helpers--examples
|
|
51
|
+
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/dx#helpers--examples
|
|
52
52
|
def explain(to: nil)
|
|
53
53
|
params = SearchEngine::CompiledParams.from(to_typesense_params)
|
|
54
54
|
lines = []
|
|
@@ -76,7 +76,7 @@ module SearchEngine
|
|
|
76
76
|
# Returns nil when no records match.
|
|
77
77
|
# @param fields [Array<#to_sym,#to_s>]
|
|
78
78
|
# @return [Object, Array<Object>, nil]
|
|
79
|
-
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/materializers#pick
|
|
79
|
+
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/materializers#pick
|
|
80
80
|
def pick(*fields)
|
|
81
81
|
SearchEngine::Hydration::Materializers.pick(self, *fields)
|
|
82
82
|
end
|
|
@@ -44,7 +44,7 @@ module SearchEngine
|
|
|
44
44
|
unless value.is_a?(Hash)
|
|
45
45
|
raise SearchEngine::Errors::InvalidOption.new(
|
|
46
46
|
'InvalidOption: hit_limits expects a Hash of options',
|
|
47
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/hit-limits'
|
|
47
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/hit-limits'
|
|
48
48
|
)
|
|
49
49
|
end
|
|
50
50
|
|
|
@@ -591,7 +591,7 @@ module SearchEngine
|
|
|
591
591
|
raise SearchEngine::Errors::HitLimitExceeded.new(
|
|
592
592
|
msg,
|
|
593
593
|
hint: 'Increase `validate_hits!(max:)` or narrow filters. Prefer `limit_hits(n)` to avoid work when supported.',
|
|
594
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/hit-limits#validation',
|
|
594
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/hit-limits#validation',
|
|
595
595
|
details: { total_hits: th, max: max, collection: coll, relation_summary: inspect }
|
|
596
596
|
)
|
|
597
597
|
end
|
data/lib/search_engine/result.rb
CHANGED
|
@@ -500,7 +500,7 @@ module SearchEngine
|
|
|
500
500
|
raise SearchEngine::Errors::MissingField.new(
|
|
501
501
|
msg,
|
|
502
502
|
hint: 'Adjust select/exclude or disable strict_missing to avoid raising.',
|
|
503
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/field-selection#strict-vs-lenient-selection',
|
|
503
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/field-selection#strict-vs-lenient-selection',
|
|
504
504
|
details: { requested: requested, present_keys: present_keys }
|
|
505
505
|
)
|
|
506
506
|
end
|
data/lib/search_engine/schema.rb
CHANGED
|
@@ -71,7 +71,7 @@ module SearchEngine
|
|
|
71
71
|
# @param klass [Class] model class inheriting from {SearchEngine::Base}
|
|
72
72
|
# @param client [SearchEngine::Client] optional client wrapper (for tests)
|
|
73
73
|
# @return [Hash] { diff: Hash, pretty: String }
|
|
74
|
-
# @see `https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/schema-indexer-e2e`
|
|
74
|
+
# @see `https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/schema-indexer-e2e`
|
|
75
75
|
# @see `https://typesense.org/docs/latest/api/collections.html`
|
|
76
76
|
def diff(klass, client: nil)
|
|
77
77
|
client ||= SearchEngine.client
|
|
@@ -154,7 +154,7 @@ module SearchEngine
|
|
|
154
154
|
# @yieldparam physical_name [String] the newly created physical collection name
|
|
155
155
|
# @return [Hash] { logical: String, new_physical: String, previous_physical: String, alias_target: String, dropped_physicals: Array<String> }
|
|
156
156
|
# @raise [SearchEngine::Errors::Api, ArgumentError]
|
|
157
|
-
# @see `https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/schema#lifecycle`
|
|
157
|
+
# @see `https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/schema#lifecycle`
|
|
158
158
|
# @see `https://typesense.org/docs/latest/api/collections.html`
|
|
159
159
|
def apply!(klass, client: nil, force_rebuild: false)
|
|
160
160
|
client ||= SearchEngine.client
|
|
@@ -245,7 +245,7 @@ module SearchEngine
|
|
|
245
245
|
# @param client [SearchEngine::Client]
|
|
246
246
|
# @return [Hash] { logical: String, new_target: String, previous_target: String }
|
|
247
247
|
# @raise [ArgumentError] when no previous physical exists
|
|
248
|
-
# @see `https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/schema#retention`
|
|
248
|
+
# @see `https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/schema#retention`
|
|
249
249
|
def rollback(klass, client: nil)
|
|
250
250
|
client ||= SearchEngine.client
|
|
251
251
|
compiled = compile(klass)
|
|
@@ -477,7 +477,7 @@ module SearchEngine
|
|
|
477
477
|
"(got #{type_descriptor.inspect}).",
|
|
478
478
|
hint: "Declare attribute :#{attribute_name}, :string in #{klass.name} to match " \
|
|
479
479
|
'Typesense reference requirements.',
|
|
480
|
-
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/joins#declaring-references',
|
|
480
|
+
doc: 'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/joins#declaring-references',
|
|
481
481
|
details: {
|
|
482
482
|
field: attribute_name.to_s,
|
|
483
483
|
declared_type: type_descriptor,
|
|
@@ -81,7 +81,6 @@ module SearchEngine
|
|
|
81
81
|
end
|
|
82
82
|
elsif relation.respond_to?(:find_in_batches)
|
|
83
83
|
relation.find_in_batches(batch_size: @batch_size) do |rows|
|
|
84
|
-
rows = rows.map { |r| r }
|
|
85
84
|
duration = monotonic_ms - started
|
|
86
85
|
instrument_batch_fetched(source: 'active_record', batch_index: idx, rows_count: rows.size,
|
|
87
86
|
duration_ms: duration, partition: partition, cursor: cursor,
|
|
@@ -11,7 +11,7 @@ module SearchEngine
|
|
|
11
11
|
# src = SearchEngine::Sources::LambdaSource.new(->(cursor:, partition:) { [[row1, row2]] })
|
|
12
12
|
# src.each_batch { |rows| ... }
|
|
13
13
|
#
|
|
14
|
-
# @see `https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/indexer`
|
|
14
|
+
# @see `https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/indexer`
|
|
15
15
|
class LambdaSource
|
|
16
16
|
include Base
|
|
17
17
|
|
|
@@ -12,7 +12,7 @@ module SearchEngine
|
|
|
12
12
|
# src.each_batch { |rows| ... }
|
|
13
13
|
#
|
|
14
14
|
# @note Emits "search_engine.source.batch_fetched" and "search_engine.source.error".
|
|
15
|
-
# @see `https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/indexer`
|
|
15
|
+
# @see `https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/indexer`
|
|
16
16
|
class SqlSource
|
|
17
17
|
include Base
|
|
18
18
|
|
|
@@ -28,7 +28,7 @@ module SearchEngine
|
|
|
28
28
|
unless model.is_a?(Class)
|
|
29
29
|
raise SearchEngine::Errors::InvalidParams,
|
|
30
30
|
'active_record source requires :model (ActiveRecord class). See ' \
|
|
31
|
-
'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/indexer.'
|
|
31
|
+
'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/indexer.'
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
scope = options[:scope]
|
|
@@ -43,7 +43,7 @@ module SearchEngine
|
|
|
43
43
|
unless sql.is_a?(String) && !sql.strip.empty?
|
|
44
44
|
raise SearchEngine::Errors::InvalidParams,
|
|
45
45
|
'sql source requires :sql (String). See ' \
|
|
46
|
-
'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/indexer.'
|
|
46
|
+
'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/indexer.'
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
binds = options[:binds]
|
|
@@ -58,7 +58,7 @@ module SearchEngine
|
|
|
58
58
|
unless callable
|
|
59
59
|
raise SearchEngine::Errors::InvalidParams,
|
|
60
60
|
'lambda source requires a block or :callable. See ' \
|
|
61
|
-
'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/indexer.'
|
|
61
|
+
'https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/indexer.'
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
LambdaSource.new(callable)
|
|
@@ -20,7 +20,7 @@ module SearchEngine
|
|
|
20
20
|
# or Procs that receive the captured request and return a response.
|
|
21
21
|
#
|
|
22
22
|
# @since M8
|
|
23
|
-
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/testing
|
|
23
|
+
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/testing
|
|
24
24
|
class StubClient
|
|
25
25
|
Call = Struct.new(
|
|
26
26
|
:timestamp,
|
|
@@ -45,7 +45,7 @@ module SearchEngine
|
|
|
45
45
|
# @param value [Hash, Exception, Proc]
|
|
46
46
|
# @return [void]
|
|
47
47
|
# @since M8
|
|
48
|
-
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/testing#quick-start
|
|
48
|
+
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/testing#quick-start
|
|
49
49
|
def enqueue_response(method, value)
|
|
50
50
|
@lock.synchronize do
|
|
51
51
|
queue_for(method) << value
|
|
@@ -54,7 +54,7 @@ module SearchEngine
|
|
|
54
54
|
|
|
55
55
|
# Reset all internal state (queues and captures).
|
|
56
56
|
# @since M8
|
|
57
|
-
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/testing#parallel-test-safety
|
|
57
|
+
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/testing#parallel-test-safety
|
|
58
58
|
def reset!
|
|
59
59
|
@lock.synchronize do
|
|
60
60
|
@queues.each_value(&:clear)
|
|
@@ -65,7 +65,7 @@ module SearchEngine
|
|
|
65
65
|
# Return captured calls for search.
|
|
66
66
|
# @return [Array<Call>]
|
|
67
67
|
# @since M8
|
|
68
|
-
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/testing
|
|
68
|
+
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/testing
|
|
69
69
|
def search_calls
|
|
70
70
|
@lock.synchronize { @calls[:search].dup }
|
|
71
71
|
end
|
|
@@ -73,7 +73,7 @@ module SearchEngine
|
|
|
73
73
|
# Return captured calls for multi_search.
|
|
74
74
|
# @return [Array<Call>]
|
|
75
75
|
# @since M8
|
|
76
|
-
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/testing
|
|
76
|
+
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/testing
|
|
77
77
|
def multi_search_calls
|
|
78
78
|
@lock.synchronize { @calls[:multi_search].dup }
|
|
79
79
|
end
|
|
@@ -81,7 +81,7 @@ module SearchEngine
|
|
|
81
81
|
# All calls in chronological order.
|
|
82
82
|
# @return [Array<Call>]
|
|
83
83
|
# @since M8
|
|
84
|
-
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/testing
|
|
84
|
+
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/testing
|
|
85
85
|
def all_calls
|
|
86
86
|
@lock.synchronize { (@calls[:search] + @calls[:multi_search]).sort_by(&:timestamp) }
|
|
87
87
|
end
|
|
@@ -91,7 +91,7 @@ module SearchEngine
|
|
|
91
91
|
# @param params [Hash]
|
|
92
92
|
# @param url_opts [Hash]
|
|
93
93
|
# @since M8
|
|
94
|
-
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/testing
|
|
94
|
+
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/testing
|
|
95
95
|
def search(collection:, params:, url_opts: {})
|
|
96
96
|
unless collection.is_a?(String) && !collection.strip.empty?
|
|
97
97
|
raise ArgumentError, 'collection must be a non-empty String'
|
|
@@ -109,7 +109,7 @@ module SearchEngine
|
|
|
109
109
|
# @param searches [Array<Hash>]
|
|
110
110
|
# @param url_opts [Hash]
|
|
111
111
|
# @since M8
|
|
112
|
-
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/testing
|
|
112
|
+
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/testing
|
|
113
113
|
def multi_search(searches:, url_opts: {})
|
|
114
114
|
unless searches.is_a?(Array) && searches.all? { |h| h.is_a?(Hash) }
|
|
115
115
|
raise ArgumentError, 'searches must be an Array of Hashes'
|
data/lib/search_engine/test.rb
CHANGED
|
@@ -12,7 +12,7 @@ module SearchEngine
|
|
|
12
12
|
# These helpers are allocation-light, thread-safe, and never perform network I/O.
|
|
13
13
|
#
|
|
14
14
|
# @since M8
|
|
15
|
-
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/testing
|
|
15
|
+
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/testing
|
|
16
16
|
module Test
|
|
17
17
|
class << self
|
|
18
18
|
# Subscribe to `search_engine.*` for the duration of the block and return captured events.
|
|
@@ -22,7 +22,7 @@ module SearchEngine
|
|
|
22
22
|
# @yield block within which events are captured
|
|
23
23
|
# @return [Array<Hash>]
|
|
24
24
|
# @since M8
|
|
25
|
-
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/testing#event-assertions
|
|
25
|
+
# @see https://nikita-shkoda.mintlify.app/projects/search-engine-for-typesense/v30.1/testing#event-assertions
|
|
26
26
|
def capture_events(name = nil)
|
|
27
27
|
require 'active_support/notifications'
|
|
28
28
|
pattern = name.is_a?(Regexp) ? name : /^search_engine\./
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: search-engine-for-typesense
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 30.1.
|
|
4
|
+
version: 30.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nikita Shkoda
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-03-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: concurrent-ruby
|