makeWithConfig in `@effect/[email protected]` does't accept a generic schema type.
What version of Effect is running?
3.15.0
What steps can reproduce the bug?
- Install
@effect/[email protected] - Use
@effect/sql-drizzle/Pg - Try creating a layer with
layerWithConfig
import * as PgDrizzle from '@effect/sql-drizzle/Pg';
import { PgClient } from '@effect/sql-pg';
import { Cause, Config, Console, Layer } from 'effect';
import * as todoSchema from './schemas/todo.js';
import * as authSchema from './schemas/auth.js';
const DbSchema = { ...authSchema, ...todoSchema}
const PgLive = PgClient.layerConfig({
url: Config.redacted('DATABASE_URL'),
}).pipe(Layer.tapErrorCause((cause) => Console.log(Cause.pretty(cause))));
const DrizzleLive = PgDrizzle.layerWithConfig({
casing: 'snake_case',
schema: DbSchema, // ==> gives a type error
}).pipe(Layer.provide(PgLive));
export const DatabaseLive = Layer.mergeAll(PgLive, DrizzleLive);
You will see a type of error in the schema parameter of layerWithConfig.
Error Message:
Type '{ todosTable: PgTableWithColumns<{ name: "todos"; schema: undefined; columns: { id: PgColumn<{ name: "id"; tableName: "todos"; dataType: "string"; columnType: "PgUUID"; data: string; driverParam: string; notNull: true; hasDefault: true; ... 6 more ...; generated: undefined; }, {}, {}>; title: PgColumn<...>; complete...' is not assignable to type 'Record<string, never>'.
Property 'todosTable' is incompatible with index signature.
Type 'PgTableWithColumns<{ name: "todos"; schema: undefined; columns: { id: PgColumn<{ name: "id"; tableName: "todos"; dataType: "string"; columnType: "PgUUID"; data: string; driverParam: string; notNull: true; hasDefault: true; ... 6 more ...; generated: undefined; }, {}, {}>; title: PgColumn<...>; completed: PgColumn<.....' is not assignable to type 'never'. (ts 2322)
What is the expected behavior?
I would expect makeWithConfig to accept generics just as make. With generics, we would be able to use all Drizzle table schemas as a unified schema.
const DbSchema = { ...authSchema, ...todoSchema}
What do you see instead?
/**
* Accepts a generic schema
*/
export const make = <TSchema extends Record<string, unknown> = Record<string, never>>(
config?: Omit<DrizzleConfig<TSchema>, "logger">
): Effect.Effect<PgRemoteDatabase<TSchema>, never, Client.SqlClient> =>
Effect.gen(function*() {
const client = yield* Client.SqlClient
const db = drizzle(yield* makeRemoteCallback, config)
registerDialect((db as any).dialect, client)
return db
})
/**
* Doesn't accept a generic schema
*/
export const makeWithConfig: (config: DrizzleConfig) => Effect.Effect<PgRemoteDatabase, never, Client.SqlClient> = (
config
) =>
Effect.gen(function*() {
const client = yield* Client.SqlClient
const db = drizzle(yield* makeRemoteCallback, config)
registerDialect((db as any).dialect, client)
return db
})
Additional information
As layerWithConfig depends on makeWithConfig, it's pretty much unusable given that many use-cases have their schemas defined as in the example above.
Problem is likely the lack of generic on pgRemoteDatabase on the context tag is defaulting the field value to never.
@afonsomatos yeah. Texted about it in Discord as well.
layers cannot be generic so accepting a schema in the base layer would not have any effect, the way to use ORM features like shown in tests is:
import * as SqliteDrizzle from "@effect/sql-drizzle/Sqlite"
import * as D from "drizzle-orm/sqlite-core"
import { Effect } from "effect"
export const users = D.sqliteTable("users", {
id: D.integer("id").primaryKey(),
name: D.text("name"),
snakeCase: D.text("snake_case")
})
export class ORM extends Effect.Service<ORM>()("ORM", {
effect: SqliteDrizzle.make({ schema: { users } })
}) {}
export const program = Effect.gen(function*() {
const orm = yield* ORM
yield* orm.query.users.findMany()
})
You basically need to create your own specific service that identifies the drizzle instance with the schema