Macro transformation

Molecule performs a series of transformation of the molecules we write so that they in the end become a Datomic query:

1. Source code

To find southern media communities we could make the following molecule

Community.name.`type`("twitter" or "facebook_page")
  .Neighborhood.District.region("sw" or "s" or "se")

2. Model AST

The source code of our molecule is then pattern matched in Dsl2Model element by element in order to create an abstracted Model of Atoms and Bonds:

Model(List(
  Atom("community", "name", "String", 1, VarValue, None),
  Atom("community", "type_", "String", 1, Eq(List("twitter", "facebook_page")), Some(":community.type/")),
  Bond("community", "neighborhood", "neighborhood"),
  Bond("neighborhood", "district", "district"),
  Atom("district", "region_", "String", 1, Eq(List("sw", "s", "se")), Some(":district.region/")))
)

This simple Model AST has shown to cover a surprising wide spectre of queries.

3. Query AST

Our model is then transformed in Model2Query to a Query AST which is a little more elaborate:

Query(
  Find(List(
    Var("b"))),
  In(List(), List(
    Rule("rule1", List(Var("a")), List(
      DataClause(ImplDS, Var("a"), KW("community", "type"), Val(":community.type/twitter"), Empty))),
    Rule("rule1", List(Var("a")), List(
      DataClause(ImplDS, Var("a"), KW("community", "type"), Val(":community.type/facebook_page"), Empty))),
    Rule("rule2", List(Var("e")), List(
      DataClause(ImplDS, Var("e"), KW("district", "region"), Val(":district.region/sw"), Empty))),
    Rule("rule2", List(Var("e")), List(
      DataClause(ImplDS, Var("e"), KW("district", "region"), Val(":district.region/s"), Empty))),
    Rule("rule2", List(Var("e")), List(
      DataClause(ImplDS, Var("e"), KW("district", "region"), Val(":district.region/se"), Empty)))), List(DS)),
  Where(List(
    DataClause(ImplDS, Var("a"), KW("community", "name"), Var("b"), Empty),
    RuleInvocation("rule1", List(Var("a"))),
    DataClause(ImplDS, Var("a"), KW("community", "neighborhood", "neighborhood"), Var("d"), Empty),
    DataClause(ImplDS, Var("d"), KW("neighborhood", "district", "district"), Var("e"), Empty),
    RuleInvocation("rule2", List(Var("e")))))
)

As you see this Query AST is tailored to Datomic.

In principle we should be able to use the same model to create other Query abstractions tailored to other database systems!…

4. Datomic query string

Finally Molecule transforms our Query AST in Query2String to a Datomic query text strings:

[:find  ?b
 :in    $ %
 :where [?a :community/name ?b]
        (rule1 ?a)
        [?a :community/neighborhood ?d]
        [?d :neighborhood/district ?e]
        (rule2 ?e)]

INPUTS:
List(
  1 datomic.db.Db@xxx
  2 [[(rule1 ?a) [?a :community/type ":community.type/twitter"]]
     [(rule1 ?a) [?a :community/type ":community.type/facebook_page"]]
     [(rule2 ?e) [?e :district/region ":district.region/sw"]]
     [(rule2 ?e) [?e :district/region ":district.region/s"]]
     [(rule2 ?e) [?e :district/region ":district.region/se"]]]

All 3 transformations happen at compile time and therefore have no impact on the runtime performance.

See more examples of transformation of the Seattle molecules