r9241: add type-modified database identifier support to SELECT
[clsql.git] / sql / objects.lisp
index 8e56989d01eaa6751ea673c1e8d3c9963502a109..833abd79e0510f3a47682bbea747a793fdc27b1a 100644 (file)
@@ -13,7 +13,7 @@
 ;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
 ;;;; *************************************************************************
 
-(in-package #:clsql-sys)
+(in-package #:clsql)
 
 (defclass standard-db-object ()
   ((view-database :initform nil :initarg :view-database :reader view-database
@@ -97,7 +97,7 @@ the view. The argument DATABASE has a default value of
   (when (member (view-class-slot-db-kind slotdef) '(:base :key))
     (let ((cdef
            (list (sql-expression :attribute (view-class-slot-column slotdef))
-                 (slot-type slotdef))))
+                 (specified-type slotdef))))
       (setf cdef (append cdef (list (view-class-slot-db-type slotdef))))
       (let ((const (view-class-slot-db-constraints slotdef)))
         (when const 
@@ -169,8 +169,9 @@ superclass of the newly-defined View Class."
     (defclass ,class ,supers ,slots 
       ,@(if (find :metaclass `,cl-options :key #'car)
            `,cl-options
-           (cons '(:metaclass clsql-sys::standard-db-class) `,cl-options)))
-    (finalize-inheritance (find-class ',class))))
+           (cons '(:metaclass clsql::standard-db-class) `,cl-options)))
+    (finalize-inheritance (find-class ',class))
+    (find-class ',class)))
 
 (defun keyslots-for-class (class)
   (slot-value class 'key-slots))
@@ -232,16 +233,13 @@ superclass of the newly-defined View Class."
       (car list)
       list))
 
-(defun slot-type (slotdef)
-  (specified-type slotdef))
-
 (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))
-        (slot-type   (slot-type slotdef))
+        (slot-type   (specified-type slotdef))
         (*update-context* (cons (type-of instance) slot-name)))
     (cond ((and value (null slot-reader))
            (setf (slot-value instance slot-name)
@@ -261,7 +259,7 @@ superclass of the newly-defined View Class."
 (defmethod key-value-from-db (slotdef value database) 
   (declare (optimize (speed 3) #+cmu (extensions:inhibit-warnings 3)))
   (let ((slot-reader (view-class-slot-db-reader slotdef))
-        (slot-type (slot-type slotdef)))
+        (slot-type (specified-type slotdef)))
     (cond ((and value (null slot-reader))
            (read-sql-value value (delistify slot-type) database))
           ((null value)
@@ -275,7 +273,7 @@ superclass of the newly-defined View Class."
 
 (defun db-value-from-slot (slotdef val database)
   (let ((dbwriter (view-class-slot-db-writer slotdef))
-       (dbtype (slot-type slotdef)))
+       (dbtype (specified-type slotdef)))
     (typecase dbwriter
       (string (format nil dbwriter val))
       (function (apply dbwriter (list val)))
@@ -287,7 +285,7 @@ superclass of the newly-defined View Class."
          (database-output-sql-as-type dbtype val database)))))))
 
 (defun check-slot-type (slotdef val)
-  (let* ((slot-type (slot-type slotdef))
+  (let* ((slot-type (specified-type slotdef))
          (basetype (if (listp slot-type) (car slot-type) slot-type)))
     (when (and slot-type val)
       (unless (typep val basetype)
@@ -468,6 +466,10 @@ superclass of the newly-defined View Class."
       (format nil "INT(~A)" (car args))
       "INT"))
 
+(deftype bigint () 
+  "An integer larger than a 32-bit integer, this width may vary by SQL implementation."
+  'integer)
+
 (defmethod database-get-type-specifier ((type (eql 'bigint)) args database)
   (declare (ignore args database))
   "BIGINT")
@@ -839,14 +841,37 @@ superclass of the newly-defined View Class."
 
 (defmethod instance-refreshed ((instance standard-db-object)))
 
-(defmethod select (&rest select-all-args)
-  "Selects data from database given the constraints specified. Returns
-a list of lists of record values as specified by select-all-args. By
-default, the records are each represented as lists of attribute
-values. The selections argument may be either db-identifiers, literal
-strings or view classes.  If the argument consists solely of view
-classes, the return value will be instances of objects rather than raw
-tuples."
+(defun select (&rest select-all-args) 
+   "The function SELECT selects data from DATABASE, which has a
+default value of *DEFAULT-DATABASE*, given the constraints
+specified by the rest of the ARGS. It returns a list of objects
+as specified by SELECTIONS. By default, the objects will each be
+represented as lists of attribute values. The argument SELECTIONS
+consists either of database identifiers, type-modified database
+identifiers or literal strings. A type-modifed database
+identifier is an expression such as [foo :string] which means
+that the values in column foo are returned as Lisp strings.  The
+FLATP argument, which has a default value of nil, specifies if
+full bracketed results should be returned for each matched
+entry. If FLATP is nil, the results are returned as a list of
+lists. If FLATP is t, the results are returned as elements of a
+list, only if there is only one result per row. The arguments
+ALL, SET-OPERATION, DISTINCT, FROM, WHERE, GROUP-BY, HAVING and
+ORDER-by have the same function as the equivalent SQL expression.
+The SELECT function is common across both the functional and
+object-oriented SQL interfaces. If selections refers to View
+Classes then the select operation becomes object-oriented. This
+means that SELECT returns a list of View Class instances, and
+SLOT-VALUE becomes a valid SQL operator for use within the where
+clause. In the View Class case, a second equivalent select call
+will return the same View Class instance objects. If REFRESH is
+true, then existing instances are updated if necessary, and in
+this case you might need to extend the hook INSTANCE-REFRESHED.
+The default value of REFRESH is nil. SQL expressions used in the
+SELECT function are specified using the square bracket syntax,
+once this syntax has been enabled using
+ENABLE-SQL-READER-SYNTAX."
+
   (flet ((select-objects (target-args)
            (and target-args
                 (every #'(lambda (arg)
@@ -857,13 +882,28 @@ tuples."
         (query-get-selections select-all-args)
       (if (select-objects target-args)
           (apply #'find-all target-args qualifier-args)
-          (let ((expr (apply #'make-query select-all-args)))
-            (destructuring-bind (&key (flatp nil)
-                                     (result-types :auto)
-                                     (field-names t) 
-                                     (database *default-database*)
-                                      &allow-other-keys)
-                qualifier-args
-             (query expr :flatp flatp :result-types result-types 
-                    :field-names field-names :database database)))))))
+       (let* ((expr (apply #'make-query select-all-args))
+              (specified-types
+               (mapcar #'(lambda (attrib)
+                           (if (typep attrib 'sql-ident-attribute)
+                               (let ((type (slot-value attrib 'type)))
+                                 (if type
+                                     type
+                                   t))
+                             t))
+                       (slot-value expr 'selections))))
+         (destructuring-bind (&key (flatp nil)
+                                   (result-types :auto)
+                                   (field-names t) 
+                                   (database *default-database*)
+                              &allow-other-keys)
+             qualifier-args
+           (query expr :flatp flatp 
+                  :result-types 
+                  ;; specifying a type for an attribute overrides result-types
+                  (if (some #'(lambda (x) (not (eq t x))) specified-types) 
+                      specified-types
+                    result-types)
+                  :field-names field-names
+                  :database database)))))))