Closed eraaij closed 10 years ago
This is just a guess, but try writing and executing the same code in a package that :USE
s the Crane package.
Tried:
(ql:quickload :crane) (defpackage :crane-test (:use :crane :common-lisp))
(in-package :crane-test)
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
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.
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"
¿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.
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)
Yeah, there's no need to Greenspun an entire type system when Common Lisp already has deftype
. I'll go for that.
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)
.
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: