# Inline Classes Make Great Database IDs

DevFeed: [Inline Classes Make Great Database IDs](<https://devfeed.tech/articles/inline-classes-make-great-database-ids-20940.md>)

Original publisher: [Read original article](<https://jakewharton.com/inline-classes-make-great-database-ids/>)

Published: 2019-01-10T00:00:00Z

Content type: article

Language: en

Sources: [Jake Wharton](<https://devfeed.tech/sources/jake-wharton.md>)

Topics: [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Databases](<https://devfeed.tech/topics/databases.md>), [Programming](<https://devfeed.tech/topics/programming.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [database](<https://devfeed.tech/tags/database.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [programming](<https://devfeed.tech/tags/programming.md>), [validation](<https://devfeed.tech/tags/validation.md>)

## AI overview

Kotlin inline classes can provide type-safe wrappers for database IDs, preventing different kinds of IDs from being mixed up. With SQLDelight, these types are applied to generated models and query arguments, catching erroneous ID usage at compile time.

## Source excerpt

Kotlin 1.3's experimental inline class feature allows creating type-safe, semantic wrappers around values which are erased at runtime. Database IDs are a perfect use case for this functionality. Combined with SQLDelight which automatically generates model objects and APIs for querying, different table's IDs become different types which prevent erroneous use. In modeling an app that sends payments, the domain includes customers, instruments (like debit cards and bank accounts), and payments. These otherwise would all have their IDs represented by a Long allowing programming bugs such as passing a payment ID as a customer ID to go undetected. Instead, define an inline class for each ID around a Long (or whatever your ID type is). package com.example.db inline class CustomerId(val value: Long) inline class InstrumentId(val value: Long) inline class PaymentId(val value: Long) When defining your schema, tell SQLDelight to use these types for the ID columns. -- src/main/sqldelight/com/example/db/Customer.sq CREATE TABLE customer( id INTEGER AS CustomerId PRIMARY KEY, -- other columns... ); -- src/main/sqldelight/com/example/db/Instrument.sq CREATE TABLE instrument( id INTEGER AS InstrumentId PRIMARY KEY, -- other columns... ); (Just like when specifying any other Kotlin type for a column, you will need to register a ColumnAdapter for these types) The payment table also uses these types for its own ID as well as the foreign key IDs to other tables. -- src/main/sqldelight/com/example/db/Payment.sq CREATE TABLE payment( id INTEGER AS PaymentId PRIMARY KEY, sender_id INTEGER AS CustomerId NOT NULL, recipient_id INTEGER AS CustomerId NOT NULL, instrument_id INTEGER AS InstrumentId NOT NULL, -- other columns... FOREIGN KEY(sender_id) REFERENCES customer(id), FOREIGN KEY(recipient_id) REFERENCES customer(id), FOREIGN KEY(instrument_id) REFERENCES instrument(id) ); (Note: SQLDelight will soon enforce that these FOREIGN KEY relationships use the same type so that you can't mix them up)