Associable Elixir Statement Generator
About Polymorphic Associations
A frequent pattern in database schemas is the has_and_belongs_to_many, or a many-to-many table. Quite often multiple tables will refer to a single one creating quite a few many-to-many intermediate tables.
Polymorphic associations lower the amount of many-to-many tables by setting up a table that allows relations to any other table in the database, and relates it to the associable table. In some implementations, this layout does not enforce referential integrity with database foreign key constraints, this implementation uses an additional many-to-many table with foreign key constraints to avoid this problem.
Elixir Statement Generator for Polymorphic Associations
The associable function generates the intermediary tables for an Elixir entity that should be associable with other Elixir entities and returns an Elixir Statement for use with them. This automates the process of creating the polymorphic association tables and ensuring their referential integrity.
Matching select_XXX and select_by_XXX are also added to the associated entity which allow queries to be run for the associated objects.
class Tag(Entity): name = Field(Unicode) acts_as_taggable = associable(Tag) class Entry(Entity): title = Field(Unicode) acts_as_taggable('tags') class Article(Entity): title = Field(Unicode) acts_as_taggable('tags')
Or if one of the entities being associated should only have a single member of the associated table:
class Address(Entity): street = Field(String(130)) city = Field(String(100)) is_addressable = associable(Address, 'addresses') class Person(Entity): name = Field(Unicode) orders = OneToMany('Order') is_addressable() class Order(Entity): order_num = Field(primary_key=True) item_count = Field(Integer) person = ManyToOne('Person') is_addressable('address', uselist=False) home = Address(street='123 Elm St.', city='Spooksville') user = Person(name='Jane Doe') user.addresses.append(home) neworder = Order(item_count=4) neworder.address = home user.orders.append(neworder) # Queries using the added helpers Person.select_by_addresses(city='Cupertino') Person.select_addresses(and_(Address.c.street=='132 Elm St', Address.c.city=='Smallville'))
The generated Elixir Statement has several options available:
|name||Specify a custom name for the Entity attribute. This is used to declare the attribute used to access the associated table values. Otherwise, the name will use the plural_name provided to the associable call.|
|uselist||Whether or not the associated table should be represented as a list, or a single property. It should be set to False when the entity should only have a single associated entity. Defaults to True.|
|lazy||Determines eager loading of the associated entity objects. Defaults to False, to indicate that they should not be lazily loaded.|
associable (assoc_entity, plural_name=None, lazy=True)
Generate an associable Elixir Statement