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

feat(drizzle): allow to customize the drizzle schema with before / after init hooks #8196

Merged
merged 25 commits into from
Sep 25, 2024

Conversation

r1tsuu
Copy link
Member

@r1tsuu r1tsuu commented Sep 12, 2024

Adds abillity to customize the generated Drizzle schema with beforeSchemaInit and afterSchemaInit. Could be useful if you want to preserve the existing database schema / override the generated one with features that aren't supported from the Payload config.

Docs:

beforeSchemaInit

Runs before the schema is built. You can use this hook to extend your database structure with tables that won't be managed by Payload.

import { postgresAdapter } from '@payloadcms/db-postgres'
import { integer, pgTable, serial } from 'drizzle-orm/pg-core'

postgresAdapter({
  beforeSchemaInit: [
    ({ schema, adapter }) => {
      return {
        ...schema,
        tables: {
          ...schema.tables,
          addedTable: pgTable('added_table', {
            id: serial('id').notNull(),
          }),
        },
      }
    },
  ],
})

One use case is preserving your existing database structure when migrating to Payload. By default, Payload drops the current database schema, which may not be desirable in this scenario.
To quickly generate the Drizzle schema from your database you can use Drizzle Introspection
You should get the schema.ts file which may look like this:

import { pgTable, uniqueIndex, serial, varchar, text } from 'drizzle-orm/pg-core'

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  fullName: text('full_name'),
  phone: varchar('phone', { length: 256 }),
})

export const countries = pgTable(
  'countries',
  {
    id: serial('id').primaryKey(),
    name: varchar('name', { length: 256 }),
  },
  (countries) => {
    return {
      nameIndex: uniqueIndex('name_idx').on(countries.name),
    }
  },
)

You can import them into your config and append to the schema with the beforeSchemaInit hook like this:

import { postgresAdapter } from '@payloadcms/db-postgres'
import { users, countries } from '../drizzle/schema'

postgresAdapter({
  beforeSchemaInit: [
    ({ schema, adapter }) => {
      return {
        ...schema,
        tables: {
          ...schema.tables,
          users,
          countries
        },
      }
    },
  ],
})

Make sure Payload doesn't overlap table names with its collections. For example, if you already have a collection with slug "users", you should either change the slug or dbName to change the table name for this collection.

afterSchemaInit

Runs after the Drizzle schema is built. You can use this hook to modify the schema with features that aren't supported by Payload, or if you want to add a column that you don't want to be in the Payload config.
To extend a table, Payload exposes extendTable utillity to the args. You can refer to the Drizzle documentation.
The following example adds the extra_integer_column column and a composite index on country and city columns.

import { postgresAdapter } from '@payloadcms/db-postgres'
import { index, integer } from 'drizzle-orm/pg-core'
import { buildConfig } from 'payload'

export default buildConfig({
  collections: [
    {
      slug: 'places',
      fields: [
        {
          name: 'country',
          type: 'text',
        },
        {
          name: 'city',
          type: 'text',
        },
      ],
    },
  ],
  db: postgresAdapter({
    afterSchemaInit: [
      ({ schema, extendTable, adapter }) => {
        extendTable({
          table: schema.tables.places,
          columns: {
            extraIntegerColumn: integer('extra_integer_column'),
          },
          extraConfig: (table) => ({
            country_city_composite_index: index('country_city_composite_index').on(
              table.country,
              table.city,
            ),
          }),
        })

        return schema
      },
    ],
  }),
})
@github-actions github-actions bot added the v3 label Sep 12, 2024
@r1tsuu r1tsuu marked this pull request as ready for review September 13, 2024 09:38
test/database/int.spec.ts Outdated Show resolved Hide resolved
Copy link
Contributor

@DanRibbens DanRibbens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See feedback.

packages/db-postgres/src/types.ts Show resolved Hide resolved
packages/db-postgres/src/types.ts Show resolved Hide resolved
packages/db-sqlite/src/types.ts Outdated Show resolved Hide resolved
@r1tsuu r1tsuu force-pushed the feat/drizzle-customize-schema branch from 459702a to fa9b0da Compare September 14, 2024 11:20
@r1tsuu r1tsuu force-pushed the feat/drizzle-customize-schema branch from 9ecc20d to 1568cb3 Compare September 16, 2024 02:50
Copy link
Contributor

@DanRibbens DanRibbens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

@DanRibbens DanRibbens left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drizzle confirmed that they don't intend to change the internal API we are using in this PR. They also said they can add test coverage from their end to make prevent mistaken breaking changes from their end.

@DanRibbens DanRibbens merged commit 8acbda0 into beta Sep 25, 2024
49 checks passed
@DanRibbens DanRibbens deleted the feat/drizzle-customize-schema branch September 25, 2024 19:14
Copy link

🚀 This is included in version v3.0.0-beta.109

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3 participants