Fork me on GitHub
#clojure-spec
<
2018-11-19
>
stijn09:11:52

how do people practically deal with entity maps that have required keys in one situation, but don't in another situation?

👍 4
didibus09:11:03

Multi-spec

stijn09:11:48

I understand you'll probably have to create a separate spec, but that might require duplicating the entire tree of references to other entities, no?

borkdude09:11:37

@stijn best to come up with an example

pyr10:11:34

Hi, I'm trying to spec a map (over which I dont' have control) which uses an inconvenient idiom: for a number of members it accepts either a :membername or :memberid key, but at least one must be present. If there's a single member like this, spec/or is convenient. I naively started producing a number of spec/or specs (of the sort: (spec/def :member (spec/or :by-id (spec/keys :req-un [:member/memberid]) :by-name (spec/keys :req-un [:member/membername])))) but if I merge those with spec/merge or spec/and validation becomes impossible

pyr10:11:21

Let's say that I have (spec/merge ::member1 ::member2) The input for validation of member2 seems to be the output of conform for member1, which becomes a tuple [:by-id val] instead of plain val. Beyond doing some sort of pre processing of the map, any idea of how to address this from spec?

mpenet10:11:58

can't you use (s/keys :req-un [(or ::membername ::memberid)]) ?

pyr10:11:48

or as in spec/or?

pyr10:11:58

if so, I didn't try, let me try it

mpenet10:11:03

as in or within keys

mpenet10:11:12

it supports that

mpenet10:11:21

it also supports and, kind of a cool feature

mpenet10:11:29

from the docstring: (s/keys :req [::x ::y (or ::secret (and ::user ::pwd))] :opt [::z])

pyr10:11:13

@mpenet thanks, never knew about that

borkdude10:11:52

@mpenet wow, that’s cool

borkdude10:11:16

I think Alex said this too before, but it was still an undocumented feature

mpenet10:11:40

It's in the docstring and the guide

borkdude10:11:52

ah, that must have changed then or I misremember

mpenet10:11:54

From day one i think no?

pyr10:11:00

@mpenet here it fails on 'all keys must be ns qualified'

borkdude10:11:13

@mpenet where in the guide is this?

mpenet12:11:35

that was posted when spec was introduced

borkdude12:11:55

I see it now. Not the guide, but some post. Thanks!

pyr10:11:33

(clojure 1.9.0)

borkdude10:11:48

I see the docstring, so that’s definitely supported

mpenet10:11:01

I had typos in my example, I am fairly sure it works with both req-un or req (not in front of laptop atm)

pyr10:11:21

ah got it

pyr10:11:31

I left one in opt-*

pyr11:11:52

perfect, thanks @mpenet 🙂

4
stijn12:11:32

@borkdude example would be: a Person entity in one case has required fields :person/name :person/birth-date :person/address, and Address has required fields :address/street :address/city, but in another case I want a person with required keys :person/social-security-number and :person/address, but the Address has no required fields. How do you model that? I can define a spec for Person type 1 and one for Person type 2, but both will have a required key :person/address, but the spec for :person/address is different in these two entity map specs.

urzds15:11:42

Been discussing the exact same issue just now in #graphql: https://clojurians.slack.com/archives/C4DLZKR9T/p1543316717071700

borkdude12:11:08

are all these keys in the same map, or is address in its own map?

stijn12:11:16

address in its own map

borkdude15:11:14

@alexmiller I have ran code with a spec for assoc instrumented. it went from 3s to 15 minutes (approx.). I narrowed it down to this: https://gist.github.com/borkdude/54baa8504064779094d7dd35f10865d7#file-patch-clj-L64 it’s about 400x slower than running without instrumentation

Alex Miller (Clojure team)15:11:34

well, assoc is used a lot

Alex Miller (Clojure team)15:11:13

I’m not sure what you’re looking for from me

Alex Miller (Clojure team)15:11:24

I think it’s not expensive in general, it’s expensive to have spec for things used by Clojure to do everything else

Alex Miller (Clojure team)15:11:35

because the validation is then also checked during validation

borkdude15:11:01

to be clear, I spec’ed a function like assoc, not assoc itself

borkdude15:11:26

so I made sure that it wouldn’t be used internally

borkdude15:11:45

(def my-assoc assoc) and then spec’ed my-assoc

Alex Miller (Clojure team)15:11:04

given that you’re doing these a million times each, they seem pretty fast to me? you’re talking about microseconds per?

Alex Miller (Clojure team)15:11:32

if you could provide a narrative rather than just a wall of data, that would help

borkdude15:11:06

right. I instrumented an Advent of Code puzzle and the time went from 3s to 15 minutes. That seemed a little but much for instrumentation overhead.

borkdude15:11:46

but maybe that’s just the way it is

Alex Miller (Clojure team)15:11:51

well, it depends what it’s doing and what you spec’ed

Alex Miller (Clojure team)15:11:03

if you instrument something in a hot loop…. then that will be slow

Alex Miller (Clojure team)15:11:13

was an effort to compare different fws

Alex Miller (Clojure team)15:11:36

at a micro level and spec did pretty well there

didibus06:11:47

@borkdude 's benchmark is showing that instrument is much slower then valid? The benchmark you linked used valid? Have an idea why instrument would be slower then valid?

borkdude06:11:43

Not much slower. It does a little bit more.

didibus06:11:12

Right, from the impl, it does seem it uses conform to validate. Even though it doesn't seem to do anything with the conformed value. I wonder why its not just using valid?

didibus06:11:33

Oh, valid also uses conform. Ok, well I'm learning a few things looking at the impl 😛

rickmoynihan15:11:09

What are the big changes in spec-alpha2? I’m assuming there are breaking changes, given the artifact has changed names.

Alex Miller (Clojure team)15:11:01

at the moment, the public api is the same

Alex Miller (Clojure team)15:11:14

there are some additions and likely breaking changes down the line

rickmoynihan15:11:16

ok so the repackaging is mostly precautionary? i.e. in case you were to push a breaking change?

Alex Miller (Clojure team)15:11:33

it is currently a work in progress, we’ll have more to talk about it as we get to a release point

borkdude15:11:44

cool, thanks. yes, the code was a hot loop. I also tested with spec-alpha2 and saw about the same numbers.

borkdude15:11:53

is spec itself also compiled with direct linking?

borkdude15:11:10

ah, that explains something

Alex Miller (Clojure team)15:11:02

there’s some trickiness in the circularity between clojure and spec.alpha

Alex Miller (Clojure team)15:11:14

and compilation makes that trickier than it’s worth

borkdude15:11:26

no problem. thanks for the info