Is there a way to do a fully qualified table name when using Cassaforte's CQL DSL?
I've currently got this code:
(defn get-data-by-user-id [client-name client-id user-id]
(cql/use-keyspace (get-session) client-name)
(cql/select (get-session) "some_data"
(where [[= :client_id client-id] [= :user_id user-id]])
(limit 1)))
I'm curious if it's possible to do something similar to Korma, eg:
(defn get-data-by-user-id [client-name client-id user-id]
(cql/select (get-session) "some_data"
(where [[= :client_id client-id] [= :user_id user-id]])
(limit 1)
(keyspace client-name)))
cassaforte uses/aliases hayt internaly for it's DSL (I authored this lib), so yes probably see:
https://github.com/mpenet/hayt/blob/master/test/qbits/hayt/core_test.clj#L26-L27
or just use a keyword if you don't need the escaping/quoting:
:foo.bar etc
clojure keywords used as cql identifiers are never escaped.
Related
In clojure you can create anonymous functions using #
eg
#(+ % 1)
is a function that takes in a parameter and adds 1 to it.
But we also have to use # for regex
eg
(clojure.string/split "hi, buddy" #",")
Are these two # related?
There are also sets #{}, fully qualified class name constructors #my.klass_or_type_or_record[:a :b :c], instants #inst "yyyy-mm-ddThh:mm:ss.fff+hh:mm" and some others.
They are related in a sence that in these cases # starts a sequence recognisible by clojure reader, which dispatches every such instance to an appropriate reader.There's a guide that expands on this.
I think this convention exists to reduce the number of different syntaxes to just one and thus simplify the reader.
The two uses have no (direct) relationship.
In Clojure, when you see the # symbol, it is a giant clue that you are "talking" to the Clojure Reader, not to the Clojure Compiler. See the full docs on the Reader here: https://clojure.org/reference/reader.
The Reader is responsible for converting plain text from a source file into a collection of data structures. For example, comparing Clojure to Java we have
; Clojure ; Java
"Hello" => new String( "Hello" )
and
[ "Goodbye" "cruel" "world!" ] ; Clojure vector of 3 strings
; Java ArrayList of 3 strings
var msg = new ArrayList<String>();
msg.add( "Goodbye" );
msg.add( "cruel" );
msg.add( "world!" );
Similarly, there are shortcuts that the Reader recognizes even within Clojure source code (before the compiler converts it to Java bytecode), just to save you some typing. These "Reader Macros" get converted from your "short form" source code into "standard Clojure" even before the Clojure compiler gets started. For example:
#my-atom => (deref my-atom) ; not using `#`
#'map => (var map)
#{ 1 2 3 } => (hash-set 1 2 3)
#_(launch-missiles 12.3 45.6) => `` ; i.e. "nothing"
#(+ 1 %) => (fn [x] (+ 1 x))
and so on. As the # or deref operator shows, not all Reader Macros use the # (hash/pound/octothorpe) symbol. Note that, even in the case of a vector literal:
[ "Goodbye" "cruel" "world!" ]
the Reader creates a result as if you had typed:
(vector "Goodbye" "cruel" "world!" )
Are these two # related?
No, they aren't. The # literal is used in different ways. Some of them you've already mentioned: these are an anonymous function and a regex pattern. Here are some more cases:
Prepending an expression with #_ just wipes it from the compiler as it has never been written. For example: #_(/ 0 0) will be ignored on reader level so none of the exception will appear.
Tagging primitives to coerce them to complex types, for example #inst "2019-03-09" will produce an instance of java.util.Date class. There are also #uuid and other built-in tags. You may register your own ones.
Tagging ordinary maps to coerce them to types maps, e.g. #project.models/User {:name "John" :age 42} will produce a map declared as (defrecord User ...).
Other Lisps have proper programmable readers, and consequently read macros. Clojure doesn't really have a programmable reader - users cannot easily add new read macros - but the Clojure system does internally use read macros. The # read macro is the dispatch macro, the character following the # being a key into a further read macro table.
So yes, the # does mean something; but it's so deep and geeky that you do not really need to know this.
Are there any reasons not to use a wildcard pull?
(defn pull-wild
"Pulls all attributes of a single entity."
[db ent-id]
(d/pull db '[*] ent-id))
It's much more convenient than explicitly stating the attributes.
It depends on which attributes you need to have in your application and if it's data intensive or whether you want to pull lots of entities.
In case you use the client-library, you might want to minimize the data that needs to be send over the wire.
I guess there are lots of other thoughts about that.
But as long as it's fast enough I would pull the wildcard.
fricke
You may also be interested in the entity-map function from Tupelo Datomic. Given an EID (or a Lookup Ref) it will return the full record as a regular Clojure map:
(let [
; Retrieve James' attr-val pairs as a map. An entity can be referenced either by EID or by a
; LookupRef, which is a unique attribute-value pair expressed as a vector.
james-map (td/entity-map (live-db) james-eid) ; lookup by EID
james-map2 (td/entity-map (live-db) [:person/name "James Bond"] ) ; lookup by LookupRef
]
(is (= james-map james-map2
{:person/name "James Bond" :location "London" :weapon/type #{:weapon/wit :weapon/gun} } ))
tl;dr
How can I derive a keyword from a number in ClojureScript:
(keyword 22)
;;=> :22 but in fact returns nil.
Background
In my ClojureScript/Hoplon application I make HTTP requests via cljs-http. Parts of the response I receive look like this:
{:companies
{:22 {:description ... } ; A company.
:64 {:description ... }
... }
{:offers
[{:description ... } ; An offer.
{:description ... }
... ]
Each offer within the vector behind :offers has a :companyId which represents a key in :companies. As soon as I receive the response, I reset! a cell (similar to an atom) query.
Now, I'd like to iterate over each offer and call a function offer-tpl that creates the corresponding HTML. In order to do so, offer-tpl needs the offer itself as well as the related company:
(for [offer (:offers #query)]
(offer-tpl offer (get-in #query [:companies (keyword (:companyId offer))]))))))
Despite the fact that this surely can be done more elegant (suggestions very appreciated), the get-in doesn't work. (:companyId offer) returns a number (e.g. 22) but (keyword (:companyId offer)) returns nil. Calling (keyword (str (:companyId offer))) does the trick, but aren't there any other ways to do this?
(keyword "22") or (keyword (str 22)) returns :22
The reason you are getting :22 is likely because of the keywordize-keys option of a JSON translation. For example:
cljs-http defaults to keywordize-keys for jsonp:
https://github.com/r0man/cljs-http/blob/1fb899d3f9c5728521786432b5f6c36d1d7a1452/src/cljs_http/core.cljs#L115
But you can (and should) in this case pass in a flag to disable keywordization.
Not all keys in JSON are appropriate for Clojure keywordization. For example spaces in a JSON key are valid, but not in Clojure.
Please be aware that numeric keywords are probably incorrect.
https://clojuredocs.org/clojure.core/keyword#example-542692cec026201cdc326d70
It seems like that caveat has been removed from the current Clojure website, so perhaps that means something but I'm not sure what.
http://clojure.org/reference/reader Currently states that
Keywords - Keywords are like symbols, except: They can and must begin
with a colon, e.g. :fred. They cannot contain '.' or name classes.
Like symbols, they can contain a namespace, :person/name A keyword
that begins with two colons is resolved in the current namespace: In
the user namespace, ::rect is read as :user/rect
and that
Symbols begin with a non-numeric character and can contain
alphanumeric.
This definition of a keyword excludes :22 and :with spaces
The keyword function returns a result for invalid input, but this is not an endorsement, it is simply because checking for incorrect input would be a performance overhead in a core part of Clojure.
In short, not all JSON keys translate to keywords, so you should avoid keywordize-keys unless you know the keyspace and/or doing so provides some conveniences.
i am learning clojure. My question is it posible to use (case) inside (-> ).
For example, i want something like this (this code dont work):
(defn eval-xpath [document xpath return-type]
(-> (XPathFactory/newInstance)
.newXPath
(.compile xpath)
(case return-type
:node-list (.evaluate document XPathConstants/NODESET)
:node (.evaluate document XPathConstants/NODE)
:number (.evaluate document XPathConstants/NUMBER)
)
))
Or will be better to use multimethods instead? What is the right 'clojure way for this?
Thank you.
The arrow macro (->) just rewrites its arguments so that the value of the nth form is inserted as the first argument to the n+1th form. What you are writing is equivalent to:
(case
(.compile
(.newXPath (XPathFactory/newInstance))
xpath)
return-type
:node-list (.evaluate document XPathConstants/NODESET)
:node (.evaluate document XPathConstants/NODE)
:number (.evaluate document XPathConstants/NUMBER)
In a general case you can pick one of the three forms to be your tail form ahead of time using let, and then thread that in at the end of the threading macro. Like so:
(defn eval-xpath [document xpath return-type]
(let [evaluator (case return-type
:node-list #(.evaluate % document XPathConstants/NODESET)
:node #(.evaluate % document XPathConstants/NODE)
:number #(.evaluate % document XPathConstants/NUMBER))]
(-> (XPathFactory/newInstance)
.newXPath
(.compile xpath)
(evaluator))))
However what you are really trying to do is map a keyword to a constant on XPathConstants. This can be done with a map. Consider the following:
(defn eval-xpath [document xpath return-type]
(let [constants-mapping {:node-list XPathConstants/NODESET
:node XPathConstants/NODE
:number XPathConstants/NUMBER}]
(-> (XPathFactory/newInstance)
.newXPath
(.compile xpath)
(.evaluate document (constants-mapping return-type)))))
You have a mapping of keywords to constants, so use Clojure's data structures to express that. Additionally the real value of the threading macro is helping you compile the xpath. Don't be afraid to give the data you're using locally scoped names to help you keep track of what you are doing. It also helps you avoid trying to shoehorn things into the threading macro that really don't want to fit.
Check out the following clojure library for working with xpath expressions: https://github.com/kyleburton/clj-xpath
found this on a blog : (def x ^{:type ::my-class} {})
apparently it adds meta data to a map
user=> (meta x)
{:type :user/my-class}
what else does ^ do ? does it have any other uses ? can it be used as a getter for meta data (not just to set meta data) ?
how can i find out information about some shortcuts in clojure ? like ^, ', `, ~. is it possible to get that from the repl ?
Look at the documentation for the Clojure reader, specifically the section on macro characters:
The Reader
Edit: Metadata has documentation too :-)