Hyphenate Clojure spec with underscored keys

Very often I have to deal with maps of data that comes from DB and usually keys are underscored, e.g.:

{:first_thing "one", :second_thing "two"}

But also in the code these map keys get hyphenated.

I wonder how you deal with that when you need (s/keys spec for both, with the only difference being that keys are hyphenated/underscored. Is there a better way than writing two different specs? Maybe there’s a macro?

I would only write one spec. Probably the hyphenated one. As that seems to be what your code expects.

It all depends what you’re trying to validate.

You could also do an s/keys with or keys

(s/keys :req [(or ::a-b ::a_b)])

Adding to what @didibus already suggested, I’d try to wash data at the edges of your system. With a database, that would mean I’d try to convert :first_thing to :first-thing in the function you use to query the database.

If you’re using next.jdbc, check out the docs:

https://cljdoc.org/d/seancorfield/next.jdbc/1.0.9/doc/getting-started/result-set-builders#rowbuilder-and-resultsetbuilder

As @didibus said, it depends what you’re trying to do.

However, in similar circumstances (renaming or mild transformations), I have previously written 2 sets of specs, which may overlap.

The one representing the actual DB record is invaluable for end to end tests (putting actual data into a DB and letting it work its way through your system). At the same time the transformed version is invaluable for mocking your entire DB/external layer and running through comprehensive unit tests on business logic.

You could always write a transformation to generate data from a single spec, but sometimes (often?) repeating yourself beats being clever and over complicating.