How to Make SelectFields for Prisma enums in RedwoodJS

How to Make SelectFields for Prisma enums in RedwoodJS

:point_right: Demo: https://rw-office-hours-enum-select-list.netlify.app
:point_right: GH Repo: [redwood-office-hours/2022-10-05-enum-select-options at main 路 redwoodjs/redwood-office-hours 路 GitHub](redwood-office-hours/2022-10-05-enum-select-options at main 路 redwoodjs/redwood-office-hours 路 GitHub}

The Problem

  • Cannot get values from the enum to make a select control because Redwood generates the enum as a type -- and that means you cannot iterate and build options for each entry
  • Web cannot access Prisma client types because the web side doesn't connect to the database
  • Enum values don't have friendly, readable labels, e.g: "EMPIRE_STRIKES_BACK" vs "empire Strikes Back"

Current Scaffolding

Scaffolding will render enums in forms with Radio Options or Checkboxes.

  • But, scaffolding won't pickup new enums .... you would have to re-scaffold and force update the web components.
  • Plus, select fields take up less space in a form.

Code

Let鈥檚 make a way to return enum values and labels in a friendly way!

Prisma Schema

enum Episode {
  NEW_HOPE
  EMPIRE_STRIKES_BACK
  RETURN_OF_THE_JEDI
  ROGUE_ONE
}

model Character {
  id        Int       @id @default(autoincrement())
  name      String    @unique
  appearsIn Episode[]
}

GraphQL Schema

Need Postgres for enums 鈥

// 2022-10-05-enum-select-options/api/src/graphql/options.sdl.ts

export const schema = gql`
  interface OptionItem {
    label: String!
  }

  type EpisodeOption implements OptionItem {
    value: Episode!
    label: String!
  }

  type Query {
    episodeOptions: [EpisodeOption!]! @skipAuth
  }
`

Services

// 2022-10-05-enum-select-options/api/src/services/episodeOptions/episodeOptions.ts

import { Episode } from '@prisma/client'
import type { QueryResolvers, EpisodeOption } from 'types/graphql'

import { label } from 'src/lib/helpers'

const getEnumValues = (enumType: Record<string, string>) => {
  return Object.values(enumType).map((value) => {
    return {
      value,
      label: label(value),
    }
  })
}

export const episodeOptions: QueryResolvers['episodeOptions'] = () => {
  return getEnumValues(Episode) as EpisodeOption[]
}

Other Approaches

  • Scripts to construct enums by parsing the Prisma Schema/DMMF