Skip to content

Instantly share code, notes, and snippets.

@APZelos
Last active September 4, 2025 09:41
Show Gist options
  • Select an option

  • Save APZelos/66429ea7c0928f073ebaf6fb1800cf99 to your computer and use it in GitHub Desktop.

Select an option

Save APZelos/66429ea7c0928f073ebaf6fb1800cf99 to your computer and use it in GitHub Desktop.
Surfacing the `PostgresError` from Drizzle's `DrizzleQueryError` when working with Drizzle in an Effect project.
import type {SqlError} from "@effect/sql"
import * as D from "drizzle-orm"
import {Cause, Chunk, Data, Effect as E, Option, pipe, Runtime} from "effect"
import {PostgresError} from "postgres"
interface KnownPostgresErrorPayload {
cause: PostgresError
sqlError: SqlError.SqlError
detail?: string
schemaName?: string
tableName?: string
columnName?: string
constraintName?: string
}
export class UnknownDatabaseException extends Data.TaggedError(
"database/UnknownDatabaseException",
)<{
cause: unknown
}> {}
export class DrizzleQueryError extends Data.TaggedError("database/DrizzleQueryError")<{
cause: D.DrizzleQueryError
}> {}
export class ConnectionError extends Data.TaggedError("database/ConnectionError")<{
cause: PostgresError
sqlError: SqlError.SqlError
}> {}
export class ForeignKeyViolationError extends Data.TaggedError(
"database/ForeignKeyViolationError",
)<KnownPostgresErrorPayload> {}
export class UniqueViolationError extends Data.TaggedError(
"database/UniqueViolationError",
)<KnownPostgresErrorPayload> {}
export class DataError extends Data.TaggedError("database/DataError")<KnownPostgresErrorPayload> {}
export class NotNullViolationError extends Data.TaggedError(
"database/NotNullViolationError",
)<KnownPostgresErrorPayload> {}
export class CheckViolationError extends Data.TaggedError(
"database/CheckViolationError",
)<KnownPostgresErrorPayload> {}
export class ExclusionViolationError extends Data.TaggedError(
"database/ExclusionViolationError",
)<KnownPostgresErrorPayload> {}
export class RestrictViolationError extends Data.TaggedError(
"database/RestrictViolationError",
)<KnownPostgresErrorPayload> {}
export class DeadlockDetectedError extends Data.TaggedError(
"database/DeadlockDetectedError",
)<KnownPostgresErrorPayload> {}
export class SerializationFailureError extends Data.TaggedError(
"database/SerializationFailureError",
)<KnownPostgresErrorPayload> {}
export class OutOfMemoryError extends Data.TaggedError(
"database/OutOfMemoryError",
)<KnownPostgresErrorPayload> {}
export class TooManyConnectionsError extends Data.TaggedError(
"database/TooManyConnectionsError",
)<KnownPostgresErrorPayload> {}
export class InvalidTransactionStateError extends Data.TaggedError(
"database/InvalidTransactionStateError",
)<KnownPostgresErrorPayload> {}
export class SyntaxOrAccessError extends Data.TaggedError(
"database/SyntaxOrAccessError",
)<KnownPostgresErrorPayload> {}
export class InsufficientResourcesError extends Data.TaggedError(
"database/InsufficientResourcesError",
)<KnownPostgresErrorPayload> {}
export class UnknownPostgresException extends Data.TaggedError(
"database/UnknownPostgresException",
)<{
cause: PostgresError
sqlError: SqlError.SqlError
}> {}
export function mapSqlError(sqlError: SqlError.SqlError) {
const drizzleQueryError = pipe(
Cause.failures(Cause.fail(sqlError.cause)),
Chunk.findFirst((error) => error instanceof D.DrizzleQueryError),
)
if (Option.isNone(drizzleQueryError)) {
return new UnknownDatabaseException({cause: sqlError})
}
return pipe(
drizzleQueryError,
Option.flatMap((error) => {
if (Runtime.isFiberFailure(error.cause)) {
return Cause.failureOption(error.cause[Runtime.FiberFailureCauseId])
}
return Option.none()
}),
Option.flatMap((error) => {
if (hasPostgresErrorCause(error)) {
return Option.some(error.cause)
}
return Option.none()
}),
Option.map((error) => {
const payload = {
cause: error,
sqlError,
detail: error.detail,
schemaName: error.schema_name,
tableName: error.table_name,
columnName: error.column_name,
constraintName: error.constraint_name,
}
if (error.code === "23503") return new ForeignKeyViolationError(payload)
if (error.code === "23505") return new UniqueViolationError(payload)
if (error.code === "23502") return new NotNullViolationError(payload)
if (error.code === "23514") return new CheckViolationError(payload)
if (error.code === "23P01") return new ExclusionViolationError(payload)
if (error.code === "23001") return new RestrictViolationError(payload)
if (error.code === "40001") return new SerializationFailureError(payload)
if (error.code === "40P01") return new DeadlockDetectedError(payload)
if (error.code === "53200") return new OutOfMemoryError(payload)
if (error.code === "53300") return new TooManyConnectionsError(payload)
if (error.code.startsWith("08")) return new ConnectionError(payload)
if (error.code.startsWith("22")) return new DataError(payload)
if (error.code.startsWith("25")) return new InvalidTransactionStateError(payload)
if (error.code.startsWith("42")) return new SyntaxOrAccessError(payload)
if (error.code.startsWith("53")) return new InsufficientResourcesError(payload)
return new UnknownPostgresException(payload)
}),
Option.match({
onSome: (error) => error,
onNone: () => new DrizzleQueryError({cause: drizzleQueryError.value}),
}),
)
}
export const eMapSqlError = E.mapError(mapSqlError)
function hasPostgresErrorCause(error: unknown): error is {cause: PostgresError} {
return (
!!error && typeof error === "object" && "cause" in error && error.cause instanceof PostgresError
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment