# Add attribute check to db call

**URL:** <https://forum.datomic.com/t/add-attribute-check-to-db-call/414>\
**Category:** Datomic Applications\
**Created:** [April 24, 2018, 5:44am UTC](https://forum.datomic.com/t/add-attribute-check-to-db-call/414 "2018-04-24T05:44:51Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![pcolliander](https://avatars.discourse-cdn.com/v4/letter/p/2acd7d/32.png) [@pcolliander](https://forum.datomic.com/u/pcolliander)\
**Post date:** [April 24, 2018, 5:44am UTC](https://forum.datomic.com/t/add-attribute-check-to-db-call/414/1 "2018-04-24T05:44:51Z")

</div>

In my application I was using a transaction function like this to delete an entity:  
`(d/transact conn [[:db.fn/retractEntity id]])`.

I decided to add a check that the given entity also has the same user ID attribute that’s coming from a token in the incoming request, to mitigate that someone could potentially try to just a lot of requests with different IDs and sabotage for other users. Currently solved by doing this:

```auto
(let [{:keys [user-id]} token
       entity-user-id (-> (d/pull (d/db conn) '[*] entity-id) :notebook/user :db/id)]                                                                                                                              

  (when (= user-id entity-user-id)                                                                                                                                                                         
     (d/transact conn [[:db.fn/retractEntity id]]))))})

```

I’m guessing this requires two database calls and since I’m using this pattern in all mutations now, I was wondering if anyone knows if there is a simpler/better way to do that in just one db call? I read through the documentation but couldn’t find anything.

In SQL I’d do this with:  
`DELETE FROM X WHERE id = y AND userId = z;`

Best regards,

---

<div class="post-metadata">

**Author:** ![benfle](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.datomic.com/benfle/32/164_2.png) [@benfle](https://forum.datomic.com/u/benfle)\
**Post date:** [April 24, 2018, 2:18pm UTC](https://forum.datomic.com/t/add-attribute-check-to-db-call/414/2 "2018-04-24T14:18:15Z")

</div>

It seems like it should be part of your authorization mechanism in your application. Could you use [filters](https://docs.datomic.com/on-prem/filters.html) to restrict a database to the entities “owned” by a user? You would first lookup the entity id in this filtered database and fail if you can’t find it.

---

<div class="post-metadata">

**Author:** ![marshall](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.datomic.com/marshall/32/48_2.png) [@marshall](https://forum.datomic.com/u/marshall)\
**Post date:** [April 25, 2018, 5:02pm UTC](https://forum.datomic.com/t/add-attribute-check-to-db-call/414/3 "2018-04-25T17:02:44Z")

</div>

Are you using Datomic Cloud or Datomic On-Prem?

If you’re using the Peer library with Datomic On-Prem, the n+1 roundtrip issue is not generally a problem, since much of the work you’re performing is happening locally on the peer (and is likely in cache).

If you’re using Client you could use a [compare-and-swap](https://docs.datomic.com/cloud/transactions/transaction-functions.html#sec-2) on a “permission” attribute (perhaps with an external user ID value). If the cas fails, the entire transaction will fail.

---

<div class="post-metadata">

**Author:** ![pcolliander](https://avatars.discourse-cdn.com/v4/letter/p/2acd7d/32.png) [@pcolliander](https://forum.datomic.com/u/pcolliander)\
**Post date:** [April 26, 2018, 4:52pm UTC](https://forum.datomic.com/t/add-attribute-check-to-db-call/414/4 "2018-04-26T16:52:47Z")

</div>

Thanks for the replies. I like both suggestions with filters and cas, I think I’d like to try `cas`. Am I understanding this correctly: I’d do two updates with every update, one being to set the user ID of an attribute to the same user ID again it already has like this:

```auto
[[:db/cas entity-id :notebook/user real-user-ID user-id-from-token]
[:db/retractEntity entity-ID]]]

```

And these two would be done in a transaction. So if the `:db/cas` fails because the `user-id-from-token` doesn’t match up with the `real-user-id`, the other `:db/retractEntity` fails as well?

If I understood it correctly, how would I get the `real-user-id` in that case, a lookup-ref?

---

<div class="post-metadata">

**Author:** ![marshall](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.datomic.com/marshall/32/48_2.png) [@marshall](https://forum.datomic.com/u/marshall)\
**Post date:** [April 26, 2018, 5:12pm UTC](https://forum.datomic.com/t/add-attribute-check-to-db-call/414/5 "2018-04-26T17:12:04Z")

</div>

Yes, essentially. However you won’t be able to have the cas assert the same value (i.e. the same ID) and use retractEntity in the same transaction. The reason for this is that retractEntity will generate a datom that retracts the real-user-ID, while the CAS will create a datom that asserts the same value. This will result in a “two datoms conflict” error.

I would recommend something like:

```auto
[[:db/cas entity-ID :notebook/user user-id-from-token "<userID>+RETRACTED"]
 [:db/retractEntity entity-ID]]

```

This cas structure now says “change the value of the :notebook/user attribute on the entity with entity-ID to “+RETRACTED” only if the user-id that came from the request token is the current value for that attribute”

As you surmised, if the compare fails (because the request token id doesn’t match the actual user ID in the db) the entire transaction will abort.

---

<div class="post-metadata">

**Author:** ![marshall](https://sea2.discourse-cdn.com/flex016/user_avatar/forum.datomic.com/marshall/32/48_2.png) [@marshall](https://forum.datomic.com/u/marshall)\
**Post date:** [April 26, 2018, 5:13pm UTC](https://forum.datomic.com/t/add-attribute-check-to-db-call/414/6 "2018-04-26T17:13:26Z")

</div>

Note that the one downside of this approach is you will be left with a single datom present for this entity, the `[eid :notebook/user "<userID>+RETRACTED"]` datom, as it will be asserted by the `cas` during this transaction.
