Fork me on GitHub
#beginners
<
2017-12-29
>
vinai12:12:45

Is there a more idiomatic way to call all functions in a sequence and return their values than (map #(%) seq-of-fn)? Something like (map call seq-of-fn) would look a bit nicer. Just an example, I know call doesn't exist.

leonoel12:12:30

@vinai you may consider ((apply juxt seq-of-fn))

leonoel12:12:37

I wouldn't describe your solution as unidiomatic though, choose what's most tasteful to you

vinai13:12:48

Thank you @

hans37813:12:01

Suppose I have: {"foo" "val1", "bar" "val2"} and I would like to turn it into {:foo "val1" :bar "val2"}, so essentially mapping a map to another map where the target map uses symbols instead of strings for keys...

hans37813:12:25

i found out about the keyword function

hans37813:12:45

i guess i'll need that for sure

hans37813:12:51

it's the iteration part that eludes me

pcbalodi13:12:51

one approach here can be to extract keys and vals, keyword all the keys and zipmap back with vals

pcbalodi13:12:35

or u can use reduce to do with only pass

hans37813:12:44

thank you, pcbalodi

hans37813:12:57

(map (fn[k](keyword "myns" k) ) (keys input)) is a start

pcbalodi13:12:23

also, checkout reduce-kv

manutter5113:12:46

@hans378 How familiar are you with the functional style of programming?

hans37813:12:08

w00t

(zipmap (map (fn[k](keyword "myns" k) ) (keys input)) (vals input))
{:myns/foo "val1", :myns/bar "val2"}  

manutter5113:12:54

If you’re used to OOP/imperative-style, I’d recommend trying out the reduce-kv approach pcbalodi mentioned. https://clojuredocs.org/clojure.core/reduce-kv

hans37813:12:18

@manutter51 i want to get away from that style 🙂

manutter5113:12:18

Though zipmap is pretty cool too 🙂

hans37813:12:06

@manutter51 i'm one of those java guys that wants something different

hans37813:12:17

i guess the clojure community is full of them

manutter5113:12:50

I’m certainly one

pcbalodi13:12:56

me too 😄

manutter5113:12:55

The other day at work, I was building something that required adding on to a co-worker’s code, and I looked at his code and thought “I have no idea what this code is doing.” Then I thought, “Wait a minute, this is Clojure. I can figure it out.” And sure enough, just stepping through it I could see exactly what it was doing, and then the intent became more obvious.

manutter5113:12:22

Not an experience I was used to having in Java. (PHP was worse though.)

hans37813:12:37

lots of that is down to the quality of the programmer, of course 🙂

hans37813:12:00

i mean, the one originally writing the code

manutter5113:12:56

I once had to take over maintenance of some Perl code written by a guy who had just become Catholic. He named his subroutines after Catholic saints. I kid you not.

hans37813:12:03

if somebody does java and uses a functional-style of programming that improves readabilty a lot... still java requires a lot of ceremony

pcbalodi13:12:03

I think Clojure is one of the better languages if you want to read code, I feel comfortable in checking out any open source lib and reading the code.

hans37813:12:20

@manutter51 hahaha really

sabbatical201713:12:45

Hi @amit5881, you need zipmap to go from (:first :second :third) and ("9" "2" "5") to {:first "9" :second "2" :third "5"}. To answer your full question, you need to map that zipmap over your inputs, like this: (map zipmap (repeat '(:first :second :third)) '(("9" "2" "5") ("1" "2" "3"))). (The repeat is needed since you want to zipmap the same (:first :second :third) with both of your lists.)

hans37813:12:15

@manutter51 that is almost as crazy as naming your function-results after http status codes

hans37813:12:33

but that's a whole different conversation 🙂

sabbatical201713:12:14

What's the idiomatic way to take a map and to produce another map with a given subset of the keys (each key having the same value as in the original map)?

sabbatical201713:12:52

@manutter51 Thank you!

hiskennyness15:12:03

Three HTML tag names conflict with clj/cljs names: map, meta, and time. My new HTML library (ironically named Tag) wants to provide macros for all tag names.

hiskennyness15:12:06

I get warnings

`WARNING: meta already refers to: #'clojure.core/meta in namespace: tiltontec.tag.gen, being replaced by: #'tiltontec.tag.gen/meta
` when I compile.

hiskennyness15:12:18

OK, just warning, but looking ahead I will be shadowing (worst of all) map.

manutter5115:12:10

@hiskennyness are you familiar with refer-clojure? https://clojuredocs.org/clojure.core/refer-clojure

manutter5115:12:42

As long as your usages are namespaced, you should be ok with using them elsewhere, and refer-clojure will let you silence those warnings.

hiskennyness15:12:56

I had the same conflict with the keyword :type (which sneaks in as an attribute for input tags, inter alia) but there I could ns qualify with type and (I think!) avoid warnings or shadowing.

hiskennyness15:12:07

Yes, thx, I know about refer-clojure, but with something as ubiquitous as map I would not want to lose that. Lemme read up on refer-clojure. Thx

hiskennyness16:12:20

OK, so refer-clojure muffles the warning and then I just have to code clojure.core/map where I want to use that. Then my users only have a problem if they want to code those tags?

alexmiller16:12:41

In these situations it’s common to alias clojure.core to something like c, so you can use c/map instead of clojure.core/map

noisesmith16:12:00

they should be requiring your code with an alias anyway, in which case the issue doesn't come up

noisesmith16:12:24

and if they want to use it without an alias, they can also use refer-clojure with :exclude

drewverlee18:12:01

None clojure question. Why not have a front end client just send a database query directly to retrieve the data it wants rather then going through a “restful” API. I dont feel like i see this very often, or maybe i do and i dont recognize it?

drewverlee18:12:48

Is this the same question as “why have an interface” or are their database and network specific concepts at play?

seancorfield18:12:45

@drewverlee What about security? SQL injection attacks etc?

drewverlee19:12:14

@seancorfield Good points. So your server can do some authentication and authorization. But past that you trust them 100% with the data. Or maybe you just restrict them to a set of views and read only.

drewverlee19:12:14

I’m going through a phase where i’m having to write a lot of. /customers/{id}/widgets -> basically turns in to “Select * from customers…” And i’m trying to figure out why i’m using a URL or a post body to convey something less declaratively then the SQL query itself.

schmee19:12:19

that is a common critique of REST-based APIs

schmee19:12:20

projects like http://graphql.org/ and om.next were created to remedy that, and I’m sure there are tons of others

drewverlee19:12:54

Is om.next different then reframe in that regard? I dont know much about either but people often consider them together.

schmee19:12:15

I don’t know enough about reframe to compare the two, sorry

wmichaelshirk19:12:06

drewverlee - I’ve felt that pain too. Like, why is the DB doing all this validation and roles and everything just to recreate it in between?

seancorfield19:12:08

@drewverlee Well, you could write a generic route handler for /{entities}/{id}/{thing} and "trust" the entities as a table name, id as the PK and so on...

seancorfield19:12:14

But watch out for someone requesting /mysql.user/1/... kind of stuff and lifting all sorts of sensitive data out of your DB.

seancorfield19:12:04

And then there's the whole "Bobby Tables" thing to watch out for if you're trusting user input to help you generate SQL 🙂

wmichaelshirk19:12:48

on the other side, couchdb has a rest api as it’s api.

seancorfield19:12:30

Essentially you need a DSL inbetween the client and the DB to prevent problems. And that DSL can't be "raw SQL" because that's too powerful.

drewverlee17:01:05

Thanks for talking to me about this. I’m sure there are concrete limitations that i’m not seeing, otherwise i feel this approach would be used. Your saying that SQL is to powerful, but what i’m interpreting that statement to mean, is that the client should only be able to interact with the data in limited ways. Aren’t there ways of limiting access to the database that still involve the main language being SQL? For instance, a database role can be restricted to certain actions, tables and views… right? What if users were given the passwords to limited roles, so your limiting the scope of what they can do, but not defining it as precisely as i feel we do with APIS.

seancorfield18:01:01

SQL GRANTs are not particularly granular -- that's one problem -- and another is that the client, which is plain text by definition in JavaScript, would have to contain the usernames and passwords for any DB access and therefore "anyone" can write a client using those credentials to pull any and all data out of your DB that the client theoretically has access to. If you app has "users" and they need to "login" to interact with the DB, those user accounts have to be in the DB and thus their raw data is available to anyone -- and if you have encryption, the client needs to have that encryption logic in it, in order to interact with the DB so that's public too.

seancorfield18:01:35

Most apps need more than SELECT access so you'd have to have some UPDATE access and that means anyone has that level of access to those tables and can write unchecked into your DB.

drewverlee21:01:24

I can imagine an application between the client (browser) and the database that could handle the authentication and then pass the client a authorization token with its specific permissions on the database. Does that seem reasonable? I briefly read about SQL Grants, at a glance you can specify INSERT, SELECT,UPDATE,EXECUTE over a specific table or view. So, as you suggest, i think more work would have to be done in creating custom tables/views for clients. Then, my idea would be to give more free reign within those views as to what clients code do. Of course, having a view for every situation would be very inefficient if i have to create them per business domain. e.g per customer. But it seems reasonable that this “authorization role” could be part of the the additional information the server has (that maybe the client doesn’t) and passed on behalf of the client. Your right, i wouldn’t want the client (browser) knowing the encryption logic!!! So I would defiantly want a back end for this. Im going to read around this subject more. If feel like GraphQueryLanguage is less expressive then SQL and currently its odd to me that there is no way to just re-use SQL. (not that i think SQL is the only query language mind you). Just that, having two query languages SQL and GraphQL feels wrong. Of course GraphQL is more then just a query language… Anyway, thanks again for talking to me.

seancorfield21:01:36

> I can imagine an application between the client (browser) and the database that could handle the authentication and then pass the client a authorization token with its specific permissions on the database. Does that seem reasonable? That application needs to mediate nearly all interactions between the client and the database tho'.

seancorfield21:01:56

As you say, restructuring your DB so that it reflects every aspect of the security requirements of the client's UI/UX is going to lead to a very complex and inefficient database (and you'd then need a whole bunch of business logic inside the database as a set of stored procedures and triggers -- which is a pretty horrible way to manage your business logic from a version / change management side).

seancorfield19:12:50

Heh, yeah, expose your entire CouchDB to the Internet... 😐

pcbalodi19:12:17

also if you just expose your db to the front end, it will be harder to build further features on top of it.

jrootham20:12:31

Using Compojure I am parsing a POST with a JSON body with a structure {"user":"name"} and the following defroutes line (POST "/login" [user :as {db :connection}] (login db user)) sets user to nil. Am I reading the documentation wrong?

jrootham20:12:15

If I destructure the body element I can parse it in the function.

noisesmith20:12:42

doesn’t compojure use normal destructuring? the way it would work with normal destructuring would be {db :connection :as user} unless I’m totally misreading this

noisesmith20:12:58

then user would be the hashmap that had db under :connection

jrootham21:12:39

The docs say there is special decoding for some fields. I read it as the body for POSTs but it may be parameters only.

jrootham21:12:21

I am pretty sure I need the :as before the {db :connection}

noisesmith21:12:01

that’s not how :as works

jrootham21:12:02

The db is coming through fine. The problem is the user.

noisesmith21:12:31

right, user :as says “look up the keyword :as on the map, bind the result to the symbol user”

noisesmith21:12:12

:as user says “bind the entire data structure being destructured currently to the symbol user”

jrootham21:12:24

Hmm, a careful parsing of destructuring docs would seem to be in order.

noisesmith21:12:19

I don’t like the way compojure defroutes subtly changes the way destructuring is used - to me it obfuscates things

noisesmith21:12:32

I mean mostly it’s the same as destructuring in a binding vector but it’s just different enough that I forget the subtleties as a non-compojure-user who occasionally tries to assist compojure users

clojuregeek21:12:31

what is the best way to test a rest api (liberator, but i am not sure that matters) - i see kerodon .. but is there anything that would actually test a route given an input to get a certain result?

noisesmith21:12:16

if using ring, I like to pass a hash-map replicating the request map that would come in, and call the handler with that, then make is assertions about the data that gets returned

noisesmith21:12:45

this way you can skip a bunch of stateful / http using stuff sicne that should be covered by the ring unit tests

noisesmith21:12:15

there’s a ring library for mocking requests but really you can just use a hash-map literal

clojuregeek21:12:18

hmm seems liberator is more complex then compojure app .. i made this app 3 years ago and look liberator hasn't hardly been touched in 3 years

noisesmith21:12:39

I’m not talking about compojure though - this approach works with any lib that uses ring

noisesmith21:12:23

mind you when I say “handler” I mean the function that handles your request, including routing and calling the apropriate function for that route

noisesmith21:12:07

it’s too bad that liberator isn’t being maintained