search-engine-for-typesense 30.1.6.3 → 30.1.6.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 228f70410334d2a324508d0d44dfd31aadbcb4a957f28425909108490a3129a2
4
- data.tar.gz: 89fd3243af9aec91757d9819136ce9b0fd783845ff1ff6e6fe72467106d20ecb
3
+ metadata.gz: 933b8b58a98c81e8e6b72f3083cfcf2ee1de5ea9f709d4c10aea5d09dba59d99
4
+ data.tar.gz: 626111c57bc0ee533d21938d7a218c13b80cc23aa27827731994a968f97de672
5
5
  SHA512:
6
- metadata.gz: 42e556e2b25d40fd5ba85cb1ae1961223420d6affb6f532936642a48159dc013a8297398cba3724ef798f2cab05a0819140c9038d415b0035c7f9a95b2408e07
7
- data.tar.gz: ea3aba9866079ade74da2712d73f6e2a7169cc0a013dff5814ccbc7034789e9f2d6ae38979e49761210e46e4a61f329fde3ae9bb356f02b643b14899a0d24d9d
6
+ metadata.gz: 3e4456f56ddd18865793f0d61890967ba53e50eac9d2b573362800ed0f509aad397bc9233b4f4a0d308e5a9dadfc0a0aac9e9ca946516b638f5eee0a4728fa3b
7
+ data.tar.gz: 80133e73075e0047968ed9afb3d7756eb5cf47aadeb1c1bbb73d332ee2d44c61e0cc6e6fb5b8932f23ab280f8259319c36d16c288e7d3817a0fdc3844fcde24a
@@ -45,18 +45,19 @@ module SearchEngine
45
45
  def cleanup(into: nil, partition: nil, clear_cache: false)
46
46
  logical = respond_to?(:collection) ? collection.to_s : name.to_s
47
47
  puts
48
- puts(%(>>>>>> Cleanup Collection "#{logical}"))
48
+ puts(SearchEngine::Logging::Color.header(%(>>>>>> Cleanup Collection "#{logical}")))
49
49
 
50
50
  filters = SearchEngine::StaleRules.compile_filters(self, partition: partition)
51
51
  filters.compact!
52
52
  filters.reject! { |f| f.to_s.strip.empty? }
53
+ step = SearchEngine::Logging::StepLine.new('Cleanup')
53
54
  if filters.empty?
54
- puts('Cleanup — skip (no stale configuration)')
55
+ step.skip('no stale configuration')
55
56
  return 0
56
57
  end
57
58
 
58
59
  merged_filter = SearchEngine::StaleRules.merge_filters(filters)
59
- puts("Cleanup — filter=#{merged_filter.inspect}")
60
+ step.update("filter=#{merged_filter.inspect}")
60
61
 
61
62
  deleted = SearchEngine::Deletion.delete_by(
62
63
  klass: self,
@@ -65,25 +66,24 @@ module SearchEngine
65
66
  partition: partition
66
67
  )
67
68
 
68
- puts("Cleanup — deleted=#{deleted}")
69
+ step.finish("deleted=#{deleted}")
69
70
  deleted
70
71
  rescue StandardError => error
71
- warn(
72
- "Cleanup — error=#{error.class}: #{error.message.to_s[0, 200]}"
73
- )
72
+ err_msg = "Cleanup — error=#{error.class}: #{error.message.to_s[0, 200]}"
73
+ warn(SearchEngine::Logging::Color.apply(err_msg, :red))
74
74
  0
75
75
  ensure
76
+ step&.close
76
77
  if clear_cache
77
78
  begin
78
- puts('Cleanup — cache clear')
79
+ puts("Cleanup — #{SearchEngine::Logging::Color.bold('cache clear')}")
79
80
  SearchEngine::Cache.clear
80
81
  rescue StandardError => error
81
- warn(
82
- "Cleanup — cache clear error=#{error.class}: #{error.message.to_s[0, 200]}"
83
- )
82
+ err_msg = "Cleanup — cache clear error=#{error.class}: #{error.message.to_s[0, 200]}"
83
+ warn(SearchEngine::Logging::Color.apply(err_msg, :red))
84
84
  end
85
85
  end
86
- puts(%(>>>>>> Cleanup Done))
86
+ puts(SearchEngine::Logging::Color.header(%(>>>>>> Cleanup Done)))
87
87
  end
88
88
 
89
89
  private
@@ -17,7 +17,7 @@ module SearchEngine
17
17
  def index_collection(partition: nil, client: nil, pre: nil, force_rebuild: false)
18
18
  logical = respond_to?(:collection) ? collection.to_s : name.to_s
19
19
  puts
20
- puts(%(>>>>>> Indexing Collection "#{logical}"))
20
+ puts(SearchEngine::Logging::Color.header(%(>>>>>> Indexing Collection "#{logical}")))
21
21
  client_obj = client || SearchEngine.client
22
22
 
23
23
  result = if partition.nil?
@@ -56,7 +56,8 @@ module SearchEngine
56
56
 
57
57
  diff = SearchEngine::Schema.diff(self, client: client)[:diff] || {}
58
58
  missing = __se_schema_missing?(diff)
59
- puts("Step 1: Presence — processing → #{missing ? 'missing' : 'present'}")
59
+ step = SearchEngine::Logging::StepLine.new('Presence')
60
+ missing ? step.finish_warn('missing') : step.finish('present')
60
61
 
61
62
  applied, indexed_inside_apply = __se_full_apply_if_missing(client, missing)
62
63
  drift = __se_full_check_drift(diff, missing, force_rebuild)
@@ -75,72 +76,90 @@ module SearchEngine
75
76
  def __se_full_apply_if_missing(client, missing)
76
77
  applied = false
77
78
  indexed_inside_apply = false
79
+ step = SearchEngine::Logging::StepLine.new('Schema')
78
80
  if missing
79
- puts('Step 2: Create+Apply Schema — processing')
81
+ step.update('creating')
80
82
  SearchEngine::Schema.apply!(self, client: client) do |new_physical|
83
+ step.yield_line!
81
84
  indexed_inside_apply = __se_index_partitions!(into: new_physical)
82
85
  end
83
86
  applied = true
84
- puts('Step 2: Create+Apply Schema — done')
87
+ step.finish('created')
85
88
  else
86
- puts('Step 2: Create+Apply Schema — skip (collection present)')
89
+ step.skip('collection present')
87
90
  end
88
91
  [applied, indexed_inside_apply]
92
+ ensure
93
+ step&.close
89
94
  end
90
95
 
91
96
  def __se_full_check_drift(diff, missing, force_rebuild)
97
+ step = SearchEngine::Logging::StepLine.new('Schema Status')
92
98
  unless missing
93
- puts('Step 3: Check Schema Status — processing')
99
+ step.update('checking')
94
100
  drift = __se_schema_drift?(diff)
95
101
  if force_rebuild && !drift
96
- puts('Step 3: Check Schema Status — force_rebuild')
102
+ step.finish_warn('force_rebuild')
97
103
  return true
98
104
  end
99
- puts("Step 3: Check Schema Status — #{drift ? 'drift' : 'in_sync'}")
105
+ drift ? step.finish_warn('drift') : step.finish('in_sync')
100
106
  return drift
101
107
  end
102
- puts('Step 3: Check Schema Status — skip (just created)')
108
+ step.skip('just created')
103
109
  false
110
+ ensure
111
+ step&.close
104
112
  end
105
113
 
106
114
  def __se_full_apply_if_drift(client, drift, applied, indexed_inside_apply, force_rebuild)
115
+ step = SearchEngine::Logging::StepLine.new('Schema Apply')
107
116
  if drift
108
- puts('Step 4: Apply New Schema — processing')
117
+ step.update('applying')
109
118
  SearchEngine::Schema.apply!(self, client: client, force_rebuild: force_rebuild) do |new_physical|
119
+ step.yield_line!
110
120
  indexed_inside_apply = __se_index_partitions!(into: new_physical)
111
121
  end
112
122
  applied = true
113
- puts('Step 4: Apply New Schema — done')
123
+ step.finish('applied')
114
124
  else
115
- puts('Step 4: Apply New Schema — skip')
125
+ step.skip
116
126
  end
117
127
  [applied, indexed_inside_apply]
128
+ ensure
129
+ step&.close
118
130
  end
119
131
 
120
132
  def __se_full_indexation(applied, indexed_inside_apply)
121
133
  result = nil
134
+ step = SearchEngine::Logging::StepLine.new('Indexing')
122
135
  if applied && indexed_inside_apply
123
- puts('Step 5: Indexing — skip (performed during schema apply)')
136
+ step.skip('performed during schema apply')
124
137
  result = indexed_inside_apply if indexed_inside_apply.is_a?(Hash)
125
138
  else
126
- puts('Step 5: Indexing — processing')
139
+ step.update('indexing')
140
+ step.yield_line!
127
141
  result = __se_index_partitions!(into: nil)
128
- puts('Step 5: Indexing — done')
142
+ step.finish('done')
129
143
  end
130
144
 
131
145
  cascade_ok = result.is_a?(Hash) ? result[:status] == :ok : false
132
146
  __se_cascade_after_indexation!(context: :full) if cascade_ok
133
147
  result
148
+ ensure
149
+ step&.close
134
150
  end
135
151
 
136
152
  def __se_full_retention(applied, logical, client)
153
+ step = SearchEngine::Logging::StepLine.new('Retention')
137
154
  if applied
138
- puts('Step 6: Retention Cleanup — skip (handled by schema apply)')
155
+ step.skip('handled by schema apply')
139
156
  else
140
- puts('Step 6: Retention Cleanup — processing')
157
+ step.update('cleaning')
141
158
  dropped = __se_retention_cleanup!(logical: logical, client: client)
142
- puts("Step 6: Retention Cleanup — dropped=#{dropped.inspect}")
159
+ step.finish("dropped=#{dropped.inspect}")
143
160
  end
161
+ ensure
162
+ step&.close
144
163
  end
145
164
 
146
165
  def __se_index_partial(partition:, client:, pre: nil)
@@ -149,70 +168,76 @@ module SearchEngine
149
168
  diff = diff_res[:diff] || {}
150
169
 
151
170
  missing = __se_schema_missing?(diff)
152
- puts("Step 1: Presence — processing → #{missing ? 'missing' : 'present'}")
171
+ step = SearchEngine::Logging::StepLine.new('Presence')
153
172
  if missing
154
- puts('Partial: collection is not present. Quit early.')
173
+ step.finish_warn('missing collection not present, exit early')
155
174
  return { status: :failed, docs_total: 0, success_total: 0, failed_total: 0,
156
175
  sample_error: 'Collection not present' }
157
176
  end
177
+ step.finish('present')
158
178
 
159
- puts('Step 2: Check Schema Status — processing')
179
+ step = SearchEngine::Logging::StepLine.new('Schema Status')
180
+ step.update('checking')
160
181
  drift = __se_schema_drift?(diff)
161
182
  if drift
162
- puts('Partial: schema is not up-to-date. Exit early (run full indexing).')
183
+ step.finish_warn('drift exit early (run full indexing)')
163
184
  return { status: :failed, docs_total: 0, success_total: 0, failed_total: 0,
164
185
  sample_error: 'Schema drift detected' }
165
186
  end
166
- puts('Step 2: Check Schema Status — in_sync')
187
+ step.finish('in_sync')
167
188
 
168
189
  __se_preflight_dependencies!(mode: pre, client: client) if pre
169
190
 
170
- puts('Step 3: Partial Indexing — processing')
191
+ step = SearchEngine::Logging::StepLine.new('Partial Indexing')
192
+ step.update('indexing')
193
+ step.yield_line!
171
194
  summaries = []
172
195
  partitions.each do |p|
173
196
  summary = SearchEngine::Indexer.rebuild_partition!(self, partition: p, into: nil)
174
197
  summaries << summary
175
198
  puts(SearchEngine::Logging::PartitionProgress.line(p, summary))
176
199
  end
177
- puts('Step 3: Partial Indexing — done')
200
+ step.finish('done')
178
201
 
179
202
  result = __se_build_index_result(summaries)
180
203
  __se_cascade_after_indexation!(context: :full) if result[:status] == :ok
181
204
  result
205
+ ensure
206
+ step&.close
182
207
  end
183
208
 
184
209
  # rubocop:disable Metrics/PerceivedComplexity, Metrics/AbcSize
185
210
  def __se_cascade_after_indexation!(context: :full)
186
211
  if SearchEngine::Instrumentation.context&.[](:bulk_suppress_cascade)
187
212
  puts
188
- puts('>>>>>> Cascade Referencers — suppressed (bulk)')
213
+ puts(SearchEngine::Logging::Color.dim('>>>>>> Cascade Referencers — suppressed (bulk)'))
189
214
  return
190
215
  end
191
216
  puts
192
- puts(%(>>>>>> Cascade Referencers))
217
+ puts(SearchEngine::Logging::Color.header(%(>>>>>> Cascade Referencers)))
193
218
  results = SearchEngine::Cascade.cascade_reindex!(source: self, ids: nil, context: context)
194
219
  outcomes = Array(results[:outcomes])
195
220
  if outcomes.empty?
196
- puts(' none')
221
+ puts(SearchEngine::Logging::Color.dim(' none'))
197
222
  else
198
223
  outcomes.each do |o|
199
224
  coll = o[:collection] || o['collection']
200
225
  mode = (o[:mode] || o['mode']).to_s
201
226
  case mode
202
227
  when 'partial'
203
- puts(%( Referencer "#{coll}" → partial reindex))
228
+ puts(%( Referencer "#{coll}" → #{SearchEngine::Logging::Color.apply('partial reindex', :green)}))
204
229
  when 'full'
205
- puts(%( Referencer "#{coll}" → full reindex))
230
+ puts(%( Referencer "#{coll}" → #{SearchEngine::Logging::Color.apply('full reindex', :green)}))
206
231
  when 'skipped_unregistered'
207
- puts(%( Referencer "#{coll}" → skipped (unregistered)))
232
+ puts(SearchEngine::Logging::Color.dim(%( Referencer "#{coll}" → skipped (unregistered))))
208
233
  when 'skipped_cycle'
209
- puts(%( Referencer "#{coll}" → skipped (cycle)))
234
+ puts(SearchEngine::Logging::Color.dim(%( Referencer "#{coll}" → skipped (cycle))))
210
235
  else
211
236
  puts(%( Referencer "#{coll}" → #{mode}))
212
237
  end
213
238
  end
214
239
  end
215
- puts('>>>>>> Cascade Done')
240
+ puts(SearchEngine::Logging::Color.header('>>>>>> Cascade Done'))
216
241
  rescue StandardError => error
217
242
  base = "Cascade — error=#{error.class}: #{error.message.to_s[0, 200]}"
218
243
  if error.respond_to?(:status) || error.respond_to?(:body)
@@ -233,9 +258,12 @@ module SearchEngine
233
258
  rescue StandardError
234
259
  nil
235
260
  end
236
- warn([base, ("status=#{status}" if status), ("body=#{body_preview}" if body_preview)].compact.join(' '))
261
+ err_parts = [base]
262
+ err_parts << "status=#{status}" if status
263
+ err_parts << "body=#{body_preview}" if body_preview
264
+ warn(SearchEngine::Logging::Color.apply(err_parts.compact.join(' '), :red))
237
265
  else
238
- warn(base)
266
+ warn(SearchEngine::Logging::Color.apply(base, :red))
239
267
  end
240
268
  end
241
269
  # rubocop:enable Metrics/PerceivedComplexity, Metrics/AbcSize
@@ -27,23 +27,24 @@ module SearchEngine
27
27
 
28
28
  def update_collection!
29
29
  client = SearchEngine.client
30
-
31
- puts 'Update Collection — analyzing diff for in-place update...'
30
+ step = SearchEngine::Logging::StepLine.new('Update Collection')
31
+ step.update('analyzing diff')
32
32
  updated = SearchEngine::Schema.update!(self, client: client)
33
33
 
34
34
  if updated
35
- puts 'Update Collection — schema updated in-place (PATCH)'
35
+ step.finish('updated in-place (PATCH)')
36
36
  else
37
- puts 'Update Collection — in-place update not possible (no changes or incompatible)'
37
+ step.skip('no changes or incompatible')
38
38
  end
39
39
  updated
40
+ ensure
41
+ step&.close
40
42
  end
41
43
 
42
44
  def drop_collection!
43
45
  client = SearchEngine.client
44
46
  logical = respond_to?(:collection) ? collection.to_s : name.to_s
45
47
 
46
- # Resolve alias with a safer timeout for control-plane operations
47
48
  alias_target = client.resolve_alias(logical, timeout_ms: 10_000)
48
49
  physical = if alias_target && !alias_target.to_s.strip.empty?
49
50
  alias_target.to_s
@@ -52,19 +53,21 @@ module SearchEngine
52
53
  live ? logical : nil
53
54
  end
54
55
 
56
+ step = SearchEngine::Logging::StepLine.new('Drop Collection')
55
57
  if physical.nil?
56
- puts('Drop Collection — skip (not present)')
58
+ step.skip('not present')
57
59
  return
58
60
  end
59
61
 
60
62
  puts
61
- puts(%(>>>>>> Dropping Collection "#{logical}"))
62
- puts("Drop Collection — processing (logical=#{logical} physical=#{physical})")
63
- # Use an extended timeout to accommodate large collection drops
63
+ puts(SearchEngine::Logging::Color.header(%(>>>>>> Dropping Collection "#{logical}")))
64
+ step.update("dropping (logical=#{logical} physical=#{physical})")
64
65
  client.delete_collection(physical, timeout_ms: 60_000)
65
- puts('Drop Collection — done')
66
- puts(%(>>>>>> Dropped Collection "#{logical}"))
66
+ step.finish('done')
67
+ puts(SearchEngine::Logging::Color.header(%(>>>>>> Dropped Collection "#{logical}")))
67
68
  nil
69
+ ensure
70
+ step&.close
68
71
  end
69
72
 
70
73
  def recreate_collection!
@@ -79,18 +82,21 @@ module SearchEngine
79
82
  live ? logical : nil
80
83
  end
81
84
 
85
+ step = SearchEngine::Logging::StepLine.new('Recreate Collection')
82
86
  if physical
83
- puts("Recreate Collection — dropping existing (logical=#{logical} physical=#{physical})")
87
+ step.update("dropping existing (logical=#{logical} physical=#{physical})")
84
88
  client.delete_collection(physical)
85
89
  else
86
- puts('Recreate Collection — no existing collection (skip drop)')
90
+ step.update("creating (logical=#{logical})")
87
91
  end
88
92
 
89
93
  schema = SearchEngine::Schema.compile(self)
90
- puts("Recreate Collection — creating collection with schema (logical=#{logical})")
94
+ step.update("creating with schema (logical=#{logical})")
91
95
  client.create_collection(schema)
92
- puts('Recreate Collection — done')
96
+ step.finish('done')
93
97
  nil
98
+ ensure
99
+ step&.close
94
100
  end
95
101
 
96
102
  def __se_retention_cleanup!(_logical:, _client:)