prompter: I am designing a database using Postgres. For my use case, I need a modular data model. Specifically, I need to store Entities of different types. All Entities have a set of common fields, and then they have additional properties depending on their type. For instance, suppose that Entities represent Events. All Events have a title and a description. But if an Event is of type Comment, it will also have additional fields like topic and number of likes.
My main requirements are as follows:
- I need to enforce NOT NULL constraints for the type-specific columns
- The data model should be easily extendable. Adding a new type of Entity should be easy, and require no downtime for the database
- In my application, I will have a view showing all Entities, sorted by date. So I need to be able to query all Entities, independently of their type, in a fast and efficient way

Can you explain to me a design pattern that can be used to achieve these requirements? Please describe it with a concrete example.
assistant: One design pattern that can be used to achieve these requirements is the Entity-Attribute-Value (EAV) model.

In the EAV model, a single table is used to store all Entities and their associated attributes. Each Entity is identified by a unique identifier, and the attributes are stored as key-value pairs in the same table. In this way, the model allows for flexibility in adding new types of Entities and their associated properties, while still enforcing NOT NULL constraints on the type-specific columns.

Here is an example of how the EAV model could be used to store Event Entities with different types:

```
CREATE TABLE entities (
   id SERIAL PRIMARY KEY,
   type VARCHAR(50) NOT NULL,
   title VARCHAR(100) NOT NULL,
   description TEXT NOT NULL,
   attribute_key VARCHAR(50) NOT NULL,
   attribute_value TEXT
);
```
For the example of the Events, we can add a record for a Comment event like this:

```
INSERT INTO entities (type, title, description, attribute_key, attribute_value)
VALUES ('comment', 'My Comment Title', 'This is a comment', 'topic', 'My Comment Topic'),
       ('comment', 'My Comment Title', 'This is a comment', 'likes', '10');
```
In this example, all Entities have a type, title, and description. In addition, the Comment event has two additional attributes: topic and likes. These attributes are stored as key-value pairs in the same table. The type field allows us to distinguish between different types of Entities, while the attribute_key and attribute_value fields allow us to store type-specific attributes.

To query all Entities in a fast and efficient way, we can use an index on the date field, which can be added to the table as needed. Here is an example query that retrieves all Entities, sorted by date:

```
SELECT id, type, title, description, attribute_key, attribute_value
FROM entities
ORDER BY date;
```
To add a new type of Entity, we can simply add a new record with the appropriate type field and any additional attributes as needed. There is no need to modify the table schema, which allows for easy extensibility without downtime for the database.

While the EAV model has its advantages, it also has some drawbacks. One potential issue is that the model can be more difficult to query and maintain than a traditional relational model, especially when it comes to complex queries involving multiple types of Entities and their attributes. Additionally, the EAV model can result in a large number of records in the table, which can impact performance if not managed carefully.
prompter: Why is it difficule to maintain? I'm interested in EAV but I need to understand the impact.
assistant: To explain this, I will simplify the table schema a bit.
Let's suppose we INSERT the following entries into the `entities` table:
```
INSERT INTO entities (type, attribute_key, attribute_value)
VALUES ('user', 'id', 'user1'),
       ('user', 'username', 'Foobar')
       ('comment', 'id', 'comment1'),
       ('comment', 'topic', 'My Comment Topic'),
       ('comment', 'author', 'user1');
```

In a traditional relational model where the tables `user => id, username` and `comment => id, author (user.id), topic` are given, we could JOIN ON user.id = comment.author. In this EAV approach, such an easy join is not possible.

Another problem with this approach is that it is not clearly documented what attributes (keys) an entity has. This makes apps that use the database more error prone, since they could query undefined data more often. The developer needs to spend more time investigating what attributes belong to an entity.