eudoxia0 / crane

An ORM for Common Lisp.
http://eudoxia.me/crane/
201 stars 19 forks source link

SQLITE3 (filter.. seems to fail on deflating #6

Closed eraaij closed 10 years ago

eraaij commented 10 years ago

Reproduction path: (ql:quickload :crane)

(crane:setup :migrations-directory #p"/Users/eraaij/vrcproj/sqlitedb/migrations/" :databases '(:main (:type :sqlite3 :name #p"/Users/eraaij/vrcproj/sqlitedb/test.db")) :debug t)

(crane:deftable users () (user_name :type text) (age :type integer :indexp t))

(crane:filter 'users)

This emits (SBCL 1.2) There is no applicable method for the generic function

<STANDARD-GENERIC-FUNCTION CRANE.INFLATE-DEFLATE:INFLATE (2)>

when called with arguments ("Emile" TEST). [Condition of type SIMPLE-ERROR]

Restarts: 0: [RETRY] Retry calling the generic function. 1: [RETRY] Retry SLIME REPL evaluation request. 2: [*ABORT] Return to SLIME's top level. 3: [REMOVE-FD-HANDLER] Remove #<SB-IMPL::HANDLER INPUT on descriptor 9: #<CLOSURE (LABELS SWANK-BACKEND::RUN :IN SWANK-BACKEND:ADD-FD-HANDLER) {1002CA301B}>> 4: [ABORT] Exit debugger, returning to top level.

Backtrace: 0: ((:METHOD NO-APPLICABLE-METHOD (T)) #<STANDARD-GENERIC-FUNCTION CRANE.INFLATE-DEFLATE:INFLATE (2)> "Emile" TEST) [fast-method] 1: (SB-PCL::CALL-NO-APPLICABLE-METHOD #<STANDARD-GENERIC-FUNCTION CRANE.INFLATE-DEFLATE:INFLATE (2)> ("Emile" TEST)) 2: ((:METHOD CRANE.INTERFACE::CLEAN-TUPLE (CRANE.META:TABLE-CLASS T)) # (:|id| 1 :|user_name| "Emile" :|age| 46)) [fast-method] 3: ((:METHOD CRANE.INTERFACE::TUPLE->OBJECT (CRANE.META:TABLE-CLASS T)) # (:|id| 1 :|user_name| "Emile" :|age| 46)) [fast-method] 4: (SB-IMPL::MAP1 #<FUNCTION (LAMBDA (CRANE.INTERFACE::TUPLE)) {1007F23E6B}> (((:|id| 1 :|user_name| "Emile" :|age| 46) (:|id| 2 :|user_name| "Natascha" :|age| 46) (:|id| 3 :|user_name| "Eva" :|age| 13) .. 5: (MAPCAR #<FUNCTION (LAMBDA (CRANE.INTERFACE::TUPLE)) {1007F23E6B}> ((:|id| 1 :|user_name| "Emile" :|age| 46) (:|id| 2 :|user_name| "Natascha" :|age| 46) (:|id| 3 :|user_name| "Eva" :|age| 13) (:|id| 4.. 6: (SB-INT:SIMPLE-EVAL-IN-LEXENV (CRANE.INTERFACE:FILTER (QUOTE USERS)) #) 7:

eudoxia0 commented 10 years ago

This is just a guess, but try writing and executing the same code in a package that :USEs the Crane package.

eraaij commented 10 years ago

Tried:

(ql:quickload :crane) (defpackage :crane-test (:use :crane :common-lisp))

(in-package :crane-test)

setup, connect deftable stuff

CRANE-TEST> (filter 'users)

Emits (debug t) Query: SELECT * FROM "users"

gives the same stack with: There is no applicable method for the generic function

<STANDARD-GENERIC-FUNCTION CRANE.INFLATE-DEFLATE:INFLATE (2)>

when called with arguments ("Emile" TEXT). [Condition of type SIMPLE-ERROR]

On Sun, Jun 15, 2014 at 9:04 PM, Fernando Borretti <notifications@github.com

wrote:

This is just a guess, but try writing and executing the same code in a package that :USEs the Crane package.

— Reply to this email directly or view it on GitHub https://github.com/eudoxia0/crane/issues/6#issuecomment-46124524.

lucashpandolfo commented 10 years ago
CL-USER> (crane.inflate-deflate:inflate "Some Text" 'text)

There is no applicable method for the generic function
  #<STANDARD-GENERIC-FUNCTION CRANE.INFLATE-DEFLATE:INFLATE (2)>
when called with arguments
  ("Some Text" TEXT).
   [Condition of type SIMPLE-ERROR]
CL-USER> (in-package :crane.inflate-deflate)
#<PACKAGE "CRANE.INFLATE-DEFLATE">
INFLATE-DEFLATE> (inflate "Some Text" 'text)
"Some Text"
INFLATE-DEFLATE> (in-package :cl-user)
#<PACKAGE "COMMON-LISP-USER">
CL-USER> (crane.inflate-deflate:inflate "Some Text" 'crane.inflate-deflate::text)
"Some Text"

¿Why not switch to keywords?

For a quick fix (inflate-deflate.lisp):

(defgeneric inflate% (obj type-name)
  (:documentation "Turn a string into a CLOS object."))

(defmacro definflate ((obj-name obj-type-name) &rest body)
  `(defmethod inflate% (,obj-name
            (type (eql ,(intern (symbol-name obj-type-name) :keyword))))
     ,@body))

(defun inflate (object type)
  (inflate% object (intern (symbol-name type) :keyword)))

(definflate (obj text) obj)
(definflate (obj integer) obj)

Then

CL-USER> (crane.inflate-deflate:inflate "Some text" 'text)
"Some text"
eudoxia0 commented 10 years ago

¿Why not switch to keywords?

I considered this when I suspected this was the problem. Now that it's confirmed I guess it's time to make a decision. Keywords would probably be the simplest answer, but my problem with them is that they are, well, keywords: Crane extensions might export names of new database types and they might conflict using keywords, leading to naming conventions like :vendor-type or something. Additionally, while this is entirely a matter of taste, I feel the deftable macro wouldn't benefit from being more keyword-dense.

The alternative would be a more complex type system, where types can have different representations for each database and that would subsume the inflation/deflation system.

If having to hack around this for a little extra while is not an inconvenience, I would like to take some time to consider the options. Any input is, of course, appreciated.

lucashpandolfo commented 10 years ago

Then ¿Why not stick to standard types? (string instead of text)

Or/and do something like Django and define standard types like CharField, DateTimeField, EmailField, etc.

CL-USER> (defpackage :crane.types (:use :cl) (:export :text))
#<PACKAGE "CRANE.TYPES">
CL-USER> (in-package :crane.types)
#<PACKAGE "CRANE.TYPES">
TYPES> (deftype text () `string)
TEXT

TYPES> (in-package :crane.inflate-deflate)
#<PACKAGE "CRANE.INFLATE-DEFLATE">
INFLATE-DEFLATE> (definflate (obj 'crane.types:text) obj)
#<STANDARD-METHOD INFLATE (T (EQL CRANE.TYPES:TEXT)) {10091E5FB3}>
INFLATE-DEFLATE> (in-package :cl-user)
#<PACKAGE "COMMON-LISP-USER">
CL-USER> (crane.inflate-deflate:inflate "Some string" 'crane.types:text)
"Some string"

CL-USER> (crane:deftable ship ()
           (name    :type crane.types:text :uniquep t)
           (tonnage :type integer))
Query: CREATE TABLE "ship" (    "id" INTEGER PRIMARY KEY AUTOINCREMENT,     "tonnage" INTEGER,     "name" TEXT,    CONSTRAINT "crane_ship_id_nullp" CHECK ("id" IS NOT NULL),     CONSTRAINT "crane_ship_name_uniquep" UNIQUE ("name"));
#<DBD.SQLITE3::<DBD-SQLITE3-QUERY> {10066F04C3}>
CL-USER> (crane:create 'ship :name "Ship1" :tonnage 1)
#<SHIP {10069B0BD3}>
CL-USER> (crane:create 'ship :name "Ship2" :tonnage 2)
#<SHIP {1006BA89A3}>
CL-USER> (mapcar #'describe (crane:filter 'ship))
#<SHIP {1006C942C3}>
  [standard-object]

Slots with :INSTANCE allocation:
  ID       = 1
  TONNAGE  = 1
  NAME     = "Ship1"
#<SHIP {1006C95353}>
  [standard-object]

Slots with :INSTANCE allocation:
  ID       = 2
  TONNAGE  = 2
  NAME     = "Ship2"
(NIL NIL)
eudoxia0 commented 10 years ago

Yeah, there's no need to Greenspun an entire type system when Common Lisp already has deftype. I'll go for that.

eudoxia0 commented 10 years ago

9a5cf3c443 fixes this. You'll still have to use the symbols exported by the crane package for the type names, so overall I recommend doing (:use :crane).