feat: case-insensitive, whitespace-normalized name handles#6
Merged
Conversation
For a name to work as a lookup handle it must be unique and consistently normalized. This establishes that contract for usernames now and lays the schema groundwork so rooms inherit it when room.rs is complete. - Case-insensitive uniqueness via LOWER() functional indexes on username and room_name: "Alice" and "alice" can't coexist, and a lookup resolves regardless of the casing the client sends. Original casing is preserved for display. - trim_ws(): a SQL helper stripping all leading/trailing whitespace (space, tab, newline, ...), unlike bare TRIM which only removes spaces. Applied on every write and lookup so padded input can't produce near-duplicate or unreachable rows. - Optional fields (first/last/alias) collapse empty/whitespace input to NULL. On edit, an absent field is left unchanged while an explicit blank clears it; a username can't be blanked. - CHECK (col <> '') on every text column (users, rooms, messages) as a backstop, so an empty string can never be stored via any code path. Writes and lookups route through LOWER()/trim_ws() consistently so they still use the functional indexes. room_name's index and CHECK are added ahead of room.rs so the room actor's queries can rely on them directly.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
For a name to work as a lookup handle it has to be unique and consistently normalized — otherwise one human-entered name can resolve to zero rows or to several.
This PR establishes that contract for usernames now and lays the schema groundwork so rooms benefits when
room.rslands. It contains no room-actor code itself — just the normalization rules and theroom_nameschema those queries will depend on.What changed
LOWER()functional indexes onusernameandroom_name."Alice"and"alice"can't coexist, and a lookup resolves regardless of the casing the client sends. Stored casing is preserved for display.trim_ws()— a SQL helper that strips all leading/trailing whitespace (space, tab, newline, CR, …), unlike bareTRIM, which only removes spaces. Routed through every write and lookup so padded input can't create near-duplicate or unreachable rows.first_name/last_name/alias): blank input collapses toNULL. On edit, an absent field is left can't be blanked.CHECK (col <> '')on every text column (users,rooms,messages) as a hard backstop, so''can never be stored via any code path — present or future.Writes and lookups go through
LOWER()/trim_ws()consistently so they still hit the functional indexes.Testing
tests/normalization.rs(16 tests): case-insensitive uniqueness + auth + lookup, casing preserved on read, whitespace-complete trimming (incl. tab/newline-only → rejected), empty→NULL on create, and the three-way edit semantics (none / blank / value).Notes for reviewers
tests/edit_user.rshas one intentional existing-test change: theempty_string_fields_overwrite_existing_valuescanary now expectsNoneinstead ofSome(""), matching the new empty→NULL contract (its own comment predicted this). The CI test-modification check will flag it — that flag is expected here.room_name's index and CHECK are added ahead ofroom.rsso the room actor can rely on them; carry the sametrim_ws($1)/LOWER(room_name) = LOWER(trim_ws($1))convention into those queries.