parse-stack-next 5.1.1 → 5.2.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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.env.sample +12 -0
  3. data/.env.test +4 -4
  4. data/CHANGELOG.md +630 -0
  5. data/Gemfile +3 -0
  6. data/Gemfile.lock +6 -1
  7. data/README.md +226 -39
  8. data/Rakefile +56 -10
  9. data/docs/atlas_vector_search_guide.md +110 -9
  10. data/docs/mcp_guide.md +504 -0
  11. data/docs/mongodb_direct_guide.md +66 -1
  12. data/docs/mongodb_index_optimization_guide.md +22 -1
  13. data/docs/usage_guide.md +15 -0
  14. data/lib/parse/agent/approval_gate.rb +0 -0
  15. data/lib/parse/agent/constraint_translator.rb +90 -19
  16. data/lib/parse/agent/describe.rb +1 -0
  17. data/lib/parse/agent/errors.rb +16 -0
  18. data/lib/parse/agent/mcp_client.rb +9 -0
  19. data/lib/parse/agent/mcp_dispatcher.rb +139 -7
  20. data/lib/parse/agent/mcp_rack_app.rb +621 -17
  21. data/lib/parse/agent/mcp_subscriptions.rb +607 -0
  22. data/lib/parse/agent/metadata_dsl.rb +58 -0
  23. data/lib/parse/agent/metadata_registry.rb +141 -1
  24. data/lib/parse/agent/prompt_hardening.rb +213 -0
  25. data/lib/parse/agent/result_formatter.rb +18 -3
  26. data/lib/parse/agent/tools.rb +167 -24
  27. data/lib/parse/agent.rb +692 -21
  28. data/lib/parse/client/request.rb +55 -4
  29. data/lib/parse/client/response.rb +4 -0
  30. data/lib/parse/client.rb +205 -7
  31. data/lib/parse/model/classes/installation.rb +27 -10
  32. data/lib/parse/model/classes/user.rb +8 -0
  33. data/lib/parse/model/core/actions.rb +65 -13
  34. data/lib/parse/model/core/embed_managed.rb +19 -14
  35. data/lib/parse/model/core/indexing.rb +108 -16
  36. data/lib/parse/model/core/querying.rb +29 -0
  37. data/lib/parse/model/model.rb +34 -3
  38. data/lib/parse/model/object.rb +42 -0
  39. data/lib/parse/query.rb +90 -24
  40. data/lib/parse/retrieval/agent_tool.rb +369 -0
  41. data/lib/parse/retrieval/chunk.rb +74 -0
  42. data/lib/parse/retrieval/chunker.rb +208 -0
  43. data/lib/parse/retrieval/retriever.rb +274 -0
  44. data/lib/parse/retrieval.rb +10 -0
  45. data/lib/parse/schema.rb +69 -20
  46. data/lib/parse/stack/version.rb +2 -2
  47. data/lib/parse/webhooks/payload.rb +62 -34
  48. data/lib/parse/webhooks.rb +15 -3
  49. data/parse-stack-next.gemspec +1 -1
  50. data/scripts/docker/docker-compose.atlas.yml +14 -10
  51. data/scripts/docker/docker-compose.test.yml +24 -20
  52. data/scripts/docker/mongo-init.js +3 -3
  53. data/scripts/start-parse.sh +10 -0
  54. data/scripts/start_mcp_server.rb +1 -1
  55. data/scripts/test_server_connection.rb +1 -1
  56. data/scripts/vector_prototype/create_vector_index.js +1 -1
  57. data/scripts/vector_prototype/fetch_embeddings.py +2 -2
  58. data/scripts/vector_prototype/query_prototype.rb +1 -1
  59. data/scripts/vector_prototype/run.sh +4 -4
  60. metadata +10 -2
@@ -8,7 +8,7 @@
8
8
  # Reset: docker-compose -f scripts/docker/docker-compose.atlas.yml down -v && docker-compose -f scripts/docker/docker-compose.atlas.yml up -d
9
9
  #
10
10
  # Run tests:
11
- # ATLAS_URI="mongodb://localhost:27020/parse_atlas_test?directConnection=true" ruby -Ilib:test test/lib/parse/atlas_search_integration_test.rb
11
+ # ATLAS_URI="mongodb://localhost:29020/parse_atlas_test?directConnection=true" ruby -Ilib:test test/lib/parse/atlas_search_integration_test.rb
12
12
  #
13
13
  # Stability notes (see commit history for context):
14
14
  # The mongodb-atlas-local image runs a supervisor ("runner") that intentionally
@@ -19,13 +19,17 @@
19
19
  # which checks both mongod AND mongot. We rely on that built-in healthcheck
20
20
  # rather than overriding it with a faster mongosh probe.
21
21
 
22
+ # Distinct Compose project name — kept separate from the main test stack
23
+ # (psnext-it) so `down` on one never tears down the other.
24
+ name: ${PSNEXT_PREFIX:-psnext-it}-atlas
25
+
22
26
  services:
23
27
  atlas-local:
24
28
  # Pinned patch tag rather than the floating :8.0 — mongodb-atlas-local has
25
29
  # known per-patch start-up flakiness (see testcontainers/testcontainers-java#10267
26
30
  # and MongoDB community forum 321179). Bump deliberately, not by drift.
27
31
  image: mongodb/mongodb-atlas-local:8.0.10
28
- container_name: parse-stack-atlas-local
32
+ container_name: ${PSNEXT_PREFIX:-psnext-it}-atlas
29
33
  # `hostname` is called out by the official compose example — the embedded
30
34
  # single-node replica set advertises this name, and a stable value makes
31
35
  # restart-after-down work cleanly.
@@ -37,15 +41,15 @@ services:
37
41
  MONGOT_LOG_FILE: /dev/stderr
38
42
  # Loopback-only by default — Atlas Local has no auth configured.
39
43
  ports:
40
- - "${ATLAS_BIND:-127.0.0.1}:27020:27017"
44
+ - "${ATLAS_BIND:-127.0.0.1}:${ATLAS_HOST_PORT:-29020}:27017"
41
45
  volumes:
42
46
  # Persist mongod data, replset config, and — critically — the mongot
43
47
  # Lucene index directory. Without /data/mongot persistence, every restart
44
48
  # forces a full search re-index, which lengthens "ready" time and is a
45
49
  # real source of test flakiness. Matches the official compose example.
46
- - atlas-data:/data/db
47
- - atlas-configdb:/data/configdb
48
- - atlas-mongot:/data/mongot
50
+ - psnext-it-atlas-data:/data/db
51
+ - psnext-it-atlas-configdb:/data/configdb
52
+ - psnext-it-atlas-mongot:/data/mongot
49
53
  # Recover from genuine crashes automatically. Test runs `docker compose down`
50
54
  # explicitly, so this does not interfere with teardown.
51
55
  restart: unless-stopped
@@ -59,7 +63,7 @@ services:
59
63
 
60
64
  atlas-init:
61
65
  image: mongodb/mongodb-atlas-local:8.0.10
62
- container_name: parse-stack-atlas-init
66
+ container_name: ${PSNEXT_PREFIX:-psnext-it}-atlas-init
63
67
  depends_on:
64
68
  atlas-local:
65
69
  # Uses the image's built-in healthcheck (see above), so this now waits
@@ -71,6 +75,6 @@ services:
71
75
  restart: "no"
72
76
 
73
77
  volumes:
74
- atlas-data:
75
- atlas-configdb:
76
- atlas-mongot:
78
+ psnext-it-atlas-data:
79
+ psnext-it-atlas-configdb:
80
+ psnext-it-atlas-mongot:
@@ -1,31 +1,35 @@
1
1
  version: '3.8'
2
2
 
3
+ # Distinct Compose project name so this stack never shares containers,
4
+ # networks, or volumes with another Parse test system on the same host.
5
+ name: ${PSNEXT_PREFIX:-psnext-it}
6
+
3
7
  services:
4
8
  mongo:
5
9
  image: mongo:8
6
- container_name: parse-stack-test-mongo
10
+ container_name: ${PSNEXT_PREFIX:-psnext-it}-mongo
7
11
  # Bind to loopback so the test database isn't reachable from the LAN
8
12
  # when a developer runs `docker-compose up`. Override with
9
13
  # `MONGO_BIND=0.0.0.0` if you really want it exposed.
10
14
  ports:
11
- - "${MONGO_BIND:-127.0.0.1}:27019:27017"
15
+ - "${MONGO_BIND:-127.0.0.1}:${MONGO_HOST_PORT:-29017}:27017"
12
16
  environment:
13
17
  MONGO_INITDB_ROOT_USERNAME: ${MONGO_ROOT_USER:-admin}
14
18
  MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD:-password}
15
19
  MONGO_INITDB_DATABASE: admin
16
20
  volumes:
17
- - mongo-data:/data/db
21
+ - psnext-it-mongo-data:/data/db
18
22
  - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro
19
23
 
20
24
  parse:
21
25
  build:
22
26
  context: ..
23
27
  dockerfile: docker/Dockerfile.parse
24
- container_name: parse-stack-test-server
28
+ container_name: ${PSNEXT_PREFIX:-psnext-it}-server
25
29
  # Bind to loopback by default — Parse Server with the test master key
26
30
  # has no business being reachable on a developer's LAN.
27
31
  ports:
28
- - "${PARSE_BIND:-127.0.0.1}:2337:1337"
32
+ - "${PARSE_BIND:-127.0.0.1}:${PARSE_HOST_PORT:-29337}:1337"
29
33
  # `host.docker.internal` is needed so Parse Server can POST to the
30
34
  # in-process WEBrick that backs webhook integration tests. Docker
31
35
  # Desktop on Mac/Windows resolves this natively; on Linux we map it
@@ -45,10 +49,10 @@ services:
45
49
  # `start-parse.sh` will abort if any of these is unset, so any
46
50
  # name drift here surfaces immediately rather than booting Parse
47
51
  # Server with whatever placeholder default the SDK README documents.
48
- PARSE_SERVER_APPLICATION_ID: ${PARSE_APP_ID:-myAppId}
49
- PARSE_SERVER_MASTER_KEY: ${PARSE_MASTER_KEY:-myMasterKey}
50
- PARSE_SERVER_REST_API_KEY: ${PARSE_API_KEY:-test-rest-key}
51
- PARSE_SERVER_DATABASE_URI: mongodb://${MONGO_ROOT_USER:-admin}:${MONGO_ROOT_PASSWORD:-password}@mongo:27017/parse?authSource=admin
52
+ PARSE_SERVER_APPLICATION_ID: ${PARSE_APP_ID:-psnextItAppId}
53
+ PARSE_SERVER_MASTER_KEY: ${PARSE_MASTER_KEY:-psnextItMasterKey}
54
+ PARSE_SERVER_REST_API_KEY: ${PARSE_API_KEY:-psnext-it-rest-key}
55
+ PARSE_SERVER_DATABASE_URI: mongodb://${MONGO_ROOT_USER:-admin}:${MONGO_ROOT_PASSWORD:-password}@mongo:27017/parse_stack_next_it?authSource=admin
52
56
  # Accept client-supplied objectId on create. Required by the
53
57
  # `parse_reference precompute: true` DSL. The SDK only forwards
54
58
  # client objectIds under master-key authority; for non-master
@@ -78,36 +82,36 @@ services:
78
82
 
79
83
  redis:
80
84
  image: redis:7-alpine
81
- container_name: parse-stack-test-redis
85
+ container_name: ${PSNEXT_PREFIX:-psnext-it}-redis
82
86
  # Loopback-only by default. Used by the cache integration test
83
87
  # (cache_redis_integration_test.rb) and the synchronize-create lock
84
88
  # tests. Override with `REDIS_BIND=0.0.0.0` if you need to point a
85
89
  # remote client at it during debugging.
86
90
  ports:
87
- - "${REDIS_BIND:-127.0.0.1}:6399:6379"
91
+ - "${REDIS_BIND:-127.0.0.1}:${REDIS_HOST_PORT:-29379}:6379"
88
92
  command: ["redis-server", "--save", "", "--appendonly", "no"]
89
93
 
90
94
  parse-dashboard:
91
95
  image: parseplatform/parse-dashboard:9
92
- container_name: parse-stack-test-dashboard
96
+ container_name: ${PSNEXT_PREFIX:-psnext-it}-dashboard
93
97
  # Loopback-only by default. This compose is for `rake test:integration`
94
98
  # and local debugging; do not expose to the network.
95
99
  ports:
96
- - "${DASHBOARD_BIND:-127.0.0.1}:4040:4040"
100
+ - "${DASHBOARD_BIND:-127.0.0.1}:${DASHBOARD_HOST_PORT:-29040}:4040"
97
101
  environment:
98
102
  # `allowInsecureHTTP` and `useEncryptedPasswords: false` are kept
99
103
  # because this stack runs over plain HTTP on loopback. Do NOT copy
100
104
  # these settings to a deployed environment.
101
105
  PARSE_DASHBOARD_ALLOW_INSECURE_HTTP: "1"
102
- PARSE_SERVER_MASTER_KEY: ${PARSE_MASTER_KEY:-myMasterKey}
103
- PARSE_SERVER_APPLICATION_ID: ${PARSE_APP_ID:-myAppId}
104
- PARSE_SERVER_URL: http://localhost:2337/parse
106
+ PARSE_SERVER_MASTER_KEY: ${PARSE_MASTER_KEY:-psnextItMasterKey}
107
+ PARSE_SERVER_APPLICATION_ID: ${PARSE_APP_ID:-psnextItAppId}
108
+ PARSE_SERVER_URL: http://localhost:${PARSE_HOST_PORT:-29337}/parse
105
109
  PARSE_DASHBOARD_CONFIG: |
106
110
  {
107
111
  "apps": [{
108
- "serverURL": "http://localhost:2337/parse",
109
- "appId": "${PARSE_APP_ID:-myAppId}",
110
- "masterKey": "${PARSE_MASTER_KEY:-myMasterKey}",
112
+ "serverURL": "http://localhost:${PARSE_HOST_PORT:-29337}/parse",
113
+ "appId": "${PARSE_APP_ID:-psnextItAppId}",
114
+ "masterKey": "${PARSE_MASTER_KEY:-psnextItMasterKey}",
111
115
  "appName": "ParseStackTest"
112
116
  }],
113
117
  "users": [{
@@ -121,4 +125,4 @@ services:
121
125
  - parse
122
126
 
123
127
  volumes:
124
- mongo-data:
128
+ psnext-it-mongo-data:
@@ -1,6 +1,6 @@
1
1
  // MongoDB initialization script
2
2
  // This script runs when the MongoDB container is first created
3
- // It grants the admin user access to the parse database for direct queries
3
+ // It grants the admin user access to the parse_stack_next_it database for direct queries
4
4
 
5
5
  // The admin user needs readWriteAnyDatabase role to access all databases
6
6
  db = db.getSiblingDB('admin');
@@ -11,8 +11,8 @@ db.grantRolesToUser('admin', [
11
11
  { role: 'dbAdminAnyDatabase', db: 'admin' }
12
12
  ]);
13
13
 
14
- // Initialize the parse database
15
- db = db.getSiblingDB('parse');
14
+ // Initialize the parse_stack_next_it database
15
+ db = db.getSiblingDB('parse_stack_next_it');
16
16
 
17
17
  // Create a placeholder collection to ensure the database exists
18
18
  db.createCollection('_init');
@@ -70,6 +70,16 @@ export PARSE_SERVER_START_LIVE_QUERY_SERVER="${PARSE_SERVER_START_LIVE_QUERY_SER
70
70
  # both pathways: authed upload succeeds, anon upload is rejected.
71
71
  export PARSE_SERVER_FILE_UPLOAD="${PARSE_SERVER_FILE_UPLOAD:-{\"enableForPublic\":false,\"enableForAnonymousUser\":false,\"enableForAuthenticatedUser\":true}}"
72
72
 
73
+ # Request-id idempotency — test-stack only, scoped to a single probe class so
74
+ # it deduplicates ONLY writes the request-id integration test targets and has
75
+ # zero effect on every other suite. Parse Server dedups POST/PUT carrying the
76
+ # same X-Parse-Request-Id within the TTL for paths matching `paths` (regex).
77
+ # The SDK's idempotent-retry feature relies on exactly this server-side dedup
78
+ # when `Parse::Request.assume_server_idempotency = true`. NOTE: Parse Server
79
+ # names this env var with an `EXPERIMENTAL_` infix and treats the value as a
80
+ # JSON object (objectParser). Override the whole JSON to widen coverage.
81
+ export PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_OPTIONS="${PARSE_SERVER_EXPERIMENTAL_IDEMPOTENCY_OPTIONS:-{\"paths\":[\"classes/IdempotencyProbe\"],\"ttl\":120}}"
82
+
73
83
  echo "Environment configured:"
74
84
  echo " PARSE_SERVER_APPLICATION_ID: $PARSE_SERVER_APPLICATION_ID"
75
85
  echo " PARSE_SERVER_LIVE_QUERY: $PARSE_SERVER_LIVE_QUERY"
@@ -18,7 +18,7 @@
18
18
  # binding to a non-loopback host
19
19
  #
20
20
  # Why no fallback values: previously this script accepted
21
- # `ENV["PARSE_APP_ID"] || "myAppId"` and the equivalent for the master
21
+ # `ENV["PARSE_APP_ID"] || "psnextItAppId"` and the equivalent for the master
22
22
  # key. A deployment that forgot to set the env var (typo'd name, missing
23
23
  # secret manager binding, container startup race) would silently boot
24
24
  # with the placeholder credentials documented in the README — credentials
@@ -75,7 +75,7 @@ end
75
75
 
76
76
  puts "\n5. Connection information:"
77
77
  puts " Parse Server: http://localhost:1337/parse"
78
- puts " Parse Dashboard: http://localhost:4040"
78
+ puts " Parse Dashboard: http://localhost:29040"
79
79
  puts " Dashboard login: admin/admin"
80
80
 
81
81
  puts "\nTo stop the containers, run:"
@@ -10,7 +10,7 @@
10
10
  // fetch_embeddings.py.
11
11
  //
12
12
  // Run:
13
- // mongosh "mongodb://localhost:27020/vector_prototype?directConnection=true" \
13
+ // mongosh "mongodb://localhost:29020/vector_prototype?directConnection=true" \
14
14
  // scripts/vector_prototype/create_vector_index.js
15
15
  //
16
16
  // To switch to 1024-dim (voyage-multimodal-3 compat), set DIMS=1024
@@ -3,7 +3,7 @@
3
3
  Vector-search & RAG test fixture loader.
4
4
 
5
5
  Pulls a subset of a pre-computed embeddings dataset from HuggingFace and
6
- loads it into Atlas Local at localhost:27020 (the same container managed
6
+ loads it into Atlas Local at localhost:29020 (the same container managed
7
7
  by scripts/docker/docker-compose.atlas.yml). Designed to be reused by both:
8
8
 
9
9
  1. Vector search integration tests (Parse::VectorSearch — v4.3 plan)
@@ -90,7 +90,7 @@ ID_FIELD = _p["id_field"]
90
90
 
91
91
  _ext = "parquet" if DATA_FORMAT == "parquet" else "json"
92
92
  LOCAL_FILE = os.environ.get("LOCAL_FILE", f"/tmp/parse-stack-fixture-{PRESET}.{_ext}")
93
- MONGO_URI = os.environ.get("ATLAS_URI", "mongodb://localhost:27020/?directConnection=true")
93
+ MONGO_URI = os.environ.get("ATLAS_URI", "mongodb://localhost:29020/?directConnection=true")
94
94
  DB_NAME = os.environ.get("DB_NAME", "vector_prototype")
95
95
  # Collection name mirrors the dataset shape so RAG tests can pivot
96
96
  # without coupling test assertions to a hard-coded class name.
@@ -24,7 +24,7 @@ unless File.exist?(MANIFEST_PATH)
24
24
  end
25
25
  MANIFEST = JSON.parse(File.read(MANIFEST_PATH))
26
26
 
27
- MONGO_URI = ENV.fetch("ATLAS_URI", "mongodb://localhost:27020/#{MANIFEST['db']}?directConnection=true")
27
+ MONGO_URI = ENV.fetch("ATLAS_URI", "mongodb://localhost:29020/#{MANIFEST['db']}?directConnection=true")
28
28
  INDEX_NAME = ENV.fetch("VECTOR_INDEX", MANIFEST["index_name"])
29
29
  COLL_NAME = MANIFEST["collection"].to_sym
30
30
 
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bash
2
2
  # Orchestrate the vector-search / RAG test fixture setup.
3
3
  # Assumes the Atlas Local container from docker-compose.atlas.yml is up
4
- # (i.e. localhost:27020 is reachable).
4
+ # (i.e. localhost:29020 is reachable).
5
5
  #
6
6
  # Usage: ./scripts/vector_prototype/run.sh
7
7
  #
@@ -13,9 +13,9 @@ set -euo pipefail
13
13
 
14
14
  HERE="$(cd "$(dirname "$0")" && pwd)"
15
15
 
16
- echo "[1/3] verifying Atlas Local on localhost:27020"
16
+ echo "[1/3] verifying Atlas Local on localhost:29020"
17
17
  if ! mongosh --quiet --eval "db.runCommand({ ping: 1 })" \
18
- "mongodb://localhost:27020/?directConnection=true" >/dev/null; then
18
+ "mongodb://localhost:29020/?directConnection=true" >/dev/null; then
19
19
  echo " ERROR: Atlas Local not reachable. Start it with:"
20
20
  echo " docker-compose -f scripts/docker/docker-compose.atlas.yml up -d"
21
21
  exit 1
@@ -26,7 +26,7 @@ echo "[2/3] downloading + loading embeddings"
26
26
  python3 "$HERE/fetch_embeddings.py"
27
27
 
28
28
  echo "[3/3] creating vectorSearch index"
29
- mongosh --quiet "mongodb://localhost:27020/vector_prototype?directConnection=true" \
29
+ mongosh --quiet "mongodb://localhost:29020/vector_prototype?directConnection=true" \
30
30
  "$HERE/create_vector_index.js"
31
31
 
32
32
  echo
metadata CHANGED
@@ -1,12 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parse-stack-next
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.1
4
+ version: 5.2.1
5
5
  platform: ruby
6
6
  authors:
7
+ - Adrian Curtin
7
8
  - Anthony Persaud
8
9
  - Henry Spindell
9
- - Adrian Curtin
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
  date: 1980-01-02 00:00:00.000000000 Z
@@ -257,6 +257,7 @@ files:
257
257
  - lib/parse-stack.rb
258
258
  - lib/parse/acl_scope.rb
259
259
  - lib/parse/agent.rb
260
+ - lib/parse/agent/approval_gate.rb
260
261
  - lib/parse/agent/cancellation_token.rb
261
262
  - lib/parse/agent/constraint_translator.rb
262
263
  - lib/parse/agent/describe.rb
@@ -265,10 +266,12 @@ files:
265
266
  - lib/parse/agent/mcp_dispatcher.rb
266
267
  - lib/parse/agent/mcp_rack_app.rb
267
268
  - lib/parse/agent/mcp_server.rb
269
+ - lib/parse/agent/mcp_subscriptions.rb
268
270
  - lib/parse/agent/metadata_audit.rb
269
271
  - lib/parse/agent/metadata_dsl.rb
270
272
  - lib/parse/agent/metadata_registry.rb
271
273
  - lib/parse/agent/pipeline_validator.rb
274
+ - lib/parse/agent/prompt_hardening.rb
272
275
  - lib/parse/agent/prompts.rb
273
276
  - lib/parse/agent/rate_limiter.rb
274
277
  - lib/parse/agent/relation_graph.rb
@@ -391,6 +394,11 @@ files:
391
394
  - lib/parse/query/n_plus_one_detector.rb
392
395
  - lib/parse/query/operation.rb
393
396
  - lib/parse/query/ordering.rb
397
+ - lib/parse/retrieval.rb
398
+ - lib/parse/retrieval/agent_tool.rb
399
+ - lib/parse/retrieval/chunk.rb
400
+ - lib/parse/retrieval/chunker.rb
401
+ - lib/parse/retrieval/retriever.rb
394
402
  - lib/parse/schema.rb
395
403
  - lib/parse/schema/index_migrator.rb
396
404
  - lib/parse/schema/search_index_migrator.rb