I am using a h2 database with clojure. I made a table and put some data in like this
(j/create-table :locations
[:id "bigint primary key auto_increment"]
[:title "varchar (255)"]
[:part "clob"])
(j/insert-records :locations
{:title "Steven Gerrard: I'm not the new Beckham" :part "He might not have the Becks appeal -- but Steven Gerrard says he's ready to light up Hollywood in his own way..."}))
)
)
And then I selected the data
(defn newest []
(database/mysql-db)
(let [results (j/with-connection db-spec
(j/with-query-results res
["select id, title, part from locations"]
(doall res)))]
results))
And I used the data on a clostache page
<div class="container">
<sections>
{{#newest}}
<p style="padding-bottom: 15px;">{{title}}<p>
<p style="padding-bottom: 15px;">{{part}}<p>
{{/newest}}
</sections>
</div>
On the page i get
Steven Gerrard: I'm not the new Beckham
clob0: 'He might not have the Becks appeal -- but Steven Gerrard says he''s ready to light up Hollywood in his own way...'
How can I remove the clob0: string that is attached to the text I have in the database? This happens even if I use text instead of clob for the part column in my database.
The 'clob0:' prefix is not actually attached to your data in database.
The reason you get this is because ResultSet returns instances of class java.sql.Clob for column "part" (for both CLOB and TEXT data types, they are actually synonyms).
It's not proper way to convert Clob to String by using toString() method, implementation is free to return any human-readable form. Correct way may be found in other answers.
You might have noticed that new lines get lost by the above... something like this adds them back in...
(defn clob-to-string [clob]
"Turn an Clob into a String, with new new lines"
(with-open [rdr (java.io.BufferedReader. (.getCharacterStream clob))]
(let [lseq (line-seq rdr)
butlast-line (butlast lseq)
butlast-line-mapped (map (fn [l] (str l "\n")) butlast-line)
last-line (last lseq)
all-lines-with-newline (concat butlast-line-mapped last-line)
]
(apply str all-lines-with-newline)
)))
I removed the clob: with:
(defn clob-to-string [row]
(assoc row :text (with-open [rdr (java.io.BufferedReader. (.getCharacterStream (:text row)))]
(apply str (line-seq rdr)))))
(defn newest []
(database/mysql-db)
(j/query db-spec
["select id, title, text from news"]
:row-fn clob-to-string
))
Related
I have an org-agenda-custom-commands like so:
("u" "Unscheduled TODO"
todo ""
((org-agenda-overriding-header "\nUnscheduled TODO")
(org-agenda-skip-function '(org-agenda-skip-entry-if
'scheduled 'deadline 'timestamp
'todo '("BACKBURNER")))))
I would like to reuse the todo part of this agenda view in other block agenda views. So for instance defining an unscheduled-todo list for reuse (pseudocode, not working):
(setq unscheduled-todo '((org-agenda-overriding-header "\nUnscheduled TODO")
(org-agenda-skip-function '(org-agenda-skip-entry-if
'scheduled 'deadline 'timestamp
'todo '("BACKBURNER")))))
(setq org-agenda-custom-commands
'(("u" "Unscheduled TODO"
(todo "" unscheduled-todo))
("c" "Complete View"
((agenda "")
(todo "" unscheduled-todo))))
How do I get the above code to work? I think I have a fundamental misunderstanding of how and when the code and lists are getting evaluated. I've tried a number of configurations of ' and () in both setq and org-agenda-custom-commands, along with append to create lists, but I'd also like to understand what's going on here.
Here's an implementation along the lines of my comment (although I think you really don't need a macro here: a function does just as well or better):
(defun unscheduled-todo ()
'((org-agenda-overriding-header "\nUnscheduled TODO")
(org-agenda-skip-function '(org-agenda-skip-entry-if
'scheduled 'deadline 'timestamp
'todo '("BACKBURNER")))))
(setq org-agenda-custom-commands
; N.B. the character following this comment is a *backquote*
; (the key to the left of the 1 key on a standard US keyboard);
; it is *NOT* a quote (the key to the left of the ENTER key
; on a standard US keyboard).
`(("u" "Unscheduled TODO"
todo "" ,(unscheduled-todo))
("c" "Complete View"
((agenda "")
(todo "" ,(unscheduled-todo))))))
I hope it's correct now (I had to fix it a couple of bugs) but it's only lightly tested.
Note that this uses the backquote mechanism to quote most of the value in the
setq of org-agenda-custom-commands while allowing the evaluation of the call to the macro using the comma mechanism.
EDIT: As #Rorschach points out in a (now deleted) comment, I'm overcomplicating things. You still need backquote and comma, but you can use the variable you defined:
(setq unscheduled-todo
'((org-agenda-overriding-header "\nUnscheduled TODO")
(org-agenda-skip-function '(org-agenda-skip-entry-if
'scheduled 'deadline 'timestamp
'todo '("BACKBURNER")))))
(setq org-agenda-custom-commands
; N.B. the character following this comment is a *backquote*
; (the key to the left of the 1 key on a standard US keyboard);
; it is *NOT* a quote (the key to the left of the ENTER key
; on a standard US keyboard).
`(("u" "Unscheduled TODO"
todo "" ,unscheduled-todo)
("c" "Complete View"
((agenda "")
(todo "" ,unscheduled-todo)))))
The backquote/comma mechanism allows the evaluation of a spliced-in variable just as well as it allows the evaluation of a spliced-in function call.
I've wrote this function to insert an "account" in the database:
(defn create-account [accountnumber]
(if (= nil (find-by-number accountnumber))
(jdbc/insert! db-spec :accounts {:accountnumber accountnumber})
nil
))
This tests passes, so the function it's working:
(testing "create and find-by-number account"
(account/create-account 10)
(is (= 10 ((account/find-by-number 10) :accountnumber)))
)
But when I try to use this route:
(defroutes app-routes
(GET "/:account" [account] (account/create-account account))
(route/not-found "Not Found"))
(def app
(-> app-routes
rmp/wrap-params
wrap-json-response
wrap-json-body))
I got this error:
org.postgresql.util.PSQLException
ERROR: column "accountnumber" is of type integer but expression is of
type character varying Hint: You will need to rewrite or cast the
expression.
Verifying types, I can see that when I run the test, accountnumber type is java.lang.Long and when it comes from routes, it's type is java.lang.String, I've tried to convert it but got no success.
This is because the route is returning a param. Params are strings.
If you change your route to be something like this:
(defroutes app-routes
(GET "/:account" [account] (account/create-account (Integer/parseInt account)))
(route/not-found "Not Found"))
it should work.
I'm trying to make a simple bookmarking web-app in Racket.
It's meant to receive a url as a CGI argument, and right now, I'm just trying to confirm I received it by reflecting it back.
(define (start request)
(response/xexpr
(let* ([bindings (request-bindings request)]
[url (if (exists-binding? 'url bindings)
(extract-binding/single 'url bindings)
"NO URL")])
`(html
(head (title "TITLE"))
(body (h2 "TITLE")
(p "URL = " url))
))))
However, instead of seeing what I expect to see .. which is a page that contains
URL = http://google.com
I'm seeing
URL = &url;
Which suggests that url is being quoted literally in the xexpr (treated as an entity), rather than being evaluated as a variable.
So what am I doing wrong? How do I get url evaluated?
You need to use quasiquote and unquote to inject values into a quoted experession, more often seen as their reader abbreviation equivalents, ` and ,, respectively. When you use unquote/, inside of quasiquote/`, it will evaluate the expression and insert it into the surrounding quotation:
> (define url "http://google.com")
> `(p "URL = " ,url)
(p "URL = " "http://google.com")
You should put , in front of url in your template to unquote it.
For a more detailed explanation of quotation and quasiquotation, see Appendix A of this answer.
Use ,url :
`(html
(head (title "TITLE"))
(body (h2 "TITLE")
(p "URL = " ,url))
))))
Look for unquote in the documentation: http://docs.racket-lang.org/reference/quasiquote.html?q=unquote#%28form.%28%28quote.~23~25kernel%29._unquote%29%29
I'm writing an elisp file that's evolving into a package, so I'm translating some of its variables into defcustom statements and documenting them. A few of these defcustom variables are related, and I'd like to validate values entered through the Customize system to ensure that the relationships hold true.
Here's an example of what I have:
(defcustom widget-canonical-names '("my_widget" . "widget_assembly 8911_j4")
"Documentation"
:type '(alist :key-type (string :tag "Widget's short name")
:value-type (string :tag "Full widget name"))
:risky nil
:group 'widgets)
(defcustom widget-colors '("my_widget" . "brown")
"Documentation"
:type '(alist :key-type (string :tag "Widget's short name")
:value-type (color :tag "color of the widget"))
:risky nil
:group 'widgets)
(defcustom widget-paths '("my_widget" . "~/widgets")
"Documentation"
:type '(alist :key-type (string :tag "Widget's short name")
:value-type (directory :tag "support files for widget"))
:risky nil
:group 'widgets)
So there are widgets and they have various settings, and I need to be able to access an arbitrary setting for a widget by knowing just the widget's short name. I'd like to make a validation function of some kind (googling around for "emacs defcustom validate" hasn't helped, unfortunately) such that if the user enters a widget name in widget-paths or widget-colors that is not in the widget-canonical-names list, they get an "are you sure?" warning and are cautioned about entering mismatched names. Can I attach such a validation function to my defcustoms? If so, what's the syntax for that?
Of course, what would be ideal would be to just make the user enter the short name once, but I can't figure out how to do that from the 'Composite Types' elisp documentation. So an even better answer to my question would tell me how to arrange a defcustom that sets up a data structure similar to this Python dict:
customized_widgets = {
"my_widget": { "canonical_name": "widget_assembly 8911_j4",
"widget_color": "brown",
"widget_path": "~/widgets",
},
"another_widget": { "canonical_name" : "widget_obsolete 11.0",
"widget_color": "blue",
"widget_path": "~/blue_widgets",
},
}
So: how can I get the behavior I want, where settings are grouped according to the data that'll be used to access them, or where a validation function warns users when they might be entering inconsistent data?
This will define the closest Emacs equivalent of that Python structure, with dicts represented as alists, and fixed keys of the inner dict represented as symbols.
(defcustom my-customized-widgets ()
"My widget customization alist"
:type '(alist
:tag "Widgets"
:key-type (string :tag "Short name")
:value-type
(set
:format "%v"
:entry-format "%b %v"
(cons :format "%v"
(const :format "" widget-canonical-name)
(string :tag "CName"))
(cons :format "%v"
(const :format "" widget-color)
(color :tag "Color"))
(cons :format "%v"
(const :format "" widget-path)
(directory :tag " Path"))))
:group 'widgets)
The crux of the action is in this file:
https://github.com/gdoteof/exodus/blob/42c5ee09f09dcb718fa3bdfd79bfe5182c03faaa/Handler/GamingSession.hs
The general idea that I am going for is to accept POSTED input, and use that input, combined with the UTCTime from getCurrentTime to create a new GamingSession.
Then the GamingSession would be inserted into the database.
What's happening now at /session is a form that posts to /session, with prefilled in values. But I am getting an error
Prelude.read: no parse
(relevant config/routes: https://github.com/gdoteof/exodus/blob/d07bea21e7699b44739ceadf3c3a18533a9ef462/config/routes
)
When I have a form for persist keys, I usually prefer a drop down rather than manual entry. Try the code below. Also, try to follow the idiomatic style in the book, it will help.
gs <- runInputPost $ GamingSession
start
Nothing
<$> ireq (selectField (optionsPersistKey [] [] (toPathPiece . entityKey))) "player"
<*> ireq (selectField (optionsPersistKey [] [] (toPathPiece . entityKey))) "table"
<*> iopt intField "seat"
-- | The optionsPersist builtin to the Yesod.Forms package unfortunately only
-- works well with whole persist entities. We are only interested in the entity
-- id s which is why we add in this function here:
optionsPersistKey
:: (YesodPersist master
, PersistEntity a
, PersistQuery (YesodPersistBackend master) (GHandler sub master)
, PathPiece (Key (YesodPersistBackend master) a)
, RenderMessage master msg
, PersistEntityBackend a ~ YesodPersistBackend master)
=> [Filter a]
-> [SelectOpt a]
-> (Entity a -> msg)
-> GHandler sub master (OptionList (Key (PersistEntityBackend a) a))
optionsPersistKey filts ords toDisplay = fmap mkOptionList $ do
mr <- getMessageRender
pairs <- runDB $ selectList filts ords
return $ map (\(Entity key value) -> Option
{ optionDisplay = mr (toDisplay $ Entity key value)
, optionInternalValue = key
, optionExternalValue = toPathPiece key
}) pairs
You're getting a read fail b/c you're trying to read values like "4f6150251c21230c78000000" to PersistInt64. The MongoDB backend does not use PersistInt64s for key values so that code won't build a proper key for your setup. I'd try PersistText.
The error you're getting means the input does not look like a normal integer. What do the prefilled values actually look like? The strings from ireq textField "player" and ireq textField "table" have to just contain a number possibly padded with whitespace.
Also, to make handling bad parses easier, you should look at the safe package. This contains a version of read (and similar functions) that returns a Maybe, so you get a Nothing instead of an exception if it can't parse the input.
Ok, try this:
import Data.Text (unpack)
...
(player, table, seat) <- runInputPost $ (,,)
<$> (ireq textField "player")
<*> (ireq textField "table")
<*> iopt intField "seat"
playerId <- maybe (invalidArgs ["couldn't parse: ", player]) return $ fromPathPiece player
tableId <- maybe (invalidArgs ["couldn't parse: ", table]) return $ formPathPiece table
let gs = GamingSession start Nothing playerId tableId seat
...
changing
textToKey = Key . PersistText . read . unpack
to
textToKey a = fromJust . fromPathPiece $ a
fixed it for me