Fork me on GitHub
#datalevin
<
2024-08-10
fs4205:08:47

When you transact-kv and :put a key with a nil value, it seems that it won't overwrite the key or do anything - no exception or error code. Not sure what the correct behavior should be (?). A clj map can have a nil value for a key... I tried to follow the code through the datalevin and lmdb source code, but I realized that is not an exercise for mere mortals... hat tip to the authors!

fs4205:08:47

Ok... just noticed some unexpected behavior that may not be "correct": -- clj꞉datalevin-kvutils꞉> (d/get-range db "tst-dbi" [:all]) [] clj꞉datalevin-kvutils꞉> (d/transact-kv db [[:put "tst-dbi" 1 222 :data :data]]) nil clj꞉datalevin-kvutils꞉> (d/get-range db "tst-dbi" [:all]) [[1 222]] clj꞉datalevin-kvutils꞉> (d/transact-kv db [[:put "tst-dbi" 1 nil :data :data]]) nil clj꞉datalevin-kvutils꞉> (d/get-range db "tst-dbi" [:all]) [[1 222]] clj꞉datalevin-kvutils꞉> (d/transact-kv db [[:put "tst-dbi" 2 nil :data :data]]) nil clj꞉datalevin-kvutils꞉> (d/get-range db "tst-dbi" [:all]) [[1 222] [2 222]] clj꞉datalevin-kvutils꞉> (d/transact-kv db [[:put "tst-dbi" 3 nil :data :data]]) nil clj꞉datalevin-kvutils꞉> (d/transact-kv db [[:put "tst-dbi" 4 nil :data :data]]) nil clj꞉datalevin-kvutils꞉> (d/get-range db "tst-dbi" [:all]) [[1 222] [2 222] [3 222] [4 222]] clj꞉datalevin-kvutils꞉>

fs4205:08:09

It seems that if you use assign nil to the value in :put, it will take the value from the last :put - probably left in a buffer that wasn't cleared or isn't overwritten by "nil" (?)

Huahai11:08:44

it should throw instead

Huahai11:08:34

Nil cannot be transacted

🚀 1
fs4215:08:49

Right now it doesn’t transact nil but does transact the previous non-nil value. Would you like me to submit an issue on github about this?

fs4216:08:58

Another option would be to implement a “:put key nil” as “:del key”, which would interpret the intend.

fs4216:08:34

Please ignore as I noticed that you added an issue about it - should have checked first.

fs4217:08:24

... and already fixed in the code!!! woohoo

Huahai11:08:32

Basically, nil means absence

Huahai11:08:33

E.g. when get-value returns nil, it means that key does not exist

Huahai11:08:33

If it is possible to store nil as value, ambiguity would arise

🎯 2
fs4215:08:44

I appreciate your interpretation and implementation of nil as a value in the kv-db, but I’d just like to note that a clojure map does allow {:a nil} and there is no ambiguity as you can distinguish between the key :a being there or not. Now, I am not religious at all about this and just want to understand how the datalevin kv-store deals with that. I was looking at the kv-store as some kind of transactional mutable clojure sorted map… guess that abstraction is still mostly valid with a few caveats about the use of nil. I’d be happy to suggest a few lines of documentation for datalevin, to add a little more clarification about the use of nil.