marijnh / Postmodern

A Common Lisp PostgreSQL programming interface
http://marijnhaverbeke.nl/postmodern
Other
400 stars 90 forks source link

:col-export is not getting called early enough. #277

Closed K1D77A closed 3 years ago

K1D77A commented 3 years ago

I have my class definition with a slot like

(defclass user ()
  (...
   (authorized-in
    :accessor authorized-in
    :initarg :authorized-in
    :initform #()
    :type list
    :col-type  (array integer)
    :col-import server-ids->servers
    :col-export servers->id-array
    :documentation "An array of server domains that this user is authorized in. 
Authorized means they have a valid transaction.")
   ...)
  (:metaclass pomo:dao-class)
  (:keys userid id)
  (:table-name users))

(info removed for brevity)

I have my col-export function


(defun servers->id-array (entry)
  (print entry)
  (if (null entry)
      (make-array 0)
      (map 'vector #'id entry))

I have my instance made in my repl:


[ ]  ACCEPTED-CURRENCIES = ...
[ ]  AUTHORIZED-IN       = NIL
[ ]  EXTRA-INFORMATION   = ""
[ ]  ID                  = 1
[ ]  MERCHANT-ID         = ""
[ ]  TOKEN               = "..."
[ ]  TRANSACTIONS        = #<HASH-TABLE :TEST EQUAL :COUNT 0 {100703CC33}>
[ ]  USERID              = "..."

(some info removed for privacy) Now if I (upsert-dao )

#<USER @...::...>
LUNA-SITE> (pomo:upsert-dao *)
; Debugger entered on #<CL-POSTGRES-ERROR:SYNTAX-ERROR-OR-ACCESS-VIOLATION {100C3EC853}>

(info removed for privacy again)

The debugger:


Database error 42804: column "authorized_in" is of type integer[] but expression is of type boolean
HINT: You will need to rewrite or cast the expression.
QUERY: UPDATE users SET merchant_id = E'', accepted_currencies = E'...', authorized_in = false, token = E'...', extra_information = E'' WHERE ((userid = E'@...') and (id = 1))
   [Condition of type CL-POSTGRES-ERROR:SYNTAX-ERROR-OR-ACCESS-VIOLATION]

Restarts:
 0: [RETRY] Retry SLY mREPL evaluation request.
 1: [*ABORT] Return to SLY's top level.
 2: [ABORT] abort thread (#<THREAD "sly-channel-1-mrepl-remote-1" RUNNING {100E7C8333}>)

(again info removed for privacy) But as you can see it is passing a boolean value even though I assume the :col-export function should have been called, which it isn't, I tried tracing but nothing is displayed. If I change (authorized-in ..) to #() then I can upsert the dao and the :col-export function is called, but at that point whats the point???

Thanks.

K1D77A commented 3 years ago

Maybe misleading actually because it seems :col-export is working for other slots, just dont know why this one isn't working. Is #() being converted to a false??

K1D77A commented 3 years ago

Yes I changed the col-type to (or db-null string) and changed my function to

(defun servers->id-array (entry)
  (print entry)
  (if (null entry)
      ""
      (format nil "~{~A~^ ~}" (mapcar #'id entry))))

and it works. :shrug:

sabracrolleton commented 3 years ago

What do you get if the col-type is (or db-null (array integer)) and the export function adjusted accordingly?

sabracrolleton commented 3 years ago

By the way, you do not actually need an export function if you are just going from a CL array to a Postgresql array without any special manipulations. Postgresql is going to read an empty array as NULL, so if you are going to pass an empty array, you would need the (or db-null (array integer)) col-type specification.

K1D77A commented 3 years ago

alright i have


   (authorized-in
    :accessor authorized-in
    :initarg :authorized-in
    :initform ()
    :type list
    :col-type (or pomo:db-null (integer array))
    :col-import arr->list
    :col-export list->arr
    :documentation "A list of server ids the user is authorized in")

Within my defclass. These are my converters:


(defun arr->list (arr)
  (coerce arr 'list))

(defun list->arr (list)
  (coerce list 'vector))

Now I try to put an instance of an object with that slot in:

LUNA-SITE> (authorized-in *)
NIL

Database error 42804: column "authorized_in" is of type integer but expression is of type boolean
HINT: You will need to rewrite or cast the expression.
QUERY: INSERT INTO users (extra_information, token, authorized_in, accepted_currencies, merchant_id, userid)  VALUES (E'', E'...', false, E'(...

If I made it into a string I'm sure it would work but I dont see the point of parsing a string for its integers every time I restore a user from my DB.

sabracrolleton commented 3 years ago

Found the problem (I think). The export function was not being called if the slot value was nil which is the case with empty lists.

Please try this: Comment out line 537 in Postmodern/postmodern/table.lisp.

Does it work now?

sabracrolleton commented 3 years ago

And comment out line 603. Both of them should say "(slot-value object field)"

K1D77A commented 3 years ago
Database error 22P02: invalid input syntax for type integer: "{}"
QUERY: INSERT INTO users (extra_information, token, authorized_in,

I dropped all my tables, remade them and tried to insert into the table using upsert-dao.

K1D77A commented 3 years ago

I changed


(defun list->arr (list)
  (if (null list)
      nil 
      (coerce list 'vector)))

And tried again:

Database error 42804: column "authorized_in" is of type integer but expression is of type boolean
HINT: You will need to rewrite or cast the expression.
K1D77A commented 3 years ago

Okay I sorted it by doing the following:

(defun list->arr (list)
  (if (null list)
      :null
      (coerce list 'vector)))
K1D77A commented 3 years ago

Just to confirm I removed those changes I made from table.lisp and i was unable to upsert my object, when I reapplied the changes I was, so your suggested fix did work :+1:

sabracrolleton commented 3 years ago

Resolved with today's commit.