Creating a Generic Service for a Drizzle/Postgres Database in Effect Typescript

Hey, so I want to create an Effect.Service which loosely abstracts over a drizzle/postgres database.
When I say "loosely" here I mean that I want to pass a drizzle schema to the service and let the schema's type be reflected in the drizzle object the service returns.
I can't just pass the schema as an argument to some Layer function as I do with the database connection details, because then the schema type will not be reflected in the service.
This brought me into the rabbit hole of "generic services" and after digging through discord and learning that this is an anti pattern and best solved with a "service factory" I came up with the following code and am now looking for feedback if what I did is fine or not and if it could maybe be solved better. Here is the code:

export const makePgDatabase = <
  Id extends string,
  TSchema extends Record<string, unknown> = Record<string, never>,
>(
  id: Id,
  schema: TSchema
) =>
  class PgDatabase extends Effect.Service<PgDatabase>()(
    `@db/PgDatabase<${id}>`,
    {
      effect: PgDrizzle.make({
        schema,
        casing: 'snake_case',
      }),
    }
  ) {
    static PgClient = (config: Config) =>
      PgDatabase.Default.pipe(Layer.provide(PgClient.layer(config)))

    static PgClientFromEnv = Effect.gen(function* () {
      const config = yield* Config.all({
        url: Config.redacted('DATABASE_URL'),
      })
      return PgDatabase.PgClient(config)
    }).pipe(Layer.unwrapEffect)
  }

class TestPgDatabase extends makePgDatabase('Test', schema) {}

Effect.gen(function* () {
  const db = yield* TestPgDatabase
  // db is now properly typed with the schema so stuff like db.query.someTable.findMany() will work
})
Was this page helpful?