Normalize entity names to capitalized form throughout config - #1479
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughEntity-name access now uses capitalized keys across schema validation, runtime configuration, test-indexer outputs, and generated maps. Physical GraphQL and database names remain unchanged, and tests cover lowercase names, relationships, and capitalization collisions. ChangesEntity Name Normalization
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/envio-tests/test/MockIndexerHandlers_test.res`:
- Line 44: Remove the issue-link-only comment near the lowercase entity-name
coverage in MockIndexerHandlers_test.res; do not add replacement text unless a
concise invariant is needed to explain behavior not evident from the test.
In `@packages/envio/src/Config.res`:
- Line 427: Update config parsing around entityName normalization to detect
duplicate capitalized entity names before constructing the entity dictionary.
Reject the configuration with a clear error when distinct raw names normalize to
the same key, preserving one-to-one entity lookup and generated table-name
behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 41db8161-7c08-406e-9bd9-c1a5e955e5b3
📒 Files selected for processing (3)
packages/cli/src/hbs_templating/codegen_templates.rspackages/envio-tests/test/MockIndexerHandlers_test.respackages/envio/src/Config.res
| t.expect(config.name).toBe("mock-handlers") | ||
| }) | ||
|
|
||
| // https://github.com/enviodev/hyperindex/issues/1478 |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Remove the issue-link-only comment.
This comment records issue history but does not explain behavior the code cannot show. Remove it or replace it with a concise invariant explaining why lowercase entity names are covered.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/envio-tests/test/MockIndexerHandlers_test.res` at line 44, Remove
the issue-link-only comment near the lowercase entity-name coverage in
MockIndexerHandlers_test.res; do not add replacement text unless a concise
invariant is needed to explain behavior not evident from the test.
Source: Coding guidelines
| let entityName = entityJson["name"] | ||
| // Entity names are normalized to capitalized, matching the generated | ||
| // types which key entities by the capitalized name. | ||
| let entityName = entityJson["name"]->Utils.String.capitalize |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Map the relevant file and search for name-normalization/lookup logic.
ast-grep outline packages/envio/src/Config.res --view expanded || true
printf '\n--- search ---\n'
rg -n "userEntitiesByName|capitalize|entityName|entityJson\\[\"name\"\\]|duplicate|collision|normalize" packages/envio/src/Config.res packages/envio/src -g '!**/node_modules/**' || true
printf '\n--- surrounding lines ---\n'
sed -n '380,500p' packages/envio/src/Config.resRepository: enviodev/hyperindex
Length of output: 21238
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect any helpers used to derive entity names and keys.
rg -n "capitalize|camel|pascal|userEntitiesByName|entitiesByName|entity.*name" packages/envio/src -g '!**/node_modules/**' || true
# If there is a parser/validator, inspect its nearby code.
fd -a "Config.res|*.res" packages/envio/src | head -n 20Repository: enviodev/hyperindex
Length of output: 7868
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Read the exact section around the reported line and a bit earlier/later.
nl -ba packages/envio/src/Config.res | sed -n '410,470p'Repository: enviodev/hyperindex
Length of output: 197
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n--- Config.res around userEntitiesByName ---\n'
sed -n '980,1045p' packages/envio/src/Config.res
printf '\n--- Utils.capitalize ---\n'
sed -n '410,455p' packages/envio/src/Utils.res
printf '\n--- dict helpers for duplicate behavior ---\n'
rg -n "fromArray|set\\(|push\\(|dangerouslyGetNonOption|duplicate|overwrite" packages/envio/src/Utils.res packages/envio/src/Config.res packages/envio/src -g '!**/node_modules/**' | sed -n '1,120p'Repository: enviodev/hyperindex
Length of output: 16084
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Look for any explicit duplicate-name validation on entities or contracts.
rg -n "duplicate.*entity|entity.*duplicate|already exists|same name|normalized.*unique|capitalize.*unique|collision" packages/envio/src -g '!**/node_modules/**' | sed -n '1,160p'Repository: enviodev/hyperindex
Length of output: 647
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n--- Config.res around userEntitiesByName ---\n'
sed -n '990,1040p' packages/envio/src/Config.res
printf '\n--- Utils.capitalize ---\n'
sed -n '420,450p' packages/envio/src/Utils.res
printf '\n--- explicit duplicate-name validation search ---\n'
rg -n "duplicate.*entity|entity.*duplicate|already exists|same name|normalized.*unique|capitalize.*unique|collision" packages/envio/src -g '!**/node_modules/**' | sed -n '1,200p'Repository: enviodev/hyperindex
Length of output: 3348
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
text = Path('packages/envio/src/Config.res').read_text()
start = text.index(' let userEntitiesByName =')
print(text[start:start+900])
PYRepository: enviodev/hyperindex
Length of output: 1058
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n--- Utils.Dict implementation ---\n'
sed -n '600,690p' packages/envio/src/Utils.res
printf '\n--- Table.makeTable / entity config shape ---\n'
rg -n "makeTable|entityConfig|name:" packages/envio/src/db/Table.res packages/envio/src/Internal.res packages/envio/src/Config.res -g '!**/node_modules/**' | sed -n '1,160p'
printf '\n--- parseEntitiesFromJson context ---\n'
sed -n '430,540p' packages/envio/src/Config.resRepository: enviodev/hyperindex
Length of output: 8793
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Focus specifically on whether Dict.fromArray rejects duplicates or overwrites them.
rg -n "let fromArray|external fromArray|fromArrayUnsafe|fromArray" packages/envio/src/Utils.res packages/envio/src -g '!**/node_modules/**' | sed -n '1,200p'Repository: enviodev/hyperindex
Length of output: 3267
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n--- allEntities usages ---\n'
rg -n "\ballEntities\b" packages/envio/src -g '!**/node_modules/**' | sed -n '1,200p'
printf '\n--- userEntitiesByName usages ---\n'
rg -n "\buserEntitiesByName\b" packages/envio/src -g '!**/node_modules/**' | sed -n '1,200p'
printf '\n--- entityConfig.name in table/db code ---\n'
rg -n "entityConfig\.name|tableName|mkTable\(" packages/envio/src/db packages/envio/src/PgStorage.res packages/envio/src/Hasura.res packages/envio/src/Config.res -g '!**/node_modules/**' | sed -n '1,220p'Repository: enviodev/hyperindex
Length of output: 15361
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n--- places all entities are indexed into dicts ---\n'
rg -n "Dict\.fromArray|Array\.map\(.*entityConfig|entityConfig\)\s*->Dict\.fromArray|entityConfigs->Dict\.set|entities->Dict\.set" packages/envio/src -g '!**/node_modules/**' | sed -n '1,240p'
printf '\n--- table name generation / use of entityName ---\n'
sed -n '1,180p' packages/envio/src/db/Table.resRepository: enviodev/hyperindex
Length of output: 6899
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n--- db/Schema.res ---\n'
sed -n '1,120p' packages/envio/src/db/Schema.res
printf '\n--- EntityTables / any name-keyed collection ---\n'
rg -n "EntityTables|fromArray|tableName|entityConfig.name" packages/envio/src/IndexerState.res packages/envio/src/db packages/envio/src/Internal.res -g '!**/node_modules/**' | sed -n '1,220p'Repository: enviodev/hyperindex
Length of output: 4461
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n--- UserContext lookup path ---\n'
sed -n '300,340p' packages/envio/src/UserContext.res
printf '\n--- Testing current capitalization behavior on sample names ---\n'
python3 - <<'PY'
def capitalize(s):
return (s[:1].upper() + s[1:])
for s in ["pool_snapshots", "Pool_snapshots", "poolSnapshots", "PoolSnapshots"]:
print(s, "=>", capitalize(s))
PYRepository: enviodev/hyperindex
Length of output: 1754
Reject normalized-name collisions. capitalize can map distinct raw names to the same entity key, and Dict.fromArray will drop one of them. Validate normalized entity names are unique during config parsing so lookups and generated table names stay one-to-one.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/envio/src/Config.res` at line 427, Update config parsing around
entityName normalization to detect duplicate capitalized entity names before
constructing the entity dictionary. Reject the configuration with a clear error
when distinct raw names normalize to the same key, preserving one-to-one entity
lookup and generated table-name behavior.
Fixes #1478. Since v3.3.x the generated TS handler-context types key entities by the capitalized entity name, while the runtime resolved context properties by the original schema.graphql name — so any entity whose name didn't already start with an uppercase letter (e.g. snake_case `pool_snapshots`) typechecked against `context.Pool_snapshots` but threw "Invalid context access" at runtime. The entity name serves two distinct roles: the user-facing accessor (`context.Pool_snapshots`, `indexer.Pool_snapshots`, `process()` changes) and the physical identifier (Postgres/ClickHouse tables and views, entity history tables, derivedFrom/linkedEntity references). Only the accessor should be capitalized; the GraphQL schema name and the physical DB tables stay exactly as authored. - Key `userEntitiesByName` by the capitalized name so the handler-context proxy resolves `context.Pool_snapshots`, while `entityConfig.name` keeps the original schema name that drives table/view/history identifiers. - Capitalize the TestIndexer entity-ops and `process()` change keys to match the same accessor contract. - Key the generated ReScript `handlerContext` and `testIndexer` types by the capitalized name (the TS `Entities` table and `Entities.name` GADT were already capitalized). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017JaWuRUKH6ZWdQu3Vw4WNX
225a847 to
258ebe1
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/envio/src/Config.res`:
- Around line 998-1007: Update parseEntitiesFromJson in
packages/envio/src/Config.res at lines 998-1007 to detect duplicate keys
produced by capitalizing entityConfig.name before calling Dict.fromArray, and
reject the configuration with the existing parsing error mechanism instead of
allowing shadowing. Keep the capitalized accessor-key behavior unchanged; the
TestIndexer mappings at packages/envio/src/TestIndexer.res lines 202-206 and
706-708 require no direct changes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 10d4e178-bb67-4dd7-8352-2f999398d513
📒 Files selected for processing (4)
packages/cli/src/hbs_templating/codegen_templates.rspackages/envio-tests/test/MockIndexerHandlers_test.respackages/envio/src/Config.respackages/envio/src/TestIndexer.res
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/envio-tests/test/MockIndexerHandlers_test.res
- packages/cli/src/hbs_templating/codegen_templates.rs
| // Keyed by the capitalized entity name to match the handler-context | ||
| // accessor (`context.Pool_snapshots`) the generated types expose, while | ||
| // entityConfig.name stays the original schema name used for the physical | ||
| // Postgres/ClickHouse tables. | ||
| let userEntitiesByName = | ||
| userEntities | ||
| ->Array.map(entityConfig => { | ||
| (entityConfig.name, entityConfig) | ||
| (entityConfig.name->Utils.String.capitalize, entityConfig) | ||
| }) | ||
| ->Dict.fromArray |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n "fromArray|capitalize|userEntitiesByName" \
packages/envio/src/Config.res \
packages/envio/src/TestIndexer.res \
packages/envio/src/Utils.resRepository: enviodev/hyperindex
Length of output: 2910
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '930,1060p' packages/envio/src/Config.res
printf '\n---\n'
sed -n '180,220p' packages/envio/src/TestIndexer.res
printf '\n---\n'
sed -n '690,720p' packages/envio/src/TestIndexer.res
printf '\n---\n'
sed -n '415,440p' packages/envio/src/Utils.res
printf '\n---\n'
sed -n '615,640p' packages/envio/src/Utils.resRepository: enviodev/hyperindex
Length of output: 9025
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n "duplicate|collision|unique|entity.*name|name.*duplicate|capitalize" packages/envio/src/Config.res packages/envio/src -g '!**/node_modules/**'Repository: enviodev/hyperindex
Length of output: 11730
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '1,220p' packages/envio/src/Utils.res | sed -n '120,220p'
printf '\n---\n'
sed -n '560,700p' packages/envio/src/Utils.resRepository: enviodev/hyperindex
Length of output: 7761
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n "entityConfig|userEntities|entities" packages/envio/src/Config.res -nRepository: enviodev/hyperindex
Length of output: 1386
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n "entity.*(set|unique|duplicate|collision)|Dict\\.fromArray|fromArrayUnsafe|capitalize" packages/envio/src/Config.res packages/envio/src -g '!**/node_modules/**'Repository: enviodev/hyperindex
Length of output: 5713
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n "^[^/].*name.*regex|regex.*name|lowercase|snake_case|entity name|contract name|validate.*name|allowed.*name" packages/envio/src/Config.res packages/envio/src -g '!**/node_modules/**'Repository: enviodev/hyperindex
Length of output: 5368
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '400,560p' packages/envio/src/Config.res
printf '\n---\n'
sed -n '560,700p' packages/envio/src/Config.res
printf '\n---\n'
rg -n "entityJsonSchema|name:|parseEntitiesFromJson|capitalize" packages/envio/src/Config.res packages/envio/src -g '!**/node_modules/**'Repository: enviodev/hyperindex
Length of output: 17702
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '400,560p' packages/envio/src/Config.res
printf '\n---\n'
sed -n '560,700p' packages/envio/src/Config.res
printf '\n---\n'
rg -n "entityJsonSchema|parseEntitiesFromJson|capitalize|name:" packages/envio/src/Config.res packages/envio/src -g '!**/node_modules/**'Repository: enviodev/hyperindex
Length of output: 17702
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '320,420p' packages/envio/src/Config.res
printf '\n---\n'
python3 - <<'PY'
def capitalize(s):
return s[:1].upper() + s[1:]
samples = ["foo", "Foo", "fOo", "bar", "Bar", "pool_snapshots", "Pool_snapshots"]
mapped = {}
for s in samples:
k = capitalize(s)
mapped.setdefault(k, []).append(s)
print(mapped)
PYRepository: enviodev/hyperindex
Length of output: 3780
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n "^module Dict|fromArray" packages/envio/src/Utils.res
printf '\n---\n'
sed -n '500,650p' packages/envio/src/Utils.resRepository: enviodev/hyperindex
Length of output: 5467
Reject capitalized entity-name collisions in config parsing. parseEntitiesFromJson accepts arbitrary strings, and Utils.String.capitalize can map distinct entities like foo and Foo to the same userEntitiesByName key. Enforce uniqueness before Dict.fromArray in packages/envio/src/Config.res so one entity can’t silently shadow another; the TestIndexer maps can keep using the capitalized accessor keys.
📍 Affects 2 files
packages/envio/src/Config.res#L998-L1007(this comment)packages/envio/src/TestIndexer.res#L202-L206packages/envio/src/TestIndexer.res#L706-L708
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/envio/src/Config.res` around lines 998 - 1007, Update
parseEntitiesFromJson in packages/envio/src/Config.res at lines 998-1007 to
detect duplicate keys produced by capitalizing entityConfig.name before calling
Dict.fromArray, and reject the configuration with the existing parsing error
mechanism instead of allowing shadowing. Keep the capitalized accessor-key
behavior unchanged; the TestIndexer mappings at
packages/envio/src/TestIndexer.res lines 202-206 and 706-708 require no direct
changes.
The handler context and generated types expose each entity under its capitalized name (context.Pool_snapshots), so two entities differing only in the first letter's case (e.g. `user` and `User`) map to the same accessor and would silently shadow each other in userEntitiesByName at runtime. Catch this at schema-validation time with a clear error instead. Adds a case to the UserApiValidation schema-error suite and Rust unit tests covering the collision and the unique-when-capitalized happy path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017JaWuRUKH6ZWdQu3Vw4WNX
Summary
Ensures entity names are consistently capitalized across the entire configuration pipeline, from schema parsing through code generation and runtime config. This fixes an issue where lowercase entity names in the schema weren't being properly capitalized in generated types and runtime operations.
Key Changes
Config parsing (
Config.res): Capitalize entity names when parsing from JSON schema, including:Code generation (
codegen_templates.rs): Use capitalized entity names as keys in generated handler entity operations maps, ensuring consistency with how entities are keyed in the runtime configTest coverage: Added comprehensive test case validating that lowercase entity names (
pool_snapshots,user_account) are properly capitalized in both generated types and runtime configImplementation Details
The normalization happens at the config parsing layer, ensuring all downstream consumers (code generation, runtime) work with consistently capitalized names. This aligns with the generated TypeScript types which use capitalized entity names as keys.
https://claude.ai/code/session_017JaWuRUKH6ZWdQu3Vw4WNX
Summary by CodeRabbit