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]: pick columns from getTableColumns #3034

Open
hyunbinseo opened this issue Oct 1, 2024 · 4 comments · May be fixed by #3921
Open

[FEATURE]: pick columns from getTableColumns #3034

hyunbinseo opened this issue Oct 1, 2024 · 4 comments · May be fixed by #3921

Comments

@hyunbinseo
Copy link

Describe what you want

Current getTableColumns() does not support partial select.

You need to destructure and leave unused variables behind:

https://orm.drizzle.team/docs/goodies#get-table-information

// password, role is unused
const { password, role, ...rest } = getTableColumns(user);

await db.select({ ...rest }).from(users);

I hope pickTableColumns is provided by Drizzle for better DX.

// { id: string; code: string }[];
const select1 = await db
  .select(pickTableColumns(loginTable, ['id', 'code'])) //
  .from(loginTable);

// { contact: string; id: string; code: string }[];
const select2 = await db
  .select({
    ...pickTableColumns(loginTable, ['id', 'code']),
    ...pickTableColumns(userTable, ['contact'])
  })
  .from(loginTable)
  .innerJoin(userTable, eq(userTable.id, loginTable.userId));

This is the source code I am using:

import { getTableColumns, type Table } from 'drizzle-orm';

export const pickTableColumns = <
  T extends Table, //
  const ColumnName extends keyof T['_']['columns']
>(
  table: T,
  columnNames: ColumnName[]
) => {
  type Picked = Pick<T['_']['columns'], ColumnName>;
  const picked: Partial<Picked> = {};
  const columns = getTableColumns(table);
  for (const columnName of columnNames) {
    picked[columnName] = columns[columnName];
  }
  return picked as Picked;
};
@hyunbinseo hyunbinseo added the enhancement New feature or request label Oct 1, 2024
@lasseklovstad
Copy link

lasseklovstad commented Oct 21, 2024

Could do somthing simular to the query syntax maybe? So you could reuse them.

await db.select(getTableColumns(users, { id: true, name: true })).from(users);

@L-Mario564 L-Mario564 added improvement qb/crud and removed enhancement New feature or request labels Oct 24, 2024
@lasseklovstad
Copy link

lasseklovstad commented Dec 13, 2024

I made a simple util function that works for me:

import type { Table} from "drizzle-orm";

export const getFilteredTableColumns = <
  T extends Table,
  K extends keyof T["_"]["columns"],
>(
  table: T,
  includedColumns: Record<K, true>,
): Pick<T["_"]["columns"], K> => {
  const allColumns = getTableColumns(table);
  const result = {} as Pick<T["_"]["columns"], K>;

  for (const key in includedColumns) {
    if (includedColumns[key]) {
      result[key] = allColumns[key];
    }
  }
  return result;
};

I am not a typescript wizard, but I have tested it with the drizzle selects and it should infere everything:

const users = table(
  "users",
  {
    id: uuid().primaryKey().defaultRandom(),
    firstName: text(),
    lastName: text(),
  },
  (table) => [index().on(table.clerkUserId)],
);

const test = () => {
  return db
    .select(getFilteredTableColumns(users, { lastName: true }))
    .from(users);
};

const result = await test();

/**
Return type:
const result: {
    lastName: string | null;
}[]

**/

@productdevbook
Copy link

@lasseklovstad pr sent, I included you in the commit. For your information. I played a little bit in the code.

@lasseklovstad
Copy link

Nice

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants