Question

I've discovered a new thing about Postgres: Composite types. I really like this approach and it will be very useful for me.

The problem is that rails' ActiveRecord don't have native support for this.

Do you ever used Postgres' composite types with Rails? Was a good experience or do you prefer the common approach of creating new models for this nested data?

http://www.postgresql.org/docs/8.4/static/rowtypes.html

Tks! :-)

Was it helpful?

Solution

This is an interesting feature of PostgreSQL, however I have not had a chance to work with it.

A few things come to mind on the Rails side:

  1. ActiveRecord would have a tough time formatting the SQL necessary to query these objects. You would probably have to write custom SQL to take the special syntax into account.
  2. ActiveRecord will not be able to do implicit casting of the custom types. This could be problematic when trying to access the attributes through ActiveRecord. You can extend the PostgreSQL adapter for ActiveRecord to cast these special data types into custom classes, however this is a non-traditional approach.

A few things come to mind on the database side:

  1. Because of the way these types collapse multiple attributes into a single entity, this approach could be difficult to query. This includes specifying conditions where you need to check an individual attribute for a particular value. Additionally, if any of these composite types contain a key references, it could be difficult to perform CASCADE options.
  2. This schema approach could be difficult to index if performance becomes an issue
  3. This schema approach doesn't seem to be normalized in a way a database should be. In the examples provided, this composite data should exist as a separate table definition, with a foreign key reference in the parent table.

Unless the specific application you have in mind has compelling benefits, I would suggest a more normalized approach. Instead of:

CREATE TYPE inventory_item AS (
    name            text,
    supplier_id     integer,
    price           numeric
);

CREATE TABLE on_hand (
    item      inventory_item,
    count     integer
);

INSERT INTO on_hand VALUES (ROW('fuzzy dice', 42, 1.99), 1000);

You could achieve a similar result by doing the following, while keeping full support for ActiveRecord without having to extend the Postgres adapter, or create custom classes:

CREATE TABLE inventory_item (
    id              integer,
    name            text,
    supplier_id     integer,
    price           numeric
);

CREATE TABLE on_hand (
    inventory_item_id     integer,
    count                 integer
);

INSERT INTO inventory_item VALUES ('fuzzy dice', 42, 1.99) RETURNS INTEGER;
INSERT INTO on_hand VALUES (<inventory_item_id>, 1000);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top