I am starting out a new project with Drizzle ORM. Starting out with some assumptions:
The primary keys on all the tables in my database will be uniformly uniformly typed and they will all be called id
.
All the foreign keys will be in the form of table_name_id
in the database and the model property will always be tableNameId
.
Since I can make these assumptions, I thought I could significantly reduce the amount of boilerplate required for specifying foreign keys:
import {
type PgColumn,
type PgTableWithColumns,
pgTableCreator,
serial,
} from "drizzle-orm/pg-core";
import { camelCase, snakeCase } from "lodash";
export const pgTable = pgTableCreator((name) => {
return `some-app_${name}`;
});
export function id() {
return serial("id").primaryKey();
}
type TableWithId = PgTableWithColumns<{
name: string;
schema: string | undefined;
dialect: "pg";
columns: {
id: PgColumn;
};
}>;
export function fk(...relations: (TableWithId | TableWithId[])[]) {
return Object.fromEntries(
relations.flatMap((entry) => {
const isOptional = Array.isArray(entry);
const tables = isOptional ? entry : [entry];
return tables.map((table) => {
const columnName = `${snakeCase(`)}_id`;
const propertyName = `${camelCase(table._.name)}Id`;
const column = bigint(columnName, { mode: "number" }).references(() => {
return table.id;
});
return [propertyName, isOptional ? column : column.notNull()];
});
}),
);
}
This code is intended to be used as such:
export const contact = pgTable("contacts", {
id: id(),
firstName: varchar("first_name", { length: 128 }).notNull(),
lastName: varchar("last_name", { length: 128 }).notNull(),
...fk(phone, [email], [address]),
...timestamps(),
});
Here a relation to the phone and email tables are mandatory (not null), but the relation to the email and address are optional.
The issue arises with accessing the name for a given PgTable
. When I inspect the type of contact
in my editor I see that they are type hinted with PgTableWithColumns
. Which is what I used in the type hint to the fk
function.
As a result as far as Typescript is concerned the function is correct. However when I run the code, I get the error:
TypeError: Cannot read properties of undefined (reading 'name')
This is referring to the expression: table._.name
. When I log out table, I see that it does not match the type. The underscore property is infact missing, but the name provided to the table is present in a symbol key Symbol(drizzle:BaseName)
.
However, I am not sure how to access this property as I have not been able to import the symbol from anywhere.
It seems like the types for this package are broken and I might end up filing a bug with drizzle. But I kind of want to get this to work.
Any ideas?
How about getTableName
?
import { getTableName } from "drizzle-orm";
const tableName = getTableName(table);