Version 6 (modified by ged, 5 years ago)

--

Behind the scene

Here is some detailed explanation of what happens behind your back when using Elixir. Let's use our tutorial example:

class Movie(Entity):
    using_options(tablename="movies")

    title = Field(Unicode(30))
    year = Field(Integer)
    description = Field(Unicode)

Note that in the following text, I'll use the term entity and class interchangeably to refer to that class.

First, when the class is declared, using_options is called and each of those three attributes is "parsed" and 3 Field instances are created. Since using_options is a (an instance of) ClassMutator (a kind of class decorator using methods), all it does when it's first called is store the arguments and keyword arguments which it was called with in a special/hidden attribute of the class1 2. Why not act directly, you might ask? Well, for the simple reason that at this point those mutators do not know about the class they are used on. As for the fields, so far, they don't know either they have anything to do with the Movie entity.

1 in __elixir_mutators__ for those who need to know.
2 it's done using some stack frame trickery.

MetaClass

Then, the metaclass (EntityMeta) kicks in. Among others, it:

  • give the opportunity to ClassMutators to act. Which means that each of the class mutators for our class will be processed in turn. Being processed means, in the simple case, that the handler function registered for them is called with the arguments stored3. In our example, that will result in the following call: using_options_handler(tablename="movies").
  • process each of the class attributes, looking for instances of the Property class, and attach those to the entity. This simply calls the attach method on those properties, and give them the ability to know which entity they belong to and the name of the attribute they "manage". Since the Field class is a specialized form of (it inherits from) the Property class, our fields above are included in that processing. Attaching a Property to its entity also has two more effects: it delete the attribute from the class (as to not interfere with SQLAlchemy's attribute management system) and register it in the list of EntityBuilder objects for that entity. More on what those are later.
  • if the entity is configured with the option autosetup=True, the setup triggers are installed.

3 As we have often handlers which do the same thing, we also provided some specialized ClassMutators which do a bit more than just calling the handler method.

Setup phase

Then comes the setup phase. When that phase happens depend on whether you used autosetup or not, and if using autosetup, when you hit one of the triggers. The objective of the setup phase is to construct the table and mapper for your entities. This is done by calling the entity builders and also a few methods on the entity itself (or rather its descriptor which is just a object created to ease the initialization phase without adding lots of methods on the entity itself).

Now, what is an EntityBuilder? To quote the API-docs:

An Entity builder is a class of objects which can be added to an Entity (usually by using special properties or statements) to "build" that entity. Building an entity, meaning to add columns to its "main" table, create other tables, add properties to its mapper, ... To do so an EntityBuilder must override the corresponding method(s). This is to ensure the different operations happen in the correct order (for example, that the table is fully created before the mapper that use it is defined).

Please look at the exact methods those EntityBuilders have. The exact sequence of initialization is currently as follow. Steps marked with EB are done by calling the corresponding4 method on all entity builders of the entity.

  • setup_autoload_table
  • create_pk_cols (EB)
  • setup_relkeys (EB)
  • before_table (EB)
  • setup_table
  • setup_reltables (EB)
  • after_table (EB)
  • setup_events
  • setup_properties (EB)
  • before_mapper (EB)
  • setup_mapper
  • after_mapper (EB)
  • finalize (EB)

Note that the exact sequence is likely to change in a future version as the entire setup job will probably be done by entity builders in the future. The important point is that all those steps are done in order for all entities at once. That means, that the first step is done for all registered entities, then the second one and so on.

4 The method name on the entity builder is not always exactly the same, but you get the idea.

TODO

  • Related entities / classes lookup
  • To document briefly in tutorial and/or API docs if not already
    • Inverse relationships matching
    • Related entities / classes lookup
    • M2M table