Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with model and json-encode #83

Open
lifeisfoo opened this issue May 18, 2016 · 4 comments
Open

Issue with model and json-encode #83

lifeisfoo opened this issue May 18, 2016 · 4 comments

Comments

@lifeisfoo
Copy link

I'm trying Caveman2 with a postgres db and a simple books collection:

(with-connection (db)
  (execute
   (create-table (:books :if-not-exists t)
       ((id :type :bigserial
            :primary-key t)
        (title :type :text)
        (author :type :text)
        (created_at :type :timestamp)))))
@model
(defstruct book
  id
  title
  author
  created_at)

I'm expecting to get a book by id with this function:

@route GET "/books/:id"
(lambda (&key id)
  (handler-case
      (with-connection (db)
        (let ((l
                (retrieve-one
                 (select :*
                         (from :books)
                         (where (:= :id id)))
                 :as 'book)))
          (cond (l (render-json l))
                (t (throw-code 404)))))
    (dbi.error:<dbi-error> (e)
      (throw-code 500))))

But it doesn't work as expected:

Backtrace for: #<SB-THREAD:THREAD "hunchentoot-worker-127.0.0.1:63696" RUNNING {1002A0D863}>
0: ((:METHOD JONATHAN.ENCODE:%TO-JSON (STRING)) #<unavailable argument>) [fast-method]
1: (DATAFLY.JSON::CONVERT-FOR-JSON #<unavailable argument>)
2: ((:METHOD DATAFLY.JSON:ENCODE-JSON (T)) #S(LISPIBLO.WEB::BOOK :ID 1 :TITLE "MyBookTitle" :AUTHOR "MyBookAuthor" :CREATED_AT NIL) NIL) [fast-method]
...
...
debugger invoked on a TYPE-ERROR in thread
#<THREAD "hunchentoot-worker-127.0.0.1:63696" RUNNING {1002A0D863}>:
  The value "MyBookTitle" is not of type SIMPLE-STRING.

Seem that the slot value title is a (VECTOR CHARACTER 64).

I've also tried using a varchar column instead of text but the same error is thrown.

Thank you for your work.

@knobo
Copy link
Contributor

knobo commented May 19, 2016

I don't know why json-encode expects simple-string, but here is what I do:

(defun ensure-simple-string (db-result)
  (typecase db-result
    (cons (mapcar 'ensure-string db-result))
    ((vector character *) (coerce db-result 'simple-string))
    (t db-result)))

(encode-json  (ensure-simple-string db-result))

@lifeisfoo
Copy link
Author

Thank you @knobo for the function, but seems that nothing is changed, the same error is thrown:

debugger invoked on a TYPE-ERROR in thread
#<THREAD "hunchentoot-worker-127.0.0.1:52138" RUNNING {1002C590D3}>:
  The value "MyBookTitle" is not of type SIMPLE-STRING.

Yesterday I found a workaround using a custom render function that use coerce (just like your function) to convert the value to a simple-string

(defun render-book-as-json (book)
  (setf (getf (response-headers *response*) :content-type) "application/json")
  (let ((json
          (with-output-to-string*
              (with-object
                (write-key-value "id" (book-id book))
                (write-key-value "title" (coerce (book-title book) 'simple-string))
                (write-key-value "author" (coerce (book-author book) 'simple-string))
                (write-key-value "created" (book-created book))))))
    (setf (response-body *response*) json)))

(render-book-as-json my-model-from-db)

Then I've found a better, at least from my point of view, solution using a custom datafly inflation function:

(defun chars-vector-to-string (val)
  (etypecase val
    (null nil)
    ((vector character) (coerce val 'simple-string))))

@model
(defstruct (book (:inflate created #'datetime-to-timestamp)
                  (:inflate (title author) #'chars-vector-to-string)) 
  id
  title
  author
  created)

Using this I can just evaluate (render-json my-book-model-from-db) to get the right json.

I don't now if this is an issue or if there is something wrong or missing in my code

I'm using hunchentoot and postgres 9.5.2.

@knobo
Copy link
Contributor

knobo commented May 19, 2016

Ref this:
DO NOT expect simple-strings!
This issue belongs in https://github.com/Rudolph-Miller/jonathan/issues
So maybe you close it here?

@lifeisfoo
Copy link
Author

lifeisfoo commented May 19, 2016

Nice catch @knobo.

Seems that declare type simple-string was added in this commit, then moved to its actual position with another commit.

So, since caveman isn't using jonhatan directly, but it's using datafly encode-json function, and datafly uses jonhatan internally, I think that this is an issue of datafly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants