That’s a very common situation, makes perfect sense!
Generally, rather than scattering these checks across my codebase, I’d try to exert them within modules singly responsible for interacting with ecto structs that have these quirks—for example, perhaps inside the schema modules themselves with changesets, or a context module that validates and navigates all of this conditional logic in one place.
Specific to this common empty-string data-model case however, I’d propose a simpler way to handle this—at least, if your team is willing to make a schema change, and using postgres—other dbs may have similar solutions but I’m not sure:
ALTER TABLE thing ADD CHECK (field <> '');
This simply ensures that a given field can not be an empty string.
Whether or not my
text fields are
NOT NULL these days, I simply do not allow empty strings in my data model. It never makes sense in the domain layer, causes semantic confusion in nullable columns, and as you experience, pushes a whole bevy of edge case handling to application logic.
Empty strings are the opposite of data, moreso than
NULLs! Get’em out of your database! Make invalid states unrepresentable! Have your nullable changesets cast
nil once, your non-nullable ones error, and never think about it again.
The one exception is maybe if I have a user-entered free-form text area like a description and I want to discern between “never interacted with” and “had a value manually deleted”. But that’s really something that should be modeled differently, with change tracking or an enum-type state machine.
Edit: I just noticed your mention that
Feel free to ignore my rant against empty strings, then! If your team finds signal in them, by all means normalize in the application layer rather than the data model! @D4no0 's suggestion is a great one.