Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE]: Ability to specify selected fields dynamically #948

Closed
moshest opened this issue Jul 28, 2023 · 7 comments
Closed

[FEATURE]: Ability to specify selected fields dynamically #948

moshest opened this issue Jul 28, 2023 · 7 comments
Labels
enhancement New feature or request

Comments

@moshest
Copy link

moshest commented Jul 28, 2023

Describe what you want

I have a model on my project that fetching users from the database. Each time I need different set of fields and I would like to define a function with generics so only the exact fields I asked for will be return:

const findByEmail = async <P>(email: string, projection: P) => {
  const rows = await db
    .select(projection)
    .from(users)
    .where(eq(users.email, email))
    .limit(1);
  
  if (!rows.length) {
    return;
  }
  
  return rows[0];
}

And then I can ask only for the fields I want:

const userWithIdOnly = await findByEmail(email, { id: users.id });
      // ^ { id: number }
           
const userWithName =  = await findByEmail(email, { id: users.id, name: users.name });
      // ^ { id: number; name: string }

I encounter 2 problems when trying to implement this:

  1. There is no type I can use to extend P. I'm looking for something like P extends SelectedFields<typeof users>
  2. The current implementation breaks and produce invalid types in response. It seems that Drizzle expecting only static projection types and can't handle generic properly.

Any help will be appreciated.

@moshest moshest added the enhancement New feature or request label Jul 28, 2023
@Angelelz
Copy link
Collaborator

Angelelz commented Nov 21, 2023

The selection passed to select is too wide, you could select whatever you want from the database. like count, max, all kinds of functions, etc.
I guess you just need to manually type the generic parameter and the help the compiler by type casting.
Check this example implementation.

@Angelelz
Copy link
Collaborator

The trick is actually the "partial" generic parameter. That needs to exists somewhere for the inference to work. That's why type casting is needed. I think we can close this issue and if you think we could expose a type helper for something like this, please create a new one with your idea. I even went ahead and extended my last example to accept extra properties with proper types. See here

@FredericLatour
Copy link

Hi,
Does not seem to work with MySql.
I tried to convert the provided example implementation but it seems to be missing a parameter for MySqlSelectBase.
Would you mind providing the missing parameter. I tried to follow the never ending suite of extends but could not get it.
Thanks in advance.

example implementation converted to MySql

@Angelelz
Copy link
Collaborator

Angelelz commented Dec 7, 2023

The types changed a little bit in the last release. You actually need to use 'single' instead of 'partial' and mysql has an extra type parameter. See here

@FredericLatour
Copy link

Thanks a lot...
I just had to make a slight change because I'm using this in an effect-ts context. I had first to cast the result to unknown. I made some tests and it works correctly.

Here is a link for anyone who would be looking for the same thing:
mysql implementation in an effect-ts context

I had also published a post in the help section of Discord. I will answer myself by pointing to your solution and my slight change.

@mjbergman92
Copy link

mjbergman92 commented Oct 1, 2024

Dynamic selection is "impossible" once you try to do joins. I have tried for hours, even with type casting.

EDIT: I did find a way that is not fully dynamic by creating a fixed set of preset options and type casting... but that is not good for the long term.

@cyrilchapon
Copy link

@mjbergman92 , found a way. See #3560 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants