[FEATURE]: Extending base schemas
Describe what you want
Is there a way for us to extends aschema declaration from existing schema? This way, we don't need to repeatedly declaring repeated columns over and over again.
For example:
export const timeSchemas = pgTable({
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
deletedAt: timestamp("deleted_at"),
})
export const songs = pgTable('songs', {
id: serial('id').primaryKey(),
// I can reuse the existing objects/schema/something similar
...timeSchemas,
});
You can inverse your approach
export const baseTable = <
TTableName extends string,
TColumnsMap extends Record<string, AnyPgColumnBuilder>
>(
name: TTableName,
columns: TColumnsMap
) => {
return pgTable(name, {
...columns,
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
deletedAt: timestamp("deleted_at"),
});
};
export const usersTable = baseTable("users", {
id: integer("id").primaryKey(),
});
I've split every table's schema in a different file (just like in the docs).
And I put the baseTable inside the index.ts file (I've tried to change the filename or the directory too).
But, I've got the following errors:
drizzle-kit generate:pg --schema=./src/db/schema/ --out=./src/db/migrations/
drizzle-kit: v0.18.0
drizzle-orm: v0.26.5
ReferenceError: Cannot access 'baseTable' before initialization
at Object.baseTable (/Users/hisamafahri/myprojects/packages/api/src/db/schema/index.ts:1:1)
at Object.get [as baseTable] (/Users/hisamafahri/myprojects/packages/api/src/db/schema/index.ts:14:45)
at Object.<anonymous> (/Users/hisamafahri/myprojects/packages/api/src/db/schema/accountsInVault.ts:7:32)
at Module._compile (node:internal/modules/cjs/loader:1159:14)
at Module._compile (/Users/hisamafahri/myprojects/node_modules/drizzle-kit/index.js:16334:30)
at Module._extensions..js (node:internal/modules/cjs/loader:1213:10)
at Object.newLoader [as .ts] (/Users/hisamafahri/myprojects/node_modules/drizzle-kit/index.js:16338:13)
at Module.load (node:internal/modules/cjs/loader:1037:32)
at Module._load (node:internal/modules/cjs/loader:878:12)
at Module.require (node:internal/modules/cjs/loader:1061:19)
Why not just use a plain object like so:
const timestamps = {
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
deletedAt: timestamp("deleted_at"),
}
export const songs = pgTable('songs', {
id: serial('id').primaryKey(),
// spread the object
...timestamps,
});
Follwing because its very important feature
Why not just use a plain object like so:
const timestamps = { createdAt: timestamp("created_at").defaultNow().notNull(), updatedAt: timestamp("updated_at").defaultNow().notNull(), deletedAt: timestamp("deleted_at"), } export const songs = pgTable('songs', { id: serial('id').primaryKey(), // spread the object ...timestamps, });
Seems to me that this is the best workaround. Is there something else Drizzle could provide to make this simpler?
I've split every table's schema in a different file (just like in the docs). And I put the
baseTableinside theindex.tsfile (I've tried to change the filename or the directory too).But, I've got the following errors:
drizzle-kit generate:pg --schema=./src/db/schema/ --out=./src/db/migrations/ drizzle-kit: v0.18.0 drizzle-orm: v0.26.5 ReferenceError: Cannot access 'baseTable' before initialization at Object.baseTable (/Users/hisamafahri/myprojects/packages/api/src/db/schema/index.ts:1:1) at Object.get [as baseTable] (/Users/hisamafahri/myprojects/packages/api/src/db/schema/index.ts:14:45) at Object.<anonymous> (/Users/hisamafahri/myprojects/packages/api/src/db/schema/accountsInVault.ts:7:32) at Module._compile (node:internal/modules/cjs/loader:1159:14) at Module._compile (/Users/hisamafahri/myprojects/node_modules/drizzle-kit/index.js:16334:30) at Module._extensions..js (node:internal/modules/cjs/loader:1213:10) at Object.newLoader [as .ts] (/Users/hisamafahri/myprojects/node_modules/drizzle-kit/index.js:16338:13) at Module.load (node:internal/modules/cjs/loader:1037:32) at Module._load (node:internal/modules/cjs/loader:878:12) at Module.require (node:internal/modules/cjs/loader:1061:19)
Just bring all common base schemas into another file like common.ts, and import it in other schema files.
DO NOT put these common base schemas in index.ts where you will export other schemas.
I am working in a monorepo. If I spread the object like mentioned:
const timestamps = {
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
}
export const songs = pgTable('songs', {
id: serial('id').primaryKey(),
// spread the object
...timestamps,
});
export type Song = typeof songs.$inferSelect;
and import the type in another package, I get:
(alias) type Song = {
[x: string]: any;
}
If I remove the spread timestamps, the type is passed successfully. I can create a new issue if needed.
@trompx try adding as const like so:
const timestamps = {
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
} as const
@ranjan-purbey It doesn't work unfortunately.
I also wanted to do the following:
export const date = (name: string) => {
return timestamp(name).defaultNow().notNull();
};
export const datesColumns = {
createdAt: date("created_at"),
updatedAt: date("updated_at"),
};
But doesn't work either.
In pgTable:
- doing:
...datesColumns,
The whole table types are lost:
(alias) type User = {
[x: string]: any;
}
- doing:
createdAt: date("created_at"),
updatedAt: date("updated_at"),
I get types
createdAt: any;
updatedAt: any;
- doing:
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
I get the correct types
createdAt: Date;
updatedAt: Date;
I want to mention that I use drizzle-orm/kysely.
drizzle-orm : 0.30.1
Please share a minimal reproducible example