Handling null and undefined values in where conditions
In 'WHERE' conditions the values null
and undefined
are not strictly valid values in TypeORM.
Passing a known null
value is disallowed by TypeScript (when you've enabled strictNullChecks
in tsconfig.json) at compile time. But the default behavior is for null
values encountered at runtime to be ignored. Similarly, undefined
values are allowed by TypeScript and ignored at runtime.
The acceptance of null
and undefined
values can sometimes cause unexpected results and requires caution. This is especially a concern when values are passed from user input without adequate validation.
For example, calling Repository.findOneBy({ id: undefined })
returns the first row from the table, and Repository.findBy({ userId: null })
is unfiltered and returns all rows.
The way in which null
and undefined
values are handled can be customised through the invalidWhereValuesBehavior
configuration option in your data source options. This applies to all operations that support 'WHERE' conditions, including find operations, query builders, and repository methods.
The current behavior will be changing in future versions of TypeORM,
we recommend setting both null
and undefined
behaviors to throw to prepare for these changes
Default Behavior​
By default, TypeORM skips both null
and undefined
values in where conditions. This means that if you include a property with a null
or undefined
value in your where clause, it will be ignored:
// Both queries will return all posts, ignoring the text property
const posts1 = await repository.find({
where: {
text: null,
},
})
const posts2 = await repository.find({
where: {
text: undefined,
},
})
The correct way to match null values in where conditions is to use the IsNull
operator (for details see Find Options):
const posts = await repository.find({
where: {
text: IsNull(),
},
})
Configuration​
You can customize how null and undefined values are handled using the invalidWhereValuesBehavior
option in your connection configuration:
const dataSource = new DataSource({
// ... other options
invalidWhereValuesBehavior: {
null: "ignore" | "sql-null" | "throw",
undefined: "ignore" | "throw",
},
})
Null Behavior Options​
The null
behavior can be set to one of three values:
'ignore'
(default)​
JavaScript null
values in where conditions are ignored and the property is skipped:
const dataSource = new DataSource({
// ... other options
invalidWhereValuesBehavior: {
null: "ignore",
},
})
// This will return all posts, ignoring the text property
const posts = await repository.find({
where: {
text: null,
},
})
'sql-null'
​
JavaScript null
values are transformed into SQL NULL
conditions:
const dataSource = new DataSource({
// ... other options
invalidWhereValuesBehavior: {
null: "sql-null",
},
})
// This will only return posts where the text column is NULL in the database
const posts = await repository.find({
where: {
text: null,
},
})
'throw'
​
JavaScript null
values cause a TypeORMError to be thrown:
const dataSource = new DataSource({
// ... other options
invalidWhereValuesBehavior: {
null: "throw",
},
})
// This will throw an error
const posts = await repository.find({
where: {
text: null,
},
})
// Error: Null value encountered in property 'text' of a where condition.
// To match with SQL NULL, the IsNull() operator must be used.
// Set 'invalidWhereValuesBehavior.null' to 'ignore' or 'sql-null' in connection options to skip or handle null values.
Undefined Behavior Options​
The undefined
behavior can be set to one of two values:
'ignore'
(default)​
JavaScript undefined
values in where conditions are ignored and the property is skipped:
const dataSource = new DataSource({
// ... other options
invalidWhereValuesBehavior: {
undefined: "ignore",
},
})
// This will return all posts, ignoring the text property
const posts = await repository.find({
where: {
text: undefined,
},
})
'throw'
​
JavaScript undefined
values cause a TypeORMError to be thrown:
const dataSource = new DataSource({
// ... other options
invalidWhereValuesBehavior: {
undefined: "throw",
},
})
// This will throw an error
const posts = await repository.find({
where: {
text: undefined,
},
})
// Error: Undefined value encountered in property 'text' of a where condition.
// Set 'invalidWhereValuesBehavior.undefined' to 'ignore' in connection options to skip properties with undefined values.
Note that this only applies to explicitly set undefined
values, not omitted properties.
Using Both Options Together​
You can configure both behaviors independently for comprehensive control:
const dataSource = new DataSource({
// ... other options
invalidWhereValuesBehavior: {
null: "sql-null",
undefined: "throw",
},
})
This configuration will:
- Transform JavaScript
null
values to SQLNULL
in where conditions - Throw an error if any
undefined
values are encountered - Still ignore properties that are not provided in the where clause
This combination is useful when you want to:
- Be explicit about searching for NULL values in the database
- Catch potential programming errors where undefined values might slip into your queries
Works with all where operations​
The invalidWhereValuesBehavior
configuration applies to all TypeORM operations that support where conditions, not just repository find methods:
Query Builders​
// UpdateQueryBuilder
await dataSource
.createQueryBuilder()
.update(Post)
.set({ title: "Updated" })
.where({ text: null }) // Respects invalidWhereValuesBehavior
.execute()
// DeleteQueryBuilder
await dataSource
.createQueryBuilder()
.delete()
.from(Post)
.where({ text: null }) // Respects invalidWhereValuesBehavior
.execute()
// SoftDeleteQueryBuilder
await dataSource
.createQueryBuilder()
.softDelete()
.from(Post)
.where({ text: null }) // Respects invalidWhereValuesBehavior
.execute()
Repository Methods​
// Repository.update()
await repository.update({ text: null }, { title: "Updated" }) // Respects invalidWhereValuesBehavior
// Repository.delete()
await repository.delete({ text: null }) // Respects invalidWhereValuesBehavior
// EntityManager.update()
await manager.update(Post, { text: null }, { title: "Updated" }) // Respects invalidWhereValuesBehavior
// EntityManager.delete()
await manager.delete(Post, { text: null }) // Respects invalidWhereValuesBehavior
// EntityManager.softDelete()
await manager.softDelete(Post, { text: null }) // Respects invalidWhereValuesBehavior
All these operations will consistently apply your configured invalidWhereValuesBehavior
settings.