datomic_gen_server v2.1.0 DatomicGenServer

DatomicGenServer is an Elixir GenServer that communicates with a Clojure Datomic peer running in the JVM, using clojure-erlastic.

The interface functions in this module communicate with Datomic using edn strings. To use Elixir data structures, see the accompanying DatomicGenServer.db module.

Examples

DatomicGenServer.start(
  "datomic:mem://test", 
  true, 
  [{:timeout, 20_000}, {:default_message_timeout, 20_000}, {:name, DatomicGenServer}]
)

query = "[:find ?c :where [?c :db/doc \"Some docstring that isn't in the database\"]]"
DatomicGenServer.q(DatomicGenServer, query)

# => {:ok, "#{}\n"}

data_to_add = """
  [ { :db/id #db/id[:db.part/db]
      :db/ident :person/name
      :db/valueType :db.type/string
      :db/cardinality :db.cardinality/one
      :db/doc \"A person's name\"
      :db.install/_attribute :db.part/db}]
"""

DatomicGenServer.transact(DatomicGenServer, data_to_add)

# => {:ok, "{:db-before {:basis-t 1000}, :db-after {:basis-t 1000}, 
              :tx-data [{:a 50, :e 13194139534313, :v #inst \"2016-02-14T02:10:54.580-00:00\", 
              :tx 13194139534313, :added true} {:a 10, :e 64, :v :person/name, :tx 13194139534313, 
              :added true} {:a 40, :e 64, :v 23, :tx 13194139534313, :added true} {:a 41, 
              :e 64, :v 35, :tx 13194139534313, :added true} {:a 62, :e 64, 
              :v \"A person's name\", :tx 13194139534313, :added true} {:a 13, 
              :e 0, :v 64, :tx 13194139534313, :added true}], :tempids {-9223367638809264705 64}}"}

Summary

Functions

Issues an entity call that is passed to the Datomic entity API function

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

Issues a call to net.phobot.datomic/migrator to migrate a database using database migration files in edn format

Saves a snapshot of the current database state using a supplied key, and creates a mock connection (using the datomock library) using that database as a starting point. Requires the :allow_datomic_mocking? configuration parameter to be set in the :datomic_gen_server application environment; otherwise the current connection and database continue to be active. Subsequent operations on the database will use the mock connection until you call either the reset or unmock functions

Queries a DatomicGenServer using a query formulated as an edn string. This query is passed to the Datomic q API function

Generates a new mock connection using a database snapshot previously saved using the mock function. Requires the :allow_datomic_mocking? configuration parameter to be set in the :datomic_gen_server application enviroment; otherwise the current connection and database continue to be active

Starts the GenServer in a linked process

Issues a transaction against a DatomicGenServer using a transaction formulated as an edn string. This transaction is passed to the Datomic transact API function

Reverts to using a database derived from the real database connection rather than a mocked connection. If no mock connection is active, this function is a no-op

Types

datomic_call :: {datomic_message, message_timeout :: non_neg_integer}
datomic_message ::
  {:q, integer, String.t, [String.t]} |
  {:transact, integer, String.t} |
  {:entity, integer, String.t, [atom] | :all} |
  {:migrate, integer, String.t} |
  {:load, integer, String.t} |
  {:mock, integer, atom} |
  {:reset, integer, atom} |
  {:unmock, integer}
datomic_result :: {:ok, String.t} | {:error, term}
send_option ::
  {:message_timeout, non_neg_integer} |
  {:client_timeout, non_neg_integer}
start_option ::
  GenServer.option |
  {:default_message_timeout, non_neg_integer}

Functions

entity(server_identifier, edn_str, attr_names \\ :all, options \\ [])

Specs

entity(GenServer.server, String.t, [atom] | :all, [send_option]) :: datomic_result

Issues an entity call 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

DatomicGenServer.entity(DatomicGenServer, ":person/email", [:"db/valueType", :"db/doc"])

=> {:ok, "{:db/valueType :db.type/string, :db/doc \"A person's email\"}\n"}
load(server_identifier, data_path, options \\ [])

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. If you want this result in a struct, call the wrapper load function in the DatomicGenServer.Db module.

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}, ...
migrate(server_identifier, migration_path, options \\ [])

Issues a call to net.phobot.datomic/migrator to migrate a database using database migration files in edn format.

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. Files will be processed in sort order. The Clojure Conformity library is used to keep the migrations 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

DatomicGenServer.migrate(DatomicGenServer, Path.join [System.cwd(), "migrations"])

=> {:ok, :migrated}
mock(server_identifier, db_key, options \\ [])

Specs

Saves a snapshot of the current database state using a supplied key, and creates a mock connection (using the datomock library) using that database as a starting point. Requires the :allow_datomic_mocking? configuration parameter to be set in the :datomic_gen_server application environment; otherwise the current connection and database continue to be active. Subsequent operations on the database will use the mock connection until you call either the reset or unmock functions.

The first parameter to this function is the pid or alias of the GenServer process; the second is the key under which to store the database snapshot. If successful, the return value is a tuple of :ok and the key that was passed to the function.

The active database can be reverted to the initial snapshot using the reset function, or can be switched back to use the real, live connection and database using the unmock function.

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

DatomicGenServer.mock(DatomicGenServer, :"just-migrated")

=> {:ok, :"just-migrated"}
q(server_identifier, edn_str, bindings_edn \\ [], options \\ [])

Queries a DatomicGenServer using a query formulated as an edn string. This query is 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 passed in the form of 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 these bindings are sanitized and that you are not passing anything that you don’t control. In general, you should prefer the DatomicGenServer.Db.q/3 function which accepts data structures and converts them to edn.

Bindings may include datomic_gen_server.peer/*db* for the current database.

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 response message is never returned from the Clojure peer.

Example

query = "[:find ?c :where [?c :db/doc \"Some docstring that isn't in the database\"]]"
DatomicGenServer.q(DatomicGenServer, query)

=> {:ok, "#{}\n"}
reset(server_identifier, db_key, options \\ [])

Specs

Generates a new mock connection using a database snapshot previously saved using the mock function. Requires the :allow_datomic_mocking? configuration parameter to be set in the :datomic_gen_server application enviroment; otherwise the current connection and database continue to be active.

The first parameter to this function is the pid or alias of the GenServer process; the second is the key under which the database snapshot was saved. If successful, the return value is a tuple of :ok and the key that was passed to the function.

The database can be switched back to a real connection using the unmock function. It is also possible to manipulate the mocked database and save that new database state in a snapshot using the mock function.

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

DatomicGenServer.reset(DatomicGenServer, :"just-migrated")

=> {:ok, :"just-migrated"}
start(db_uri, create? \\ false, options \\ [])

Specs

start(String.t, boolean, [start_option]) :: GenServer.on_start

Starts the GenServer.

This function is basically a pass-through to GenServer.start, but with some additional parameters: The first is the URL of the Datomic transactor to which to connect, and the second a boolean parameter indicating whether or not to create the database if it does not yet exist.

The options keyword list may include the normal options accepted by GenServer.start, as well as a :default_message_timeout option that controls the default time in milliseconds that the server will wait for a message before crashing. Note that if the :timeout option is provided, the GenServer will crash if that timeout is exceeded.

Example

DatomicGenServer.start(
  "datomic:mem://test", 
  true, 
  [{:timeout, 20_000}, {:default_message_timeout, 20_000}, {:name, DatomicGenServer}]
)
start_link(db_uri, create? \\ false, options \\ [])

Specs

start_link(String.t, boolean, [start_option]) :: GenServer.on_start

Starts the GenServer in a linked process.

This function is basically a pass-through to GenServer.start_link, but with some additional parameters: The first is the URL of the Datomic transactor to which to connect, and the second a boolean parameter indicating whether or not to create the database if it does not yet exist.

The options keyword list may include the normal options accepted by GenServer.start_link, as well as a :default_message_timeout option that controls the default time in milliseconds that the server will wait for a message before crashing. Note that if the :timeout option is provided, the GenServer will crash if that timeout is exceeded.

Example

DatomicGenServer.start_link(
  "datomic:mem://test", 
  true, 
  [{:timeout, 20_000}, {:default_message_timeout, 20_000}, {:name, DatomicGenServer}]
)
transact(server_identifier, edn_str, options \\ [])

Issues a transaction against a DatomicGenServer using a transaction formulated as an edn string. This transaction is 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 in edn format. 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 response message is never returned from the Clojure peer.

Example

data_to_add = """
  [ { :db/id #db/id[:db.part/db]
      :db/ident :person/name
      :db/valueType :db.type/string
      :db/cardinality :db.cardinality/one
      :db/doc \"A person's name\"
      :db.install/_attribute :db.part/db}]
"""

DatomicGenServer.transact(DatomicGenServer, data_to_add)

=> {:ok, "{:db-before {:basis-t 1000}, :db-after {:basis-t 1000}, 
          :tx-data [{:a 50, :e 13194139534313, :v #inst \"2016-02-14T02:10:54.580-00:00\", 
          :tx 13194139534313, :added true} {:a 10, :e 64, :v :person/name, :tx 13194139534313, 
          :added true} {:a 40, :e 64, :v 23, :tx 13194139534313, :added true} {:a 41, 
          :e 64, :v 35, :tx 13194139534313, :added true} {:a 62, :e 64, 
          :v \"A person's name\", :tx 13194139534313, :added true} {:a 13, 
          :e 0, :v 64, :tx 13194139534313, :added true}], :tempids {-9223367638809264705 64}}"}
unmock(server_identifier, options \\ [])

Reverts to using a database derived from the real database connection rather than a mocked connection. If no mock connection is active, this function is a no-op.

If the call is successful, the return value is a tuple of :ok and :unmocked.

The first parameter to this function is the pid or alias of the GenServer process.

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

DatomicGenServer.unmock(DatomicGenServer)

=> {:ok, :unmocked}