This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-02-27
Channels
- # beginners (113)
- # calva (39)
- # cider (18)
- # cljs-dev (19)
- # cljsrn (1)
- # clojure (80)
- # clojure-dusseldorf (1)
- # clojure-finland (1)
- # clojure-gamedev (1)
- # clojure-germany (2)
- # clojure-italy (38)
- # clojure-nl (16)
- # clojure-spec (90)
- # clojure-uk (81)
- # clojurescript (28)
- # clojutre (9)
- # cursive (47)
- # data-science (4)
- # datomic (21)
- # emacs (1)
- # events (2)
- # fulcro (11)
- # graphql (2)
- # hoplon (8)
- # hyperfiddle (23)
- # jobs (2)
- # kaocha (4)
- # lein-figwheel (1)
- # luminus (1)
- # mount (1)
- # off-topic (41)
- # pathom (5)
- # pedestal (27)
- # reitit (6)
- # remote-jobs (7)
- # ring-swagger (6)
- # shadow-cljs (42)
- # spacemacs (1)
- # sql (9)
- # tools-deps (6)
- # uncomplicate (2)
- # vim (5)
Can I have spec for a map entry that it has keyword, but corresponds to a different spec?
I have such map {::value "" ::other-map {::value {::bla 1}}}
so my ::value sometimes is string sometimes is map...
No. Spec is philosophically opposed to this distinction: https://clojure.org/about/spec#_map_specs_should_be_of_keysets_only
I wrote one out of necessity, but I don't necessarily recommend using it: https://gist.github.com/favila/ab03ba63e6854a449d64d509aae74618
@vale Real World Data (tm) has fields whose type may change depending on what map it is in
I appreciate and understand the philosophical stance of spec here, but it does cause friction
The case I always seem to run in to is a field which has a baseline type (e.g. it should be number?
) wherever it appears, but in certain kinds of maps (defined with s/keys) it must be some subset of its allowed values (e.g. even?
)
that is imo the most spec-friendly way to say "a value
as in outer-map
and value
as in inner-map
"
@audrius if you control the keys and the shape of your data, you should use different keys (even just namespaces) as @vale suggests
why would you have two names in the same namespace refer to multiple different things
An example would be like we are trying to spec a user’s medical records. They have a coverage type:
:coverage/type
that can be #{:medical :dental :vision}
and then in a certain context, you want to specify it must be :medical
along with some other facts about the user’s data
here's an extreme example for a datomic transaction map: {:db/id (string, or tempid-record, or entity-id-long, or keyword-ident, or tuple[entity-id-long or keyword-ident, indexable-datomic-valuetype)}
and suppose for a particular function you want to specify that no tempids are legal for :db/id
you can add a predicate, but you have the burden of maintaining the predicate, a less useful s/merge, and custom generators
yeah. atm we have a specific medical-coverage?
predicate that we combine with others. it’s not the greatest
(keys+ :req [:coverage/type] :conf {:coverage/type #{:medical}})
would produce an s/keys spec where :coverage/type
was checked both against its natural spec and any override you have in :conf
, and :conf
is the one used for generators
for things related (but not the same) to this, we use different records with specs. the records may have overlapping keys, and records of different kinds can be determined by their record (really, class) type
ex: {:coverage/type :medical :coverage/code 1234 :coverage/status :active}
answers "does user have XYZ program", for example
multi-spec uses a multi-method to retrieve the correct spec based on whatever dispatch function you choose. so you could dispatch on the value of :coverage/type
and return different specs for each of your coverage record “types”
Will and I were discussing the situation where we want to spec a map where an entry is only allowed some subset of what is normally allowed
> spec a map where an entry is only allowed some subset of what is normally allowed you mean a coverage map tagged as :medical can only contain some subset of all coverage map keys?
we mean there's a map type "coverage", one of its keys is coverage/type which can be #{:medical :dental} this function only deals with :coverage/type = :medical
given this data model, I’m not seeing how else you’re proposing to check this aside from looking at the tag?
(keys+ :req [:coverage/type] :conf {:coverage/type #{:medical}})
is what it looks like
:coverage/type -> :coverage/type=medical, then you can (s/keys :conf [:coverage/type=medical)
, but that just shifts the pain around
so, why not just have specs to represent each of the kinds of coverage: medical-coverage, dental-coverage, ...
and then a type that represents the common, generic coverage?
so you can either chain predicates to your s/key with s/and (and lose niceties like s/merge, automatically correct generators, fewer predicates), or you can rewrite your key so that type and value match (and end up with key rewriting layers everywhere)
what you cant do is say "for this keys spec, only allow some of what would normally be in :coverage/type"
@mrevelle the point is that I don't actually care about the coverage type. what I do care about is answering some higher-level question about the data