So just another jump into the unknown, I wondered great wonders about creating a macro in Common Lisp that would just print out what I type between the () into T-Sql. Essentially, I want to type this:
(select user.name age)
And get:
"SELECT user.name, age"
Now there are probably a billion (or slightly less) examples of using keywords like:
(select 'user.name...
or:
(select :user name)
Or whatever. Â Not good enough for me. I am more demanding.
So the first stab was something simple; Â Just take an arbitrarily (I actually spelled that correctly the first time) long list of names, and create a string from it. And here it was:
(defmacro select (&rest args) `(mapcar #'write-to-string (list ,@args)))
Basically, take the parameter “args”, strip the () surrounding it, create a new list, and create a string from every member. A quick macroexpand show the outcome:
(macroexpand-1 '(select 'test 'me)) -> (MAPCAR #'WRITE-TO-STRING (LIST 'TEST 'ME)) -> ("TEST" "ME")
As shown, that is just a list of “test” and “me”. Doesn’t make the cut, mostly because I had to use “APOSTROPHEtest” instead of just “test”. Oh and there’s no string. Time to take care of that:
(defmacro select (&rest args) `(concatenate 'string ,@(mapcar #'write-to-string args)))
So now it should take the list of strings ‘(“TEST” “ME”)’, and make it a nice string. DOES IT?!?!?
(macroexpand-1 '(select 'test 'me)) -> (CONCATENATE 'STRING "'TEST" "'ME") -> OOPS
Go figure, it left the APOSTROPHE on the words. Actually, this is good sign. It means I don need to prefix the names with an APOSTROPHE Â anymore. Next attempt:
(macroexpand-1 '(select test me)) -> (CONCATENATE 'STRING "TEST" "ME") -> "TESTME"
Now it’s getting there. Only thing is: There needs to be a separation added. Duh, right? Might as well throw in the “SELECT” part too.
(defmacro select (&rest args) `(concatenate 'string "SELECT " ,@(mapcar #'(lambda (z) (concatenate 'string (write-to-string z) ", ")) args)))
Big change here was adding the “, ” to the converted keywords, then take the newly created partial string and make one long string.
(macroexpand-1 '(select user.name age)) -> (CONCATENATE 'STRING "SELECT " "USER.NAME, " "AGE, ") -> "SELECT USER.NAME, AGE, "
And there it is. Can’t get much better than that.
why not just
“`
(defmacro select (&rest args)
(format nil “SELECT ~{~a~^, ~}” args))
“`
and if you want the case of the names being preserved you can also `(setf (readtable-case *readtable*) :preserve)`
but this macro is stupid anyway