Module: Parse::Core::SearchIndexing
- Included in:
- Object
- Defined in:
- lib/parse/model/core/search_indexing.rb
Overview
Model-declarative Atlas Search index DSL. Mixed into Parse::Object so subclasses can declare the Atlas Search indexes they expect to exist on their collection. Declarations are inert at load time —they only land on Atlas when Schema::SearchIndexMigrator reads them and ‘apply_search_indexes!` is invoked through the writer connection.
Parallels Indexing (the regular ‘mongo_index` DSL) but with three meaningful differences:
- **Multi-per-class.** A single model can declare several search
indexes (one for full-text, one for autocomplete, one for
vector search), each with a unique name.
- **Definition is opaque.** The DSL doesn't introspect field
references — Atlas owns the mapping schema. The DSL validates
name shape and Hash-non-emptiness only; everything else is
forwarded to Atlas verbatim.
- **Async build.** Mutations don't return a "READY" guarantee
— the migrator's rake task is fire-and-forget by default,
`WAIT=true` opts into polling via
{Parse::AtlasSearch::IndexManager.wait_for_ready}.
SECURITY POSTURE — purely declarative. No network I/O at declaration time, no class introspection. The validation rules below surface typos as load-time errors instead of runtime surprises during ‘rake parse:mongo:search_indexes:apply` in prod.
Constant Summary collapse
- INDEX_NAME_PATTERN =
Atlas Search index name shape. Same regex used at the MongoDB.create_search_index layer.
/\A[A-Za-z][A-Za-z0-9_-]{0,63}\z/.freeze
- ALLOWED_INDEX_TYPES =
Allowed ‘type:` values for `mongo_search_index`. `search` is the default and covers the conventional text-search / autocomplete / faceted-search use cases; `vectorSearch` is for vector similarity indexes. Atlas rejects any other value at command time, but we check at declaration time so the typo doesn’t survive to prod.
%w[search vectorSearch].freeze
Instance Method Summary collapse
-
#apply_search_indexes!(update: false, drop: false, wait: false, timeout: 600) ⇒ Hash
Apply declared search-index changes via the writer connection.
-
#mongo_search_index(name, definition, type: "search") ⇒ Hash
Declare an Atlas Search index for this model’s collection.
-
#mongo_search_index_declarations ⇒ Array<Hash>
Storage for declared search indexes.
-
#search_indexes_plan ⇒ Hash
Dry-run reconciliation between declared search indexes and what exists on Atlas.
Instance Method Details
#apply_search_indexes!(update: false, drop: false, wait: false, timeout: 600) ⇒ Hash
Apply declared search-index changes via the writer connection.
148 149 150 151 152 |
# File 'lib/parse/model/core/search_indexing.rb', line 148 def apply_search_indexes!(update: false, drop: false, wait: false, timeout: 600) Parse::Schema::SearchIndexMigrator.new(self).apply!( update: update, drop: drop, wait: wait, timeout: timeout, ) end |
#mongo_search_index(name, definition, type: "search") ⇒ Hash
Declare an Atlas Search index for this model’s collection.
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/parse/model/core/search_indexing.rb', line 85 def mongo_search_index(name, definition, type: "search") name_str = name.to_s unless name_str.match?(INDEX_NAME_PATTERN) raise ArgumentError, "#{self}.mongo_search_index name #{name.inspect} must match #{INDEX_NAME_PATTERN.inspect}" end unless definition.is_a?(Hash) && !definition.empty? raise ArgumentError, "#{self}.mongo_search_index #{name_str.inspect} requires a non-empty Hash definition; got #{definition.inspect}" end type_str = type.to_s unless ALLOWED_INDEX_TYPES.include?(type_str) raise ArgumentError, "#{self}.mongo_search_index #{name_str.inspect} type=#{type.inspect} must be one of #{ALLOWED_INDEX_TYPES.inspect}" end declaration = { name: name_str, definition: deep_freeze(definition), type: type_str, }.freeze existing = mongo_search_index_declarations.find { |d| d[:name] == name_str } if existing # Idempotent redeclaration with identical content — common in # autoloading / class-reopening setups. Re-declarations that # disagree on definition or type fail loudly so the operator # notices the conflict at class load instead of at apply time. if existing[:definition] == declaration[:definition] && existing[:type] == declaration[:type] return existing end raise ArgumentError, "#{self}.mongo_search_index #{name_str.inspect} re-declared with a different " \ "definition or type. Each name may have one declaration per class. " \ "Use a unique name for the new index, or update the existing declaration in place." end mongo_search_index_declarations << declaration declaration end |
#mongo_search_index_declarations ⇒ Array<Hash>
Storage for declared search indexes. Each entry is a frozen Hash with keys ‘:name`, `:definition`, `:type`.
65 66 67 |
# File 'lib/parse/model/core/search_indexing.rb', line 65 def mongo_search_index_declarations @mongo_search_index_declarations ||= [] end |
#search_indexes_plan ⇒ Hash
Dry-run reconciliation between declared search indexes and what exists on Atlas. Delegates to Schema::SearchIndexMigrator.
129 130 131 |
# File 'lib/parse/model/core/search_indexing.rb', line 129 def search_indexes_plan Parse::Schema::SearchIndexMigrator.new(self).plan end |