I’ve been working with Prisma as an object-relational mapping tool for my projects. Coming from a background of using raw SQL along with ActiveRecord, I’ve noticed that default Prisma caters to JavaScript over other established standards. Ensuring database table columns are snake_case along with creating associations that are lowercase and plural doesn’t come for free but Prisma does provide a way to configure these within your schema.

Prisma Schema

Prisma provides a schema to help define the model and database layers of your application. By definition it is mapping the concept of a Model to a database table. Now out-of-the-box if you were to create a new table your schema may look something like this. We’ll use an example of a blog application where a User can have many Posts.

model User {
  id            String    @id @default(uuid())
  email         String    @unique
  emailVerified DateTime?
  name          String?
  createdAt     DateTime  @default(now())
  updatedAt     DateTime  @updatedAt
}

model Posts {
  id        String   @id @default(uuid())
  title     String
  content   String?
  publishedAt DateTime?
  authorId  String
  author    User     @relation(fields: [authorId], references: [id])
}

Now migrating this schema you’d end up with a Users and Posts table with that casing. Generally this isn’t an issue but the general best practice is to use plural snake_case conventions for table names. Additionally, several of the columns like publishedAt, authorId, and emailVerified follow camelCase conventions which typically isn’t found at the database level.

The @map and @@map directives

Prisma provides two Schema directives that allow you to control the naming conventions of your table names along with column names. We can use the @map directive to control the column names to adhere to snake_case conventions.

@map: Maps a field name or enum value from the Prisma schema to a column or document field with a different name in the database. @@map: Maps the Prisma schema model name to a table (relational databases) or collection (MongoDB) with a different name.

Prisma Documentation
model User {
  id            String    @id @default(uuid())
  email         String    @unique
  emailVerified DateTime? @map("email_verified")
  name          String?
  createdAt     DateTime  @default(now()) @map("created_at")
  updatedAt     DateTime  @updatedAt @map("updated_at")
}

model Posts {
  id        String   @id @default(uuid()) @map("id")
  title     String
  content   String?
  publishedAt DateTime? @map("published_at")
  authorId  String @map("author_id")
  author    User     @relation(fields: [authorId], references: [id])
}

This has the benefit of connecting the model to the database table while preserving the correct naming conventions in both use-cases. The model can still utilize camelCase to interact at the JavaScript layer, while the database table uses the more commonly found snake_case equivlent.

For table naming, the @@map directive can be used in much the same way. We’ll use it to ensure that our database tables are named users and posts respectively.

model User {
  id            String    @id @default(uuid())

  @@map("users")
}

model Posts {
  id        String   @id @default(uuid())

  @@map("posts")
}

We now have SQL that uses database naming conventions while the Prisma models use camelCase conventions to better integrate with the JavaScript language.

Associations

This same approach can also be used for associations. For example, if there were a join table between Users and Posts, you could name the association with camelCase conventions. In this case, @map and @@map are not needed since Prisma provides a built-in mechanism to define the relationship. This relationship is virtual and does not exist in the database layer.

model User {
  id            String    @id @default(uuid())

  userPosts     Post[]
}

// Prisma used elsewhere in the codebase
// Collection of Posts associated with the User
user.userPosts

Conclusion

And with all of that you can keep both the Database and JavaScript layers focused on their own conventions.

Know about a trick with Prisma? Let me know in the comments below!

Previous

ViewComponents, the Missing View Layer for Rails

Next

Simple Background Jobs with After in Next.js

Join the conversation

comments powered by Disqus