Skip to content

Commit

Permalink
Merge pull request #73 from leonardoborges/master
Browse files Browse the repository at this point in the history
Add expressions support to put-item and update-item.
  • Loading branch information
ptaoussanis committed Nov 30, 2015
2 parents 0b59f73 + d0c24e5 commit 8974bd1
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 27 deletions.
83 changes: 58 additions & 25 deletions src/taoensso/faraday.clj
Expand Up @@ -680,22 +680,37 @@
(ExpectedAttributeValue. (clj-val->db-val %))))
expected-map)))

(defn clj->db-expr-values-map [m]
(into {} (for [[k v] m]
[k (clj-val->db-val v)])))

(defn put-item-request
[table item & [{:keys [return expected return-cc?]
[table item & [{:keys [return expected return-cc? condition-expression expression-attr-names expression-attr-values]
:or {return :none}}]]
(doto-cond [g (PutItemRequest.)]
:always (.setTableName (name table))
:always (.setItem (clj-item->db-item item))
expected (.setExpected (expected-values g))
return (.setReturnValues (utils/enum g))
return-cc? (.setReturnConsumedCapacity (utils/enum :total))))
:always (.setTableName (name table))
:always (.setItem (clj-item->db-item item))
expected (.setExpected (expected-values g))
condition-expression (.setConditionExpression condition-expression)
expression-attr-names (.withExpressionAttributeNames expression-attr-names)
expression-attr-values (.withExpressionAttributeValues
(clj->db-expr-values-map expression-attr-values))
return (.setReturnValues (utils/enum g))
return-cc? (.setReturnConsumedCapacity (utils/enum :total))))

(defn put-item
"Adds an item (Clojure map) to a table with options:
:return - e/o #{:none :all-old}.
:expected - {<attr> <#{:exists :not-exists [comparison-operators <value>] <value>}> ...}."
[client-opts table item & [{:keys [return expected return-cc?]
:condition-expression - \"attribute_exists(attr_name) AND|OR ...\"
:expression-attr-names - {\"#attr_name\" \"name\"}
:expression-attr-values - {\":attr_value\" \"value\"}"
[client-opts table item & [{:keys [return expected return-cc? condition-expression]
:as opts}]]
(assert (not (and expected
condition-expression))
"Only one of :expected or :condition-expression should be provided.")
(when expected
(prn "WARNING - :expected is a legacy option and has been deprecated. Please use :condition-expression instead"))
(as-map
(.putItem (db-client client-opts)
(put-item-request table item opts))))
Expand All @@ -714,29 +729,47 @@
update-map)))

(defn update-item-request
[table prim-kvs update-map & [{:keys [return expected return-cc?]
[table prim-kvs update-map & [{:keys [return expected return-cc?
condition-expression
update-expression expression-attr-names expression-attr-values]
:or {return :none}}]]
(doto-cond [g (UpdateItemRequest.)]
:always (.setTableName (name table))
:always (.setKey (clj-item->db-item prim-kvs))
:always (.setAttributeUpdates (attribute-updates update-map))
expected (.setExpected (expected-values g))
return (.setReturnValues (utils/enum g))
return-cc? (.setReturnConsumedCapacity (utils/enum :total))))
:always (.setTableName (name table))
:always (.setKey (clj-item->db-item prim-kvs))
update-map (.setAttributeUpdates (attribute-updates update-map))
update-expression (.setUpdateExpression update-expression)
expression-attr-names (.withExpressionAttributeNames expression-attr-names)
expression-attr-values (.withExpressionAttributeValues
(clj->db-expr-values-map expression-attr-values))
expected (.setExpected (expected-values g))
condition-expression (.setConditionExpression condition-expression)
return (.setReturnValues (utils/enum g))
return-cc? (.setReturnConsumedCapacity (utils/enum :total))))

(defn update-item
"Updates an item in a table by its primary key with options:
prim-kvs - {<hash-key> <val>} or {<hash-key> <val> <range-key> <val>}.
update-map - {<attr> [<#{:put :add :delete}> <optional value>]}.
:return - e/o #{:none :all-old :updated-old :all-new :updated-new}.
:expected - {<attr> <#{:exists :not-exists [comparison-operators <value>] <value>}> ...}.
Where comparison-operators e/o #{:eq :le :lt :ge :gt :begins-with :between}."
[client-opts table prim-kvs update-map & [{:keys [return expected return-cc?]
:as opts}]]
(as-map
(.updateItem (db-client client-opts)
(update-item-request table prim-kvs update-map opts))))
:condition-expression - \"attribute_exists(attr_name) AND|OR ...\"
:update-expression - \"SET #attr_name = :attr_value\"
:expression-attr-names - {\"#attr_name\" \"name\"}
:expression-attr-values - {\":attr_value\" \"value\"}
:return - e/o #{:none :all-old :updated-old :all-new :updated-new}."
([client-opts table prim-kvs update-map & [{:keys [return expected return-cc?
condition-expression update-expression]
:as opts}]]
(assert (not (and expected
condition-expression))
"Only one of :expected or :condition-expression should be provided.")
(assert (not (and (not (empty? update-map))
update-expression))
"Only one of 'update-map' or :update-expression should be provided.")
(when expected
(prn "WARNING - :expected is a legacy option and has been deprecated. Please use :condition-expression instead"))
(when update-map
(prn "WARNING - update-map is a legacy option and has been deprecated. Please use :condition-expression instead"))
(as-map
(.updateItem (db-client client-opts)
(update-item-request table prim-kvs update-map opts)))))

(defn delete-item-request "Implementation detail."
[table prim-kvs & [{:keys [return expected return-cc?]
Expand Down
42 changes: 40 additions & 2 deletions test/taoensso/faraday/tests/main.clj
Expand Up @@ -97,8 +97,46 @@
(expect
#= (far/ex :conditional-check-failed)
(far/update-item *client-opts* ttable
{:id 10} {:name [:put "baz"]}
{:expected {:name "garbage"}})))
{:id 10} {:name [:put "baz"]}
{:expected {:name "garbage"}})))



;; Expressions support
(let [i {:id 10 :name "update me"}]
(after-setup!
#(far/delete-item *client-opts* ttable {:id 10}))

(expect ; Update expression support in update-item
{:id 10 :name "foo"}
(do
(far/update-item *client-opts* ttable
{:id 10}
{}
{:update-expression "SET #name = :name"
:expression-attr-names {"#name" "name"}
:expression-attr-values {":name" "foo"}
:return :all-new})))

(expect ; Condition expression support in update-item
#= (far/ex :conditional-check-failed)
(do
(far/update-item *client-opts* ttable
{:id 10}
{}
{:update-expression "SET #name = :name"
:expression-attr-names {"#name" "name"}
:expression-attr-values {":name" "foo"}
:condition-expression "#name <> :name"
:return :all-new})))

(expect ; Condition expression support in put-item
#= (far/ex :conditional-check-failed)
(do
(far/put-item *client-opts* ttable i
{:condition-expression "attribute_not_exists(id) AND #name <> :name"
:expression-attr-names {"#name" "name"}
:expression-attr-values {":name" "foo"}}))))

(let [items [{:id 11 :name "eleven" :test "batch"}
{:id 12 :name "twelve" :test "batch"}
Expand Down

0 comments on commit 8974bd1

Please sign in to comment.