s3arch 0.0.3 → 0.0.4

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: cd57db198f9598324792e16e5b84e9c22914ebfdfd4fddeb09fc99641458322c
4
- data.tar.gz: e107d35cd4b7084d3cf90e3d014bb4fe3c6089475b26419524d9132867565592
3
+ metadata.gz: 5b5d2b31636cdd8dd3d02bfd8140a82263f462207bf80525ef55167e1267a057
4
+ data.tar.gz: 8cfa541ae296debeb4ca01737673733805b81268a415280241a57eaba1f22821
5
5
  SHA512:
6
- metadata.gz: 65aba03e3064bf597dc8bb4e53d7552c07f0b89ebb7ca24b9e6c74a7f5c22f9c95746cec237d1e100fce63cb8f285f782487300abd7f4d1b6e1c76553fdad5ff
7
- data.tar.gz: 28f5d435ce384c0c1c8e05d17d478ad9fdb9e0a949506350384886fdfcedbfaa2cbd9308dfd08d2faf91dfe4bf02ac07ac6d6749470143914a977f29ab0aef04
6
+ metadata.gz: fd0c3fabee28274d50d46951fde563bc9196263d59174ee87047bdb8a06d7ae1ee7964ae82d431c6c22ee875e40512918a01c6110292d0a0d06c89e54201e25e
7
+ data.tar.gz: '008755884d519604931a7ccfebff4492c0308900230d5e9cd535aa452afb9e7a48d9274c04b15867b2bfd3bbe031aeb2ae08d1c2b6ffdf8759a7a90518ce7b60'
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.0.4] - 2025-06-09
4
+
5
+ ### Fixed
6
+
7
+ - `Indexer#fetch_records` now uses `expression_attribute_names` for DynamoDB reserved words (e.g., `status`), fixing `ValidationException` on `rebuild()`
8
+
9
+ ### Added
10
+
11
+ - `Configuration#filter_fields` — declare which fields the `record_filter` proc needs projected from DynamoDB
12
+
13
+ ### Removed
14
+
15
+ - Hardcoded `filter_fields` method (`%w[status bin_id]`) — replaced by configurable `filter_fields`
16
+
3
17
  ## [0.0.2] - 2025-06-08
4
18
 
5
19
  ### Added
@@ -30,6 +30,9 @@ module S3arch
30
30
  # Filter proc — receives a record hash, returns true to include in index
31
31
  attr_accessor :record_filter
32
32
 
33
+ # Fields needed by the record_filter for projection (e.g., %w[status])
34
+ attr_accessor :filter_fields
35
+
33
36
  # Owner extractor — proc that extracts owner_id from a DynamoDB stream record
34
37
  attr_accessor :owner_extractor
35
38
 
@@ -45,6 +48,7 @@ module S3arch
45
48
  @token_field = 'searchTokens'
46
49
  @metadata_fields = %w[status created_at]
47
50
  @record_filter = ->(_record) { true }
51
+ @filter_fields = %w[status]
48
52
  @owner_extractor = lambda { |stream_record|
49
53
  image = stream_record.dig('dynamodb', 'NewImage') || stream_record.dig('dynamodb', 'OldImage') || {}
50
54
  image.dig(owner_key, 'S')
@@ -4,7 +4,6 @@ require 'aws-sdk-dynamodb'
4
4
  require 'aws-sdk-s3'
5
5
  require 'sqlite3'
6
6
  require 'json'
7
-
8
7
  module S3arch
9
8
  # Builds SQLite FTS5 databases per owner from pre-computed tokens stored in DynamoDB.
10
9
  # The indexer never sees raw content — only tokens. Supports incremental updates via
@@ -80,6 +79,8 @@ module S3arch
80
79
  { statusCode: 200, body: JSON.generate(rebuilt: grouped.size) }
81
80
  end
82
81
 
82
+ RESERVED_WORDS = Set.new(%w[status name comment count size type]).freeze
83
+
83
84
  private
84
85
 
85
86
  def group_changes(sqs_records)
@@ -244,11 +245,7 @@ module S3arch
244
245
  # Full rebuild: fetches token field from DynamoDB (never reads content)
245
246
  def fetch_records(owner_id)
246
247
  records = []
247
- fields_to_project = ['id', @config.token_field, @config.owner_key] + @config.metadata_fields + filter_fields
248
- params = { table_name: @config.source_table, index_name: @config.source_index,
249
- key_condition_expression: "#{@config.owner_key} = :owner",
250
- expression_attribute_values: { ':owner' => owner_id },
251
- projection_expression: fields_to_project.uniq.join(', ') }
248
+ params = build_query_params(owner_id)
252
249
 
253
250
  loop do
254
251
  result = @dynamodb.query(params)
@@ -268,17 +265,29 @@ module S3arch
268
265
  records
269
266
  end
270
267
 
271
- def extract_meta_from_item(item)
272
- @config.metadata_fields.to_h do |field|
273
- [field, item[field].to_s]
274
- end
268
+ def build_query_params(owner_id)
269
+ fields = (['id', @config.token_field, @config.owner_key] +
270
+ @config.metadata_fields + @config.filter_fields).uniq
271
+ expression_names = {}
272
+ projected = fields.map { |f| reserved_word?(f) ? "##{f}".tap { |p| expression_names[p] = f } : f }
273
+
274
+ owner_placeholder = reserved_word?(@config.owner_key) ? "##{@config.owner_key}" : @config.owner_key
275
+ expression_names["##{@config.owner_key}"] = @config.owner_key if reserved_word?(@config.owner_key)
276
+
277
+ params = { table_name: @config.source_table, index_name: @config.source_index,
278
+ key_condition_expression: "#{owner_placeholder} = :owner",
279
+ expression_attribute_values: { ':owner' => owner_id },
280
+ projection_expression: projected.join(', ') }
281
+ params[:expression_attribute_names] = expression_names if expression_names.any?
282
+ params
275
283
  end
276
284
 
277
- def filter_fields
278
- # Fields needed by the record_filter (best-effort — add status/bin_id for default filter)
279
- %w[status bin_id]
285
+ def extract_meta_from_item(item)
286
+ @config.metadata_fields.to_h { |field| [field, item[field].to_s] }
280
287
  end
281
288
 
289
+ def reserved_word?(field) = RESERVED_WORDS.include?(field.downcase)
290
+
282
291
  def build_database(db_path, records)
283
292
  FileUtils.rm_f(db_path)
284
293
  db = SQLite3::Database.new(db_path)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module S3arch
4
- VERSION = '0.0.3'
4
+ VERSION = '0.0.4'
5
5
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: s3arch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Dalton
metadata.gz.sig CHANGED
@@ -1 +1,2 @@
1
- Oco�2��I�?D����0�̌��\�z,V��i���جԻX�� �f���f��$^�o������+"3R04q$�#`7���?���E�MF�A� �x���f�����]���~j�]�/�IK�Dz#ni��B[XS������m��%��jQ+�a��_GhfaJ"(o�~|I��y�&��kXڈL �Ϟ�jY�<��C���e�:�Pø�A��2X�P��)����nxLy�<�L�� jeL7���|������_�pG��pnfPw���P_+�$�Ne8�!����2�ա�̕g0#����WEdp8��0v�#_\G�^lU���(2jǨ��@�o^)��x�R%3���x���|��=���Ǻ
1
+ �٣��b���A��t��1<ۈճ;w�@��^�����(,Z��\�r����XZƠ��B���:DewV�ԭ�h���x�KNI��%,`�Tf��8C��@��r;f��l}7F�==TV��b/!MP��ι[̦ @�ȁ��<�tR���ȜXuudH��kT��!��A�N~�_���^atOZ�p%h{n ��fMTY_'g��=�#���/���6!��TS(�|�l����7ݸ���{��
2
+ ��e~ʞ���uE���BG�S�7����ݼ�����*�q=�6r�_r��Q�P�|g�]�V]j��+ˍ���Qú�.B�������r