datomic_gen_server v1.1.0 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 \ [])
seed(server_identifier, migration_path, seed_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)
Bindings and find specifications
single_scalar
blank_binding
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
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 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 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 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"
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"
Issues a call to net.phobot.datomic/seed to seed a database using database migration files and seed data files in edn format. The database is not dropped or recreated before migrating and seeding
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.
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
blank_binding :: {: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
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
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
q(GenServer.server, [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 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
seed(GenServer.server, String.t, String.t, [DatomicGenServer.send_option]) ::
{:ok, DatomicGenServer.Db.DatomicTransaction.t} |
{:error, term}
Issues a call to net.phobot.datomic/seed to seed a database using database migration files and seed data files in edn format. The database is not dropped or recreated before migrating and seeding.
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 migration files. The third parameter is the path to a (different) directory containing the seed data files. The migration files will be processed in the sort order of their directory, and then the seed data files in the sort order of their directory.
Seed 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.
The Clojure Conformity library is used to keep the migrations idempotent, but the loading of seed data 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
migration_dir = Path.join [System.cwd(), "migrations"]
seed_data_dir = Path.join [System.cwd(), "seed-data"]
DatomicGenServer.seed(DatomicGenServer, migration_dir, seed_data_dir)
=> {:ok, "{:db-before {:basis-t 1000}, :db-after {:basis-t 1000}, ...
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, DatomicGenServer.Db.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"