r3615: *** empty log message ***
[hyperobject.git] / sqlgen.lisp
index 37a2c0102e8ce814d2a7de89de40b8e7c60630b2..9ff023d35079010cb78a0e1876c42576792532ff 100644 (file)
@@ -1,4 +1,4 @@
-;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10; Package: umlisp -*-
+;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10; Package: umlisp -*-
 ;;;; *************************************************************************
 ;;;; FILE IDENTIFICATION
 ;;;;
 ;;;; Programmer:    Kevin M. Rosenberg
 ;;;; Date Started:  Apr 2000
 ;;;;
-;;;; $Id: sqlgen.lisp,v 1.1 2002/12/01 21:07:28 kevin Exp $
+;;;; $Id: sqlgen.lisp,v 1.4 2002/12/06 16:18:49 kevin Exp $
 ;;;;
 ;;;; This file, part of Hyperobject-SQL, is
 ;;;;    Copyright (c) 2000-2002 by Kevin M. Rosenberg, M.D.
 ;;;; *************************************************************************
 
 (in-package :hyperobject)
-(declaim (optimize (speed 3) (safety 1) (compilation-speed 0) (debug 3)))
+(eval-when (:compile-toplevel :execute)
+  (declaim (optimize (speed 2) (safety 2) (compilation-speed 0) (debug 2))))
 
 
 ;;;; Metaclass initialization commands
-(defun process-sql (cl)
-  (let ((esds (class-slots cl)))
-    (let* ((table-name-slot (slot-value cl 'sql-name))
-           (generate-table-cmd (generate-create-table-string 
-                                (if (consp table-name-slot)
-                                    (car table-name-slot)
-                                  table-name-slot)
-                                dsds)))
-      (setf (slot-value cl 'create-table-cmd) generate-table-cmd))
 
-    (dolist (dsd dsds)
-      (when (dsd-inverse dsd)
-       (define-inverse cl dsd))))
+(defun finalize-sql (cl)
+  (setf (slot-value cl 'sql-name) (sql-name cl))
+  (setf (slot-value cl 'drop-table-cmd) (generate-drop-table-cmd
+                                        (slot-value cl 'sql-name)))
+  (let ((esds (class-slots cl)))
+    (dolist (esd esds)
+      (setf (slot-value cl 'sql-name) (sql-name esd)))
+    (setf (slot-value cl 'create-table-cmd)
+         (generate-create-table-cmd (slot-value cl 'sql-name) esds))
+    (setf (slot-value cl 'create-indices-cmds)
+         (generate-create-indices-cmds (slot-value cl 'sql-name) esds))
+    (dolist (esd esds)
+      (when (slot-value esd 'inverse)
+       (define-inverse cl esd))))
   )
 
-(defun define-inverse (class dsd)
-  (let ((inverse (dsd-inverse dsd)))
+(defmethod sql-name ((cl hyperobject-class))
+  "Return name of SQL table for a class"
+  (let-if (it (slot-value cl 'sql-name))
+    (let* ((name (if (consp it) (car it) it))
+          (lisp-name (if name name (class-name cl))))
+      (lisp-name-to-sql-name lisp-name))))
+
+(defmethod sql-name ((esd hyperobject-esd))
+  (let-if (it (slot-value esd 'sql-name))
+    (let* ((name (if (consp it) (car it) it))
+          (lisp-name (if name name (slot-definition-name esd))))
+      (lisp-name-to-sql-name lisp-name))))
+
+
+(defun lisp-name-to-sql-name (lisp)
+  "Convert a lisp name (atom or list, string or symbol) into a canonical
+SQL name"
+  (unless (stringp lisp)
+    (setq lisp (write-to-string lisp)))
+  (let ((sql (make-string (length lisp))))
+    (dotimes (i (length lisp))
+      (declare (fixnum i))
+      (let ((c (char lisp i)))
+       (case c
+         (#\- #\_)
+         (#\$ #\_)
+         (#\+ #\_)
+         (otherwise c))))
+    (string-upcase sql)))
+
+                       
+(defun define-inverse (class esd)
+  "Define an inverse function for a slot"
+  (let ((inverse (slot-value esd 'inverse)))
     (when inverse
       (eval
-       `(defun ,inverse (key)
-         (format t "~&Finding key: ~a~%" key)
-         (make-instance 'st)
+       `(defun ,inverse (obj)
+         (format t "~&Finding key: ~S for class ~S ~%" obj ,class)
+         ;; create inverse function
          ))
-          
-      ;; create inverse function
       ))
   )
 
-(defun generate-create-table-string (table-name dsds)
-  (let ((cmd (format nil "CREATE TABLE ~A (" 
-                    (slot-name-to-sql-name table-name))))
-    (dolist (dsd dsds)
-      (unless (eq dsd (car dsds))
+(defun generate-create-table-cmd (table-name esds)
+  (let ((cmd (format nil "CREATE TABLE ~A (" table-name)))
+    (dolist (esd esds)
+      (unless (eq esd (car esds))
        (string-append cmd ", "))
-      (string-append cmd (slot-name-to-sql-name 
-                             #+allegro (clos:slot-definition-name dsd)
-                             #+lispworks (clos:slot-definition-name dsd)
-                             ) " ")
-      (let ((length (dsd-length dsd))
-           (sql-type (dsd-sql-type dsd)))
+      (string-append cmd (lisp-name-to-sql-name (slot-definition-name esd))
+                             " ")
+      (let ((length (slot-value esd 'length))
+           (sql-type (slot-value esd 'sql-type)))
        (string-append cmd (sql-field-cmd sql-type length))))
     (string-append cmd ")")))
 
 
-;;;; Runtime Commands
+(defun sql-field-cmd (type length)
+  (ecase type
+    (:string
+     (cond
+       ((null length)
+       "LONGTEXT")
+       ((< length 8)
+        (format nil "CHAR(~d)" length))
+       (t
+       (format nil "VARCHAR(~d)" length))))
+    (:text
+     "LONGTEXT")
+    (:fixnum
+     "INTEGER")
+    (:bigint
+     "BIGINT")
+    (:short-float
+     "SINGLE")
+    (:long-float
+     "DOUBLE")))
 
-(defclass sqltable ()
-  ()
-  )
+(defun generate-drop-table-cmd (table-name)
+  (format nil "DROP TABLE ~a" table-name))
 
-(defmethod sql-create ((self sqltable))
-  (sql (sql-cmd-create-table self))
-  (dolist (cmd (sql-cmd-create-indices self))
-    (sql cmd))
-  (values))
+(defun generate-create-indices-cmds (table-name slots)
+  (let (indices)
+    (dolist (slot slots)
+      (when (slot-value slot 'indexed)
+       (let ((sql-name (slot-value slot 'sql-name)))
+         (push (sql-cmd-index table-name sql-name (slot-value slot 'unique))
+               indices))))
+    indices))
 
-(defmethod sql-drop ((self sqltable))
-  (sql (sql-cmd-drop-table self))
+(defun sql-cmd-index (table field unique)
+  (let ((*print-circle* nil))
+    (format nil "CREATE ~A INDEX ~A ON ~A(~A)"
+           (if unique "UNIQUE" "")
+           table
+           (sql-index-name table field)
+           table
+           field)))
+
+(defun sql-index-name (table field)
+  (format nil "~A_~A" table field))
+
+;;;; Runtime Commands
+
+(defmethod sql-create (cl)
+  (with-sql-connection (conn)
+    (sql-execute (slot-value cl 'create-table-cmd) conn)
+    (dolist (cmd (slot-value cl 'create-indices-cmds))
+      (sql-execute cmd conn))
+    (values)))
+
+(defmethod sql-drop (cl)
+  (mutex-sql-execute (slot-value cl 'drop-table-cmd))
   (values))
 
-(defmethod sql-insert ((self sqltable))
-  (sql
+#|
+(defmethod sql-insert (obj)
+  (mutex-sql-execute
    (format nil "INSERT INTO ~a (~a) VALUES (~a)"
-          (table-name self) (sql-cmd-field-names self) (format-values self))))
+          (sql-name self) (sql-cmd-field-names self) (format-values self))))
 
-(defmethod sql-select ((self sqltable) key)
+(defmethod sql-select (obj lisp-name key)
   (let ((tuple 
         (car 
-         (sql
+         (mutex-sql-query
           (format nil "SELECT ~a FROM ~a WHERE ~a=~a"
-                  (sql-cmd-field-names self) (table-name self)
+                  (sql-cmd-field-names self) (sql-name self)
                   (inverse-field-name self) key)))))
     (when tuple
       (format t "process returned fields"))))
                                          (slot-value self name))))))))))
     values))
 
-(defmacro defsqltable (tname &key fields)
-  `(progn
-     (defclass ,tname (sqltable)
-       ,(parse-fields tname fields)
-       ,(default-initargs fields))
-     
-     (defmethod table-name ((self ,tname))
-       ,(substitute #\_ #\- (write-to-string tname)))
-
-     (defmethod fields ((self ,tname))
-       (quote ,fields))
-     
-     (defmethod sql-cmd-create-table ((self ,tname))
-       ,(create-table-string tname fields))
-
-     (defmethod sql-cmd-create-indices ((self ,tname))
-       "Return a list of index cmds"
-       (quote ,(create-indices-string tname fields)))
 
-     (defmethod sql-cmd-drop-table ((self ,tname))
-       ,(format nil "DROP TABLE ~a" tname))
-     
-     (defmethod sql-cmd-field-names ((self ,tname))
-       ,(row-field-string fields))
-
-     (defmethod inverse-field-name ((self ,tname))
-       ,(inverse-field-string fields))
-     ))
-
-(defun create-indices-string (table-name fields)
-  (let (indices)
-    (dolist (field fields)
-      (let ((name-string (write-to-string (car field))))
-       (with-key-value-list (key value (rest field))
-         (when (eq key :unique)
-           (case value
-             (nil
-              (push (sql-cmd-index table-name name-string nil) indices))
-             (t
-              (push (sql-cmd-index table-name name-string t) indices)))))))
-    indices))
 
 (defun inverse-field-string (fields)
   (let (inverse)
     (when inverse
       (write-to-string inverse))))
 
-(defun sql-cmd-index (table field unique)
-  (let ((*print-circle* nil))
-    (format nil "CREATE ~A INDEX ~A_~A ON ~A(~A)"
-           (if unique "UNIQUE" "")
-           (slot-name-to-sql-name table) 
-           (slot-name-to-sql-name field)
-           (slot-name-to-sql-name table)
-           (slot-name-to-sql-name field))))
-
 (defun row-field-string (fields)
   (let ((names ""))
     (dolist (field fields)
       (unless (eq field (car fields))
        (string-append names ","))
-      (string-append names (slot-name-to-sql-name (car field))))
+      (string-append names (lisp-name-to-sql-name (car field))))
     names))
-         
-(defun slot-name-to-sql-name (name)
-  (substitute #\_ #\- (format nil "~a" name)))
 
-(defun create-table-string (table-name fields)
-  (let ((cmd (format nil "CREATE TABLE ~A (" (slot-name-to-sql-name table-name))))
-    (dolist (field fields)
-      (unless (eq field (car fields))
-       (string-append cmd ", "))
-      (string-append cmd (slot-name-to-sql-name (car field)) " ")
-      (let (length type)
-       (with-key-value-list (key value (rest field))
-         (case key
-           (:length
-            (setq length value))
-           (:type
-            (setq type value))))
-       (string-append cmd (sql-field-cmd type length))))
-    (string-append cmd ")")))
-  
-
-(defun sql-field-cmd (type length)
-  (ecase type
-    (:string
-     (if (< length 8)
-        (format nil "CHAR(~d)" length)
-       (format nil "VARCHAR(~d)" length)))
-    (:text
-     "LONGTEXT")
-    (:fixnum
-     "INTEGER")
-    (:bigint
-     "BIGINT")
-    (:short-float
-     "SINGLE")
-    (:long-float
-     "DOUBLE")))
       
-(defmacro with-key-value-list ((key value list) form)
-  (let ((i (gensym)))
-    `(loop for ,i from 0 to (1- (length ,list)) by 2 do
-          (let ((,key (nth ,i ,list))
-                (,value (nth (1+ ,i) ,list)))
-            ,form))))
-                                                  
 (defun parse-fields (table-name fields)
   (let (class-fields)
     (dolist (field fields)
        (push def class-fields)))
     class-fields))
 
-(defun default-initargs (fields)
-  (let ((initargs (list :default-initargs)))
-    (dolist (field fields)
-      (let* ((fname (car field))
-            (name-string (write-to-string fname))
-            (initarg (intern name-string :keyword)))
-       (setq initargs (nconc initargs (list initarg nil)))))
-    initargs))
-
-
+||#