datomic_gen_server v2.0.1 DatomicGenServer.Db
DatomicGenServer.Db is a module intended to facilitate the use of Elixir data structures instead of edn strings for communicating with Datomic. This module maps the DatomicGenServer interface functions in wrappers that accept and return Elixir data structures, and also provides slightly more syntactically pleasant equivalents for Datomic keys and structures that would otherwise need to be represented using a lot of punctuation that isn’t required in Clojure.
The hexdoc organizes the functions in this module alphabetically; here is a list by topic:
Interface functions
q(server_identifier, exdn, options \ [])
transact(server_identifier, exdn, options \ [])
entity(server_identifier, exdn, attr_names \ :all, options \ [])
load(server_identifier, data_path, options \ [])
Datomic Shortcuts
Id/ident
dbid(db_part)
id
ident
Transaction creation
add
retract
install_attribute
alter_attribute
tx_instant
Value types
value_type
type_long
type_keyword
type_string
type_boolean
type_bigint
type_float
type_double
type_bigdec
type_ref
type_instant
type_uuid
type_uri
type_bytes
Cardinalities
cardinality
cardinality_one
cardinality_many
Optional Schema Attributes
doc
unique
unique_value
unique_identity
index
fulltext
is_component
no_history
Functions
_fn
fn_retract_entity
fn_cas
Common partions
schema_partition
transaction_partition
user_partition
Query placeholders
q?(atom)
Data sources
implicit
inS(placeholder_atom)
db
as_of(tx_id)
since(tx_id)
history
Bindings and find specifications
single_scalar
blank
collection_binding(placeholder_atom)
Clauses
_not(inner_clause)
_not_join(binding_list, inner_clause_list)
_or(inner_clauses)
_or_join(binding_list, inner_clause_list)
_and(inner_clauses)
_pull({:symbol, entity_var}, pattern_clauses)
_expr(function_symbol, remaining_expressions, bindings)
Examples
DatomicGenServer.start(
"datomic:mem://test",
true,
[{:timeout, 20_000}, {:default_message_timeout, 20_000}, {:name, DatomicGenServer}]
)
data_to_add = [%{
Db.id => Db.dbid(Db.schema_partition),
Db.ident => :"person/name",
Db.value_type => Db.type_string,
Db.cardinality => Db.cardinality_one,
Db.doc => "A person's name",
Db.install_attribute => Db.schema_partition
}]
Db.transact(DatomicGenServer, data_to_add)
# => {:ok, %DatomicGenServer.Db.DatomicTransaction{
basis_t_before: 1001,
basis_t_after: 1002,
retracted_datoms: [],
added_datoms: [
%DatomicGenServer.Db.Datom{a: 50, added: true, e: 13194139534314, tx: 13194139534314,
v: %Calendar.DateTime{abbr: "UTC", day: 15, hour: 3, min: 20, month: 2, sec: 1, std_off: 0,
timezone: "Etc/UTC", usec: 746000, utc_off: 0, year: 2016}},
%DatomicGenServer.Db.Datom{a: 41, added: true, e: 65, tx: 13194139534314, v: 35},
%DatomicGenServer.Db.Datom{a: 62, added: true, e: 65, tx: 13194139534314, v: "A person's name"},
%DatomicGenServer.Db.Datom{a: 10, added: true, e: 65, tx: 13194139534314, v: :"person/name"},
%DatomicGenServer.Db.Datom{a: 40, added: true, e: 65, tx: 13194139534314, v: 23},
%DatomicGenServer.Db.Datom{a: 13, added: true, e: 0, tx: 13194139534314, v: 65}],
tempids: %{-9223367638809264706 => 65}}}
query = [:find, Db.q?(:c), :where, [Db.q?(:c), Db.doc, "A person's name"]]
Db.q(DatomicGenServer, query)
#=> {:ok, #MapSet<['A']>} # ASCII representation of ID 65
Summary
Functions
Convenience shortcut for creating an and
clause
Convenience shortcut for creating a Datomic expression clause. Note that this is not the same as a simple Clojure expression inside parentheses
Convenience shortcut for :"db/fn"
Convenience shortcut for creating a not
clause
Convenience shortcut for creating a not-join
clause
Convenience shortcut for creating an or
clause
Convenience shortcut for creating an or-join
clause
Convenience shortcut for creating a Datomic pull expression
Convenience shortcut for :"db/add"
Convenience shortcut for :"db.alter/attribute"
Convenience function to allow passing a call to the Datomic as-of
API function
when creating data source bindings to a query or transaction
Convenience shortcut for the blank binding _
as used, for example, in:
[:find ?x :where [_ :likes ?x]]
Convenience shortcut for :"db/cardinality"
Convenience shortcut for :"db.cardinality/many"
Convenience shortcut for :"db.cardinality/one"
Convenience shortcut for collection binding find specification ...
as used, for example, in: [:find ?e in $ [?a ...] :where [?e age ?a] ]
Convenience shortcut to allow you to pass the current database in the data source bindings to a query or transaction
Convenience function that generates #db/id[ <partition> ]
Convenience shortcut for :"db/doc"
Issues an entity
call to that is passed to the Datomic entity
API function
Convenience shortcut for :"db.fn/cas"
Convenience shortcut for :"db.fn/retractEntity"
Convenience shortcut for :"db/fulltext"
Convenience shortcut to allw passing a call to the Datomic history
API function
when creating data source bindings to a query or transaction
Convenience shortcut for :"db/id"
Convenience shortcut for :"db/ident"
Convenience shortcut for the implicit data source $
Convenience function to generate Datomic data source specifications—i.e., symbols prefixed by a dollar sign
Convenience shortcut for :"db/index"
Convenience shortcut for :"db.install/_attribute"
Convenience shortcut for :"db/isComponent"
Issues a call to the Clojure net.phobot.datomic/seed library to load data into a database using data files in edn format. The database is not dropped, recreated, or migrated before loading
Convenience shortcut for :"db/noHistory"
Queries a DatomicGenServer using a query formulated as an Elixir list.
This query is translated to an edn string which is then passed to the Datomic
q
API function
Convenience function to generate Datomic query placeholders—i.e., symbols prefixed by a question mark
Convenience shortcut for :"db/retract"
Convenience shortcut for :"db.part/db"
Convenience function to allow passing a call to the Datomic since
API function
when creating data source bindings to a query or transaction
Convenience shortcut for the single scalar find specification .
as used, for example, in: [:find ?e . :where [?e age 42] ]
Issues a transaction against a DatomicGenServer using a transaction
formulated as an Elixir list of maps. This transaction is translated to an edn
string which is then passed to the Datomic transact
API function
Convenience shortcut for :"db.part/tx"
Convenience shortcut for :"db/txInstant"
Convenience shortcut for :"db.type/bigdec"
Convenience shortcut for :"db.type/bigint"
Convenience shortcut for :"db.type/boolean"
Convenience shortcut for :"db.type/bytes"
Convenience shortcut for :"db.type/double"
Convenience shortcut for :"db.type/float"
Convenience shortcut for :"db.type/instant"
Convenience shortcut for :"db.type/keyword"
Convenience shortcut for :"db.type/long"
Convenience shortcut for :"db.type/ref"
Convenience shortcut for :"db.type/string"
Convenience shortcut for :"db.type/uri"
Convenience shortcut for :"db.type/uuid"
Convenience shortcut for :"db/unique"
Convenience shortcut for :"db.unique/identity"
Convenience shortcut for :"db.unique/value"
Convenience shortcut for :"db.part/user"
Convenience shortcut for :"db/valueType"
Types
datom_map :: %{e: integer, a: atom, v: term, tx: integer, added: boolean}
query_option ::
DatomicGenServer.send_option |
{:response_converter, (Exdn.exdn -> term)} |
{:edn_tag_handlers, [{atom, Exdn.handler}, ...]}
transaction_result :: %{"db-before": %{"basis-t": integer}, "db-after": %{"basis-t": integer}, "tx-data": [datom_map], tempids: %{integer => integer}}
Functions
Specs
_and([Exdn.exdn]) :: {:list, [Exdn.exdn]}
Convenience shortcut for creating an and
clause.
Note that in Datomic, and
clauses are only for use inside or
clauses; and
is the default otherwise.
In Exdn, Clojure lists are represented as tuples with the tag :list
, so this
function allows us not to have to sprinkle that syntax all over the place.
Example
Db._and([
[Db.q?(:org), :"organization/ngo" true],
[Db.q?(:org), :"organization/country" :"country/france"]
])
sends the following to Datomic:
(and [?org :organization/ngo true]
[?org :organization/country :country/france])
Specs
_expr(atom, [Exdn.exdn], [Exdn.exdn]) :: [{:list, [Exdn.exdn]}]
Convenience shortcut for creating a Datomic expression clause. Note that this is not the same as a simple Clojure expression inside parentheses.
An expression clause allows arbitrary Java or Clojure functions to be used
inside of Datalog queries; they are either of form [(predicate ...)]
or
[(function ...) bindings]
. An expression clause is thus a Clojure list inside
a vector.
In Exdn, Clojure lists are represented as tuples with the tag :list
, so this
function allows us not to have to sprinkle that syntax all over the place.
Specs
_not([Exdn.exdn]) :: {:list, [Exdn.exdn]}
Convenience shortcut for creating a not
clause.
In Exdn, Clojure lists are represented as tuples with the tag :list
, so this
allows us not to have to sprinkle that syntax all over the place.
Example
Db._not([Db.q?(:eid), :"person/age" 13])
sends the following to Datomic:
(not [?eid :person/age 13])
Specs
_not_join([{:symbol, atom}, ...], [Exdn.exdn]) :: {:list, [Exdn.exdn]}
Convenience shortcut for creating a not-join
clause.
In Exdn, Clojure lists are represented as tuples with the tag :list
, so this
function allows us not to have to sprinkle that syntax all over the place.
Example
Db._not_join(
[ Db.q?(:employer) ],
[ [Db.q?(:employer), :"business/employee" Db.q?(:person)],
[Db.q?(:employer), :"business/nonprofit" true]
]
)
sends the following to Datomic:
(not-join [?employer]
[?employer :business/employee ?person]
[?employer :business/nonprofit true])
Specs
_or([Exdn.exdn]) :: {:list, [Exdn.exdn]}
Convenience shortcut for creating an or
clause.
In Exdn, Clojure lists are represented as tuples with the tag :list
, so this
function allows us not to have to sprinkle that syntax all over the place.
Example
Db._or([
[Db.q?(:org), :"business/nonprofit" true],
[Db.q?(:org), :"organization/ngo" true]
])
sends the following to Datomic:
(or [?org :business/nonprofit true]
[?org :organization/ngo true])
Specs
_or_join([{:symbol, atom}, ...], [Exdn.exdn]) :: {:list, [Exdn.exdn]}
Convenience shortcut for creating an or-join
clause.
The first parameter to this function should be a list of bindings; the second the list of clauses.
In Exdn, Clojure lists are represented as tuples with the tag :list
, so this
function allows us not to have to sprinkle that syntax all over the place.
Example
Db._or_join(
[ Db.q?(:person) ],
[ Db._and([
[Db.q?(:employer), :"business/employee", Db.q?(:person)],
[Db.q?(:employer), :"business/nonprofit", true]
]),
[Db.q?(:person), :"person/age", 65]
]
)
sends the following to Datomic:
(or-join [?person]
(and [?employer :business/employee ?person]
[?employer :business/nonprofit true])
[?person :person/age 65])
Specs
_pull({:symbol, atom}, [Exdn.exdn]) :: {:list, [Exdn.exdn]}
Convenience shortcut for creating a Datomic pull expression.
In Exdn, Clojure lists are represented as tuples with the tag :list
, so this
function allows us not to have to sprinkle that syntax all over the place.
Example
Db._pull(Db.q?(:e), [:"person/address"])
sends the following to Datomic:
(pull ?e [:person/address])
Specs
alter_attribute :: :"db.alter/attribute"
Convenience shortcut for :"db.alter/attribute"
Specs
as_of(integer) :: {:list, [Exdn.exdn]}
Convenience function to allow passing a call to the Datomic as-of
API function
when creating data source bindings to a query or transaction.
Accepts an integer as its argument, representing a transaction number or transaction ID. Dates are not yet supported.
Example
Db.q(DatomicGenServer,
[:find, Db.q?(:c), :in, Db.implicit, Db.q?(:docstring),
:where, [Db.q?(:c), Db.doc, Db.q?(:docstring)]],
[Db.as_of(transaction.basis_t_after), "A person's address"]
)
Specs
blank :: {:symbol, :_}
Convenience shortcut for the blank binding _
as used, for example, in:
[:find ?x :where [_ :likes ?x]]
Specs
cardinality_many :: :"db.cardinality/many"
Convenience shortcut for :"db.cardinality/many"
Specs
cardinality_one :: :"db.cardinality/one"
Convenience shortcut for :"db.cardinality/one"
Specs
collection_binding(atom) :: [{:symbol, atom}, ...]
Convenience shortcut for collection binding find specification ...
as used, for example, in: [:find ?e in $ [?a ...] :where [?e age ?a] ]
Specs
db :: {:symbol, :"datomic_gen_server.peer/*db*"}
Convenience shortcut to allow you to pass the current database in the data source bindings to a query or transaction.
This gets bound to the value of the Clojure dynamic variable
datomic_gen_server.peer/*db*
inside the peer.
This value is also used inside functions such as as_of
which take the database
and return a different database value based on transaction time etc.
Example
Db.q(DatomicGenServer,
[:find, Db.q?(:c), :in, Db.implicit, Db.q?(:docstring),
:where, [Db.q?(:c), Db.doc, Db.q?(:docstring)]],
[Db.db, "A person's address"]
)
Specs
dbid(atom) :: {:tag, :"db/id", [atom]}
Convenience function that generates #db/id[ <partition> ]
Specs
entity(GenServer.server, [Exdn.exdn], [atom] | :all, [query_option]) ::
{:ok, term} |
{:error, term}
Issues an entity
call to that is passed to the Datomic entity
API function.
The first parameter to this function is the pid or alias of the GenServer process;
the second is an edn string representing the parameter that is to be passed to
entity
: either an entity id, an ident, or a lookup ref. The third parameter
is a list of atoms that represent the keys of the attributes you wish to fetch,
or :all
if you want all the entity’s attributes.
The options keyword list may include a :client_timeout
option that specifies
the milliseconds timeout passed to GenServer.call, and a :message_timeout
option that specifies how long the GenServer should wait for a response before
crashing (overriding the default value set in start
or start_link
). Note
that if the :client_timeout
is shorter than the :message_timeout
value,
the call will return an error but the server will not crash even if the message
is never returned from the Clojure peer.
Example
Db.entity(DatomicGenServer, :"person/email")
# => {ok, %{ Db.ident => :"person/email",
Db.value_type => Db.type_string,
Db.cardinality => Db.cardinality_one,
Db.doc => "A person's email"}}
Specs
fn_retract_entity :: :"db.fn/retractEntity"
Convenience shortcut for :"db.fn/retractEntity"
Specs
history :: {:list, [Exdn.exdn]}
Convenience shortcut to allw passing a call to the Datomic history
API function
when creating data source bindings to a query or transaction.
This will become of use when datoms and index-range calls and queries are supported.
Specs
inS(atom) :: {:symbol, atom}
Convenience function to generate Datomic data source specifications—i.e., symbols prefixed by a dollar sign.
Accepts an atom as its argument, representing the symbol to which the dollar sign is to be prepended.
Specs
install_attribute :: :"db.install/_attribute"
Convenience shortcut for :"db.install/_attribute"
Specs
load(GenServer.server, String.t, [DatomicGenServer.send_option]) ::
{:ok, DatomicTransaction.t} |
{:error, term}
Issues a call to the Clojure net.phobot.datomic/seed library to load data into a database using data files in edn format. The database is not dropped, recreated, or migrated before loading.
The first parameter to this function is the pid or alias of the GenServer process; the second is the path to the directory containing the data files. The data files will be processed in the sort order of their directory.
Data is loaded in a single transaction. The return value of the function
is the result of the Datomic transact
API function call that executed the
transaction, wrapped in a DatomicTransaction
struct.
Loading data does not use the Clojure Conformity library and is not idempotent.
The options keyword list may include a :client_timeout
option that specifies
the milliseconds timeout passed to GenServer.call, and a :message_timeout
option that specifies how long the GenServer should wait for a response before
crashing (overriding the default value set in start
or start_link
). Note
that if the :client_timeout
is shorter than the :message_timeout
value,
the call will return an error but the server will not crash even if the message
is never returned from the Clojure peer.
Example
data_dir = Path.join [System.cwd(), "seed-data"]
DatomicGenServer.load(DatomicGenServer, data_dir)
=> {:ok, "{:db-before {:basis-t 1000}, :db-after {:basis-t 1000}, ...
Specs
q(GenServer.server, [Exdn.exdn], [Exdn.exdn], [query_option]) ::
{:ok, term} |
{:error, term}
Queries a DatomicGenServer using a query formulated as an Elixir list.
This query is translated to an edn string which is then passed to the Datomic
q
API function.
The first parameter to this function is the pid or alias of the GenServer process; the second is the query.
The optional third parameter is a list of bindings for the data sources in the
query, passed to the inputs
argument of the Datomic q
function. IMPORTANT:
These bindings are converted to edn strings which are read back in the Clojure
peer and then passed to Clojure eval
. Since any arbitrary Clojure forms that
are passed in are evaluated, you must be particularly careful that the bindings
are sanitized and that you are not passing anything in {:list, [...]}
expressions that you don’t control.
Bindings may include datomic_gen_server.peer/*db*
for the current database
(or the db
shortcut below), as well as the forms produced by as_of
and
since
below. These accept transaction times or transaction IDs.
The options keyword list may include a :client_timeout
option that specifies
the milliseconds timeout passed to GenServer.call
, and a :message_timeout
option that specifies how long the GenServer should wait for a response before
crashing (overriding the default value set in DatomicGenServer.start
or
DatomicGenServer.start_link
). Note that if the :client_timeout
is shorter
than the :message_timeout
value, the call will return an error but the server
will not crash even if the response message is never returned from the Clojure peer.
Example
query = [:find, Db.q?(:c), :where, [Db.q?(:c), Db.doc, "A person's name"]]
Db.q(DatomicGenServer, query)
#=> {:ok, #MapSet<['A']>} # ASCII representation of ID 65
Specs
q?(atom) :: {:symbol, atom}
Convenience function to generate Datomic query placeholders—i.e., symbols prefixed by a question mark.
Accepts an atom as its argument, representing the symbol to which the question mark is to be prepended.
Specs
since(integer) :: {:list, [Exdn.exdn]}
Convenience function to allow passing a call to the Datomic since
API function
when creating data source bindings to a query or transaction.
Accepts an integer as its argument, representing a transaction number or transaction ID. Dates are not yet supported.
Example
Db.q(DatomicGenServer,
[:find, Db.q?(:c), :in, Db.implicit, Db.q?(:docstring),
:where, [Db.q?(:c), Db.doc, Db.q?(:docstring)]],
[Db.since(transaction.basis_t_after), "A person's address"]
)
Specs
single_scalar :: {:symbol, :.}
Convenience shortcut for the single scalar find specification .
as used, for example, in: [:find ?e . :where [?e age 42] ]
Specs
transact(GenServer.server, [Exdn.exdn], [DatomicGenServer.send_option]) ::
{:ok, DatomicTransaction.t} |
{:error, term}
Issues a transaction against a DatomicGenServer using a transaction
formulated as an Elixir list of maps. This transaction is translated to an edn
string which is then passed to the Datomic transact
API function.
The first parameter to this function is the pid or alias of the GenServer process; the second is the transaction data.
The options keyword list may include a :client_timeout
option that specifies
the milliseconds timeout passed to GenServer.call, and a :message_timeout
option that specifies how long the GenServer should wait for a response before
crashing (overriding the default value set in DatomicGenServer.start
or
DatomicGenServer.start_link
). Note that if the :client_timeout
is shorter
than the :message_timeout
value, the call will return an error but the server
will not crash even if the response message is never returned from the Clojure peer.
Example
data_to_add = [%{
Db.id => Db.dbid(Db.schema_partition),
Db.ident => :"person/name",
Db.value_type => Db.type_string,
Db.cardinality => Db.cardinality_one,
Db.doc => "A person's name",
Db.install_attribute => Db.schema_partition
}]
Db.transact(DatomicGenServer, data_to_add)
# => {:ok, %DatomicGenServer.Db.DatomicTransaction{
basis_t_before: 1001,
basis_t_after: 1002,
retracted_datoms: [],
added_datoms: [
%DatomicGenServer.Db.Datom{a: 50, added: true, e: 13194139534314, tx: 13194139534314,
v: %Calendar.DateTime{abbr: "UTC", day: 15, hour: 3, min: 20, month: 2, sec: 1, std_off: 0,
timezone: "Etc/UTC", usec: 746000, utc_off: 0, year: 2016}},
%DatomicGenServer.Db.Datom{a: 41, added: true, e: 65, tx: 13194139534314, v: 35},
%DatomicGenServer.Db.Datom{a: 62, added: true, e: 65, tx: 13194139534314, v: "A person's name"},
%DatomicGenServer.Db.Datom{a: 10, added: true, e: 65, tx: 13194139534314, v: :"person/name"},
%DatomicGenServer.Db.Datom{a: 40, added: true, e: 65, tx: 13194139534314, v: 23},
%DatomicGenServer.Db.Datom{a: 13, added: true, e: 0, tx: 13194139534314, v: 65}],
tempids: %{-9223367638809264706 => 65}}}
Specs
transaction_partition :: :"db.part/tx"
Convenience shortcut for :"db.part/tx"
Specs
unique_identity :: :"db.unique/identity"
Convenience shortcut for :"db.unique/identity"