Packages

  • package root

    Documentation/API for the Molecule library - a meta DSL for the Datomic database.

    Manual | scalamolecule.org | Github | Forum

    Definition Classes
    root
  • package molecule

    Molecule library - a Scala meta-DSL for the Datomic database.

    Molecule library - a Scala meta-DSL for the Datomic database.

    See api package for various api imports to start using Molecule.

    Sub-packages

    api Molecule API.
    ast Internal Molecule ASTs.
    boilerplate Internal interfaces for auto-generated DSL boilerplate code.
    composition    Builder methods to compose molecules.
    exceptions Exceptions thrown by Molecule.
    expression Attribute expressions and operations.
    facade Molecule facades to Datomic.
    factory Implicit macro methods `m` to instantiate molecules from custom DSL molecule constructs.
    input Input molecules awaiting input.
    macros Internal macros generating molecule code from custom DSL molecule constructs.
    generic Interfaces to generic information about datoms and Datomic database.
    ops Internal operational helpers for transforming DSL to molecule.
    schema Schema definition DSL.
    transform Internal transformers from DSL to Model/Query/Transaction.
    util Internal Java database functions for Datomic.

    Definition Classes
    root
  • package api
    Definition Classes
    molecule
  • package ast

    Internal Molecule ASTs.

    Internal Molecule ASTs.

    Definition Classes
    molecule
  • package boilerplate

    Internal interfaces for auto-generated DSL boilerplate code.

    Internal interfaces for auto-generated DSL boilerplate code.

    Interfaces to the generated schema-defined DSL boilerplate code that the sbt-plugin generates when doing a sbt-compile. Molecule macros can then type-safely deduct the type structure of composed molecules.

    Definition Classes
    molecule
  • package composition

    Methods to build transaction, composite and nested molecules.

    Methods to build transaction, composite and nested molecules.

    Definition Classes
    molecule
  • package exceptions

    Exceptions thrown by Molecule.

    Exceptions thrown by Molecule.

    Definition Classes
    molecule
  • package expression

    Attribute expressions and operations.

    Attribute expressions and operations.

    Refine attribute matches with various attribute expressions:

    Person.age(42)                           // equality
    Person.name.contains("John")             // fulltext search
    Person.age.!=(42)                        // negation (or `not`)
    Person.age.<(42)                         // comparison (< > <= >=)
    Person.name("John" or "Jonas")           // OR-logic
    Person.age()                             // apply empty value to retract value(s) in updates
    Person.hobbies.assert("golf")               // add value(s) to card-many attributes
    Person.hobbies.retract("golf")            // retract value(s) of card-many attributes
    Person.hobbies.replace("golf", "diving") // replace value(s) of card-many attributes
    Person.tags.k("en")                      // match values of map attributes by key
    Person.age(Nil)                          // match non-asserted datoms (null)
    Person.name(?)                           // initiate input molecules awaiting input at runtime
    Person.name(unify)                       // Unify attributes in self-joins

    Apply aggregate keywords to aggregate attribute value(s):

    // Aggregates on any attribute type
    Person.age(count).get.head         === 3   // count of asserted `age` attribute values
    Person.age(countDistinct).get.head === 3   // count of asserted distinct `age` attribute values
    Person.age(max).get.head           === 38  // maximum `age` value (using `compare`)
    Person.age(min).get.head           === 5   // maximum `age` value (using `compare`)
    Person.age(rand).get.head          === 25  // single random `age` value
    Person.age(sample).get.head        === 27  // single sample `age` value (when single value, same as random)
    
    // Aggregates on any attribute type, returning multiple values
    Person.age(distinct).get.head  === Vector(5, 7, 38)  // distinct `age` values
    Person.age(max(2)).get.head    === Vector(38, 7)     // 2 maximum `age` values
    Person.age(min(2)).get.head    === Vector(5, 7)      // 2 minimum `age` values
    Person.age(rand(2)).get.head   === Stream(5, ?)      // 2 random `age` values (values can re-occur)
    Person.age(sample(2)).get.head === Vector(7, 38)     // 2 sample `age` values
    
    // Aggregates on number attributes
    Person.age(sum).get.head      === 50               // sum of all `age` numbers
    Person.age(avg).get.head      === 16.66666667      // average of all `age` numbers
    Person.age(median).get.head   === 7                // median of all `age` numbers
    Person.age(stddev).get.head   === 15.107025591499  // standard deviation of all `age` numbers
    Person.age(variance).get.head === 228.2222222222   // variance of all `age` numbers
    Definition Classes
    molecule
    See also

    Manual: expressions | aggregates | input molecules

    Tests: expressions

  • package facade
    Definition Classes
    molecule
  • package factory

    Factory methods m to instantiate molecules from custom DSL molecule constructs.

    Factory methods m to instantiate molecules from custom DSL molecule constructs.

    Definition Classes
    molecule
  • package generic
    Definition Classes
    molecule
  • package datom

    Generic Datom attribute interfaces of all arities.

    Generic Datom attribute interfaces of all arities.

    "Generic attributes" are special pre-defined attributes that can be combined with custom attributes in molecules to return meta data:

    // Get id of Ben entity with `e`
    Person.e.name.get.head === (benEntityId, "Ben")
    
    // When was Ben's age updated? Using `txInstant`
    Person(benEntityId).age.txInstant.get.head === (42, <April 4, 2019>) // (Date)
    
    // With a history db we can access the transaction number `t` and
    // assertion/retraction statusses with `op`
    Person(benEntityId).age.t.op.getHistory === List(
      (41, t1, true),  // age 41 asserted in transaction t1
      (41, t2, false), // age 41 retracted in transaction t2
      (42, t2, true)   // age 42 asserted in transaction t2
    )

    Available generic attributes:

    • e - Entity id (Long)
    • a - Full attribute name like ":Person/name" (String)
    • v - Value of Datoms (Any)
    • t - Transaction pointer (Long/Int)
    • tx - Transaction entity id (Long)
    • txInstant - Transaction wall clock time (java.util.Date)
    • op - Operation status: assertion (true) / retraction (false)
    See also

    Tests for more generic attribute query examples.

  • package index

    Datomic Index APIs in Molecule.

    Datomic Index APIs in Molecule.

    Datomic maintains four indexes that contain ordered sets of datoms. Each of these indexes is named based on the sort order used:

    • EAVT - Datoms sorted by Entity-Attribute-Value-Transaction
    • AVET - Datoms sorted by Attribute-Value-Entity-Transaction
    • AEVT - Datoms sorted by Attribute-Entity-Value-Transaction
    • VAET - "Reverse index" for reverse lookup of ref types

    Create an Index molecule by instantiating an Index object with one or more arguments in the order of the Index's elements. Datoms are returned as tuples of data depending of which generic attributes you add to the Index molecule:

    // Create EAVT Index molecule with 1 entity id argument
    EAVT(e1).e.a.v.t.get === List(
      (e1, ":Person/name", "Ben", t1),
      (e1, ":Person/age", 42, t2),
      (e1, ":Golf/score", 5.7, t2)
    )
    
    // Maybe we are only interested in the attribute/value pairs:
    EAVT(e1).a.v.get === List(
      (":Person/name", "Ben"),
      (":Person/age", 42),
      (":Golf/score", 5.7)
    )
    
    // Two arguments to narrow the search
    EAVT(e1, ":Person/age").a.v.get === List(
      (":Person/age", 42)
    )
    Note

    The Molecule Index API's don't allow returning the whole Index/the whole database. So omitting arguments constructing the Index object (like EAVT.e.a.v.t.get) will throw an exception.
    Please use Datomics API if you need to return the whole database Index:
    conn.db.datoms(datomic.Database.EAVT)

    See also

    Tests for more Index query examples.

  • package schema

    Generic Schema attribute interfaces of all arities.

    Generic Schema attribute interfaces of all arities.

    The generic Schema interface provides attributes to build molecules that query the Schema structure of the current database.

    // List of attribute entity ids
    val attrIds: Seq[Long] = Schema.id.get
    
    // Attribute name elements
    Schema.a.part.ns.nsFull.attr.get === List (
      (":sales_Customer/name", "sales", "Customer", "sales_Customer", "name"),
      (":sales_Customer/name", "sales", "Customer", "sales_Customer", "name"),
      // etc..
    )
    
    // Datomic type and cardinality of attributes
    Schema.a.tpe.card.get === List (
      (":sales_Customer/name", "string", "one"),
      (":accounting_Invoice/invoiceLine", "ref", "many"),
    )
    
    // Optional docs and attribute options
    // These can be retrieved as mandatory or optional values
    Schema.a
          .index
          .doc$
          .unique$
          .fulltext$
          .isComponent$
          .noHistory$
          .get === List(
      (":sales_Customer/name",
        true,            // indexed
        "Customer name", // doc
        None,            // Uniqueness not set
        Some(true),      // Fulltext search set so that we can search for names
        None,            // Not a component
        None             // History is preserved (noHistory not set)
        ),
      (":accounting_Invoice/invoiceLine",
        true,                   // indexed
        "Ref to Invoice lines", // doc
        None,                   // Uniqueness not set
        None,                   // Fulltext search not set
        Some(true),             // Invoice is a component - owns invoice lines
        None                    // History is preserved (noHistory not set)
        ),
    )
    
    // Defined enum values
    Schema.a.enum.get.groupBy(_._1).map(g => g._1 -> g._2) === Map(
      ":Person/gender" -> List("female", "male"),
      ":Interests/sports" -> List("golf", "basket", "badminton")
    )
    
    // Schema transaction times
    Schema.t.tx.txInstant.get === List(
      (t1, tx1, <Date: 2018-11-07 09:28:10>), // Initial schema transaction
      (t2, tx2, <Date: 2019-01-12 12:43:27>), // Additional schema attribute definitions...
    )

    Apply expressions to narrow the returned selection of Schema data:

    // Namespaces in the "gen" partition (partition name tacit)
    Schema.part_("location").ns.get === List("Country", "Region", etc...)
    
    // Attributes in the "Person" namespace
    Schema.ns_("Person").attr.get === List("name", "age", "hobbies", etc...)
    
    // How many enum attributes?
    Schema.enum_.a(count).get === List(2)
    Note

    Schema attributes defined in Datomic's bootstrap process that are not related to the current database are transparently filtered out from all Schema queries.

    See also

    Tests for more Schema query examples.

  • GenericLog
  • Log
  • Log_0
  • Log_1
  • Log_2
  • Log_3
  • Log_4
  • Log_5
  • Log_6
  • Log_7
  • package input

    Input molecules awaiting input.

    Input molecules awaiting input.

    Input molecules are molecules that awaits one or more inputs at runtime. When input value is applied, the input molecule is resolved and a standard molecule is returned that we can then call actions on.

    Input molecule queries are cached by Datomic. So there is a runtime performance gain in using input molecules. Furthermore, input molecules are a good fit for re-use for queries where only a few parameters change.

    Input molecules can await 1, 2 or 3 inputs and are constructed by applying the ? marker to attributes. If one marker is applied, we get a InputMolecule_1, 2 inputs creates an InputMolecule_2 and 3 an InputMolecule_3.

    The three input molecule interfaces come in arity-versions corresponding to the number of non-?-marked attributes in the input molecule. Let's see a simple example:

    // Sample data
    Person.name.age insert List(("Ben", 42), ("Liz", 34))
    
    // Input molecule created at compile time. Awaits a name of type String
    val ageOfPersons: InputMolecule_1.InputMolecule_1_01[String, Int] = m(Person.name_(?).age)
    
    // Resolved molecule. "Ben" input is matched against name attribute
    val ageOfPersonsNamedBen: Molecule.Molecule01[Int] = ageOfPersons.apply("Ben")
    
    // Calling action on resolved molecule.
    // (Only age is returned since name was marked as tacit with the underscore notation)
    ageOfPersonsNamedBen.get === List(42)
    
    // Or we can re-use the input molecule straight away
    ageOfPersons("Liz").get === List(34)
    Definition Classes
    molecule
  • package macros
    Definition Classes
    molecule
  • package ops

    Internal operational helpers for transforming DSL to molecules.

    Internal operational helpers for transforming DSL to molecules.

    Definition Classes
    molecule
  • package schema

    Schema definition DSL and API.

    Schema definition DSL and API.

    Definition Classes
    molecule
  • package transform

    Internal transformers from DSL to Model/Query/Transaction/Datomic.

    Internal transformers from DSL to Model/Query/Transaction/Datomic.

    Molecule transforms custom boilerplate DSL constructs to Datomic queries in 3 steps:

    Custom DSL molecule --> Model --> Query --> Datomic query string

    Definition Classes
    molecule
    See also

    http://www.scalamolecule.org/dev/transformation/

  • package util

    Internal database functions for Datomic.

    Internal database functions for Datomic.

    Definition Classes
    molecule
p

molecule

generic

package generic

Content Hierarchy

Package Members

  1. package datom

    Generic Datom attribute interfaces of all arities.

    Generic Datom attribute interfaces of all arities.

    "Generic attributes" are special pre-defined attributes that can be combined with custom attributes in molecules to return meta data:

    // Get id of Ben entity with `e`
    Person.e.name.get.head === (benEntityId, "Ben")
    
    // When was Ben's age updated? Using `txInstant`
    Person(benEntityId).age.txInstant.get.head === (42, <April 4, 2019>) // (Date)
    
    // With a history db we can access the transaction number `t` and
    // assertion/retraction statusses with `op`
    Person(benEntityId).age.t.op.getHistory === List(
      (41, t1, true),  // age 41 asserted in transaction t1
      (41, t2, false), // age 41 retracted in transaction t2
      (42, t2, true)   // age 42 asserted in transaction t2
    )

    Available generic attributes:

    • e - Entity id (Long)
    • a - Full attribute name like ":Person/name" (String)
    • v - Value of Datoms (Any)
    • t - Transaction pointer (Long/Int)
    • tx - Transaction entity id (Long)
    • txInstant - Transaction wall clock time (java.util.Date)
    • op - Operation status: assertion (true) / retraction (false)
    See also

    Tests for more generic attribute query examples.

  2. package index

    Datomic Index APIs in Molecule.

    Datomic Index APIs in Molecule.

    Datomic maintains four indexes that contain ordered sets of datoms. Each of these indexes is named based on the sort order used:

    • EAVT - Datoms sorted by Entity-Attribute-Value-Transaction
    • AVET - Datoms sorted by Attribute-Value-Entity-Transaction
    • AEVT - Datoms sorted by Attribute-Entity-Value-Transaction
    • VAET - "Reverse index" for reverse lookup of ref types

    Create an Index molecule by instantiating an Index object with one or more arguments in the order of the Index's elements. Datoms are returned as tuples of data depending of which generic attributes you add to the Index molecule:

    // Create EAVT Index molecule with 1 entity id argument
    EAVT(e1).e.a.v.t.get === List(
      (e1, ":Person/name", "Ben", t1),
      (e1, ":Person/age", 42, t2),
      (e1, ":Golf/score", 5.7, t2)
    )
    
    // Maybe we are only interested in the attribute/value pairs:
    EAVT(e1).a.v.get === List(
      (":Person/name", "Ben"),
      (":Person/age", 42),
      (":Golf/score", 5.7)
    )
    
    // Two arguments to narrow the search
    EAVT(e1, ":Person/age").a.v.get === List(
      (":Person/age", 42)
    )
    Note

    The Molecule Index API's don't allow returning the whole Index/the whole database. So omitting arguments constructing the Index object (like EAVT.e.a.v.t.get) will throw an exception.
    Please use Datomics API if you need to return the whole database Index:
    conn.db.datoms(datomic.Database.EAVT)

    See also

    Tests for more Index query examples.

  3. package schema

    Generic Schema attribute interfaces of all arities.

    Generic Schema attribute interfaces of all arities.

    The generic Schema interface provides attributes to build molecules that query the Schema structure of the current database.

    // List of attribute entity ids
    val attrIds: Seq[Long] = Schema.id.get
    
    // Attribute name elements
    Schema.a.part.ns.nsFull.attr.get === List (
      (":sales_Customer/name", "sales", "Customer", "sales_Customer", "name"),
      (":sales_Customer/name", "sales", "Customer", "sales_Customer", "name"),
      // etc..
    )
    
    // Datomic type and cardinality of attributes
    Schema.a.tpe.card.get === List (
      (":sales_Customer/name", "string", "one"),
      (":accounting_Invoice/invoiceLine", "ref", "many"),
    )
    
    // Optional docs and attribute options
    // These can be retrieved as mandatory or optional values
    Schema.a
          .index
          .doc$
          .unique$
          .fulltext$
          .isComponent$
          .noHistory$
          .get === List(
      (":sales_Customer/name",
        true,            // indexed
        "Customer name", // doc
        None,            // Uniqueness not set
        Some(true),      // Fulltext search set so that we can search for names
        None,            // Not a component
        None             // History is preserved (noHistory not set)
        ),
      (":accounting_Invoice/invoiceLine",
        true,                   // indexed
        "Ref to Invoice lines", // doc
        None,                   // Uniqueness not set
        None,                   // Fulltext search not set
        Some(true),             // Invoice is a component - owns invoice lines
        None                    // History is preserved (noHistory not set)
        ),
    )
    
    // Defined enum values
    Schema.a.enum.get.groupBy(_._1).map(g => g._1 -> g._2) === Map(
      ":Person/gender" -> List("female", "male"),
      ":Interests/sports" -> List("golf", "basket", "badminton")
    )
    
    // Schema transaction times
    Schema.t.tx.txInstant.get === List(
      (t1, tx1, <Date: 2018-11-07 09:28:10>), // Initial schema transaction
      (t2, tx2, <Date: 2019-01-12 12:43:27>), // Additional schema attribute definitions...
    )

    Apply expressions to narrow the returned selection of Schema data:

    // Namespaces in the "gen" partition (partition name tacit)
    Schema.part_("location").ns.get === List("Country", "Region", etc...)
    
    // Attributes in the "Person" namespace
    Schema.ns_("Person").attr.get === List("name", "age", "hobbies", etc...)
    
    // How many enum attributes?
    Schema.enum_.a(count).get === List(2)
    Note

    Schema attributes defined in Datomic's bootstrap process that are not related to the current database are transparently filtered out from all Schema queries.

    See also

    Tests for more Schema query examples.

Type Members

  1. trait GenericLog extends AnyRef

    Container for Log object.

  2. trait Log extends GenericNs

    Log interface.

    Log interface.

    Datomic's database log is a recording of all transaction data in historic order, organized for efficient access by transaction.

    Instantiate Log object with tx range arguments between from (inclusive) and until (exclusive), and add Log attributes to be returned as tuples of data:

    // Data from transaction t1 until t4 (exclusive)
    Log(Some(t1), Some(t4)).t.e.a.v.op.get === List(
      (t1, e1, ":Person/name", "Ben", true),
      (t1, e1, ":Person/age", 41, true),
    
      (t2, e2, ":Person/name", "Liz", true),
      (t2, e2, ":Person/age", 37, true),
    
      (t3, e1, ":Person/age", 41, false),
      (t3, e1, ":Person/age", 42, true)
    )
    
    // If `from` is None, the range starts from the beginning
    Log(None, Some(t3)).v.e.t.get === List(
      (t1, e1, ":Person/name", "Ben", true),
      (t1, e1, ":Person/age", 41, true),
    
      (t2, e2, ":Person/name", "Liz", true),
      (t2, e2, ":Person/age", 37, true)
    
      // t3 not included
    )
    
    // If `until` is None, the range goes to the end
    Log(Some(t2), None).v.e.t.get === List(
      // t1 not included
    
      (t2, e2, ":Person/name", "Liz", true),
      (t2, e2, ":Person/age", 37, true),
    
      (t3, e1, ":Person/age", 41, false),
      (t3, e1, ":Person/age", 42, true)
    )

    Log attributes available:

    • e - Entity id (Long)
    • a - Full attribute name like ":Person/name" (String)
    • v - Value of Datoms (Any)
    • t - Transaction pointer (Long/Int)
    • tx - Transaction entity id (Long)
    • txInstant - Transaction wall clock time (java.util.Date)
    • op - Operation status: assertion (true) / retraction (false)
    Note

    Contrary to the Datomic Log which is map of individual transactions the Molecule Log implementation is flattened to be one continuous list of transaction data. This is to have a transparent unified return type as all other molecules returning data. Data can always be grouped if needed.

  3. trait Log_0 extends Log with OutIndex_0

    Log interface to add a first generic attribute to molecule.

  4. trait Log_1[A] extends Log with OutIndex_1[A]

    Log interface to add a second generic attribute to molecule.

  5. trait Log_2[A, B] extends Log with OutIndex_2[A, B]
  6. trait Log_3[A, B, C] extends Log with OutIndex_3[A, B, C]
  7. trait Log_4[A, B, C, D] extends Log with OutIndex_4[A, B, C, D]
  8. trait Log_5[A, B, C, D, E] extends Log with OutIndex_5[A, B, C, D, E]
  9. trait Log_6[A, B, C, D, E, F] extends Log with OutIndex_6[A, B, C, D, E, F]
  10. trait Log_7[A, B, C, D, E, F, G] extends Log with OutIndex_7[A, B, C, D, E, F, G]

Ungrouped