clojure.data.xml and parsing jdbc xml object - postgresql

I'm attempting to read xml (actual xml type) from a postgres database in clojure, however i'm not sure how to cast the org.postgresql.jdbc4.Jdbc4SQLXML object to something clojure.data.xml can make sense of.
When running (xml/parse ...) on this object i'm getting the following error:
IllegalArgumentException No matching method found: createXMLStreamReader for class com.sun.xml.internal.stream.XMLInputFactoryImpl clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:80)
code below:
(ns clj-xml-dbms.core-test
(:require [clojure.test :refer :all]
[clojure.java.jdbc :as j]
[clojure.data.xml :as xml]
[clj-xml-dbms.core :refer :all])
(:use [clojure.pprint ] ))
(def db-spec {
:classname "org.postgres.Driver"
:subprotocol "postgres"
:subname "//localhost:5432/mydb"
:user "me"
:password "secret"
})
;; get the results of a query
(def results
(let [
sql "select row_id, xml_col from stg.some_table limit 1 "
db-connection (j/get-connection db-spec )
statement (j/prepare-statement db-connection sql)
query-results (j/query db-connection [statement]) ]
(first query-results)))
(pprint results)
;; {:row_id 18627,
;; :xml_col #object[org.postgresql.jdbc4.Jdbc4SQLXML 0x6897f635 "org.postgresql.jdbc4.Jdbc4SQLXML#6897f635"]}
;; obviously clojure.data.xml/parse isn't going to work on that:
(xml/parse (:xml_col results))
;; IllegalArgumentException No matching method found: createXMLStreamReader for class com.sun.xml.internal.stream.XMLInputFactoryImpl clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:80)
I guess i could cast the xml type in the db to a string, but there has to be something cleaner that that i would think. Any tips appreciated, thanks.

Related

How to pass the variable name as a string to a function? (ClojureScript)

Description of the situation
I want to make a form template for an element, but they must be dynamically created. The meta data involved in the Component should use the variable-name passed as it's meta-data.
Code
For example,
In the view,
(ns my.app
(:require [my.app.templating :as template])
(defn view-component [nOperacaoExtrato]
[:<>
(template/temp-form nOperacaoExtrato)])
The templating function,
(ns my.app.templating)
(defn temp-form
"Template input"
[dado]
#_(js/console.log (str "meta-data: " (meta #'dado)))
(let [nome-var (:name (meta #'dado))]
[:div.col
[:label
{:for (str "form1_" nome-var)}
"Natureza do Dispendio"]
[:p
{:class "form-control",
:id (str "form1_" nome-var)
:name (str "form1" nome-var)}
dado]]))
The result should be, something like this (because the variable passed is nOperacaoExtrato):
[:div.col
[:label
{:for "form1_re-fin-n-operacao-extrato-prop"}
"Nº da Operação no Extrato"]
[:p
{:class "form-control",
:id "form1_re-fin-n-operacao-extrato-prop",
:name "form1_re-fin-n-operacao-extrato-prop"}
(h/preencher-str nOperacaoExtrato)]]
The issue:
Both of these return null.
(meta #'data)
(meta data)
``
You should probably convert this function to a macro. Let me show you fellow Portuguese speaker:
src/cljs/user.cljc
(ns cljs.user)
(defn temp-form-fn
"Template input"
[dado nome-var]
[:div.col
[:label
{:for (str "form1_" nome-var)}
"Natureza do Dispendio"]
[:p
{:class "form-control",
:id (str "form1_" nome-var)
:name (str "form1" nome-var)}
dado]])
#?
(:clj
(defmacro temp-form
[dado]
`(temp-form-fn ~dado ~(name dado))))
Then in the repl:
cljs.user> (require '[cljs.user :refer-macros [temp-form]])
nil
cljs.user> (let [nOperacaoExtrato 1234]
(temp-form nOperacaoExtrato))
[:div.col
[:label {:for "form1_nOperacaoExtrato"} "Natureza do Dispendio"]
[:p
{:class "form-control",
:id "form1_nOperacaoExtrato",
:name "form1nOperacaoExtrato"}
1234]]

Running "repairDatabase" with Monger?

Is it possible to execute the "repairDatabase" command with Monger? If so how?
you can do like this:
(:require [clojure.test :refer :all]
[monger.core :as mc]))
(deftest ^:focused repair-db-test
(let [conn (mc/connect)
db (mc/get-db conn "test-db")]
(is (= {"ok" 1.0}
(mc/command db {:repairDatabase 1})))))
I found out that you can just do:
(monger.core/command db {:repairDatabase 1})

Setting ReadPreference in Clojure MongoDb Driver Monger

How do I set ReadPreference while using find-maps in Monger ? The Monger documentation only specifies the usage with with-collection of monger.query as shown below
(ns my.service.server
(:refer-clojure :exclude [sort find])
(:require [monger.core :as mg]
[monger.query :refer :all])
(:import com.mongodb.ReadPreference))
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")
coll "scores"]
;; reads from primary (master) to guarantee consistency
;; (at the cost of putting extra load on the primary)
(with-collection db coll
(find {:email "joe#example.com"})
(read-preference (ReadPreference/primary))))
One way of doing it is setting the read preference while connecting to Mongo:
(mg/connect
(mg/server-address "127.0.0.1" 27017)
(mg/mongo-options {:read-preference (com.mongodb.ReadPreference/secondaryPreferred)}))
If you're thinking about using this method in the Java API: https://mongodb.github.io/mongo-java-driver/3.4/javadoc/com/mongodb/DBCollection.html#setReadPreference-com.mongodb.ReadPreference- I did not find a way to use this via monger. However, you can roll your own functions to take advantage of this API:
(defn find-with-read-preference [db coll]
(.find (doto
(.getCollection db (name coll))
(.setReadPreference (ReadPreference/secondaryPreferred)))))
(defn find-maps-with-read-preference
([^DB db ^String coll]
(with-open [result (find-with-read-preference db coll)]
(map (fn [x] (monger.conversion/from-db-object x true)) result))))

ring redirect after login

(ns ...
(:require [ring.util.response :refer [ response redirect]))
My original code be-all-like
(-> (response "You are now logged in! communist party time!")
(assoc :session new-session)
(assoc :headers {"Content-Type" "text/html"}))
Which worked well, but the user still has to navigate elsewhere manually.
Trying to use http://ring-clojure.github.io/ring/ring.util.response.html#var-redirect
(-> (redirect requri)
(assoc :session new-session)
(assoc :headers {"Content-Type" "text/html"}))
doesn't do anything (aside from returning a blank page).
How can I achieve a redirect to a known uri using ring?
response is return a body.
you code is (response requri),but the param of the funtion reponse is html body,not a uri,you can use the this function
like this
(ns foo
(:require [ring.util.response :as response]))
(def requi "/")
(-> (response/redirect requri)
(assoc :session new-session)
(assoc :headers {"Content-Type" "text/html"}))
ps: if you are writing a web site.the lib-noir is a good way to control the session and other.
ipaomian has the answer.
Wanted to share a nice redirect hack:
(ns foo
(:require [ring.util.response :as response]))
(defn redirect
"Like ring.util.response/redirect but also accepts key value pairs
to assoc to response."
[url & kvs]
(let [resp (response/redirect url)]
(if kvs (apply assoc resp kvs) resp)))
(redirect "/" :session new-session :headers {"Content-Type" "text/html"})
ipaomian is right however mine worked by removing the headers. This is my code:
(:require
[ring.util.response :refer [redirect]])
(defn set-user! [id {session :session}]
(-> (redirect "/home")
(assoc :session (assoc session :user id))))

"Shared" Connection on Monger Clojure

I am start with monger today, the docs use examples like this:
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")
coll "documents"]
(mc/insert db coll {:first_name "John" :last_name "Lennon"})
(mc/insert db coll {:first_name "Ringo" :last_name "Starr"})
(mc/find db coll {:first_name "Ringo"}))
All documentation examples use that structure. Always connect to MongoDB, then use db on mc/insert... . The question is, how I can put this code on a function and use it in my functions that execute mongodb queries, without repeat below code all time:
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")
coll "documents"] ...
Thanks.
Here's how I did it:
(defmacro with-db [body]
`(let [conn# (mg/connect)
db# (mg/get-db conn "monger-test")]
(-> db#
~body)))
Used like this:
(with-db (mc/find-maps "mycoll"))
you can also do this without defining a macro, using just a plain old function:
(def db-name "monger-test")
(defn with-db [op & args]
(let [conn (mongo/connect)
db (mongo/get-db conn db-name)]
(apply op db args)))
(with-db monger.collection/find-maps "test-collection")
will list all the entries in the collection named "test-collection"