specter

Latest version: 1.1.3
2018-09-23T16:31:54.000100Z

Hey, so I'm working with specter a bit, and one problem that I've noticed has come up several times which I feel has to have a normal solution, is that when I use transform there's no way to set the value if there is none already there. The solution I've had to use on several occasions is this:

(let [value (select-first [:path :to :val] structure)
      value (update-fn value)
      structure (setval [:path :to :val] value structure)]
  structure)
And this feels wrong on many levels, not the least of which because if structure is an atom, and I use ATOM in the path, that means that the operation is no longer atomic.

2018-09-23T16:35:19.000100Z

Everything else I've used in specter always feels like a great addition to Clojure, but this one hiccup is something that I've run into enough times that it almost makes me want to express this instead using a normal swap!

jsa-aerial 2018-09-23T16:53:27.000100Z

I'm a bit confused. This sort of thing (sp/transform [sp/ATOM key-path] update-fn db)) works just fine for me whether the final key exists or not. Also there is sp/BEGINNING and friends, which all work fine as well.

jsa-aerial 2018-09-23T16:53:49.000100Z

@suskeyhose ^^^^

2018-09-23T16:54:28.000100Z

Really? I'm not getting the function called at all with an example. Just a moment and I can give you the example that I'm running.

jsa-aerial 2018-09-23T16:55:47.000100Z

Yeah, works great - if it didn't, I would be hurting

2018-09-23T16:56:01.000100Z

Hmm. Well now it's working on the small example. Curious why it's not working in my larger code.

jsa-aerial 2018-09-23T16:56:21.000100Z

likely something else is happening

jsa-aerial 2018-09-23T16:58:05.000100Z

Further, yielding sp/NONE for the value removes the element (for example, k/v pair in a map) which is really wonderful

2018-09-23T17:04:15.000100Z

Yeah, I've used that a few times, which is fantastic

2018-09-23T17:14:37.000100Z

Okay, so the example in my code which this is working with is like this:

(transform [ATOM
            ::ds/rate-limits
            ::ds/endpoint-specific-rate-limits
            {::ds/action :create-message
             ::ds/major-variable {::ds/major-variable-type ::ds/channel-id
                                  ::ds/major-variable-value "286241942356885504"}}]
           #(println %)
           (atom #:discljord.specs{:rate-limits #:discljord.specs{:endpoint-specific-rate-limits {}}, :channel (a/chan 100), :token "TOKEN"}))
The println doesn't get called at all

2018-09-23T17:15:33.000200Z

(transform [:key {:doesnt-exist :blah}] #(do (println %) :blah) {:key {}})
here's a minimal example

2018-09-23T17:15:41.000100Z

so apparently I can't use a map as a key and have it work

2018-09-23T17:19:14.000100Z

user> (select-first [{:blah :blah}] {{:blah :blah} :blah})
nil
user> (transform [{:blah :blah}] #(do (println %) :blah2) {{:blah :blah} :blah})
{{:blah :blah} :blah}
Here's some more stuff from my repl session which shows a more minimal case of failure.

schmee 2018-09-23T17:23:15.000100Z

AFAIK using maps as paths doesn’t do anything

2018-09-23T17:24:56.000100Z

Yeah, that's the problem. I have need of using a map as a key, and if specter can't select or transform paths with maps, then I'm kind of screwed.

2018-09-23T17:25:04.000100Z

And just have to go back to traditional data manipulation

jsa-aerial 2018-09-23T17:33:55.000100Z

Well, you could try sp/map-key which maybe will work - but you are still not screwed. But you will need to create a custom navigator : https://github.com/nathanmarz/specter/wiki/Cheat-Sheet#custom-navigators

jsa-aerial 2018-09-23T17:34:07.000100Z

@suskeyhose ^^^

2018-09-23T17:34:49.000100Z

Okay, thanks. I'll take a look at it

nathanmarz 2018-09-23T17:59:55.000100Z

@suskeyhose if you want to use a map as a key wrap it in keypath

2018-09-23T18:00:03.000100Z

oh, thanks!

nathanmarz 2018-09-23T18:00:30.000100Z

keypath is the navigator that's implicitly used by keywords in paths

2018-09-23T18:01:05.000100Z

Ah, okay. Well that's exactly the behavior that I'd wanted, so that's exactly it. Thanks so much!

schmee 2018-09-23T18:14:58.000100Z

out of curiosity, is it possible to provide custom implicit navigators?

nathanmarz 2018-09-23T18:38:11.000100Z

@schmee yes, through the ImplicitNav protocol

👍 1