Skip to content

Allow not() to compose with and()/or() (undefined-safe)#6007

Open
J0su3Code wants to merge 1 commit into
drizzle-team:mainfrom
J0su3Code:fix/not-accepts-and-or-undefined
Open

Allow not() to compose with and()/or() (undefined-safe)#6007
J0su3Code wants to merge 1 commit into
drizzle-team:mainfrom
J0su3Code:fix/not-accepts-and-or-undefined

Conversation

@J0su3Code

Copy link
Copy Markdown

Summary

Fixes #1818.

and() and or() are typed to return SQL | undefined (they drop
undefined conditions and return undefined when nothing is left).
not(), however, only accepted SQLWrapper, so composing them:

db.query.users.findMany({
  where: not(and(ilike(users.name, '%asdf%'))),
})

failed to type-check with:

TS2345: Argument of type 'SQL | undefined' is not assignable to parameter of type 'SQLWrapper'.
  Type 'undefined' is not assignable to type 'SQLWrapper'.

and forced a manual as SQLWrapper cast on the inner expression.

Change

Add an overload to not() so it also accepts SQLWrapper | undefined
and returns SQL | undefined, passing undefined straight through — the
same way and() / or() already ignore undefined conditions.

export function not(condition: SQLWrapper): SQL;
export function not(condition: SQLWrapper | undefined): SQL | undefined;
export function not(condition: SQLWrapper | undefined): SQL | undefined {
  return condition === undefined ? undefined : sql`not ${condition}`;
}

The original overload is kept, so not(eq(...)) still returns SQL
(not SQL | undefined). No existing call site changes its inferred type,
so this is non-breaking.

Tests

Added type-test coverage for not(and(...)) and not(or(...)) in the
allOperators block of the pg, mysql, sqlite, singlestore and geldb
type-tests/*/select.ts files. These lines fail to compile on main
(the exact TS2345 above) and compile with this change.

Note on conventions

This is a core, dialect-agnostic operator change, so it doesn't map to a
single [<dialect>]: tag — the type-tests are updated for every dialect
instead.

`and()` and `or()` return `SQL | undefined`, but `not()` only accepted
`SQLWrapper`. As a result `not(and(...))` and `not(or(...))` raised a
TS2345 type error ("'SQL | undefined' is not assignable to 'SQLWrapper'")
and forced users to cast the inner expression to `SQLWrapper`.

Add an overload so `not()` also accepts `SQLWrapper | undefined` and
returns `SQL | undefined`, passing `undefined` straight through the same
way `and()` and `or()` already ignore undefined conditions. The original
overload still returns `SQL` for a definite condition, so existing call
sites keep their exact return type and no behavior changes for them.

Add type-test coverage for not(and(...)) and not(or(...)) across the pg,
mysql, sqlite, singlestore and geldb dialects.

Fixes drizzle-team#1818
@J0su3Code J0su3Code force-pushed the fix/not-accepts-and-or-undefined branch from a1399b9 to 4e4c8ed Compare July 10, 2026 17:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: not type doesn't work with and and or

1 participant