Text Field Nullability Defaults #7158
Replies: 5 comments 10 replies
-
Personally, I'm not convinced the current behaviour is ideal – I'd prefer consistency with developers needing to opt into this special "natural text" behaviour. Maybe we can solve this with additional, more targeted field types in future. Regardless, the above describes the rational for decisions made. |
Beta Was this translation helpful? Give feedback.
-
This just feels sooooo much more intuitive. (Also, consistency in code/data tends to cause fewer bugs.)
If it is important not to allow empty strings then use defaultValue=''. I would consider empty strings to be more of a frontend issue, not graphql or database. (I also have to admit that I don't intend to let my end users anywhere near the admin ui, so what happens there is of secondary concern to me) |
Beta Was this translation helpful? Give feedback.
-
It feels a bit like I'm always complaining, but I think this package is awesome! (I come from Strapi, but they totally dropped the ball.) Thank you! 🙏🌷 |
Beta Was this translation helpful? Give feedback.
-
Btw, is there any way I can set a |
Beta Was this translation helpful? Give feedback.
-
When it comes to If I think of anything I will let you know 😉 |
Beta Was this translation helpful? Give feedback.
-
Aka. Why aren't text fields nullable by default in Keystone 6?
Almost all scalar field types in Keystone 6 implement the same behaviour for the
validation.isRequired
,db.isNullable
anddefaultValue
options:validation.isRequired
defaults tofalse
db.isNullable
defaults to the inverse ofvalidation.isRequired
(validation.isRequired ? false : true
)defaultValue
defaults toundefined
ornull
Unless these options are overridden, columns in the DB schema will be nullable and items inserted that don't specify a value for the field – either in the input data or due to a hook being executed – will have a
null
value. This is the case for theinteger
,float
,decimal
,select
andtimestamp
field types. Thepassword
type differs only in that it has nodefaultValue
.But the
text
field type options behave differently:validation.isRequired
still defaults tofalse
db.isNullable
also defaults to literalfalse
, regardless of the resolved value ofvalidation.isRequired
db.isNullable
is true,defaultValue
defaults toundefined
otherwise an empty stringAs such, unless
db.isNullable
is explicitly set totrue
, the DB columns created will be not nullable with missing values replaced with zero-length strings when items are created.So why does this inconsistency exist?
To understand why Keystone
text
fields behave the way they do, we first need to understand some of the issues unique to textual data.Empty Inputs are Ambiguous
For most types of non-textual data – like numbers, dates, times, etc. – there's an intuitive and obvious distinction between a missing value (ie.
null
) and any other valid value. If a user is entering, say, prices for products in their ecommerce backend, they're not going to confuse a missing value with a value of5
,1000
or even0
. A price of0
indicates the product is free while a missing value (ie. an empty field) likely indicates that data simply hasn't yet been populated.The same goes for dates and times. There's no special date or time that represents a missing value – even
0000-01-01 00:00:00
or1970-01-01 00:00:00
(which some may claim are "blank" values) represent real moments in time. If you're filling out a form with atimestamp
field, and want to indicate there is no value, you simply leave the relevant field empty.That, for non-textual data, a field can be left empty (or an existing value removed) to indicate a missing value is intuitive for most users. After all, what else could an empty field mean? A zero-length string submitted for an
integer
field has no obvious, equivalent value in the set of valid integers. Evenselect
fields are often given an obvious "blank" first option, indicating no value has been selected.But
text
fields aren't able to exploit this mechanium. Leaving atext
field blank could indicate the value should benull
, or it could indicate the correct, known value is a literal zero-length string. After all, zero-length strings are sometimes a perfectly reasonable thing to store.Entering
null
ValuesSo leaving a text field blank is ambiguous; maybe we can make
null
values explicit?Although it's technically possible to type a UTF NULL charactor, it's fair to say that users generally won't. There's simply no standard way to enter a
null
into a text input in a browser.In Keystone, if you have a nullable
text
field, the Admin UI will add a checkbox to indicate a null should be submitted, like this:(screenshot of text field with "Set field as null" checkbox)
If you want this behaviour, simply add
db: { isNullable: true }
to yourtext
field config. It's super handy for some use cases, specifically, when the text you're dealing with is technical in nature.Technical text values usually come from or are consumed by software and often have a defined format or schema, for example:
#1279FC
)For this category of field, storing a zero-length string often isn't helpful. If someone doesn't enter an email address, it's much clearer to indicate the missing value by storing
null
than by storing an empty string. It usually also makes checking the format of values simpler – validation rules and regex won't be run againstnull
values.Long term, we're planning to roll out specific field types for these use cases, with "Set to null" mechaniums built in. For example, a dedicated
URL
field type could add a lot of value by providing a specific UI, default validation rules and other features. AnEmail
field type could correctly account for validation and casing concerns, etc.However, for a lot of non-technical text data – what I'm going to call natural text data –
null
values don't really make sense.Natural Text
Natural text values are parts of the day-to-day language people use to communicate with each other.
They encompasses things like:
The concept of
null
generally isn't used here in these contexts.For example, say I'm filling out a form of personal information. If I leave the "Middle name" field blank it's obvious to anyone looking at that form that I have no middle name. No one would see that completed form and think, "Huh, this guy has a zero-length string for a middle name!". In these contexts missing and zero-length values effectively have the same meaning.
And this – natural text data – is the primary use case the Keystone 6
text
field was designed to address.Given that, in this context,
null
usually aren't needed or wanted, the decision was made to replace them with zero-length strings in the default configuration. This gives us a simpler UI, more intuitive filtering and avoids ever accidentally outputting'undefined'
or'null'
when missing values are incorrectly templated or concatenated into a string.If this isn't the behaviour you want, setting
db: { isNullable: true }
will make the DB column nullable and give the field a "Set field as null" checkbox in the Admin UI. Note though, it's often best to pair this withvalidation: { isRequired: true }
or a minimum length. Having both zero-length strings andnull
values in a column can cause unexpected sorting behaviour and complicates filtering – if you want items without a value set you need to remember to check for both conditions, eg:If you're also concerned with the nullability of
text
fields at the GraphQL layer, see also thegraphql.isNonNull.read
andgraphql.isNonNull.[create|update]
config options. As always, see the docs for details.Beta Was this translation helpful? Give feedback.
All reactions