Add support for :default in db constraints. make-constraint-description: use next...
[clsql.git] / tests / test-oodml.lisp
1 ;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
2 ;;;; ======================================================================
3 ;;;; File:    test-oodml.lisp
4 ;;;; Created: 01/04/2004
5 ;;;;
6 ;;;; Tests for the CLSQL Object Oriented Data Definition Language
7 ;;;; (OODML).
8 ;;;;
9 ;;;; This file is part of CLSQL.
10 ;;;;
11 ;;;; CLSQL users are granted the rights to distribute and use this software
12 ;;;; as governed by the terms of the Lisp Lesser GNU Public License
13 ;;;; (http://opensource.franz.com/preamble.html), also known as the LLGPL.
14 ;;;; ======================================================================
15
16 (in-package #:clsql-tests)
17
18 #.(clsql:locally-enable-sql-reader-syntax)
19
20 (setq *rt-oodml*
21       '(
22
23 (deftest :oodml/select/1
24     (with-dataset *ds-employees*
25       (mapcar #'(lambda (e) (slot-value e 'last-name))
26               (clsql:select 'employee :order-by [last-name] :flatp t :caching nil)))
27   ("Andropov" "Brezhnev" "Chernenko" "Gorbachev" "Kruschev" "Lenin" "Putin"
28               "Stalin" "Trotsky" "Yeltsin"))
29
30 (deftest :oodml/select/2
31     (with-dataset *ds-employees*
32       (mapcar #'(lambda (e) (slot-value e 'name))
33               (clsql:select 'company :flatp t :caching nil)))
34   ("Widgets Inc."))
35
36 (deftest :oodml/select/3
37     (with-dataset *ds-employees*
38       (mapcar #'(lambda (e) (slot-value e 'ecompanyid))
39               (clsql:select 'employee
40                             :where [and [= [slot-value 'employee 'ecompanyid]
41                                            [slot-value 'company 'companyid]]
42                                         [= [slot-value 'company 'name]
43                                            "Widgets Inc."]]
44                             :flatp t
45                             :caching nil)))
46   (1 1 1 1 1 1 1 1 1 1))
47
48 (deftest :oodml/select/4
49     (with-dataset *ds-employees*
50       (mapcar #'(lambda (e)
51                   (concatenate 'string (slot-value e 'first-name)
52                                " "
53                                (slot-value e 'last-name)))
54               (clsql:select 'employee :where [= [slot-value 'employee 'first-name]
55                                                 "Vladimir"]
56                             :flatp t
57                             :order-by [last-name]
58                             :caching nil)))
59   ("Vladimir Lenin" "Vladimir Putin"))
60
61 (deftest :oodml/select/5
62     (with-dataset *ds-employees*
63       (length (clsql:select 'employee :where [married] :flatp t :caching nil)))
64   3)
65
66 (deftest :oodml/select/6
67     (with-dataset *ds-employees*
68       (let ((a (caar (clsql:select 'address :where [= 1 [addressid]] :caching nil))))
69         (values
70           (slot-value a 'street-number)
71           (slot-value a 'street-name)
72           (slot-value a 'city)
73           (slot-value a 'postal-code))))
74   10 "Park Place" "Leningrad" 123)
75
76 (deftest :oodml/select/7
77     (with-dataset *ds-employees*
78       (let ((a (caar (clsql:select 'address :where [= 2 [addressid]] :caching nil))))
79         (values
80           (slot-value a 'street-number)
81           (slot-value a 'street-name)
82           (slot-value a 'city)
83           (slot-value a 'postal-code))))
84   nil "" "no city" 0)
85
86 (deftest :oodml/select/8
87     (with-dataset *ds-employees*
88       (mapcar #'(lambda (e) (slot-value e 'married))
89               (clsql:select 'employee :flatp t :order-by [emplid] :caching nil)))
90   (t t t nil nil nil nil nil nil nil))
91
92 (deftest :oodml/select/9
93     (with-dataset *ds-employees*
94       (mapcar #'(lambda (pair)
95                   (list
96                    (typep (car pair) 'address)
97                    (typep (second pair) 'employee-address)
98                    (slot-value (car pair) 'addressid)
99                    (slot-value (second pair) 'aaddressid)
100                    (slot-value (second pair) 'aemplid)))
101               (employee-addresses employee1)))
102   ((t t 1 1 1) (t t 2 2 1)))
103
104 (deftest :oodml/select/10
105     (with-dataset *ds-employees*
106       (mapcar #'(lambda (pair)
107                   (list
108                    (typep (car pair) 'address)
109                    (typep (second pair) 'employee-address)
110                    (slot-value (car pair) 'addressid)
111                    (slot-value (second pair) 'aaddressid)
112                    (slot-value (second pair) 'aemplid)))
113               (employee-addresses employee2)))
114   ((t t 2 2 2)))
115
116 (deftest :oodml/select/11
117     (with-dataset *ds-employees*
118       (values (mapcar #'(lambda (x) (slot-value x 'emplid))
119                       (clsql:select 'employee :order-by '(([emplid] :asc))
120                                     :flatp t))
121               (mapcar #'(lambda (x) (slot-value x 'emplid))
122                       (clsql:select 'employee :order-by '(([emplid] :desc))
123                                     :flatp t))))
124   (1 2 3 4 5 6 7 8 9 10)
125   (10 9 8 7 6 5 4 3 2 1))
126
127 ;; test retrieval of node, derived nodes etc
128 (deftest :oodml/select/12
129     (with-dataset *ds-nodes*
130       (length (clsql:select 'node :where [node-id] :flatp t :caching nil)))
131   11)
132
133 (deftest :oodml/select/13
134     (with-dataset *ds-nodes*
135       (let ((a (car (clsql:select 'node :where [= 1 [node-id]] :flatp t :caching nil))))
136         (values
137           (slot-value a 'node-id)
138           (slot-value a 'title))))
139   1 "Bare node")
140
141 (deftest :oodml/select/14
142     (with-dataset *ds-nodes*
143       (length (clsql:select 'setting :where [setting-id] :flatp t :caching nil)))
144   4)
145
146 (deftest :oodml/select/15
147     (with-dataset *ds-nodes*
148       (let ((a (car (clsql:select 'setting :where [= 3 [setting-id]] :flatp t :caching nil))))
149         (values
150           (slot-value a 'node-id)
151           (slot-value a 'setting-id)
152           (slot-value a 'title)
153           (slot-value a 'vars))))
154   3 3 "Setting2" "var 2")
155
156 (deftest :oodml/select/16
157     (with-dataset *ds-nodes*
158       (length (clsql:select 'user :where [user-id] :flatp t :caching nil)))
159   2)
160
161 (deftest :oodml/select/17
162     (with-dataset *ds-nodes*
163       (let ((a (car (clsql:select 'user :where [= 4 [user-id]] :flatp t :caching nil))))
164         (values
165           (slot-value a 'node-id)
166           (slot-value a 'user-id)
167           (slot-value a 'title)
168           (slot-value a 'nick))))
169   4 4 "user-1" "first user")
170
171 (deftest :oodml/select/18
172     (with-dataset *ds-nodes*
173       (length (clsql:select 'theme :where [theme-id] :flatp t :caching nil)))
174   2)
175
176 (deftest :oodml/select/19
177     (with-dataset *ds-nodes*
178       (let ((a (car (clsql:select 'theme :where [= 6 [theme-id]] :flatp t :caching nil))))
179         (slot-value a 'theme-id)))
180   6)
181
182 (deftest :oodml/select/20
183     (with-dataset *ds-nodes*
184       (let ((a (car (clsql:select 'theme :where [= 7 [theme-id]] :flatp t :caching nil))))
185         (values
186           (slot-value a 'node-id)
187           (slot-value a 'theme-id)
188           (slot-value a 'title)
189           (slot-value a 'vars)
190           (slot-value a 'doc)
191           )))
192   7 7 "theme-2"
193   nil "second theme")
194
195 ;; Some tests to check weird subclassed nodes (node without own table, or subclassed of same)
196 (deftest :oodml/select/21
197     (with-dataset *ds-nodes*
198       (let ((a (car (clsql:select 'location :where [= [title] "location-1"] :flatp t :caching nil))))
199         (values
200           (slot-value a 'node-id)
201           (slot-value a 'title))))
202   8 "location-1")
203
204 (deftest :oodml/select/22
205     (with-dataset *ds-nodes*
206       (let ((a (car (clsql:select 'subloc :where [subloc-id] :flatp t :caching nil))))
207         (values
208           (slot-value a 'node-id)
209           (slot-value a 'subloc-id)
210           (slot-value a 'title)
211           (slot-value a 'loc))))
212   10 10 "subloc-1" "a subloc")
213
214 (deftest :oodml/select/23
215     (with-dataset *ds-artists*
216       (length (clsql:select 'artist :flatp t :caching nil)))
217   0)
218
219
220
221 ;; test retrieval is deferred
222 (deftest :oodm/retrieval/1
223     (with-dataset *ds-employees*
224       (every #'(lambda (e) (not (slot-boundp e 'company)))
225              (select 'employee :flatp t :caching nil)))
226   t)
227
228 (deftest :oodm/retrieval/2
229     (with-dataset *ds-employees*
230       (every #'(lambda (e) (not (slot-boundp e 'address)))
231              (select 'deferred-employee-address :flatp t :caching nil)))
232   t)
233
234 ;; :retrieval :immediate should be boundp before accessed
235 (deftest :oodm/retrieval/3
236     (with-dataset *ds-employees*
237       (every #'(lambda (ea) (slot-boundp ea 'address))
238              (select 'employee-address :flatp t :caching nil)))
239   t)
240
241 (deftest :oodm/retrieval/4
242     (with-dataset *ds-employees*
243       (mapcar #'(lambda (ea) (typep (slot-value ea 'address) 'address))
244               (select 'employee-address :flatp t :caching nil)))
245   (t t t t t))
246
247 (deftest :oodm/retrieval/5
248     (with-dataset *ds-employees*
249       (mapcar #'(lambda (ea) (typep (slot-value ea 'address) 'address))
250               (select 'deferred-employee-address :flatp t :caching nil)))
251   (t t t t t))
252
253 (deftest :oodm/retrieval/6
254     (with-dataset *ds-employees*
255       (every #'(lambda (ea) (slot-boundp (slot-value ea 'address) 'addressid))
256              (select 'employee-address :flatp t :caching nil)))
257   t)
258
259 (deftest :oodm/retrieval/7
260     (with-dataset *ds-employees*
261       (every #'(lambda (ea) (slot-boundp (slot-value ea 'address) 'addressid))
262              (select 'deferred-employee-address :flatp t :caching nil)))
263   t)
264
265 (deftest :oodm/retrieval/8
266     (with-dataset *ds-employees*
267       (mapcar #'(lambda (ea) (slot-value (slot-value ea 'address) 'street-number))
268               (select 'employee-address :flatp t :order-by [aaddressid] :caching nil)))
269   (10 10 nil nil nil))
270
271 (deftest :oodm/retrieval/9
272     (with-dataset *ds-employees*
273       (mapcar #'(lambda (ea) (slot-value (slot-value ea 'address) 'street-number))
274               (select 'deferred-employee-address :flatp t :order-by [aaddressid] :caching nil)))
275   (10 10 nil nil nil))
276
277 ;; tests update-records-from-instance
278 (deftest :oodml/update-records/1
279     (with-dataset *ds-employees*
280       (values
281         (progn
282           (let ((lenin (car (clsql:select 'employee
283                                           :where [= 1 [slot-value 'employee 'emplid]]
284                                           :flatp t
285                                           :caching nil))))
286             (format nil "~a ~a: ~a"
287                 (first-name lenin)
288                 (last-name lenin)
289                 (employee-email lenin))))
290         (progn
291           (setf (slot-value employee1 'first-name) "Dimitriy"
292                 (slot-value employee1 'last-name) "Ivanovich"
293                 (slot-value employee1 'email) "ivanovich@soviet.org")
294           (clsql:update-records-from-instance employee1)
295           (let ((lenin (car (clsql:select 'employee
296                                           :where [= 1 [slot-value 'employee 'emplid]]
297                                           :flatp t
298                                           :caching nil))))
299             (format nil "~a ~a: ~a"
300                 (first-name lenin)
301                 (last-name lenin)
302                 (employee-email lenin))))))
303   "Vladimir Lenin: lenin@soviet.org"
304   "Dimitriy Ivanovich: ivanovich@soviet.org")
305
306 ;; tests update-record-from-slot
307 (deftest :oodml/update-records/2
308     (with-dataset *ds-employees*
309       ;(start-sql-recording :type :both)
310       (values
311         (employee-email
312          (car (clsql:select 'employee
313                             :where [= 1 [slot-value 'employee 'emplid]]
314                             :flatp t
315                             :caching nil)))
316         (progn
317           (setf (slot-value employee1 'email) "lenin-nospam@soviet.org")
318           (clsql:update-record-from-slot employee1 'email)
319           (employee-email
320            (car (clsql:select 'employee
321                               :where [= 1 [slot-value 'employee 'emplid]]
322                               :flatp t
323                               :caching nil))))))
324   "lenin@soviet.org" "lenin-nospam@soviet.org")
325
326 ;; tests update-record-from-slots
327 (deftest :oodml/update-records/3
328     (with-dataset *ds-employees*
329       (values
330         (let ((lenin (car (clsql:select 'employee
331                                         :where [= 1 [slot-value 'employee 'emplid]]
332                                         :flatp t
333                                         :caching nil))))
334           (format nil "~a ~a: ~a"
335                   (first-name lenin)
336                   (last-name lenin)
337                   (employee-email lenin)))
338         (progn
339           (setf (slot-value employee1 'first-name) "Dimitriy"
340                 (slot-value employee1 'last-name) "Ivanovich"
341                 (slot-value employee1 'email) "ivanovich@soviet.org")
342           (clsql:update-record-from-slots employee1 '(first-name last-name email))
343           (let ((lenin (car (clsql:select 'employee
344                                           :where [= 1 [slot-value 'employee 'emplid]]
345                                           :flatp t
346                                           :caching nil))))
347             (format nil "~a ~a: ~a"
348                     (first-name lenin)
349                     (last-name lenin)
350                     (employee-email lenin))))))
351   "Vladimir Lenin: lenin@soviet.org"
352   "Dimitriy Ivanovich: ivanovich@soviet.org")
353
354 (deftest :oodml/update-records/4
355     (with-dataset *ds-nodes*
356       (flet ((print-fresh-node ()
357                (let ((base (car (clsql:select 'node
358                                               :where [= 1 [slot-value 'node 'node-id]]
359                                               :flatp t :caching nil))))
360                  (format nil "~a ~a"
361                          (slot-value base 'node-id)
362                          (slot-value base 'title)))))
363         (values
364           (print-fresh-node)
365           (let ((base (car (clsql:select 'node
366                                          :where [= 1 [slot-value 'node 'node-id]]
367                                          :flatp t :caching nil))))
368             (setf (slot-value base 'title) "Altered title")
369             (clsql:update-records-from-instance base)
370             (print-fresh-node)))))
371   "1 Bare node"
372   "1 Altered title")
373
374 (deftest :oodml/update-records/4-slots ;just like 4, but use slots fns.
375     (with-dataset *ds-nodes*
376       (flet ((print-fresh-setting ()
377                (let ((node (car (clsql:select 'setting
378                                               :where [= 3 [slot-value 'setting 'setting-id]]
379                                               :flatp t :caching nil))))
380                  (format nil "~a ~a ~a"
381                          (slot-value node 'setting-id)
382                          (slot-value node 'title)
383                          (slot-value node 'vars)))))
384         (values
385           (print-fresh-setting)
386           (let ((node (car (clsql:select 'setting
387                                          :where [= 3 [slot-value 'setting 'setting-id]]
388                                          :flatp t :caching nil))))
389             (setf (slot-value node 'title) "Altered title")
390             (setf (slot-value node 'vars) "Altered vars")
391             (clsql-sys:update-record-from-slot node 'title)
392             (clsql-sys:update-record-from-slot node 'vars)
393             (print-fresh-setting))
394           (let ((node (car (clsql:select 'setting
395                                          :where [= 3 [slot-value 'setting 'setting-id]]
396                                          :flatp t :caching nil))))
397             (setf (slot-value node 'title) "Setting2")
398             (setf (slot-value node 'vars) "var 2")
399             (clsql:update-records-from-instance node)
400             (clsql-sys:update-record-from-slots node '(vars title))
401             (print-fresh-setting)))))
402   "3 Setting2 var 2"
403   "3 Altered title Altered vars"
404   "3 Setting2 var 2")
405
406 (deftest :oodml/update-records/5
407     (with-dataset *ds-nodes*
408       (flet ((print-fresh-setting ()
409                (let ((node (car (clsql:select 'setting
410                                               :where [= 3 [slot-value 'setting 'setting-id]]
411                                               :flatp t :caching nil))))
412                  (format nil "~a ~a ~a"
413                          (slot-value node 'setting-id)
414                          (slot-value node 'title)
415                          (slot-value node 'vars)))))
416         (values
417           (print-fresh-setting)
418           (let ((node (car (clsql:select 'setting
419                                          :where [= 3 [slot-value 'setting 'setting-id]]
420                                          :flatp t :caching nil))))
421             (setf (slot-value node 'title) "Altered title")
422             (setf (slot-value node 'vars) "Altered vars")
423             (clsql:update-records-from-instance node)
424             (print-fresh-setting)))))
425   "3 Setting2 var 2"
426   "3 Altered title Altered vars")
427
428 (deftest :oodml/update-records/5-slots
429     (with-dataset *ds-nodes*
430       (flet ((print-fresh-setting ()
431                (let ((node (car (clsql:select 'setting
432                                               :where [= 3 [slot-value 'setting 'setting-id]]
433                                               :flatp t :caching nil))))
434                  (format nil "~a ~a ~a"
435                          (slot-value node 'setting-id)
436                          (slot-value node 'title)
437                          (slot-value node 'vars)))))
438         (values
439           (print-fresh-setting)
440           (let ((node (car (clsql:select 'setting
441                                          :where [= 3 [slot-value 'setting 'setting-id]]
442                                          :flatp t :caching nil))))
443             (setf (slot-value node 'title) "Altered title")
444             (setf (slot-value node 'vars) "Altered vars")
445             (clsql-sys:update-record-from-slot node 'title)
446             (clsql-sys:update-record-from-slot node 'vars)
447             (print-fresh-setting))
448           (let ((node (car (clsql:select 'setting
449                                          :where [= 3 [slot-value 'setting 'setting-id]]
450                                          :flatp t :caching nil))))
451             (setf (slot-value node 'title) "Setting2")
452             (setf (slot-value node 'vars) "var 2")
453             (clsql-sys:update-record-from-slots node '(title vars))
454             (print-fresh-setting)))))
455   "3 Setting2 var 2"
456   "3 Altered title Altered vars"
457   "3 Setting2 var 2")
458
459 (deftest :oodml/update-records/6
460     (with-dataset *ds-nodes*
461       (flet ((print-fresh-setting ()
462                (let ((node (car (clsql:select 'setting
463                                               :where [= 7 [slot-value 'setting 'setting-id]]
464                                               :flatp t :caching nil))))
465                  (format nil "~a ~a ~a"
466                          (slot-value node 'setting-id)
467                          (slot-value node 'title)
468                          (or (slot-value node 'vars) "NIL")))))
469         (values
470           (print-fresh-setting)
471           (let ((node (car (clsql:select 'setting
472                                          :where [= 7 [slot-value 'setting 'setting-id]]
473                                          :flatp t :caching nil))))
474             (setf (slot-value node 'title) "Altered title")
475             (setf (slot-value node 'vars) "Altered vars")
476             (clsql:update-records-from-instance node)
477             (print-fresh-setting))
478           (let ((node (car (clsql:select 'setting
479                                          :where [= 7 [slot-value 'setting 'setting-id]]
480                                          :flatp t :caching nil))))
481             (setf (slot-value node 'title) "theme-2")
482             (setf (slot-value node 'vars) nil)
483             (clsql:update-records-from-instance node)
484             (print-fresh-setting)))))
485   "7 theme-2 NIL"
486   "7 Altered title Altered vars"
487   "7 theme-2 NIL")
488
489 (deftest :oodml/update-records/7
490     (with-dataset *ds-nodes*
491       (flet ((print-fresh-user ()
492                "requery to get what the db has, and print out."
493                (let ((node (car (clsql:select 'user
494                                               :where [= 5 [slot-value 'user 'user-id]]
495                                               :flatp t :caching nil))))
496                  (format nil "~a ~a ~a"
497                          (slot-value node 'user-id)
498                          (slot-value node 'title)
499                          (slot-value node 'nick)))))
500         (values
501           (print-fresh-user)
502           (let ((node (car (clsql:select 'user
503                                          :where [= 5 [slot-value 'user 'user-id]]
504                                          :flatp t :caching nil))))
505             (setf (slot-value node 'title) "Altered title")
506             (setf (slot-value node 'nick) "Altered nick")
507             (clsql:update-records-from-instance node)
508             (print-fresh-user)))))
509   "5 user-2 second user"
510   "5 Altered title Altered nick")
511
512 (deftest :oodml/update-records/8
513     (with-dataset *ds-nodes*
514       (flet ((print-fresh-theme ()
515                (let ((node (car (clsql:select 'theme
516                                               :where [= 6 [slot-value 'theme 'theme-id]]
517                                               :flatp t :caching nil))))
518                  (with-slots (node-id setting-id theme-id title vars doc) node
519                    (format nil "~a ~a ~a ~a ~a ~a"
520                            node-id setting-id theme-id
521                            title (or vars "NIL") doc)))))
522         (values
523           (print-fresh-theme)
524           (let ((node (car (clsql:select 'setting
525                                          :where [= 6 [slot-value 'setting 'setting-id]]
526                                          :flatp t :caching nil))))
527             (setf (slot-value node 'title) "Altered title")
528             (setf (slot-value node 'vars) nil)
529             (clsql:update-records-from-instance node)
530             (print-fresh-theme))
531           (let ((node (car (clsql:select 'theme
532                                          :where [= 6 [slot-value 'theme 'theme-id]]
533                                          :flatp t :caching nil))))
534             (setf (slot-value node 'title) "Altered title again")
535             (setf (slot-value node 'doc) "altered doc")
536             (clsql:update-records-from-instance node)
537             (print-fresh-theme))
538           (let ((node (car (clsql:select 'theme
539                                          :where [= 6 [slot-value 'theme 'theme-id]]
540                                          :flatp t :caching nil))))
541             (setf (slot-value node 'title) "theme-1")
542             (setf (slot-value node 'vars) "empty")
543             (setf (slot-value node 'doc) "first theme")
544             (clsql:update-records-from-instance node)
545             (print-fresh-theme)))))
546   "6 6 6 theme-1 empty first theme"
547   "6 6 6 Altered title NIL first theme"
548   "6 6 6 Altered title again NIL altered doc"
549   "6 6 6 theme-1 empty first theme")
550
551 (deftest :oodml/update-records/9
552     (with-dataset *ds-nodes*
553       (flet ((print-fresh-subloc ()
554                (let ((sl (car (clsql:select 'subloc
555                                             :where [= 10 [slot-value 'subloc 'subloc-id]]
556                                             :flatp t :caching nil))))
557                  (format nil "~a ~a ~a"
558                          (slot-value sl 'subloc-id)
559                          (slot-value sl 'title)
560                          (slot-value sl 'loc)))))
561         (values
562           (print-fresh-subloc)
563           (let ((sl (car (clsql:select 'subloc
564                                        :where [= 10 [slot-value 'subloc 'subloc-id]]
565                                        :flatp t :caching nil))))
566             (setf (slot-value sl 'title) "Altered subloc title")
567             (setf (slot-value sl 'loc) "Altered loc")
568             (clsql:update-records-from-instance sl)
569             (print-fresh-subloc)))))
570   "10 subloc-1 a subloc"
571   "10 Altered subloc title Altered loc")
572
573 (deftest :oodml/update-records/9-slots ;like 9, but use slots fns.
574     (with-dataset *ds-nodes*
575       (flet ((print-fresh-subloc ()
576                (let ((sl (car (clsql:select 'subloc
577                                             :where [= 10 [slot-value 'subloc 'subloc-id]]
578                                             :flatp t :caching nil))))
579                  (format nil "~a ~a ~a"
580                          (slot-value sl 'subloc-id)
581                          (slot-value sl 'title)
582                          (slot-value sl 'loc)))))
583         (values
584           (print-fresh-subloc)
585           (let ((sl (car (clsql:select 'subloc
586                                        :where [= 10 [slot-value 'subloc 'subloc-id]]
587                                        :flatp t :caching nil))))
588             (setf (slot-value sl 'title) "Altered subloc title")
589             (setf (slot-value sl 'loc) "Altered loc")
590             (clsql:update-record-from-slot sl 'title)
591             (clsql:update-record-from-slot sl 'loc)
592             (print-fresh-subloc))
593           (let ((sl (car (clsql:select 'subloc
594                                        :where [= 10 [slot-value 'subloc 'subloc-id]]
595                                        :flatp t :caching nil))))
596             (setf (slot-value sl 'title) "subloc-1")
597             (setf (slot-value sl 'loc) "a subloc")
598             (clsql:update-record-from-slots sl '(title loc))
599             (print-fresh-subloc)))))
600   "10 subloc-1 a subloc"
601   "10 Altered subloc title Altered loc"
602   "10 subloc-1 a subloc")
603
604 ;; Verify that we can set a float to nil and then read it back
605 ;; (was failing in Postgresql at somepoint)
606 (deftest :oodml/update-records/10
607     (with-dataset *ds-employees*
608       (let ((emp (first (clsql:select 'employee :where [= [emplid] 1] :flatp t))))
609         (setf (height emp) nil)
610         (clsql-sys:update-record-from-slot emp 'height)
611         (values
612           (clsql:select [height] :from [employee] :where [= [emplid] 1])
613           (progn
614             (setf (height emp) 42.0)
615             (clsql-sys:update-record-from-slot emp 'height)
616             (clsql:select [height] :from [employee] :where [= [emplid] 1]))
617           (progn
618             (setf (height emp) 24.13d0)
619             (clsql-sys:update-record-from-slot emp 'height)
620             (clsql:select [height] :from [employee] :where [= [emplid] 1])))))
621   ((nil))
622   ((42.0d0))
623   ((24.13d0)))
624
625 (deftest :oodml/update-records/11
626     (with-dataset *ds-artists*
627       (clsql:update-records-from-instance artist1)
628       (list (name artist1) (artist_id artist1)))
629   ("Mogwai" 1))
630
631 (deftest :oodml/update-records/12
632     (with-dataset *ds-artists*
633       (clsql:update-records-from-instance artist1)
634       (list (name artist1) (genre artist1)))
635   ("Mogwai" "Unknown"))
636
637 ;; tests update-instance-from-records
638 (deftest :oodml/update-instance/1
639     (with-dataset *ds-employees*
640       (values
641         (format nil "~a ~a: ~a"
642                 (slot-value employee1 'first-name)
643                 (slot-value employee1 'last-name)
644                 (slot-value employee1 'email))
645         (progn
646           (clsql:update-records [employee]
647                                 :av-pairs '(([first-name] "Ivan")
648                                             ([last-name] "Petrov")
649                                             ([email] "petrov@soviet.org"))
650                                 :where [= [emplid] 1])
651           (clsql:update-instance-from-records employee1)
652           (format nil "~a ~a: ~a"
653                 (slot-value employee1 'first-name)
654                 (slot-value employee1 'last-name)
655                 (slot-value employee1 'email)))))
656   "Vladimir Lenin: lenin@soviet.org"
657   "Ivan Petrov: petrov@soviet.org")
658
659 ;; tests update-slot-from-record
660 (deftest :oodml/update-instance/2
661     (with-dataset *ds-employees*
662       (values
663         (slot-value employee1 'email)
664         (progn
665           (clsql:update-records [employee]
666                                 :av-pairs '(([email] "lenin-nospam@soviet.org"))
667                                 :where [= [emplid] 1])
668           (clsql:update-slot-from-record employee1 'email)
669           (slot-value employee1 'email))))
670   "lenin@soviet.org" "lenin-nospam@soviet.org")
671
672 ;; tests normalizedp update-instance-from-records
673 (deftest :oodml/update-instance/3
674     (with-dataset *ds-nodes*
675       (values
676         (with-output-to-string (out)
677           (format out "~a ~a ~a ~a"
678                   (slot-value theme2 'theme-id)
679                   (slot-value theme2 'title)
680                   (or (slot-value theme2 'vars) "NIL")
681                   (slot-value theme2 'doc)))
682         (progn
683           (clsql:update-records [node] :av-pairs '(([title] "Altered title"))
684                                 :where [= [node-id] 7])
685           (clsql:update-records [setting] :av-pairs '(([vars] "Altered vars"))
686                                 :where [= [setting-id] 7])
687           (clsql:update-records [theme] :av-pairs '(([doc] "Altered doc"))
688                                 :where [= [theme-id] 7])
689           (clsql:update-instance-from-records theme2)
690           (with-output-to-string (out)
691             (format out "~a ~a ~a ~a"
692                     (slot-value theme2 'theme-id)
693                     (slot-value theme2 'title)
694                     (slot-value theme2 'vars)
695                     (slot-value theme2 'doc))))))
696   "7 theme-2 NIL second theme"
697   "7 Altered title Altered vars Altered doc")
698
699 (deftest :oodml/update-instance/4
700     (with-dataset *ds-nodes*
701       (values
702         (progn
703           (setf loc2 (car (clsql:select 'location
704                                         :where [= [node-id] 9]
705                                         :flatp t :caching nil)))
706           (format nil "~a ~a"
707                   (slot-value loc2 'node-id)
708                   (slot-value loc2 'title)))
709         (progn
710           (clsql:update-records [node] :av-pairs '(([title] "Altered title"))
711                                 :where [= [node-id] 9])
712           (clsql:update-instance-from-records loc2)
713           (format nil "~a ~a"
714                   (slot-value loc2 'node-id)
715                   (slot-value loc2 'title)))))
716   "9 location-2"
717   "9 Altered title")
718
719 (deftest :oodml/update-instance/5
720     (with-dataset *ds-nodes*
721       (values
722         (format nil "~a ~a ~a"
723                 (slot-value subloc2 'subloc-id)
724                 (slot-value subloc2 'title)
725                 (slot-value subloc2 'loc))
726         (progn
727           (clsql:update-records [node] :av-pairs '(([title] "Altered title"))
728                                 :where [= [node-id] 11])
729           (clsql:update-records [subloc] :av-pairs '(([loc] "Altered loc"))
730                                 :where [= [subloc-id] 11])
731           (clsql:update-instance-from-records subloc2)
732           (format nil "~a ~a ~a"
733                   (slot-value subloc2 'subloc-id)
734                   (slot-value subloc2 'title)
735                   (slot-value subloc2 'loc)))))
736   "11 subloc-2 second subloc"
737   "11 Altered title Altered loc")
738
739 ;; tests update-slot-from-record with normalizedp stuff
740 (deftest :oodml/update-instance/6
741     (with-dataset *ds-nodes*
742       (values
743         (slot-value theme1 'doc)
744         (slot-value theme1 'vars)
745         (progn
746           (clsql:update-records [theme]
747                                 :av-pairs '(([doc] "altered doc"))
748                                 :where [= [theme-id] 6])
749           (clsql:update-slot-from-record theme1 'doc)
750           (slot-value theme1 'doc))
751         (progn
752           (clsql:update-records [setting]
753                                 :av-pairs '(([vars] "altered vars"))
754                                 :where [= [setting-id] 6])
755           (clsql:update-slot-from-record theme1 'vars)
756           (slot-value theme1 'vars))))
757   "first theme" "empty"
758   "altered doc" "altered vars")
759
760 (deftest :oodml/update-instance/7
761     (flet ((print-loc (l)
762              (format nil "~a: ~a"
763                      (slot-value l 'node-id) (slot-value l 'title)))
764            (print-subloc (sl)
765              (format nil "~a: ~a"
766                      (slot-value sl 'node-id) (slot-value sl 'loc))))
767       (with-dataset *ds-nodes*
768         (values
769           (print-loc loc2)
770           (print-subloc subloc2)
771           (progn
772             (clsql:update-records [node]
773                                   :av-pairs '(([title] "altered title"))
774                                   :where [= [node-id] 9])
775             (clsql:update-slot-from-record loc2 'title)
776             (print-loc loc2))
777           (progn
778             (clsql:update-records [subloc]
779                                   :av-pairs '(([loc] "altered loc"))
780                                   :where [= [subloc-id] 11])
781             (clsql:update-slot-from-record subloc2 'loc)
782             (print-subloc subloc2)))))
783   "9: location-2" "11: second subloc"
784   "9: altered title" "11: altered loc")
785
786 (deftest :oodml/do-query/1
787     (with-dataset *ds-employees*
788       (let ((result '()))
789         (clsql:do-query ((e) [select 'employee :order-by [emplid]])
790           (push (slot-value e 'last-name) result))
791         result))
792   ("Putin" "Yeltsin" "Gorbachev" "Chernenko" "Andropov" "Brezhnev" "Kruschev"
793            "Trotsky" "Stalin" "Lenin"))
794
795 (deftest :oodml/do-query/2
796     (with-dataset *ds-employees*
797       (let ((result '()))
798         (clsql:do-query ((e c) [select 'employee 'company
799                                        :where [= [slot-value 'employee 'last-name]
800                                                  "Lenin"]])
801           (push (list (slot-value e 'last-name) (slot-value c 'name))
802                 result))
803         result))
804   (("Lenin" "Widgets Inc.")))
805
806 (deftest :oodml/map-query/1
807     (with-dataset *ds-employees*
808       (clsql:map-query 'list #'last-name [select 'employee :order-by [emplid]]))
809   ("Lenin" "Stalin" "Trotsky" "Kruschev" "Brezhnev" "Andropov" "Chernenko"
810            "Gorbachev" "Yeltsin" "Putin"))
811
812 (deftest :oodml/map-query/2
813     (with-dataset *ds-employees*
814       (clsql:map-query 'list #'(lambda (e c) (list (slot-value e 'last-name)
815                                                    (slot-value c 'name)))
816                        [select 'employee 'company :where [= [slot-value 'employee 'last-name]
817                                                             "Lenin"]]))
818   (("Lenin" "Widgets Inc.")))
819
820 (deftest :oodml/iteration/3
821     (with-dataset *ds-employees*
822       (loop for (e) being the records in
823             [select 'employee :where [< [emplid] 4] :order-by [emplid]]
824             collect (slot-value e 'last-name)))
825   ("Lenin" "Stalin" "Trotsky"))
826
827
828 (deftest :oodml/cache/1
829     (with-dataset *ds-employees*
830       (progn
831         (setf (clsql-sys:record-caches *default-database*) nil)
832         (let ((employees (select 'employee)))
833           (every #'(lambda (a b) (eq a b))
834                  employees (select 'employee)))))
835   t)
836
837 (deftest :oodml/cache/2
838     (with-dataset *ds-employees*
839       (let ((employees (select 'employee)))
840         (equal employees (select 'employee :flatp t))))
841   nil)
842
843 (deftest :oodml/refresh/1
844     (with-dataset *ds-employees*
845       (let ((addresses (select 'address)))
846         (equal addresses (select 'address :refresh t))))
847   t)
848
849 (deftest :oodml/refresh/2
850     (with-dataset *ds-employees*
851       (let* ((addresses (select 'address :order-by [addressid] :flatp t :refresh t))
852              (city (slot-value (car addresses) 'city)))
853         (clsql:update-records [addr]
854                               :av-pairs '((city_field "A new city"))
855                               :where [= [addressid] (slot-value (car addresses) 'addressid)])
856         (let* ((new-addresses (select 'address :order-by [addressid] :refresh t :flatp t))
857                (new-city (slot-value (car addresses) 'city))
858                )
859           (clsql:update-records [addr]
860                                 :av-pairs `((city_field ,city))
861                                 :where [= [addressid] (slot-value (car addresses) 'addressid)])
862           (values (equal addresses new-addresses)
863                   city
864                   new-city))))
865   t "Leningrad" "A new city")
866
867 (deftest :oodml/refresh/3
868     (with-dataset *ds-employees*
869       (let* ((addresses (select 'address :order-by [addressid] :flatp t)))
870         (values
871           (equal addresses (select 'address :refresh t :flatp t))
872           (equal addresses (select 'address :flatp t)))))
873   nil nil)
874
875 (deftest :oodml/refresh/4
876     (with-dataset *ds-employees*
877       (let* ((addresses (select 'address :order-by [addressid] :flatp t :refresh t))
878              (*db-auto-sync* t))
879         (make-instance 'address :addressid 1000 :city "A new address city")
880         (let ((new-addresses (select 'address :order-by [addressid] :flatp t :refresh t)))
881           (delete-records :from [addr] :where [= [addressid] 1000])
882           (values
883             (length addresses)
884             (length new-addresses)
885             (eq (first addresses) (first new-addresses))
886             (eq (second addresses) (second new-addresses))))))
887   2 3 t t)
888
889
890 (deftest :oodml/uoj/1
891     (with-dataset *ds-employees*
892       (progn
893         (let* ((dea-list (select 'deferred-employee-address :caching nil :order-by ["ea_join" aaddressid]
894                                  :flatp t))
895                (dea-list-copy (copy-seq dea-list))
896                (initially-unbound (every #'(lambda (dea) (not (slot-boundp dea 'address))) dea-list)))
897           (update-objects-joins dea-list)
898           (values
899             initially-unbound
900             (equal dea-list dea-list-copy)
901             (every #'(lambda (dea) (slot-boundp dea 'address)) dea-list)
902             (every #'(lambda (dea) (typep (slot-value dea 'address) 'address)) dea-list)
903             (mapcar #'(lambda (dea) (slot-value (slot-value dea 'address) 'addressid)) dea-list)))))
904   t t t t (1 1 2 2 2))
905
906 ;; update-object-joins needs to be fixed for multiple keys
907 #+ignore
908 (deftest :oodml/uoj/2
909     (progn
910       (clsql:update-objects-joins (list company1))
911       (mapcar #'(lambda (e)
912                   (slot-value e 'ecompanyid))
913               (company-employees company1)))
914   (1 1 1 1 1 1 1 1 1 1))
915
916 (deftest :oodml/big/1
917     (with-dataset *ds-big*
918       (let ((objs (clsql:select 'big :order-by [i] :flatp t)))
919         (values
920           (length objs)
921           (do ((i 0 (1+ i))
922                (max (expt 2 60))
923                (rest objs (cdr rest)))
924               ((= i (length objs)) t)
925             (let ((obj (car rest))
926                   (index (1+ i)))
927               (unless (and (eql (slot-value obj 'i) index)
928                            (eql (slot-value obj 'bi) (truncate max index)))
929                 (print index)
930                 (describe obj)
931                 (return nil)))))))
932   555 t)
933
934 (deftest :oodml/db-auto-sync/1
935     (with-dataset *ds-employees*
936       (values
937         (progn
938           (make-instance 'employee :emplid 20 :groupid 1
939                          :last-name "Ivanovich")
940           (select [last-name] :from [employee] :where [= [emplid] 20]
941                   :flatp t :field-names nil))
942         (let ((*db-auto-sync* t))
943           (make-instance 'employee :emplid 20 :groupid 1
944                          :last-name "Ivanovich")
945           (prog1 (select [last-name] :from [employee] :flatp t
946                          :field-names nil
947                          :where [= [emplid] 20])
948             (delete-records :from [employee] :where [= [emplid] 20])))))
949   nil ("Ivanovich"))
950
951 (deftest :oodml/db-auto-sync/2
952     (with-dataset *ds-employees*
953       (values
954         (let ((instance (make-instance 'employee :emplid 20 :groupid 1
955                                        :last-name "Ivanovich")))
956           (setf (slot-value instance 'last-name) "Bulgakov")
957           (select [last-name] :from [employee] :where [= [emplid] 20]
958                   :flatp t :field-names nil))
959         (let* ((*db-auto-sync* t)
960                (instance (make-instance 'employee :emplid 20 :groupid 1
961                                         :last-name "Ivanovich")))
962           (setf (slot-value instance 'last-name) "Bulgakov")
963           (prog1 (select [last-name] :from [employee] :flatp t
964                          :field-names nil
965                          :where [= [emplid] 20])
966             (delete-records :from [employee] :where [= [emplid] 20])))))
967   nil ("Bulgakov"))
968
969 (deftest :oodml/db-auto-sync/3
970     (with-dataset *ds-nodes*
971       (values
972         (progn
973           (make-instance 'theme :title "test-theme" :vars "test-vars"
974                          :doc "test-doc")
975           (select [node-id] :from [node] :where [= [title] "test-theme"]
976                   :flatp t :field-names nil))
977         (let ((*db-auto-sync* t))
978           (make-instance 'theme :title "test-theme" :vars "test-vars"
979                          :doc "test-doc")
980           (prog1 (select [title] :from [node] :where [= [title] "test-theme"]
981                          :flatp t :field-names nil)
982             (delete-records :from [node] :where [= [title] "test-theme"])
983             (delete-records :from [setting] :where [= [vars] "test-vars"])
984             (delete-records :from [theme] :where [= [doc] "test-doc"])))))
985   nil ("test-theme"))
986
987 (deftest :oodml/db-auto-sync/4
988     (with-dataset *ds-nodes*
989       (values
990         (let ((inst (make-instance 'theme
991                                    :title "test-theme" :vars "test-vars"
992                                    :doc "test-doc"))
993               (*print-circle* nil))
994           (setf (slot-value inst 'title) "alternate-test-theme")
995           (format nil "~a ~a ~a ~a"
996                   (or (select [title] :from [node]
997                               :where [= [title] "test-theme"]
998                               :flatp t :field-names nil) "NIL")
999                   (or (select [vars] :from [setting]
1000                               :where [= [vars] "test-vars"]
1001                               :flatp t :field-names nil) "NIL")
1002                   (or (select [doc] :from [theme]
1003                               :where [= [doc] "test-doc"]
1004                               :flatp t :field-names nil) "NIL")
1005                   (or (select [title] :from [node]
1006                               :where [= [title] "alternate-test-theme"]
1007                               :flatp t :field-names nil) "NIL")))
1008         (let* ((*db-auto-sync* t)
1009                (inst (make-instance 'theme
1010                                     :title "test-theme" :vars "test-vars"
1011                                     :doc "test-doc")))
1012           (setf (slot-value inst 'title) "alternate-test-theme")
1013           (prog1
1014               (format nil "~a ~a ~a ~a"
1015                       (or (select [title] :from [node]
1016                                   :where [= [title] "test-theme"]
1017                                   :flatp t :field-names nil) "NIL")
1018                       (or (select [vars] :from [setting]
1019                                   :where [= [vars] "test-vars"]
1020                                   :flatp t :field-names nil) "NIL")
1021                       (or (select [doc] :from [theme]
1022                                   :where [= [doc] "test-doc"]
1023                                   :flatp t :field-names nil) "NIL")
1024                       (or (select [title] :from [node]
1025                                   :where [= [title] "alternate-test-theme"]
1026                                   :flatp t :field-names nil) "NIL"))
1027             (delete-records :from [node] :where [= [title] "alternate-test-theme"])
1028             (delete-records :from [setting] :where [= [vars] "test-vars"])
1029             (delete-records :from [theme] :where [= [doc] "test-doc"])))))
1030   "NIL NIL NIL NIL"
1031   "NIL (test-vars) (test-doc) (alternate-test-theme)")
1032
1033 (deftest :oodml/setf-slot-value/1
1034     (with-dataset *ds-employees*
1035       (let* ((*db-auto-sync* t)
1036              (instance (make-instance 'employee :emplid 20 :groupid 1)))
1037         (prog1
1038             (setf
1039              (slot-value instance 'first-name) "Mikhail"
1040              (slot-value instance 'last-name) "Bulgakov")
1041           (delete-records :from [employee] :where [= [emplid] 20]))))
1042   "Bulgakov")
1043
1044 (deftest :oodml/float/1
1045     (with-dataset *ds-employees*
1046       (let* ((emp1 (car (select 'employee
1047                                 :where [= [slot-value 'employee 'emplid]
1048                                           1]
1049                                 :flatp t
1050                                 :caching nil)))
1051              (height (slot-value emp1 'height)))
1052         (prog1
1053             (progn
1054               (setf (slot-value emp1 'height) 1.0E0)
1055               (clsql:update-record-from-slot emp1 'height)
1056               (= (car (clsql:select [height] :from [employee]
1057                                     :where [= [emplid] 1]
1058                                     :flatp t
1059                                     :field-names nil))
1060                  1))
1061           (setf (slot-value emp1 'height) height)
1062           (clsql:update-record-from-slot emp1 'height))))
1063   t)
1064
1065 (deftest :oodml/float/2
1066     (with-dataset *ds-employees*
1067       (let* ((emp1 (car (select 'employee
1068                                 :where [= [slot-value 'employee 'emplid]
1069                                           1]
1070                                 :flatp t
1071                                 :caching nil)))
1072              (height (slot-value emp1 'height)))
1073         (prog1
1074             (progn
1075               (setf (slot-value emp1 'height) 1.0S0)
1076               (clsql:update-record-from-slot emp1 'height)
1077               (= (car (clsql:select [height] :from [employee]
1078                                     :where [= [emplid] 1]
1079                                     :flatp t
1080                                     :field-names nil))
1081                  1))
1082           (setf (slot-value emp1 'height) height)
1083           (clsql:update-record-from-slot emp1 'height))))
1084   t)
1085
1086 (deftest :oodml/float/3
1087     (with-dataset *ds-employees*
1088       (let* ((emp1 (car (select 'employee
1089                                 :where [= [slot-value 'employee 'emplid]
1090                                           1]
1091                                 :flatp t
1092                                 :caching nil)))
1093              (height (slot-value emp1 'height)))
1094         (prog1
1095             (progn
1096               (setf (slot-value emp1 'height) 1.0F0)
1097               (clsql:update-record-from-slot emp1 'height)
1098               (= (car (clsql:select [height] :from [employee]
1099                                     :where [= [emplid] 1]
1100                                     :flatp t
1101                                     :field-names nil))
1102                  1))
1103           (setf (slot-value emp1 'height) height)
1104           (clsql:update-record-from-slot emp1 'height))))
1105   t)
1106
1107 (deftest :oodml/float/4
1108     (with-dataset *ds-employees*
1109       (let* ((emp1 (car (select 'employee
1110                                 :where [= [slot-value 'employee 'emplid]
1111                                           1]
1112                                 :flatp t
1113                                 :caching nil)))
1114              (height (slot-value emp1 'height)))
1115         (prog1
1116             (progn
1117               (setf (slot-value emp1 'height) 1.0D0)
1118               (clsql:update-record-from-slot emp1 'height)
1119               (= (car (clsql:select [height] :from [employee]
1120                                     :where [= [emplid] 1]
1121                                     :flatp t
1122                                     :field-names nil))
1123                  1))
1124           (setf (slot-value emp1 'height) height)
1125           (clsql:update-record-from-slot emp1 'height))))
1126   t)
1127
1128 (deftest :oodml/float/5
1129     (with-dataset *ds-employees*
1130       (let* ((emp1 (car (select 'employee
1131                                 :where [= [slot-value 'employee 'emplid]
1132                                           1]
1133                                 :flatp t
1134                                 :caching nil)))
1135              (height (slot-value emp1 'height)))
1136         (prog1
1137             (progn
1138               (setf (slot-value emp1 'height) 1.0L0)
1139               (clsql:update-record-from-slot emp1 'height)
1140               (= (car (clsql:select [height] :from [employee]
1141                                     :where [= [emplid] 1]
1142                                     :flatp t
1143                                     :field-names nil))
1144                  1))
1145           (setf (slot-value emp1 'height) height)
1146           (clsql:update-record-from-slot emp1 'height))))
1147   t)
1148 ))
1149
1150
1151
1152 #.(clsql:restore-sql-reader-syntax-state)