X-Git-Url: http://git.kpe.io/?a=blobdiff_plain;f=sql%2Foodml.lisp;h=d38d3b94ded9ad1b3fb03c3944173bc0540115e5;hb=30186614582039bdc3d3f86bc5165ef300c5d3e0;hp=99cf0217f31f7c8325a4cc890ae3d0df34606d51;hpb=0bed331173815bfe0544c0fdad6fb8b83ae929f1;p=clsql.git diff --git a/sql/oodml.lisp b/sql/oodml.lisp index 99cf021..d38d3b9 100644 --- a/sql/oodml.lisp +++ b/sql/oodml.lisp @@ -19,7 +19,7 @@ (flet ((qfk (k) (sql-operation '== (sql-expression :attribute - (view-class-slot-column k) + (database-identifier k database) :table tb) (db-value-from-slot k @@ -39,11 +39,11 @@ (defun generate-attribute-reference (vclass slotdef) (cond ((eq (view-class-slot-db-kind slotdef) :base) - (sql-expression :attribute (view-class-slot-column slotdef) - :table (view-table vclass))) + (sql-expression :attribute (database-identifier slotdef nil) + :table (database-identifier vclass nil))) ((eq (view-class-slot-db-kind slotdef) :key) - (sql-expression :attribute (view-class-slot-column slotdef) - :table (view-table vclass))) + (sql-expression :attribute (database-identifier slotdef nil) + :table (database-identifier vclass nil))) (t nil))) ;; @@ -196,7 +196,7 @@ (let* ((vct (view-table view-class)) (sd (slotdef-for-slot-with-class slot view-class))) (check-slot-type sd (slot-value obj slot)) - (let* ((att (view-class-slot-column sd)) + (let* ((att (database-identifier sd database)) (val (db-value-from-slot sd (slot-value obj slot) database))) (cond ((and vct sd (view-database obj)) (update-records (sql-expression :table vct) @@ -232,7 +232,7 @@ obj (slot-definition-name s)))) (check-slot-type s val) (list (sql-expression - :attribute (view-class-slot-column s)) + :attribute (database-identifier s database)) (db-value-from-slot s val database)))) sds))) (cond ((and avps (view-database obj)) @@ -263,17 +263,18 @@ (slot-value-list (slot) (let ((value (slot-value obj (slot-definition-name slot)))) (check-slot-type slot value) - (list (sql-expression :attribute (view-class-slot-column slot)) + (list (sql-expression :attribute (database-identifier slot database)) (db-value-from-slot slot value database))))) (let* ((view-class (or this-class (class-of obj))) (pk-slot (car (keyslots-for-class view-class))) + (pk-name (when pk-slot (slot-definition-name pk-slot))) (view-class-table (view-table view-class)) (pclass (car (class-direct-superclasses view-class)))) (when (normalizedp view-class) (setf pk (update-records-from-instance obj :database database :this-class pclass)) (when pk-slot - (setf (slot-value obj (slot-definition-name pk-slot)) pk))) + (setf (slot-value obj pk-name) pk))) (let* ((slots (remove-if-not #'slot-storedp (if (normalizedp view-class) (ordered-class-direct-slots view-class) @@ -297,37 +298,36 @@ :database database) (when pk-slot (setf pk (or pk - (slot-value obj (slot-definition-name pk-slot)))))) + (slot-value obj pk-name))))) (t (insert-records :into (sql-expression :table view-class-table) :av-pairs record-values :database database) - (when (and pk-slot (not pk)) - (setf pk (if (or (member :auto-increment (listify (view-class-slot-db-constraints pk-slot))) - (not (null (view-class-slot-autoincrement-sequence pk-slot)))) - (setf (slot-value obj (slot-definition-name pk-slot)) - (database-last-auto-increment-id database - view-class-table - pk-slot))))) + (setf pk + (when (auto-increment-column-p pk-slot database) + (setf (slot-value obj pk-name) + (database-last-auto-increment-id + database view-class-table pk-slot))))) (when pk-slot (setf pk (or pk - (slot-value - obj (slot-definition-name pk-slot))))) - (when (eql this-class nil) + (and (slot-boundp obj pk-name) + (slot-value obj pk-name))))) + (when (eql this-class nil) (setf (slot-value obj 'view-database) database))))))) ;; handle slots with defaults (let* ((view-class (or this-class (class-of obj))) (slots (if (normalizedp view-class) (ordered-class-direct-slots view-class) - (ordered-class-slots view-class)))) + (ordered-class-slots view-class)))) (dolist (slot slots) - (when (and (slot-exists-p slot 'db-constraints) - (listp (view-class-slot-db-constraints slot)) - (member :default (view-class-slot-db-constraints slot))) - (unless (and (slot-boundp obj (slot-definition-name slot)) - (slot-value obj (slot-definition-name slot))) - (update-slot-from-record obj (slot-definition-name slot)))))) + (let ((slot-name (slot-definition-name slot))) + (when (and (slot-exists-p slot 'db-constraints) + (listp (view-class-slot-db-constraints slot)) + (member :default (view-class-slot-db-constraints slot))) + (unless (and (slot-boundp obj slot-name) + (slot-value obj slot-name)) + (update-slot-from-record obj slot-name)))))) pk)) @@ -406,7 +406,7 @@ (sld (slotdef-for-slot-with-class slot class))) (if sld (if (eq value +no-slot-value+) - (sql-expression :attribute (view-class-slot-column sld) + (sql-expression :attribute (database-identifier sld database) :table (view-table class)) (db-value-from-slot sld @@ -941,8 +941,8 @@ maximum of MAX-LEN instances updated in each query." (symbol (sql-expression :attribute - (view-class-slot-column - (slotdef-for-slot-with-class fk sc)) + (database-identifier + (slotdef-for-slot-with-class fk sc) nil) :table (view-table sc))) (t fk)) (typecase hk @@ -989,8 +989,8 @@ maximum of MAX-LEN instances updated in each query." (symbol (sql-expression :attribute - (view-class-slot-column fksd) - :table (view-table jc))) + (database-identifier fksd nil) + :table (database-identifier jc nil))) (t fk)) (typecase hk (symbol @@ -1089,114 +1089,107 @@ maximum of MAX-LEN instances updated in each query." instances parameters) "Called by SELECT to generate object query results when the View Classes VIEW-CLASSES are passed as arguments to SELECT." - (declare (ignore all set-operation group-by having offset limit inner-join on)) + (declare (ignore all set-operation group-by having offset limit inner-join on parameters) + (dynamic-extent args)) (flet ((ref-equal (ref1 ref2) (string= (sql-output ref1 database) - (sql-output ref2 database))) - (tables-equal (table-a table-b) - (when (and table-a table-b) - (string= (string (slot-value table-a 'name)) - (string (slot-value table-b 'name)))))) - (remf args :from) - (remf args :where) - (remf args :flatp) - (remf args :additional-fields) - (remf args :result-types) - (remf args :instances) - (let* ((*db-deserializing* t) - (sclasses (mapcar #'find-class view-classes)) - (immediate-join-slots - (mapcar #'(lambda (c) (generate-retrieval-joins-list c :immediate)) sclasses)) - (immediate-join-classes - (mapcar #'(lambda (jcs) - (mapcar #'(lambda (slotdef) - (find-class (gethash :join-class (view-class-slot-db-info slotdef)))) - jcs)) - immediate-join-slots)) - (immediate-join-sels (mapcar #'generate-immediate-joins-selection-list sclasses)) - (sels (mapcar #'generate-selection-list sclasses)) - (fullsels (apply #'append (mapcar #'append sels immediate-join-sels))) - (sel-tables (collect-table-refs where)) - (tables (remove-if #'null - (remove-duplicates - (append (mapcar #'select-table-sql-expr sclasses) - (mapcan #'(lambda (jc-list) - (mapcar - #'(lambda (jc) (when jc (select-table-sql-expr jc))) - jc-list)) - immediate-join-classes) - sel-tables) - :test #'tables-equal))) - (order-by-slots (mapcar #'(lambda (ob) (if (atom ob) ob (car ob))) - (listify order-by))) - (join-where nil)) - - ;;(format t "sclasses: ~W~%ijc: ~W~%tables: ~W~%" sclasses immediate-join-classes tables) - - (dolist (ob order-by-slots) - (when (and ob (not (member ob (mapcar #'cdr fullsels) - :test #'ref-equal))) - (setq fullsels - (append fullsels (mapcar #'(lambda (att) (cons nil att)) - order-by-slots))))) - (dolist (ob (listify distinct)) - (when (and (typep ob 'sql-ident) - (not (member ob (mapcar #'cdr fullsels) - :test #'ref-equal))) - (setq fullsels - (append fullsels (mapcar #'(lambda (att) (cons nil att)) - (listify ob)))))) - (mapcar #'(lambda (vclass jclasses jslots) - (when jclasses - (mapcar - #'(lambda (jclass jslot) - (let ((dbi (view-class-slot-db-info jslot))) - (setq join-where - (append - (list (sql-operation '== - (sql-expression - :attribute (gethash :foreign-key dbi) - :table (view-table jclass)) - (sql-expression - :attribute (gethash :home-key dbi) - :table (view-table vclass)))) - (when join-where (listify join-where)))))) - jclasses jslots))) - sclasses immediate-join-classes immediate-join-slots) - ;; Reported buggy on clsql-devel - ;; (when where (setq where (listify where))) - (cond - ((and where join-where) - (setq where (list (apply #'sql-and where join-where)))) - ((and (null where) (> (length join-where) 1)) - (setq where (list (apply #'sql-and join-where))))) - - (let* ((rows (apply #'select - (append (mapcar #'cdr fullsels) - (cons :from - (list (append (when from (listify from)) - (listify tables)))) - (list :result-types result-types) - (when where - (list :where where)) - args))) - (instances-to-add (- (length rows) (length instances))) - (perhaps-extended-instances - (if (plusp instances-to-add) - (append instances (do ((i 0 (1+ i)) - (res nil)) - ((= i instances-to-add) res) - (push (make-list (length sclasses) :initial-element nil) res))) - instances)) - (objects (mapcar - #'(lambda (row instance) - (build-objects row sclasses immediate-join-classes sels - immediate-join-sels database refresh flatp - (if (and flatp (atom instance)) - (list instance) - instance))) - rows perhaps-extended-instances))) - objects)))) + (sql-output ref2 database)))) + (declare (dynamic-extent (function ref-equal))) + (let ((args (filter-plist args :from :where :flatp :additional-fields :result-types :instances))) + (let* ((*db-deserializing* t) + (sclasses (mapcar #'find-class view-classes)) + (immediate-join-slots + (mapcar #'(lambda (c) (generate-retrieval-joins-list c :immediate)) sclasses)) + (immediate-join-classes + (mapcar #'(lambda (jcs) + (mapcar #'(lambda (slotdef) + (find-class (gethash :join-class (view-class-slot-db-info slotdef)))) + jcs)) + immediate-join-slots)) + (immediate-join-sels (mapcar #'generate-immediate-joins-selection-list sclasses)) + (sels (mapcar #'generate-selection-list sclasses)) + (fullsels (apply #'append (mapcar #'append sels immediate-join-sels))) + (sel-tables (collect-table-refs where)) + (tables (remove-if #'null + (remove-duplicates + (append (mapcar #'select-table-sql-expr sclasses) + (mapcan #'(lambda (jc-list) + (mapcar + #'(lambda (jc) (when jc (select-table-sql-expr jc))) + jc-list)) + immediate-join-classes) + sel-tables) + :test #'database-identifier-equal))) + (order-by-slots (mapcar #'(lambda (ob) (if (atom ob) ob (car ob))) + (listify order-by))) + (join-where nil)) + + ;;(format t "sclasses: ~W~%ijc: ~W~%tables: ~W~%" sclasses immediate-join-classes tables) + + (dolist (ob order-by-slots) + (when (and ob (not (member ob (mapcar #'cdr fullsels) + :test #'ref-equal))) + (setq fullsels + (append fullsels (mapcar #'(lambda (att) (cons nil att)) + order-by-slots))))) + (dolist (ob (listify distinct)) + (when (and (typep ob 'sql-ident) + (not (member ob (mapcar #'cdr fullsels) + :test #'ref-equal))) + (setq fullsels + (append fullsels (mapcar #'(lambda (att) (cons nil att)) + (listify ob)))))) + (mapcar #'(lambda (vclass jclasses jslots) + (when jclasses + (mapcar + #'(lambda (jclass jslot) + (let ((dbi (view-class-slot-db-info jslot))) + (setq join-where + (append + (list (sql-operation '== + (sql-expression + :attribute (gethash :foreign-key dbi) + :table (view-table jclass)) + (sql-expression + :attribute (gethash :home-key dbi) + :table (view-table vclass)))) + (when join-where (listify join-where)))))) + jclasses jslots))) + sclasses immediate-join-classes immediate-join-slots) + ;; Reported buggy on clsql-devel + ;; (when where (setq where (listify where))) + (cond + ((and where join-where) + (setq where (list (apply #'sql-and where join-where)))) + ((and (null where) (> (length join-where) 1)) + (setq where (list (apply #'sql-and join-where))))) + + (let* ((rows (apply #'select + (append (mapcar #'cdr fullsels) + (cons :from + (list (append (when from (listify from)) + (listify tables)))) + (list :result-types result-types) + (when where + (list :where where)) + args))) + (instances-to-add (- (length rows) (length instances))) + (perhaps-extended-instances + (if (plusp instances-to-add) + (append instances (do ((i 0 (1+ i)) + (res nil)) + ((= i instances-to-add) res) + (push (make-list (length sclasses) :initial-element nil) res))) + instances)) + (objects (mapcar + #'(lambda (row instance) + (build-objects row sclasses immediate-join-classes sels + immediate-join-sels database refresh flatp + (if (and flatp (atom instance)) + (list instance) + instance))) + rows perhaps-extended-instances))) + objects))))) (defmethod instance-refreshed ((instance standard-db-object))) @@ -1248,32 +1241,29 @@ default value of nil which means that the results are returned as a list of lists. If FLATP is t and only one result is returned for each record selected in the query, the results are returned as elements of a list." + (multiple-value-bind (target-args qualifier-args) + (query-get-selections select-all-args) + (unless (or *default-database* (getf qualifier-args :database)) + (signal-no-database-error nil)) - (flet ((select-objects (target-args) - (and target-args - (every #'(lambda (arg) - (and (symbolp arg) - (find-class arg nil))) - target-args)))) - (multiple-value-bind (target-args qualifier-args) - (query-get-selections select-all-args) - (unless (or *default-database* (getf qualifier-args :database)) - (signal-no-database-error nil)) + (let ((caching (getf qualifier-args :caching *default-caching*)) + (result-types (getf qualifier-args :result-types :auto)) + (refresh (getf qualifier-args :refresh nil)) + (database (getf qualifier-args :database *default-database*))) (cond - ((select-objects target-args) - (let ((caching (getf qualifier-args :caching *default-caching*)) - (result-types (getf qualifier-args :result-types :auto)) - (refresh (getf qualifier-args :refresh nil)) - (database (or (getf qualifier-args :database) *default-database*)) - (order-by (getf qualifier-args :order-by))) - (remf qualifier-args :caching) - (remf qualifier-args :refresh) - (remf qualifier-args :result-types) - - ;; Add explicity table name to order-by if not specified and only - ;; one selected table. This is required so FIND-ALL won't duplicate - ;; the field + ((and target-args + (every #'(lambda (arg) + (and (symbolp arg) + (find-class arg nil))) + target-args)) + + (setf qualifier-args (filter-plist qualifier-args :caching :refresh :result-types)) + + ;; Add explicity table name to order-by if not specified and only + ;; one selected table. This is required so FIND-ALL won't duplicate + ;; the field + (let ((order-by (getf qualifier-args :order-by))) (when (and order-by (= 1 (length target-args))) (let ((table-name (view-table (find-class (car target-args)))) (order-by-list (copy-seq (listify order-by)))) @@ -1290,55 +1280,47 @@ as elements of a list." (loop for i from 0 below (length order-by-list) for id = (nth i order-by-list) do (set-table-if-needed id))) - (setf (getf qualifier-args :order-by) order-by-list))) - - (cond - ((null caching) - (apply #'find-all target-args - (append qualifier-args - (list :result-types result-types :refresh refresh)))) - (t - (let ((cached (records-cache-results target-args qualifier-args database))) - (cond - ((and cached (not refresh)) - cached) - ((and cached refresh) - (let ((results (apply #'find-all (append (list target-args) qualifier-args `(:instances ,cached :result-types :auto :refresh ,refresh))))) - (setf (records-cache-results target-args qualifier-args database) results) - results)) - (t - (let ((results (apply #'find-all target-args (append qualifier-args - `(:result-types :auto :refresh ,refresh))))) - (setf (records-cache-results target-args qualifier-args database) results) - results)))))))) + (setf (getf qualifier-args :order-by) order-by-list)))) + + (cond + ((null caching) + (apply #'find-all target-args :result-types result-types :refresh refresh qualifier-args)) + (t + (let ((cached (records-cache-results target-args qualifier-args database))) + (if (and cached (not refresh)) + cached + (let ((results (apply #'find-all target-args + :result-types :auto :refresh refresh + :instances cached + qualifier-args))) + (setf (records-cache-results target-args qualifier-args database) results) + + results)))))) (t (let* ((expr (apply #'make-query select-all-args)) (parameters (second (member :parameters 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 - (when parameters - (setf expr (command-object (sql-output expr database) parameters))) - (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)))))))) + (mapcar #'(lambda (attrib) + (if (typep attrib 'sql-ident-attribute) + (let ((type (slot-value attrib 'type))) + (if type + type + t)) + t)) + (slot-value expr 'selections))) + (flatp (getf qualifier-args :flatp)) + (field-names (getf qualifier-args :field-names t))) + + (when parameters + (setf expr (command-object (sql-output expr database) parameters))) + (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))))))) (defun compute-records-cache-key (targets qualifiers) (list targets @@ -1362,11 +1344,8 @@ as elements of a list." (defun (setf records-cache-results) (results targets qualifiers database) (unless (record-caches database) (setf (record-caches database) - (make-hash-table :test 'equal - #+allegro :values #+allegro :weak - #+clisp :weak #+clisp :value - #+lispworks :weak-kind #+lispworks :value))) - (setf (gethash (compute-records-cache-key targets qualifiers) + (make-weak-hash-table :test 'equal))) + (setf (gethash (compute-records-cache-key (copy-list targets) qualifiers) (record-caches database)) results) results)