Database: How to do type-specific IDs?

I'm trying to find a way of leveraging Rusts type system to handle database foreign keys.

Suppose I have these tables (simplified Sqlite):

create table order (
    id number primary key,
    customer text
)
create table item (
    id number primary key,
    description text,
    order_id number
)

Within my application, I would like to have separate types for the IDs and use those types to implement overloaded functions in the impl of my database struct, such that Rust knows that db.get(item.order_id) is of type Order while db.get(ItemId::from(1)) or something like that would return an Item.

What doesn't work is a type parameter on a primitive type, although this would look very natural but of course neither the type definitions nor the duplicate function definitions would fly:

type Id<Item> = u32;
type Id<Order> = u32;

impl Database {
    fn get<Item>(&self, id: Id<Item>) -> Item {...}
    fn get<Order>(&self, id: Id<Order>) -> Order {...}
}

Replacing Id<Item> with ItemId doesn't make it much better.

I have experimented with structs and traits which kind of works, but still looks pretty ugly.

Is there an idiomatic way of doing this?

Cheers,
Hans-Martin

It's pretty clear you need a type parameter here, because you want to express an input constraint. And since at the low level, the ID is just an u32 apparently, you can just wrap it in a newtype:

pub struct Id<T> {
    id: u32,
    marker: PhantomData<T>,
}

impl<T> Id<T> {
    pub fn new(primitive: u32) -> Self {
        Id { id: primitive, marker: PhantomData }
    }

    pub fn into_inner(self) -> u32 {
        self.id
    }
}

Bonus points if you add a trait bound on T for customizing the underlying primitive representation.

1 Like

Ah, PhantomData is what I basically missed. I'll try to experiment with it, thanks!

It'll do without the bonus points for now :slight_smile:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.