      :clj  (instance? clojure.lang.IAtom a)))
 
 (defn listen!
+  "Listen for changes on the given database connection.
+  Whenever a transaction is applied to the database the callback is called
+  with the transaction report.
+  Returns the key under which this listener is registered."
   ([conn callback] (listen! conn (rand) callback))
   ([conn key callback]
      {:pre [(conn? conn) (atom? (:listeners (meta conn)))]}
      (swap! (:listeners (meta conn)) assoc key callback)
      key))
 
-(defn unlisten! [conn key]
+(defn unlisten!
+  "Removes the listener under de given key from the database connection."
+  [conn key]
   {:pre [(conn? conn) (atom? (:listeners (meta conn)))]}
   (swap! (:listeners (meta conn)) dissoc key))
 


;; Conn

(defn conn? [conn]
  (and #?(:clj  (instance? clojure.lang.IDeref conn)
          :cljs (satisfies? cljs.core/IDeref conn))
    (db/db? @conn)))

(defn conn-from-db [db]
  (atom db :meta { :listeners (atom {}) }))

(defn conn-from-datoms
  ([datoms]        (conn-from-db (init-db datoms)))
  ([datoms schema] (conn-from-db (init-db datoms schema))))

(defn create-conn
  ([]       (conn-from-db (empty-db)))
  ([schema] (conn-from-db (empty-db schema))))



;; SUMMING UP

(def
  ^{:arglists '([q & inputs])
    :doc "Execute a datalog query.
         (For full docs see Datomic reference: https://docs.datomic.com/query.html)

         Usage:
         (q '[:find ?value :where [_ :likes ?value]] db)
         -> #{[:pizza]}"}
  q dq/q)
(def ^{:arglists '([db eid])
       :doc "Retrieves a single entity by its id from the given database.
            Retrieve using the internal db id:
            (entity db 1)
            Retrieve using a user defined id:
            (entity db [:db/ident :a-unique-key])"}
  entity de/entity)

(defn entity-db [^Entity entity]
  {:pre [(de/entity? entity)]}
  (.-db entity))

(def ^{:arglists '([e a v] [e a v tx] [e a v tx added])
       :doc "Creates a single datom that can be added to any database.
             A datom consists of [entity-id attribute value] where:
             - entity-id is the entity's unique id within the db
             - attribute is the relation that the entity has to the value
             - value is the value that the attribute applies to.
             This can be a primitive value or refer to another entity.

             For example:
             To asserts a single fact:
             (datom [1 :likes :pizza])
             To assert with transaction data:
             (datom [1 :likes :pizza 17])
             Add true to assert the fact (default), false to retract it:
             (datom [1 :likes :pizza 17 false])"}
  datom db/datom)
(def ^{:arglists '([db selector eid])
       :doc "Pull a single entity from the database using Datomic pull syntax.
            (For full docs see Datom reference: http://docs.datomic.com/pull.html)

            Usage:
            (pull db [:likes :dislikes] 1)
            -> {:likes :pizza :dislikes :ice-cream}"}
  pull dp/pull)
(def ^{:arglists '([db selector eids])
       :doc "Pull entities from the database using Datomic pull syntax.
            (For full docs see Datomic reference: http://docs.datomic.com/pull.html)

            Usage:
            (pull-many db [:likes :dislikes] [1 2])
            -> [{:likes :pizza :dislikes :ice-cream} {:likes :pie}]"}
  pull-many dp/pull-many)
(def ^{:arglists '([e])
       :doc "Retrieves all attributes for a given entity as a single map.

            Usage:
            (touch (entity db 1)) ; -> {:dislikes :pie, :likes :pizza, :db/id 1}"}
  touch de/touch)
(def ^{:arglists '([] [schema])
       :doc "Creates an empty database with an optional schema.

            Usage:
            (empty-db)
            With schema:
            (empty-db {:likes {:db/cardinality :db.cardinality/many}})"}
  empty-db db/empty-db)
(def ^{:arglists '([datoms] [datoms schema])
       :doc "Creates a database from a given collection of datoms.
            Takes an optional schema.

            Usage:
            (init-db
              [(datom 1 :likes :pizza)])
            With a schema:
            (init-db
              [(datom 1 :likes :pizza)]
              {:likes {:db/cardinality :db.cardinality/many}})"}
  init-db db/init-db)
(def ^{:arglists '([x])
       :doc "Returns true if the given value is a datom, false otherwise."}
  datom? db/datom?)
(def ^{:arglists '([x])
       :doc "Return true if the given value is a database
            (but not a database connection), false otherwise."}
  db? db/db?)
(def ^:const tx0 db/tx0)

(defn is-filtered
  "Returns true if this is an instance of a filtered database, false otherwise."
  [x]
  (instance? FilteredDB x))

(defn filter
  "Returns a database including only the datoms for which the (pred db datom)
  holds true."
  [db pred]
  {:pre [(db/db? db)]}
  (if (is-filtered db)
    (let [^FilteredDB fdb db
