Card-many relationships


Cardinality-many relationships in Molecule are modelled with the many[<RefNamespace>] syntax:

object OrderDefinition {

  trait Order {
    val id    = oneString
    val items = many[LineItem].subComponents

  trait LineItem {
    val qty     = oneInt
    val product = oneString
    val price   = oneDouble

An Order can have multiple LineItems so we define a cardinality-many ref attribute items that points to the LineItem namespace.

Note how we also make LineItems subComponents of the Order. That means that LineItems are owned by an Order and will get automatically retracted if the Order is retracted.

Now we can get an Order and its Line Items: === List(
  ("order1", 3, "Milk", 12.00),
  ("order1", 2, "Coffee", 46.00),
  ("order2", 4, "Bread", 5.00)

The Order data is repeated for each line Item which is kind of redundant. We can avoid that with a “nested” Molecule instead:

Nested results


We can nest the result with the Molecule syntax * indicating “with many”:

m( * LineItem.qty.product.price).get === List(
  ("order1", List(
    (3, "Milk", 12.00), 
    (2, "Coffee", 46.00))),
  ("order2", List(
    (4, "Bread", 5.00)))

Now each Order has its own list of typed Line Item data and there is no Order redundancy.

This becomes more and more handy the deeper the hierarchy of data is. Molecule can nest data structures up to 10 levels deep!

Entity API


We can get a similar - but un-typed - nested hierarchy of data with the Entity API by calling touch on an order id:

// Touch entity facts hierarchy recursively
orderId.touch === Map(
  ":db/id" -> 101L,
  ":order/id" -> "order1",
  ":order/items" -> List(
      ":db/id" -> 102L, 
      ":lineItem/qty" -> 3, 
      ":lineItem/product" -> "Milk",
      ":lineItem/price" -> 12.0),
      ":db/id" -> 103L, 
      ":lineItem/qty" -> 2, 
      ":lineItem/product" -> "Coffee",
      ":lineItem/price" -> 46.0)))