DB and Transaction types

I am creating a drizzle instance like this
import { drizzle } from 'drizzle-orm/postgres-js';
const db = drizzle(client, {
schema,
casing: 'snake_case',
logger: false
});
import { drizzle } from 'drizzle-orm/postgres-js';
const db = drizzle(client, {
schema,
casing: 'snake_case',
logger: false
});
Now I want to allow for functions to pass in a transaction or drizzle db
async function updateFoo(params: {
tx?: Transaction | DB,
}) : Promise<void> {
const { tx = db } = params;
async function updateFoo(params: {
tx?: Transaction | DB,
}) : Promise<void> {
const { tx = db } = params;
I am somewhat lost on the types. Or is there a better way of allowing for optional transactions in a function?
19 Replies
Mario564
Mario5642w ago
@tcurdt For DB, you can type it as typeof db; Transaction can be types as PgTransaction<PostgresJsQueryResultHKT>. If you're using RQB, you'd do this: PgTransaction<PostgresJsQueryResultHKT, typeof schema>
tcurdt
tcurdtOP2w ago
Thanks, @Mario564 ... When I use typeof db it complains. But this looks better so far.
export type DB = PostgresJsDatabase<typeof schema>;
export type Transaction = PgTransaction<PostgresJsQueryResultHKT, typeof schema>
export type DB = PostgresJsDatabase<typeof schema>;
export type Transaction = PgTransaction<PostgresJsQueryResultHKT, typeof schema>
Not entirely sure why this is better though.
Mario564
Mario5642w ago
typeof db should be almost the same as what you did above
tcurdt
tcurdtOP2w ago
But there seems to be a problem caused by & $client: any;
Mario564
Mario5642w ago
The only difference is that if you want access to the $client method, you have to add that to your definition (PostgresJsDatabase<typeof schema> & { $client: /* typeof your client instance */ } I believe for postgres.js, it should be like this:
import type postgres from 'postgres';

export type DB = PostgresJsDatabase<typeof schema> & { $client: postgres.Sql<{}> };
import type postgres from 'postgres';

export type DB = PostgresJsDatabase<typeof schema> & { $client: postgres.Sql<{}> };
tcurdt
tcurdtOP2w ago
What's the $client for? And eslint complains about the {} it suggests object or unknown
Mario564
Mario5642w ago
It's not mandatory, you can leave it out if you want, but it allows you to easily access the client instance that Drizzle uses under the hood for querying the DB A way to workaround the ESLint issue is to either ESLint ignore it or replace {} with NonNullable<unknown> which both resolve to the same type
tcurdt
tcurdtOP2w ago
That seems to work. Thank you so much. Me and the TS typing system are somehow not getting friendly enough.
Mario564
Mario5642w ago
No worries. We'll eventually document how to type common variables like these sometime in the future to save people some headache
tcurdt
tcurdtOP2w ago
I spoke to soon.
export type DB = PostgresJsDatabase<typeof schema>;
// export type DB = PostgresJsDatabase<typeof schema> & { $client: postgres.Sql<NonNullable<unknown>> };

async function updateSurveyHash(params: {
tx?: Transaction | DB,
}) : Promise<void> {

const { tx = db } = params;
export type DB = PostgresJsDatabase<typeof schema>;
// export type DB = PostgresJsDatabase<typeof schema> & { $client: postgres.Sql<NonNullable<unknown>> };

async function updateSurveyHash(params: {
tx?: Transaction | DB,
}) : Promise<void> {

const { tx = db } = params;
The first one works just fine. The 2nd one (with $client) gives
ts: The expected type comes from property 'tx' which is declared here on type '{ tx?: DB | Transaction | undefined; }'
ts: The expected type comes from property 'tx' which is declared here on type '{ tx?: DB | Transaction | undefined; }'
I guess I just go with the first version for now. But it would be nice to understand the difference that causes this here.
Mario564
Mario5642w ago
Can you show me the full type error?
tcurdt
tcurdtOP2w ago
Sure.
async function updateSurveyHash(params: {
tx?: Transaction | DB,
surveyId: SurveyId,
}) : Promise<void> {

const { surveyId, tx = db } = params;
async function updateSurveyHash(params: {
tx?: Transaction | DB,
surveyId: SurveyId,
}) : Promise<void> {

const { surveyId, tx = db } = params;
gives
ts: The expected type comes from property 'tx' which is declared here on type '{ tx?: DB | Transaction | undefined; surveyId: SurveyId; }'
ts: The expected type comes from property 'tx' which is declared here on type '{ tx?: DB | Transaction | undefined; surveyId: SurveyId; }'
Mario564
Mario5642w ago
Need more info on the last code block you gave. It shows what TS expects but doesn't contain what the error itself is
tcurdt
tcurdtOP2w ago
The complaint is on the tx? ... you mean, you need to see where it is used?
Mario564
Mario5642w ago
TS should be showing a more detailed error. Could you provide a screenshot of you hovering over the problematic line?
tcurdt
tcurdtOP2w ago
Hm ... it really is only providing that
No description
Mario564
Mario5642w ago
Oh, that's strange Not sure what to make of it, it seems like your editor isn't providing the full error, as it should look like this:
Type '...' is not assignable to type '...'. Object literal may only specify known properties, and '...' does not exist in type '...'.ts(...) ...(..., ...): The expected type comes from property '...' which is declared here on type '...'
Type '...' is not assignable to type '...'. Object literal may only specify known properties, and '...' does not exist in type '...'.ts(...) ...(..., ...): The expected type comes from property '...' which is declared here on type '...'
tcurdt
tcurdtOP2w ago
I just tried and switched editors. I had a hunch it might be the reason.
Type 'PgTransaction<PostgresJsQueryResultHKT, typeof import("foo/backend-sveltekit/src/lib/server/db/schema"), ExtractTablesWithRelations<typeof import("foo/backend-sveltekit/src/lib/server/db/schema")>>' is not assignable to type 'DB | Transaction | undefined'.
Type 'PgTransaction<PostgresJsQueryResultHKT, typeof import("foo/backend-sveltekit/src/lib/server/db/schema"), ExtractTablesWithRelations<typeof import("foo/backend-sveltekit/src/lib/server/db/schema")>>' is not assignable to type 'Transaction'.
Types of property 'schema' are incompatible.
Type '{ fullSchema: Record<string, unknown>; schema: ExtractTablesWithRelations<typeof import("foo/backend-sveltekit/src/lib/server/db/schema")>; tableNamesMap: Record<...>; } | undefined' is not assignable to type '{ fullSchema: Record<string, unknown>; schema: Record<string, never>; tableNamesMap: Record<string, string>; } | undefined'.
Type '{ fullSchema: Record<string, unknown>; schema: ExtractTablesWithRelations<typeof import("foo/backend-sveltekit/src/lib/server/db/schema")>; tableNamesMap: Record<...>; }' is not assignable to type '{ fullSchema: Record<string, unknown>; schema: Record<string, never>; tableNamesMap: Record<string, string>; }'.
Types of property 'schema' are incompatible.
Type 'ExtractTablesWithRelations<typeof import("foo/backend-sveltekit/src/lib/server/db/schema")>' is not assignable to type 'Record<string, never>'.
Property 'tableSessions' is incompatible with index signature.
Type '{ tsName: "tableSessions"; dbName: "sessions"; columns: { id: PgColumn<{ name: "id"; tableName: "sessions"; dataType: "string"; columnType: "PgText"; data: string; driverParam: string; notNull: true; hasDefault: false; ... 6 more ...; generated: undefined; }, {}, {}>; userId: PgColumn<...>; superadminId: PgColumn<.....' is not assignable to type 'never'.
Type 'PgTransaction<PostgresJsQueryResultHKT, typeof import("foo/backend-sveltekit/src/lib/server/db/schema"), ExtractTablesWithRelations<typeof import("foo/backend-sveltekit/src/lib/server/db/schema")>>' is not assignable to type 'DB | Transaction | undefined'.
Type 'PgTransaction<PostgresJsQueryResultHKT, typeof import("foo/backend-sveltekit/src/lib/server/db/schema"), ExtractTablesWithRelations<typeof import("foo/backend-sveltekit/src/lib/server/db/schema")>>' is not assignable to type 'Transaction'.
Types of property 'schema' are incompatible.
Type '{ fullSchema: Record<string, unknown>; schema: ExtractTablesWithRelations<typeof import("foo/backend-sveltekit/src/lib/server/db/schema")>; tableNamesMap: Record<...>; } | undefined' is not assignable to type '{ fullSchema: Record<string, unknown>; schema: Record<string, never>; tableNamesMap: Record<string, string>; } | undefined'.
Type '{ fullSchema: Record<string, unknown>; schema: ExtractTablesWithRelations<typeof import("foo/backend-sveltekit/src/lib/server/db/schema")>; tableNamesMap: Record<...>; }' is not assignable to type '{ fullSchema: Record<string, unknown>; schema: Record<string, never>; tableNamesMap: Record<string, string>; }'.
Types of property 'schema' are incompatible.
Type 'ExtractTablesWithRelations<typeof import("foo/backend-sveltekit/src/lib/server/db/schema")>' is not assignable to type 'Record<string, never>'.
Property 'tableSessions' is incompatible with index signature.
Type '{ tsName: "tableSessions"; dbName: "sessions"; columns: { id: PgColumn<{ name: "id"; tableName: "sessions"; dataType: "string"; columnType: "PgText"; data: string; driverParam: string; notNull: true; hasDefault: false; ... 6 more ...; generated: undefined; }, {}, {}>; userId: PgColumn<...>; superadminId: PgColumn<.....' is not assignable to type 'never'.
seems like the transaction type is slightly different
PgTransaction<PostgresJsQueryResultHKT, typeof import("foo/src/lib/server/db/schema"), ExtractTablesWithRelations<typeof import("foo/src/lib/server/db/schema")>>
PgTransaction<PostgresJsQueryResultHKT, typeof import("foo/src/lib/server/db/schema"), ExtractTablesWithRelations<typeof import("foo/src/lib/server/db/schema")>>
Deniz
Deniz2w ago
How does this work with node-postgres? I figured it out on my own!
type DB = NodePgDatabase<Schema>;
type Transaction = NodePgTransaction<
Schema,
ExtractTablesWithRelations<Schema>
>;
type DB = NodePgDatabase<Schema>;
type Transaction = NodePgTransaction<
Schema,
ExtractTablesWithRelations<Schema>
>;
This worked for me.

Did you find this page helpful?