;; IMPORTANT: Its possible to add only one datom (e. g.: only :product/name) ;(defn save-product-only-name [product-document] ; (let [result @(d/transact datomic-config/conn ; [{:db/id #db/id[:db.part/user] ; :product/name (product-document/get-name product-document)}])] ; result)) ; ;; In this case: error: if a datom is not part of an entity, its only not add it in the save operation ;(defn save-product-only-name-error [product-document] ; (let [result @(d/transact datomic-config/conn ; [{:db/id #db/id[:db.part/user] ; :product/name (product-document/get-name product-document) ; :product/slug nil}])]
; IMPORTANT: d/transact is an async operation in clojure ; WITH @: SYNC ; WITHOUT @: ASYNC (like all futures in clojure)
; getting IDS: ; considering partition, etc. other way: not considering partition ;temp-ids-v1 (val (first (:tempids result)))
Vamos dizer que temos o seguinte código:
(let [computador (model/novo-produto "Computador Novo", "/computador_novo", 2500.10M)
celular (model/novo-produto "Celular Caro", "/celular", 888888.10M)
calculadora {:produto/nome "Calculadora com 4 operações"}
celular-barato (model/novo-produto "Celular Barato", "/celular-barato", nil)]
(d/transact conn [computador celular calculadora celular-barato]))Estamos transacionando para o Datomic 4 produtos ao mesmo tempo.
Note que for o celular-barato está com o preço nulo.
Ao executarmos o código anterior, obtemos o seguinte erro:
Execution error (Exceptions$IllegalArgumentExceptionInfo) at datomic.error/arg (error.clj:79). :db.error/nil-value Nil is not a legal valueCopiar código O Datomic não aceita valores nulos. Por isso obtivemos um erro.
OK, mas apenas o último produto, o celular-barato, teve um valor nulo. O que será que aconteceu com os outros produtos? Foram inseridos ou não?
Considerando que o Datomic não tinha nenhum produto antes dessa transação, podemos verificar os produtos depois da execução com a consulta:
(pprint (db/todos-os-produtos)(d/db conn))Copiar código O resultado seria um conjunto vazio:
#{}Copiar código Ou seja, ao transacionarmos 4 produtos ao mesmo tempo, se ocorrer algum erro no último, a transação toda é cancelada.
Essa característica transacional de fazer "ou tudo ou nada" é chamada de Atomicidade: se uma parte da transação falhar, a transação toda falha e nenhuma mudança é feita no BD.
(IMPORTANT: NÂO TEM ORDEM no escopo de varias transacoes)
- Order: by where clause
- filter the more restrictive first (to limit data) (there is no action plan under a query as the SQL databases)
(defn find-product-by-name [name]
(d/q '[:find ?name ?slug ?price
:in $ ?name
:where
[?e :product/name ?name]
[?e :product/slug ?slug]
[?e :product/price ?price]]
(d/db (datomic-config/get-db)) name))(defn query-with-pagination
[db {:keys [offset limit] :or {offset 0 limit 10}}]
(let [query '[:find ?e ?name ?price
:in $ ?offset ?limit
:where
[?e :product/name ?name]
[?e :product/price ?price]]
result (->> (d/q query db offset limit)
(drop offset)
(take limit))]
result))Must use db/add by attributes
(defn update [product-document]
(let [id (get product-document :product/id)]
@(d/transact
(datomic-config/get-db)
[[:db/add id :product/name (documents.product/get-name product-document)]
[:db/add id :product/slug (documents.product/get-slug product-document)]
[:db/add id :product/price (documents.product/get-price product-document)]
])
product-document))- to remove: db/retract only
(defn find-by-bd-id-v2 [product-id]
(let [response (d/pull (datomic-config/get-db) '[*] product-id)]
response))
; for other attributes as `:db/unique :db.unique/identity`
(defn find-by-product-id [product-id]
(let [response (d/pull (datomic-config/get-db) '[*] [:product/id product-id])]
response))Using UUID as attribute of an entity, we can use this property to update the datons of a property since a db/transact with the same UUID lead to retract+ add the values of the others attributes
- Create category atomically with product
(defn save [product-document]
(let [product-document-id (add-product-id product-document)]
@(d/transact (datomic-config/get-db) [{:product/id "uuid"
:product/name "uuid"
:product/slug "uuid"
:product/price 123
:product/category {:category/id "uuid"
:category/name "name"}
}])
product-document-id))- Create product with reference to already created category
- Note that is different to add uuid directly to :product/category
(defn save [product-document]
(let [product-document-id (add-product-id product-document)]
@(d/transact (datomic-config/get-db) [{:product/id "uuid"
:product/name "uuid"
:product/slug "uuid"
:product/price 123
:product/category {:category/id "uuid"}
}])
product-document-id))- Queries under queries to have access in database once
- Atomic find (two finds can lead in inconsistency)
(defn todos-os-produtos-mais-caros [db]
(d/q '[:find (pull ?produto [*])
:where [(q '[:find (max ?preco)
:where [_ :produto/preco ?preco]]
$) [[?preco]]]
[?produto :produto/preco ?preco]]
db))- Transactions:
- Multiples maps in d/transact or multiple db/add for the same entity: same transaction
- We can add attributes in the Transaction Entity
(let [computador (model/novo-produto "Computador Novo", "/computador-novo", 2500.10M)
celular (model/novo-produto "Celular Caro", "/celular", 888888.10M)
calculadora {:produto/nome "Calculadora com 4 operações"}
celular-barato (model/novo-produto "Celular Barato", "/celular-barato", 0.1M)]
(pprint @(d/transact conn [computador, celular, calculadora, celular-barato])))(defn build-update-adds [id product-document]
(let [base-inputs [[:db/add id :product/id (documents.product/get-id product-document)]
[:db/add id :product/name (documents.product/get-name product-document)]
[:db/add id :product/slug (documents.product/get-slug product-document)]
[:db/add id :product/price (documents.product/get-price product-document)]
]
keywords (map (fn-add-property-executor id :product/keyword) (documents.product/get-keywords product-document))
inputs (vec (concat base-inputs keywords))]
inputs))Adding attributes in Transaction Entity:
(defn todos-os-produtos-do-ip [db ip]
(d/q '[:find (pull ?produto [*])
:in $ ?ip-buscado
:where [?transacao :tx-data/ip ?ip-buscado]
[?produto :produto/id _ ?transacao]]
db ip))