Help with types relational query function

I've created a function that i use to paginate data with relations, removed all the paginating stuff for the post
// Types from https://github.com/drizzle-team/drizzle-orm/issues/695
type Schema = typeof primarySchemas;
type TSchema = ExtractTablesWithRelations<Schema>;

export type IncludeRelation<TableName extends keyof TSchema> = DBQueryConfig<
'one' | 'many',
boolean,
TSchema,
TSchema[TableName]
>['with'];

export type InferResultType<
TableName extends keyof TSchema,
With extends IncludeRelation<TableName> | undefined = undefined,
> = BuildQueryResult<
TSchema,
TSchema[TableName],
{
with: With;
}
>;

async paginatedQuery<
U extends keyof drizzleOrm.ExtractTablesWithRelations<typeof schema>,
TableRelations extends IncludeRelation<U>,
>(
table: BaseTable,
{
with: queryWith,
}: {
with: TableRelations;
},
) {

const tableName = this.getTableName(table);
const data: Array<InferResultType<U, typeof queryWith>> =
await this.db.query[tableName].findMany({
with: queryWith
});

return { data, meta };
}
// Types from https://github.com/drizzle-team/drizzle-orm/issues/695
type Schema = typeof primarySchemas;
type TSchema = ExtractTablesWithRelations<Schema>;

export type IncludeRelation<TableName extends keyof TSchema> = DBQueryConfig<
'one' | 'many',
boolean,
TSchema,
TSchema[TableName]
>['with'];

export type InferResultType<
TableName extends keyof TSchema,
With extends IncludeRelation<TableName> | undefined = undefined,
> = BuildQueryResult<
TSchema,
TSchema[TableName],
{
with: With;
}
>;

async paginatedQuery<
U extends keyof drizzleOrm.ExtractTablesWithRelations<typeof schema>,
TableRelations extends IncludeRelation<U>,
>(
table: BaseTable,
{
with: queryWith,
}: {
with: TableRelations;
},
) {

const tableName = this.getTableName(table);
const data: Array<InferResultType<U, typeof queryWith>> =
await this.db.query[tableName].findMany({
with: queryWith
});

return { data, meta };
}
right now this works, but the problem is i have to define the relations twice, once as a param for the generic type and again for the with parameter This is what ive done, im not sure why this doesn't yield the same results
async paginatedQuery<
U extends keyof drizzleOrm.ExtractTablesWithRelations<typeof schema>,
TableRelations extends IncludeRelation<U>, <-- Delete this and directly assign the type to with
>(
table: BaseTable,
{
with: queryWith,
}: {
with: IncludeRelation<U>,
},
) {
async paginatedQuery<
U extends keyof drizzleOrm.ExtractTablesWithRelations<typeof schema>,
TableRelations extends IncludeRelation<U>, <-- Delete this and directly assign the type to with
>(
table: BaseTable,
{
with: queryWith,
}: {
with: IncludeRelation<U>,
},
) {
Above change causes to miss the relational types in the return type 😦 Any TS aficionados willing to help 🙂
17 Replies
Angelelz
Angelelz10mo ago
The way you have it set up, typescript does not see the relations between U and BaseTable As far as typescript is concerned, you could be quering tableA and using the with object for tableB At least in a quick look, that's what it seems to me
Suji
SujiOP10mo ago
table:BaseTable isn't used in the findMany query, 🤔 I'm using that to get the tableName Let me update code snippet
Angelelz
Angelelz10mo ago
Can you put your code snippet in the typescript playground? some table definitions and relations and lets play around with it
Suji
SujiOP10mo ago
sure gimme a few mins
Suji
SujiOP10mo ago
https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbwFBzjAnmApnAQgV2ABsATARXyynQCUsBnfImAGhTUxwBFcKr0AwhAB2AM2ABzNqgzY4AUQAeMKAEMAxjAAqqgEZEGAdWAwAFnSKqYwEfWlwoWS9dtsAvnFFQIIOAHISKGAAL2CDAFpoED8AbiRQSFgOOQQ4AEFhdAAFCR19HA8vH39AkLCsSKgQAHowCXD1aCxY+PBoeFSJLG09AyExSRY4OryDIfxCEiGAN1UodVM5uELvXwCg0Iio2vrGxxaE9sQ4Us2Cz1WSjfLKmsh6GAlHenCAK3oWpCxFRPhG4QecCw4CIEHQWAYAGUFsDVHAALzDXK9LAACj8wLAoPBDD8Q2QqHEUAeADlVCAsAAuOCzeaLKDookPAD6wnJzXxcAMwgkZmpACYAKwANmWAEp7JZSezqbSFnN0VKYKz2XjjtzeaYBSLxfZYcRZXN5QyMSBVMQ1akNXy4ELRW4xQA6fDCYAAR0oqIl7FUsxgcwAkiRqRNgCR0b6rHNmWG-E6Xe7Pd6HXEvj8jv9AWBTBAYBB6NDTLCEUjRmi-NncxBmfQYWbLewwyHJujY8mxanvr84Jn4JjsRCLFYbACS45nCP6Kj2P2wRCC3XVPZUakRFghmbMuKEQA+OAr9ioSP+qDUteoyt5hdFs34w+oTzAJwkejUgDas5x19hjuPgZIAC69gPg4WCiFQWDCOoDDvpe+aFj+YZAfeDrAcMOZXtSm7oBeGHwYu3qoKhSAdkgSC9nAtY3nCiKpJ+g5OMOrhAiCc5QouQxwd+ZrLKm1TVEC9BEMAwgwOEJDAPQKLhMI3xicJslwAAArIDDqEEYBiQwCkwNUwgQOELpSeB4RzBI+AUqJ5G2PAJC6CWpzlCuHiqPQcCqJknJUcWKZkapcAITxiKqRAoiUYucT+VogU0QoyhqJoZb0MYZhDi4AIADwxTunbpkk-kBlBRD4CQWBpSOGVlmSFJAsokEvnAADWWDoKFcDRYue6IjwfDUP04gSBl7B+GufhwAAPv42F4uwugQBABgefYHXUctMVvlV7IAUgO5vn4ADuJimH4AG5d2BViFQdCMMwWicENqCbTVcn1W5zWtWFK2wvYKWmLVMCvXAhXqMVpXlSIlUotVWB7pNLqleIskkCW8NgSJWBTDtJYEMQ5CUNQ11MDAD3tTFa2LhtUNbfYBIPodNq-XERE7amogupoI5wF0PT5NDqL+vk1IZNkyL5GKiDsBRqRsjVHiItzZb9ZI-MoqR7CODA+BQMIcAyzgrnuZkcRuGRrnoFBnjs+lwyqBIIlWBjvXoCTACq-2A+9bVKCoGg8wYyVHeDmUhWF3lmjuy0okHbkvcIDXA6DZWMelGUuxHO3TjIKJC5kORljT9701qcAevwv32G41K06gRfUmW0dM8sbDi7TFECwY0MlgrVMUirYupuw-EqS8kj6Y4ks2ScUZC1AajO4V4FQITt33S7QwhyX+PoL9O5de5+3mrZuiOqX1Bvve7dYND7AAY6iMkAAsh5OHV3Ateb2XR0V2rqAa1rOskCjMbMi1kAS2SjCWVQB8TA2ztmyAGeN+AZVNFiNi3FVANiPH6OY1IVCUHsFxXBUBKBIDcDuVE9F2KrQljXI6Vd7x-lPGgYh657yEOYSQoi7gxRkUAf6N8AAGW+jCkB8NUII2+XEgA
TS Playground - An online editor for exploring TypeScript and JavaS...
The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.
Angelelz
Angelelz10mo ago
Cool, let me take a look
Angelelz
Angelelz10mo ago
https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbwFBzjAnmApnAQgV2ABsATARXyynQCUsBnfImAGhTUxwBFcKr0AwhAB2AM2ABzNqgzY4AUQAeMKAEMAxjAAqqgEZEGAdWAwAFnSKqYwEfWlwoWS9dtsAvnFFQIIOAHISKGAAL2CDAFpoED8AbiRQSFgOOQQ4AEFhdAAFCR19HA8vH39AkLCsSKgQAHowCXD1aCxY+PBoeFSJLG09AyExSRY4OryDIfxCEiGAN1UodVM5uELvXwCg0Iio2vrGxxaE9sQ4Us2Cz1WSjfLKmsh6GAlHenCAK3oWpCxFRPhG4QecCw4CIEHQWAYAGUFsDVHAALzDXK9LAACj8wLAoPBDD8Q2QqHEUAeADlVCAsAAuOCzeaLKDookPAD6wnJzXxcAMwgkZmpACYAKwANmWAEp7JZSezqbSFnN0VKYKz2XjjtzeaYBSLxfZYcRZXN5QyMSBVMQ1akNXy4ELRW4xQA6fDCYAAR0oqIl7FUsxgcwAkiRqRNgCR0b6rHNmWG-E6Xe7Pd6HXEvj8jv9AWBTBAYBB6NDTLCEUjRmi-NncxBmfQYWbLewwyHJujY8mxanvr84Jn4JjsRCLFYbACS45nCP6Kj2P2wRCC3XVPZUakRFghmbMuKEQA+OAr9ioSP+qDUteoyt5hdFs34w+oTzAJwkejUgDas5x19hjuPgZIAC69gPg4WCiFQWDCOoDDvpe+aFj+YZAfeDrAcMOZXtSm7oBeGHwYu3qoKhSAdkgSC9nAtY3nCiKpJ+g5OMOrhAiCc5QouQxwd+ZrLKm1TVEC9BEMAwgwOEJDAPQKLhMI3xicJslwAAArIDDqEEYBiQwCkwNUwgQOELpSeB4RzBI+AUqJ5G2PAJC6CWpzlCuHiqPQcCqJknJUcWKZkapcAITxiKqRAoiUYucT+VogU0QoyhqJoZb0MYZhDi4AIADwxTunbpkk-kBlBRD4CQWBpSOGVlmSFJAsokEvnAADWWDoKFcDRYue6IjwfDUP04gSBl7B+GufhwAAPv42F4uwugQBABgefYHXUctMVvlV7IAUgO5vn4ADuJimH4AG5d2BViFQdCMMwWicENqCbTVcn1W5zWtWFK2wvYKWmLVMCvXAhXqMVpXlSIlUotVWB7pNLqleIskkCW8NgSJWBTDtJYEMQ5CUNQ11MDAD3tTFa2LhtUNbfYBIPodNq-XERE7amogupoI5wF0PT5NDqL+vk1IZNkyL5GKiDsBRqRsjVHiItzZb9ZI-MoqR7CODA+BQMIcAyzgrnuZkcRuGRrnoFBnjs+lwyqBIIlWBjvXoCTACq-2A+9bVKCoGg8wYyVHeDmUhWF3lmjuy0okHbkvcIDXA6DZWMelGUuxHO3TjIKLUi7NP3vTWpwB6-C-fYbjUrTqAF9SZbR0zyxsOLtMUQLBjQyWCtUxSqJh6ob6t1gAFq5LNknFGJaqPt5q2bojrF9Qb73gP7AAY6iMkAAsh5OGV3A1dF-j6Cl+wvnq90Ws6yQUbG2R1kArZ4+IpP0823bbIA3j-DovR7HUQ2VdHQrveP8p40BQEoGhLi1IVCUBPu4MUZEr7+jfAABlXiApASC+5oMdFxIAA
TS Playground - An online editor for exploring TypeScript and JavaS...
The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.
Angelelz
Angelelz10mo ago
You were almost there This is cool helper, totally type safe
Suji
SujiOP10mo ago
nice, thanks a lot now i have bunch of cleaning upto do 😁
Angelelz
Angelelz10mo ago
you can delete this line: const tableName = getTableName(schema[table])
shreddish
shreddish9mo ago
hahah @Angelelz just following you around this discord - I am trying to implement your playground and I'm getting an error with my with condition. It's complaining about two different types with same name It looks like on the ExtractTableWithRelations type but not positive if maybes its something in my schema
No description
No description
Angelelz
Angelelz9mo ago
If you put it together in a playground I can take a look at it
shreddish
shreddish9mo ago
okay let me throw something together thank you! okay i think it has something to do with importing my schema definition from a barrel file when I import schema like so import * as schema from '@server/db/schema/addresses'; i get that error however if i do this
import { addresses } from '@server/db/schema/addresses';
const schema = { addresses };
import { addresses } from '@server/db/schema/addresses';
const schema = { addresses };
it works so im curious if it has something to do with barrel files and import * as
Angelelz
Angelelz9mo ago
Yeah, if it's pulling other stuff in that import, maybe
shreddish
shreddish9mo ago
yeah i just refactored and made sure i only have pgTables and relations exporting out of my schema files - can not get the barrel file to work and i really don't want to individually import my tables and relations from 15 different files just to build a const schema = {locations, locationsRelations....... object for all my exports just to go even further incase my schema definitions were not setup correct - i created a testDirectory with a barrel file exporting only the schemas you defined in your playground. Importing with * as breaks but importing each table individually and building the schema object seems to work - very confused okay looks like if i spread the * as into another object this might fix the problem but curious what the difference is - i know the * as is a namespace import but i thought it was identical to an object hahah sorry just rambling in here incase someone stumbles upon this later - so the spread syntax seemed to fix the issue however that required the db being defined in the same file as the paginatedQuery function... if i import the db i get the with error again okay - so i had to import both the db and the spread schema object from the db file instead of building the same schema spread object in the consuming paginatedQuery file so doing this db.ts
import * as allSchemas from '@server/db/schema';
import { drizzle } from 'drizzle-orm/postgres-js';
import { Client } from 'pg';

const connectionString = import.meta.env.VITE_DB_URL;

if (!connectionString) {
throw new Error('DB credentials error');
}

const client = new Client({ connectionString });
await client.connect();

export const schema = { ...allSchemas };

export const db = drizzle(client, { schema });
import * as allSchemas from '@server/db/schema';
import { drizzle } from 'drizzle-orm/postgres-js';
import { Client } from 'pg';

const connectionString = import.meta.env.VITE_DB_URL;

if (!connectionString) {
throw new Error('DB credentials error');
}

const client = new Client({ connectionString });
await client.connect();

export const schema = { ...allSchemas };

export const db = drizzle(client, { schema });
and making sure I import schema from db and not to just rebuild the object by importing and spreading again
import { db, schema } from '@server/db';

... other code

async function paginatedQuery<
U extends keyof ExtractTablesWithRelations<typeof schema>,
TableRelations extends IncludeRelation<U>,
>(
table: U,
{
with: queryWith,
}: {
with: TableRelations;
},
) {
const data = await db.query[table].findMany({
with: queryWith,
});

return data;
}
import { db, schema } from '@server/db';

... other code

async function paginatedQuery<
U extends keyof ExtractTablesWithRelations<typeof schema>,
TableRelations extends IncludeRelation<U>,
>(
table: U,
{
with: queryWith,
}: {
with: TableRelations;
},
) {
const data = await db.query[table].findMany({
with: queryWith,
});

return data;
}
shreddish
shreddish9mo ago
it never ends.... went to clean up the function and build into a class or helper function that can be imported but now I am getting typescript error about the inferred type exceeding max length for ts compiler
No description
TheLifeIsYours
TheLifeIsYours8mo ago
has anyone found out how to do this yet? We hare having issues where we are using joins with one and many, but it has no types associated with it, so we are getting any as a result.
Want results from more Discord servers?
Add your server