2

Although I love Rust's enums (and the idea of making illegal states unrepresentable), I'm struggling to represent (ironic, yes) them in databases like PostgreSQL when the variants have data associated with them.

Example problem

Suppose we have something like this:

enum PetKind {
 Dog,
 Cat,
 Bird { can_fly: bool },
}
struct Pet {
 name: String,
 kind: PetKind,
}

From what I can tell, traditional databases simply don't support sum types. This makes it difficult to not only store rich enums (like PetKind) but also query them.

Imperfect solutions I found

Serialize to JSON

For example, we could serialize

let my_pet_kind = PetKind::Bird { can_fly: true };

as

{
 "Bird": {
 "can_fly": true
 }
}

and store it in a column of table pets.

This might work, but with this we probably sacrifice some of the benefits that a relational database offers.

Nullable columns with check constraints

Alternatively, we might have something like this, where data associated with variants comes in the form of nullable columns, while check constraints ensure data consistency:

CREATE TYPE pet_kind AS ENUM ('dog', 'cat', 'bird');
CREATE TABLE pets (
 id UUID PRIMARY KEY,
 name VARCHAR(255) NOT NULL,
 kind pet_kind NOT NULL,
 can_fly BOOLEAN,
);
ALTER TABLE pets ADD CHECK (
 (kind = 'dog' AND can_fly IS NULL)
 OR
 (kind = 'cat' AND can_fly IS NULL)
 OR
 (kind = 'bird' AND can_fly IS NOT NULL)
);

However, the querying of data in this schema in Rust seems very awkward. E.g., one may need to define intermediate data types in Rust, like

enum PetKindSql {
 Dog,
 Cat,
 Bird,
}
struct PetSql {
 name: String,
 kind: PetKindSql,
 can_fly: Option<bool>,
}

and convert them to the proper ones later.

Question

Is this the best we can do? Is there a way to avoid serializing enums to JSON while preserving easy retrieval of data in Rust?

I've searched through a lot of pages—and maybe I'm searching for the wrong things—but I just can't find an elegant and robust solution. But maybe that's simply because conventional databases favour product types over sum types? If so, is anyone working on the latter?

asked Jul 26, 2023 at 9:33
1
  • 2
    I'm a little confused about what you are trying to accomplish here. It seems like you are trying to attach configurable data to an enum in the DB but it's not clear what problem that solves because in Rust, these enums are static, right? How are these properties manifested in the Rust side of things? Commented Jul 26, 2023 at 21:28

1 Answer 1

2

Essentially this is just the same as a OOP class hierarchy and you can store it using the Table per Type methodology

table Pet
 Id : GUID
 Type : "Bird"/"Cat" etc
table Bird
 Id : GUID, FK Pet.Id
 canfly
table Cat
 Id : GUID, FK Pet.Id
 purVolume
//get all birds
select * 
 from Pet
 left join Bird
 on pet.Id = bird.Id
where Pet.Type='Bird'
answered Jul 26, 2023 at 17:19

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.