drizzle-team / drizzle-team/drizzle-orm

[BUG]: Composition of not and or/and yields compile error

Open
#4,160 2 comments 1 reaction 0 assignees View on GitHub
bug priority qb/crud
Dominant language
TypeScript
Stars
35.8k
Forks
1.6k
Avg merge
2d 7h
Merged PRs (30d)
4

Description

### Report hasn't been filed before.

- [x] I have verified that the bug I'm about to report hasn't been filed before.

### What version of `drizzle-orm` are you using?

0.39.3

### What version of `drizzle-kit` are you using?

0.30.4

### Other packages

_No response_

### Describe the Bug

I have this function:

```
// undeletable sessions
const DEFAULT_SESSION_NAME = "Default Session";
const BASE_SESSION_NAME = "Base Scramble";

export async function deleteSession(userId: number, sessionId: number) {
await db.delete(dbSessions).where(
and(
eq(dbSessions.id, sessionId),
eq(dbSessions.userId, userId),
not(
or(
eq(dbSessions.name, DEFAULT_SESSION_NAME),
eq(dbSessions.name, DAILY_SCRAMBLE_SESSION_NAME)
)
)
)
);
}
```

This throws the compile error:

```
./sessions.ts:32:9
Type error: Argument of type 'SQL | undefined' is not assignable to parameter of type 'SQLWrapper'.
Type 'undefined' is not assignable to type 'SQLWrapper'.

30 | eq(dbSessions.userId, userId),
31 | not(
> 32 | or(
| ^
33 | eq(dbSessions.name, DEFAULT_SESSION_NAME),
34 | eq(dbSessions.name, DAILY_SCRAMBLE_SESSION_NAME)
35 | )
```

I would assume that composing `not` and `or` like this should work. It also breaks for `and`.

I have this `tsconfig.json`:

```
{
"compilerOptions": {
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
```

The `strict` flag is set, but i this should still work even with the flag set, shouldn't it?

For reproducability here is the relevant schema.ts:

```
export const sessions = pgTable("sessions", {
id: serial("id").primaryKey(),
userId: integer("userId").references(() => users.id, { onDelete: "cascade" }).notNull(),
name: text("name").notNull().default(""),
}, (table) => ({
namePerUserUnique: uniqueIndex().on(table.name, table.userId),
}));
```

This issue can be easily overcome by utilizing De Morgan’s Law:

```
await db.delete(dbSessions).where(
and(
eq(dbSessions.id, sessionId),
eq(dbSessions.userId, userId),
ne(dbSessions.name, DEFAULT_SESSION_NAME),
ne(dbSessions.name, DAILY_SCRAMBLE_SESSION_NAME)
)
);
```

But i would still like to be able to rewrite it to the first form for better readability.

Contributor guide

Open the contributing guide

Research direction

The reproduction is in sessions.ts and the schema example is in schema.ts; start by locating the TypeScript definitions and return types of not, or, and and under strict mode. Reproduce the error with the supplied tsconfig.json, then verify that both nested compositions compile without producing SQLWrapper | undefined.

Written by the indexing model from the issue text.

Assessment

Tech stack
postgresql, typescript
Domain
databases
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.