Skip to content

Instantly share code, notes, and snippets.

@kandros
Created July 27, 2025 19:47
Show Gist options
  • Save kandros/a727135eff5840d68383b10aa33cfb52 to your computer and use it in GitHub Desktop.
Save kandros/a727135eff5840d68383b10aa33cfb52 to your computer and use it in GitHub Desktop.
import * as PgDrizzle from "@effect/sql-drizzle/Pg";
import { PgClient } from "@effect/sql-pg";
import { Config, Effect } from "effect";
import * as schema from "~/lib/server/schema";
const PgLive = PgClient.layerConfig({
url: Config.redacted("DATABASE_URL"),
});
export class DrizzleClient extends Effect.Service<DrizzleClient>()("app/DrizzleClient", {
dependencies: [PgLive],
effect: Effect.gen(function* () {
const db = yield* PgDrizzle.make<typeof schema>({
schema: schema,
});
return db;
}),
}) {}
@akshat-OwO
Copy link

hi @kandros, thanks for this. I am having trouble implementing error handling with a runtime. Can you give an example for that too?

@kandros
Copy link
Author

kandros commented Aug 19, 2025

hi @kandros, thanks for this. I am having trouble implementing error handling with a runtime. Can you give an example for that too?

Can you give an example? I’m using it with a managed runtime

@akshat-OwO
Copy link

same here

// ManagedRuntime.ManagedRuntime<Database | Auth, ConfigError | SqlError>
export const AppRuntime = ManagedRuntime.make(AppLive);

Auth here is an another service which depends on Database.Default

and the runtime is giving ConfigError or SqlError but how do you handle it?

when i call db query i don't get those errors in Effect.catchTags

const program = Effect.gen(function* () {
      const db = yield* Database;
      const todos = yield* Effect.tryPromise(() =>
          db.select().from(todoTable)
      );
      return todos
}).pipe(
      Effect.catchTag("", () => {})
)

await AppRuntime.runPromise(program)

@kandros
Copy link
Author

kandros commented Aug 20, 2025

@akshat-OwO

Use yield* of the db

const db = yield* DrizzleClient;
const result = yield* db.insert(documents).values(input).returning();

By using tryPromise you exit “effect land” and lose the errors

@akshat-OwO
Copy link

Thanks man! can you give me an example of how you are mapping SqlError.

i am getting this error cause and not able to get the PostgresError :(

(FiberFailure) SqlError: Failed to execute statement
    at cause (/home/akshat/Documents/git/commander/node_modules/.pnpm/@[email protected]_@[email protected]_@[email protected][email protected]_42ab70da82d8a05f56a95887e3aec16b/node_modules/@effect/sql-pg/src/PgClient.ts:220:31)
    at process.processTicksAndRejections (node:internal/process/task_queues:105:5) {
  [cause]: PostgresError: duplicate key value violates unique constraint "course_code_unique"
      at ErrorResponse (file:///home/akshat/Documents/git/commander/node_modules/.pnpm/[email protected]/node_modules/postgres/src/connection.js:794:26)
      at handle (file:///home/akshat/Documents/git/commander/node_modules/.pnpm/[email protected]/node_modules/postgres/src/connection.js:480:6)
      at Socket.data (file:///home/akshat/Documents/git/commander/node_modules/.pnpm/[email protected]/node_modules/postgres/src/connection.js:315:9)
      at Socket.emit (node:events:518:28)
      at addChunk (node:internal/streams/readable:561:12)
      at readableAddChunkPushByteMode (node:internal/streams/readable:512:3)
      at Readable.push (node:internal/streams/readable:392:5)
      at TCP.onStreamRead (node:internal/stream_base_commons:189:23)
      at TCP.callbackTrampoline (node:internal/async_hooks:130:17)
}```

@kandros
Copy link
Author

kandros commented Aug 20, 2025

yeah unfortunately I cannot use PostgresError from the postgres library either. I have to utils to map the SqlError to original error data. I'm not at the computer now, will add this later

@akshat-OwO
Copy link

thanks!

@kandros
Copy link
Author

kandros commented Aug 21, 2025

thanks!

this is the abomination Im using while waiting the native Drizzle effect package 😅

the json stringify and parse is to get to some detail only available during serialization (calling toJSON methods internally) or errors that are not exposed

import { SqlError } from "@effect/sql/SqlError";

export function extractSqlErrorDetails(sqlError: SqlError) {
  const jsonStr = JSON.stringify(sqlError);
  const parsed = JSON.parse(jsonStr);

  function findPostgresErrorInJson(obj: any): any {
    if (obj && typeof obj === "object") {
      if (obj.name === "PostgresError") {
        return obj;
      }

      for (const key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
          const result = findPostgresErrorInJson(obj[key]);
          if (result) return result;
        }
      }
    }
    return null;
  }

  const pgError = findPostgresErrorInJson(parsed);
  if (pgError) {
    return {
      code: pgError.code,
      detail: pgError.detail,
      constraint: pgError.constraint_name,
      schema: pgError.schema_name,
      table: pgError.table_name,
    };
  }
  return null;
}

result is like

{
  code: "23505",
  detail: "Key (name)=(due) already exists.",
  constraint: "test_name_key",
  schema: "public",
  table: "test",
}

@akshat-OwO
Copy link

thank you @kandros! I was stuck on this for a long time :)
Please update this as well when there is a better way to handle this 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment