r9727: 1 Jul 2004 Kevin Rosenberg <kevin@rosenberg.net>
[clsql.git] / sql / oodml.lisp
index e2f6b48eb2b5cc02c92bcd0fe201024f73163e27..d701f0906e3a2352cbf01262c8b4179f6b02990a 100644 (file)
 ;; Called by 'get-slot-values-from-view'
 ;;
 
 ;; Called by 'get-slot-values-from-view'
 ;;
 
-(defvar *update-context* nil)
-
 (defmethod update-slot-from-db ((instance standard-db-object) slotdef value)
   (declare (optimize (speed 3) #+cmu (extensions:inhibit-warnings 3)))
   (let* ((slot-reader (view-class-slot-db-reader slotdef))
         (slot-name   (slot-definition-name slotdef))
 (defmethod update-slot-from-db ((instance standard-db-object) slotdef value)
   (declare (optimize (speed 3) #+cmu (extensions:inhibit-warnings 3)))
   (let* ((slot-reader (view-class-slot-db-reader slotdef))
         (slot-name   (slot-definition-name slotdef))
-        (slot-type   (specified-type slotdef))
-        (*update-context* (cons (type-of instance) slot-name)))
+        (slot-type   (specified-type slotdef)))
     (cond ((and value (null slot-reader))
            (setf (slot-value instance slot-name)
                  (read-sql-value value (delistify slot-type)
     (cond ((and value (null slot-reader))
            (setf (slot-value instance slot-name)
                  (read-sql-value value (delistify slot-type)
            (error "No view-table for class ~A"  classname))
          (sql-expression :table (view-table class))))
 
            (error "No view-table for class ~A"  classname))
          (sql-expression :table (view-table class))))
 
+
 (defmethod database-get-type-specifier (type args database db-type)
   (declare (ignore type args database db-type))
 (defmethod database-get-type-specifier (type args database db-type)
   (declare (ignore type args database db-type))
-  "VARCHAR(255)")
+  (format nil "VARCHAR(~D)" *default-string-length*))
 
 (defmethod database-get-type-specifier ((type (eql 'integer)) args database db-type)
   (declare (ignore database db-type))
 
 (defmethod database-get-type-specifier ((type (eql 'integer)) args database db-type)
   (declare (ignore database db-type))
 (defmethod database-get-type-specifier ((type (eql 'bigint)) args database db-type)
   (declare (ignore args database db-type))
   "BIGINT")
 (defmethod database-get-type-specifier ((type (eql 'bigint)) args database db-type)
   (declare (ignore args database db-type))
   "BIGINT")
-              
-(defmethod database-get-type-specifier ((type (eql 'simple-base-string)) args
-                                        database db-type)
-  (declare (ignore database db-type))
-  (if args
-      (format nil "VARCHAR(~A)" (car args))
-      "VARCHAR(255)"))
 
 
-(defmethod database-get-type-specifier ((type (eql 'simple-string)) args
+(deftype varchar () 
+  "A variable length string for the SQL varchar type."
+  'string)
+
+(defmethod database-get-type-specifier ((type (eql 'varchar)) args
                                         database db-type)
   (declare (ignore database db-type))
   (if args
       (format nil "VARCHAR(~A)" (car args))
                                         database db-type)
   (declare (ignore database db-type))
   (if args
       (format nil "VARCHAR(~A)" (car args))
-      "VARCHAR(255)"))
+      (format nil "VARCHAR(~D)" *default-string-length*)))
 
 (defmethod database-get-type-specifier ((type (eql 'string)) args database db-type)
   (declare (ignore database db-type))
   (if args
 
 (defmethod database-get-type-specifier ((type (eql 'string)) args database db-type)
   (declare (ignore database db-type))
   (if args
-      (format nil "VARCHAR(~A)" (car args))
-      "VARCHAR(255)"))
+      (format nil "CHAR(~A)" (car args))
+      (format nil "VARCHAR(~D)" *default-string-length*)))
 
 (deftype universal-time () 
   "A positive integer as returned by GET-UNIVERSAL-TIME."
 
 (deftype universal-time () 
   "A positive integer as returned by GET-UNIVERSAL-TIME."
       (format nil "FLOAT(~A)" (car args))
       "FLOAT"))
 
       (format nil "FLOAT(~A)" (car args))
       "FLOAT"))
 
+(deftype generalized-boolean () 
+  "A type which outputs a SQL boolean value, though any lisp type can be stored in the slot."
+  t)
+
 (defmethod database-get-type-specifier ((type (eql 'boolean)) args database db-type)
   (declare (ignore args database db-type))
   "BOOL")
 
 (defmethod database-get-type-specifier ((type (eql 'boolean)) args database db-type)
   (declare (ignore args database db-type))
   "BOOL")
 
+(defmethod database-get-type-specifier ((type (eql 'generalized-boolean)) args database db-type)
+  (declare (ignore args database db-type))
+  "BOOL")
+
 (defmethod database-get-type-specifier ((type (eql 'number)) args database db-type)
   (declare (ignore database db-type))
   (cond
 (defmethod database-get-type-specifier ((type (eql 'number)) args database db-type)
   (declare (ignore database db-type))
   (cond
   (declare (ignore database db-type))
   (if args
       (format nil "CHAR(~D)" (first args))
   (declare (ignore database db-type))
   (if args
       (format nil "CHAR(~D)" (first args))
-    "CHAR"))
+      "CHAR(1)"))
 
 
 (defmethod database-output-sql-as-type (type val database db-type)
 
 
 (defmethod database-output-sql-as-type (type val database db-type)
 
 (defmethod database-output-sql-as-type ((type (eql 'symbol)) val database db-type)
   (declare (ignore database db-type))
 
 (defmethod database-output-sql-as-type ((type (eql 'symbol)) val database db-type)
   (declare (ignore database db-type))
-  (if (keywordp val)
-      (symbol-name val)
-      (if val
-          (concatenate 'string
-                       (package-name (symbol-package val))
-                       "::"
-                       (symbol-name val))
-          "")))
+  (if val
+    (concatenate 'string
+                 (package-name (symbol-package val))
+                 "::"
+                 (symbol-name val))
+    ""))
 
 (defmethod database-output-sql-as-type ((type (eql 'keyword)) val database db-type)
   (declare (ignore database db-type))
 
 (defmethod database-output-sql-as-type ((type (eql 'keyword)) val database db-type)
   (declare (ignore database db-type))
   (declare (ignore database db-type))
   (if val "t" "f"))
 
   (declare (ignore database db-type))
   (if val "t" "f"))
 
-(defmethod database-output-sql-as-type ((type (eql 'string)) val database db-type)
+(defmethod database-output-sql-as-type ((type (eql 'generalized-boolean)) val database db-type)
   (declare (ignore database db-type))
   (declare (ignore database db-type))
-  val)
+  (if val "t" "f"))
 
 
-(defmethod database-output-sql-as-type ((type (eql 'simple-string))
-                                       val database db-type)
+(defmethod database-output-sql-as-type ((type (eql 'string)) val database db-type)
   (declare (ignore database db-type))
   val)
 
   (declare (ignore database db-type))
   val)
 
-(defmethod database-output-sql-as-type ((type (eql 'simple-base-string))
+(defmethod database-output-sql-as-type ((type (eql 'char))
                                        val database db-type)
   (declare (ignore database db-type))
                                        val database db-type)
   (declare (ignore database db-type))
-  val)
+  (etypecase val
+    (character (write-to-string val))
+    (string val)))
 
 (defmethod read-sql-value (val type database db-type)
   (declare (ignore type database db-type))
 
 (defmethod read-sql-value (val type database db-type)
   (declare (ignore type database db-type))
   (declare (ignore database db-type))
   val)
 
   (declare (ignore database db-type))
   val)
 
-(defmethod read-sql-value (val (type (eql 'simple-string)) database db-type)
+(defmethod read-sql-value (val (type (eql 'varchar)) database db-type)
   (declare (ignore database db-type))
   val)
 
   (declare (ignore database db-type))
   val)
 
-(defmethod read-sql-value (val (type (eql 'simple-base-string)) database db-type)
+(defmethod read-sql-value (val (type (eql 'char)) database db-type)
   (declare (ignore database db-type))
   (declare (ignore database db-type))
-  val)
-
+  (schar val 0))
+              
 (defmethod read-sql-value (val (type (eql 'keyword)) database db-type)
   (declare (ignore database db-type))
   (when (< 0 (length val))
 (defmethod read-sql-value (val (type (eql 'keyword)) database db-type)
   (declare (ignore database db-type))
   (when (< 0 (length val))
   (declare (ignore database db-type))
   (when (< 0 (length val))
     (unless (string= val (symbol-name-default-case "NIL"))
   (declare (ignore database db-type))
   (when (< 0 (length val))
     (unless (string= val (symbol-name-default-case "NIL"))
-      (intern (symbol-name-default-case val)
-              (symbol-package *update-context*)))))
+      (read-from-string val))))
 
 (defmethod read-sql-value (val (type (eql 'integer)) database db-type)
   (declare (ignore database db-type))
 
 (defmethod read-sql-value (val (type (eql 'integer)) database db-type)
   (declare (ignore database db-type))
   (declare (ignore database db-type))
   (equal "t" val))
 
   (declare (ignore database db-type))
   (equal "t" val))
 
+(defmethod read-sql-value (val (type (eql 'generalized-boolean)) database db-type)
+  (declare (ignore database db-type))
+  (equal "t" val))
+
 (defmethod read-sql-value (val (type (eql 'number)) database db-type)
   (declare (ignore database db-type))
   (etypecase val
 (defmethod read-sql-value (val (type (eql 'number)) database db-type)
   (declare (ignore database db-type))
   (etypecase val
        (read-from-string val)))
     (number val)))
 
        (read-from-string val)))
     (number val)))
 
-(defmethod read-sql-value (val (type (eql 'univeral-time)) database db-type)
+(defmethod read-sql-value (val (type (eql 'universal-time)) database db-type)
   (declare (ignore database db-type))
   (unless (eq 'NULL val)
     (etypecase val
   (declare (ignore database db-type))
   (unless (eq 'NULL val)
     (etypecase val
@@ -1074,3 +1079,27 @@ as elements of a list."
   results)
 
 
   results)
 
 
+
+;;; Serialization functions
+
+(defun write-instance-to-stream (obj stream)
+  "Writes an instance to a stream where it can be later be read.
+NOTE: an error will occur if a slot holds a value which can not be written readably."
+  (let* ((class (class-of obj))
+        (alist '()))
+    (dolist (slot (ordered-class-slots (class-of obj)))
+      (let ((name (slot-definition-name slot)))
+       (when (and (not (eq 'view-database name))
+                  (slot-boundp obj name))
+         (push (cons name (slot-value obj name)) alist))))
+    (setq alist (reverse alist))
+    (write (cons (class-name class) alist) :stream stream :readably t))
+  obj)
+
+(defun read-instance-from-stream (stream)
+  (let ((raw (read stream nil nil)))
+    (when raw
+      (let ((obj (make-instance (car raw))))
+       (dolist (pair (cdr raw))
+         (setf (slot-value obj (car pair)) (cdr pair)))
+       obj))))