d1c933a432d75c8340b047651fbe092590457efa
[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 ;; test retrieval is deferred
220 (deftest :oodm/retrieval/1
221     (with-dataset *ds-employees*
222       (every #'(lambda (e) (not (slot-boundp e 'company)))
223              (select 'employee :flatp t :caching nil)))
224   t)
225
226 (deftest :oodm/retrieval/2
227     (with-dataset *ds-employees*
228       (every #'(lambda (e) (not (slot-boundp e 'address)))
229              (select 'deferred-employee-address :flatp t :caching nil)))
230   t)
231
232 ;; :retrieval :immediate should be boundp before accessed
233 (deftest :oodm/retrieval/3
234     (with-dataset *ds-employees*
235       (every #'(lambda (ea) (slot-boundp ea 'address))
236              (select 'employee-address :flatp t :caching nil)))
237   t)
238
239 (deftest :oodm/retrieval/4
240     (with-dataset *ds-employees*
241       (mapcar #'(lambda (ea) (typep (slot-value ea 'address) 'address))
242               (select 'employee-address :flatp t :caching nil)))
243   (t t t t t))
244
245 (deftest :oodm/retrieval/5
246     (with-dataset *ds-employees*
247       (mapcar #'(lambda (ea) (typep (slot-value ea 'address) 'address))
248               (select 'deferred-employee-address :flatp t :caching nil)))
249   (t t t t t))
250
251 (deftest :oodm/retrieval/6
252     (with-dataset *ds-employees*
253       (every #'(lambda (ea) (slot-boundp (slot-value ea 'address) 'addressid))
254              (select 'employee-address :flatp t :caching nil)))
255   t)
256
257 (deftest :oodm/retrieval/7
258     (with-dataset *ds-employees*
259       (every #'(lambda (ea) (slot-boundp (slot-value ea 'address) 'addressid))
260              (select 'deferred-employee-address :flatp t :caching nil)))
261   t)
262
263 (deftest :oodm/retrieval/8
264     (with-dataset *ds-employees*
265       (mapcar #'(lambda (ea) (slot-value (slot-value ea 'address) 'street-number))
266               (select 'employee-address :flatp t :order-by [aaddressid] :caching nil)))
267   (10 10 nil nil nil))
268
269 (deftest :oodm/retrieval/9
270     (with-dataset *ds-employees*
271       (mapcar #'(lambda (ea) (slot-value (slot-value ea 'address) 'street-number))
272               (select 'deferred-employee-address :flatp t :order-by [aaddressid] :caching nil)))
273   (10 10 nil nil nil))
274
275 ;; tests update-records-from-instance
276 (deftest :oodml/update-records/1
277     (with-dataset *ds-employees*
278       (values
279         (progn
280           (let ((lenin (car (clsql:select 'employee
281                                           :where [= 1 [slot-value 'employee 'emplid]]
282                                           :flatp t
283                                           :caching nil))))
284             (format nil "~a ~a: ~a"
285                 (first-name lenin)
286                 (last-name lenin)
287                 (employee-email lenin))))
288         (progn
289           (setf (slot-value employee1 'first-name) "Dimitriy"
290                 (slot-value employee1 'last-name) "Ivanovich"
291                 (slot-value employee1 'email) "ivanovich@soviet.org")
292           (clsql:update-records-from-instance employee1)
293           (let ((lenin (car (clsql:select 'employee
294                                           :where [= 1 [slot-value 'employee 'emplid]]
295                                           :flatp t
296                                           :caching nil))))
297             (format nil "~a ~a: ~a"
298                 (first-name lenin)
299                 (last-name lenin)
300                 (employee-email lenin))))))
301   "Vladimir Lenin: lenin@soviet.org"
302   "Dimitriy Ivanovich: ivanovich@soviet.org")
303
304 ;; tests update-record-from-slot
305 (deftest :oodml/update-records/2
306     (with-dataset *ds-employees*
307       (values
308         (employee-email
309          (car (clsql:select 'employee
310                             :where [= 1 [slot-value 'employee 'emplid]]
311                             :flatp t
312                             :caching nil)))
313         (progn
314           (setf (slot-value employee1 'email) "lenin-nospam@soviet.org")
315           (clsql:update-record-from-slot employee1 'email)
316           (employee-email
317            (car (clsql:select 'employee
318                               :where [= 1 [slot-value 'employee 'emplid]]
319                               :flatp t
320                               :caching nil))))))
321   "lenin@soviet.org" "lenin-nospam@soviet.org")
322
323 ;; tests update-record-from-slots
324 (deftest :oodml/update-records/3
325     (with-dataset *ds-employees*
326       (values
327         (let ((lenin (car (clsql:select 'employee
328                                         :where [= 1 [slot-value 'employee 'emplid]]
329                                         :flatp t
330                                         :caching nil))))
331           (format nil "~a ~a: ~a"
332                   (first-name lenin)
333                   (last-name lenin)
334                   (employee-email lenin)))
335         (progn
336           (setf (slot-value employee1 'first-name) "Dimitriy"
337                 (slot-value employee1 'last-name) "Ivanovich"
338                 (slot-value employee1 'email) "ivanovich@soviet.org")
339           (clsql:update-record-from-slots employee1 '(first-name last-name email))
340           (let ((lenin (car (clsql:select 'employee
341                                           :where [= 1 [slot-value 'employee 'emplid]]
342                                           :flatp t
343                                           :caching nil))))
344             (format nil "~a ~a: ~a"
345                     (first-name lenin)
346                     (last-name lenin)
347                     (employee-email lenin))))))
348   "Vladimir Lenin: lenin@soviet.org"
349   "Dimitriy Ivanovich: ivanovich@soviet.org")
350
351 (deftest :oodml/update-records/4
352     (with-dataset *ds-nodes*
353       (flet ((print-fresh-node ()
354                (let ((base (car (clsql:select 'node
355                                               :where [= 1 [slot-value 'node 'node-id]]
356                                               :flatp t :caching nil))))
357                  (format nil "~a ~a"
358                          (slot-value base 'node-id)
359                          (slot-value base 'title)))))
360         (values
361           (print-fresh-node)
362           (let ((base (car (clsql:select 'node
363                                          :where [= 1 [slot-value 'node 'node-id]]
364                                          :flatp t :caching nil))))
365             (setf (slot-value base 'title) "Altered title")
366             (clsql:update-records-from-instance base)
367             (print-fresh-node)))))
368   "1 Bare node"
369   "1 Altered title")
370
371 (deftest :oodml/update-records/4-slots ;just like 4, but use slots fns.
372     (with-dataset *ds-nodes*
373       (flet ((print-fresh-setting ()
374                (let ((node (car (clsql:select 'setting
375                                               :where [= 3 [slot-value 'setting 'setting-id]]
376                                               :flatp t :caching nil))))
377                  (format nil "~a ~a ~a"
378                          (slot-value node 'setting-id)
379                          (slot-value node 'title)
380                          (slot-value node 'vars)))))
381         (values
382           (print-fresh-setting)
383           (let ((node (car (clsql:select 'setting
384                                          :where [= 3 [slot-value 'setting 'setting-id]]
385                                          :flatp t :caching nil))))
386             (setf (slot-value node 'title) "Altered title")
387             (setf (slot-value node 'vars) "Altered vars")
388             (clsql-sys:update-record-from-slot node 'title)
389             (clsql-sys:update-record-from-slot node 'vars)
390             (print-fresh-setting))
391           (let ((node (car (clsql:select 'setting
392                                          :where [= 3 [slot-value 'setting 'setting-id]]
393                                          :flatp t :caching nil))))
394             (setf (slot-value node 'title) "Setting2")
395             (setf (slot-value node 'vars) "var 2")
396             (clsql:update-records-from-instance node)
397             (clsql-sys:update-record-from-slots node '(vars title))
398             (print-fresh-setting)))))
399   "3 Setting2 var 2"
400   "3 Altered title Altered vars"
401   "3 Setting2 var 2")
402
403 (deftest :oodml/update-records/5
404     (with-dataset *ds-nodes*
405       (flet ((print-fresh-setting ()
406                (let ((node (car (clsql:select 'setting
407                                               :where [= 3 [slot-value 'setting 'setting-id]]
408                                               :flatp t :caching nil))))
409                  (format nil "~a ~a ~a"
410                          (slot-value node 'setting-id)
411                          (slot-value node 'title)
412                          (slot-value node 'vars)))))
413         (values
414           (print-fresh-setting)
415           (let ((node (car (clsql:select 'setting
416                                          :where [= 3 [slot-value 'setting 'setting-id]]
417                                          :flatp t :caching nil))))
418             (setf (slot-value node 'title) "Altered title")
419             (setf (slot-value node 'vars) "Altered vars")
420             (clsql:update-records-from-instance node)
421             (print-fresh-setting)))))
422   "3 Setting2 var 2"
423   "3 Altered title Altered vars")
424
425 (deftest :oodml/update-records/5-slots
426     (with-dataset *ds-nodes*
427       (flet ((print-fresh-setting ()
428                (let ((node (car (clsql:select 'setting
429                                               :where [= 3 [slot-value 'setting 'setting-id]]
430                                               :flatp t :caching nil))))
431                  (format nil "~a ~a ~a"
432                          (slot-value node 'setting-id)
433                          (slot-value node 'title)
434                          (slot-value node 'vars)))))
435         (values
436           (print-fresh-setting)
437           (let ((node (car (clsql:select 'setting
438                                          :where [= 3 [slot-value 'setting 'setting-id]]
439                                          :flatp t :caching nil))))
440             (setf (slot-value node 'title) "Altered title")
441             (setf (slot-value node 'vars) "Altered vars")
442             (clsql-sys:update-record-from-slot node 'title)
443             (clsql-sys:update-record-from-slot node 'vars)
444             (print-fresh-setting))
445           (let ((node (car (clsql:select 'setting
446                                          :where [= 3 [slot-value 'setting 'setting-id]]
447                                          :flatp t :caching nil))))
448             (setf (slot-value node 'title) "Setting2")
449             (setf (slot-value node 'vars) "var 2")
450             (clsql-sys:update-record-from-slots node '(title vars))
451             (print-fresh-setting)))))
452   "3 Setting2 var 2"
453   "3 Altered title Altered vars"
454   "3 Setting2 var 2")
455
456 (deftest :oodml/update-records/6
457     (with-dataset *ds-nodes*
458       (flet ((print-fresh-setting ()
459                (let ((node (car (clsql:select 'setting
460                                               :where [= 7 [slot-value 'setting 'setting-id]]
461                                               :flatp t :caching nil))))
462                  (format nil "~a ~a ~a"
463                          (slot-value node 'setting-id)
464                          (slot-value node 'title)
465                          (or (slot-value node 'vars) "NIL")))))
466         (values
467           (print-fresh-setting)
468           (let ((node (car (clsql:select 'setting
469                                          :where [= 7 [slot-value 'setting 'setting-id]]
470                                          :flatp t :caching nil))))
471             (setf (slot-value node 'title) "Altered title")
472             (setf (slot-value node 'vars) "Altered vars")
473             (clsql:update-records-from-instance node)
474             (print-fresh-setting))
475           (let ((node (car (clsql:select 'setting
476                                          :where [= 7 [slot-value 'setting 'setting-id]]
477                                          :flatp t :caching nil))))
478             (setf (slot-value node 'title) "theme-2")
479             (setf (slot-value node 'vars) nil)
480             (clsql:update-records-from-instance node)
481             (print-fresh-setting)))))
482   "7 theme-2 NIL"
483   "7 Altered title Altered vars"
484   "7 theme-2 NIL")
485
486 (deftest :oodml/update-records/7
487     (with-dataset *ds-nodes*
488       (flet ((print-fresh-user ()
489                "requery to get what the db has, and print out."
490                (let ((node (car (clsql:select 'user
491                                               :where [= 5 [slot-value 'user 'user-id]]
492                                               :flatp t :caching nil))))
493                  (format nil "~a ~a ~a"
494                          (slot-value node 'user-id)
495                          (slot-value node 'title)
496                          (slot-value node 'nick)))))
497         (values
498           (print-fresh-user)
499           (let ((node (car (clsql:select 'user
500                                          :where [= 5 [slot-value 'user 'user-id]]
501                                          :flatp t :caching nil))))
502             (setf (slot-value node 'title) "Altered title")
503             (setf (slot-value node 'nick) "Altered nick")
504             (clsql:update-records-from-instance node)
505             (print-fresh-user)))))
506   "5 user-2 second user"
507   "5 Altered title Altered nick")
508
509 (deftest :oodml/update-records/8
510     (with-dataset *ds-nodes*
511       (flet ((print-fresh-theme ()
512                (let ((node (car (clsql:select 'theme
513                                               :where [= 6 [slot-value 'theme 'theme-id]]
514                                               :flatp t :caching nil))))
515                  (with-slots (node-id setting-id theme-id title vars doc) node
516                    (format nil "~a ~a ~a ~a ~a ~a"
517                            node-id setting-id theme-id
518                            title (or vars "NIL") doc)))))
519         (values
520           (print-fresh-theme)
521           (let ((node (car (clsql:select 'setting
522                                          :where [= 6 [slot-value 'setting 'setting-id]]
523                                          :flatp t :caching nil))))
524             (setf (slot-value node 'title) "Altered title")
525             (setf (slot-value node 'vars) nil)
526             (clsql:update-records-from-instance node)
527             (print-fresh-theme))
528           (let ((node (car (clsql:select 'theme
529                                          :where [= 6 [slot-value 'theme 'theme-id]]
530                                          :flatp t :caching nil))))
531             (setf (slot-value node 'title) "Altered title again")
532             (setf (slot-value node 'doc) "altered doc")
533             (clsql:update-records-from-instance node)
534             (print-fresh-theme))
535           (let ((node (car (clsql:select 'theme
536                                          :where [= 6 [slot-value 'theme 'theme-id]]
537                                          :flatp t :caching nil))))
538             (setf (slot-value node 'title) "theme-1")
539             (setf (slot-value node 'vars) "empty")
540             (setf (slot-value node 'doc) "first theme")
541             (clsql:update-records-from-instance node)
542             (print-fresh-theme)))))
543   "6 6 6 theme-1 empty first theme"
544   "6 6 6 Altered title NIL first theme"
545   "6 6 6 Altered title again NIL altered doc"
546   "6 6 6 theme-1 empty first theme")
547
548 (deftest :oodml/update-records/9
549     (with-dataset *ds-nodes*
550       (flet ((print-fresh-subloc ()
551                (let ((sl (car (clsql:select 'subloc
552                                             :where [= 10 [slot-value 'subloc 'subloc-id]]
553                                             :flatp t :caching nil))))
554                  (format nil "~a ~a ~a"
555                          (slot-value sl 'subloc-id)
556                          (slot-value sl 'title)
557                          (slot-value sl 'loc)))))
558         (values
559           (print-fresh-subloc)
560           (let ((sl (car (clsql:select 'subloc
561                                        :where [= 10 [slot-value 'subloc 'subloc-id]]
562                                        :flatp t :caching nil))))
563             (setf (slot-value sl 'title) "Altered subloc title")
564             (setf (slot-value sl 'loc) "Altered loc")
565             (clsql:update-records-from-instance sl)
566             (print-fresh-subloc)))))
567   "10 subloc-1 a subloc"
568   "10 Altered subloc title Altered loc")
569
570 (deftest :oodml/update-records/9-slots ;like 9, but use slots fns.
571     (with-dataset *ds-nodes*
572       (flet ((print-fresh-subloc ()
573                (let ((sl (car (clsql:select 'subloc
574                                             :where [= 10 [slot-value 'subloc 'subloc-id]]
575                                             :flatp t :caching nil))))
576                  (format nil "~a ~a ~a"
577                          (slot-value sl 'subloc-id)
578                          (slot-value sl 'title)
579                          (slot-value sl 'loc)))))
580         (values
581           (print-fresh-subloc)
582           (let ((sl (car (clsql:select 'subloc
583                                        :where [= 10 [slot-value 'subloc 'subloc-id]]
584                                        :flatp t :caching nil))))
585             (setf (slot-value sl 'title) "Altered subloc title")
586             (setf (slot-value sl 'loc) "Altered loc")
587             (clsql:update-record-from-slot sl 'title)
588             (clsql:update-record-from-slot sl 'loc)
589             (print-fresh-subloc))
590           (let ((sl (car (clsql:select 'subloc
591                                        :where [= 10 [slot-value 'subloc 'subloc-id]]
592                                        :flatp t :caching nil))))
593             (setf (slot-value sl 'title) "subloc-1")
594             (setf (slot-value sl 'loc) "a subloc")
595             (clsql:update-record-from-slot sl '(title loc))
596             (print-fresh-subloc)))))
597   "10 subloc-1 a subloc"
598   "10 Altered subloc title Altered loc"
599   "10 subloc-1 a subloc")
600
601 ;; Verify that we can set a float to nil and then read it back
602 ;; (was failing in Postgresql at somepoint)
603 (deftest :oodml/update-records/10
604     (with-dataset *ds-employees*
605       (let ((emp (first (clsql:select 'employee :where [= [emplid] 1] :flatp t))))
606         (setf (height emp) nil)
607         (clsql-sys:update-record-from-slot emp 'height)
608         (values
609           (clsql:select [height] :from [employee] :where [= [emplid] 1])
610           (progn
611             (setf (height emp) 42.0)
612             (clsql-sys:update-record-from-slot emp 'height)
613             (clsql:select [height] :from [employee] :where [= [emplid] 1]))
614           (progn
615             (setf (height emp) 24.13d0)
616             (clsql-sys:update-record-from-slot emp 'height)
617             (clsql:select [height] :from [employee] :where [= [emplid] 1])))))
618   ((nil))
619   ((42.0d0))
620   ((24.13d0)))
621
622 (deftest :oodml/update-records/11
623     (with-dataset *ds-artists*
624       (clsql:update-records-from-instance artist1)
625       (list (name artist1) (artist_id artist1)))
626   ("Mogwai" 1))
627
628 ;; tests update-instance-from-records
629 (deftest :oodml/update-instance/1
630     (with-dataset *ds-employees*
631       (values
632         (format nil "~a ~a: ~a"
633                 (slot-value employee1 'first-name)
634                 (slot-value employee1 'last-name)
635                 (slot-value employee1 'email))
636         (progn
637           (clsql:update-records [employee]
638                                 :av-pairs '(([first-name] "Ivan")
639                                             ([last-name] "Petrov")
640                                             ([email] "petrov@soviet.org"))
641                                 :where [= [emplid] 1])
642           (clsql:update-instance-from-records employee1)
643           (format nil "~a ~a: ~a"
644                 (slot-value employee1 'first-name)
645                 (slot-value employee1 'last-name)
646                 (slot-value employee1 'email)))))
647   "Vladimir Lenin: lenin@soviet.org"
648   "Ivan Petrov: petrov@soviet.org")
649
650 ;; tests update-slot-from-record
651 (deftest :oodml/update-instance/2
652     (with-dataset *ds-employees*
653       (values
654         (slot-value employee1 'email)
655         (progn
656           (clsql:update-records [employee]
657                                 :av-pairs '(([email] "lenin-nospam@soviet.org"))
658                                 :where [= [emplid] 1])
659           (clsql:update-slot-from-record employee1 'email)
660           (slot-value employee1 'email))))
661   "lenin@soviet.org" "lenin-nospam@soviet.org")
662
663 ;; tests normalizedp update-instance-from-records
664 (deftest :oodml/update-instance/3
665     (with-dataset *ds-nodes*
666       (values
667         (with-output-to-string (out)
668           (format out "~a ~a ~a ~a"
669                   (slot-value theme2 'theme-id)
670                   (slot-value theme2 'title)
671                   (or (slot-value theme2 'vars) "NIL")
672                   (slot-value theme2 'doc)))
673         (progn
674           (clsql:update-records [node] :av-pairs '(([title] "Altered title"))
675                                 :where [= [node-id] 7])
676           (clsql:update-records [setting] :av-pairs '(([vars] "Altered vars"))
677                                 :where [= [setting-id] 7])
678           (clsql:update-records [theme] :av-pairs '(([doc] "Altered doc"))
679                                 :where [= [theme-id] 7])
680           (clsql:update-instance-from-records theme2)
681           (with-output-to-string (out)
682             (format out "~a ~a ~a ~a"
683                     (slot-value theme2 'theme-id)
684                     (slot-value theme2 'title)
685                     (slot-value theme2 'vars)
686                     (slot-value theme2 'doc))))))
687   "7 theme-2 NIL second theme"
688   "7 Altered title Altered vars Altered doc")
689
690 (deftest :oodml/update-instance/4
691     (with-dataset *ds-nodes*
692       (values
693         (progn
694           (setf loc2 (car (clsql:select 'location
695                                         :where [= [node-id] 9]
696                                         :flatp t :caching nil)))
697           (format nil "~a ~a"
698                   (slot-value loc2 'node-id)
699                   (slot-value loc2 'title)))
700         (progn
701           (clsql:update-records [node] :av-pairs '(([title] "Altered title"))
702                                 :where [= [node-id] 9])
703           (clsql:update-instance-from-records loc2)
704           (format nil "~a ~a"
705                   (slot-value loc2 'node-id)
706                   (slot-value loc2 'title)))))
707   "9 location-2"
708   "9 Altered title")
709
710 (deftest :oodml/update-instance/5
711     (with-dataset *ds-nodes*
712       (values
713         (format nil "~a ~a ~a"
714                 (slot-value subloc2 'subloc-id)
715                 (slot-value subloc2 'title)
716                 (slot-value subloc2 'loc))
717         (progn
718           (clsql:update-records [node] :av-pairs '(([title] "Altered title"))
719                                 :where [= [node-id] 11])
720           (clsql:update-records [subloc] :av-pairs '(([loc] "Altered loc"))
721                                 :where [= [subloc-id] 11])
722           (clsql:update-instance-from-records subloc2)
723           (format nil "~a ~a ~a"
724                   (slot-value subloc2 'subloc-id)
725                   (slot-value subloc2 'title)
726                   (slot-value subloc2 'loc)))))
727   "11 subloc-2 second subloc"
728   "11 Altered title Altered loc")
729
730 ;; tests update-slot-from-record with normalizedp stuff
731 (deftest :oodml/update-instance/6
732     (with-dataset *ds-nodes*
733       (values
734         (slot-value theme1 'doc)
735         (slot-value theme1 'vars)
736         (progn
737           (clsql:update-records [theme]
738                                 :av-pairs '(([doc] "altered doc"))
739                                 :where [= [theme-id] 6])
740           (clsql:update-slot-from-record theme1 'doc)
741           (slot-value theme1 'doc))
742         (progn
743           (clsql:update-records [setting]
744                                 :av-pairs '(([vars] "altered vars"))
745                                 :where [= [setting-id] 6])
746           (clsql:update-slot-from-record theme1 'vars)
747           (slot-value theme1 'vars))))
748   "first theme" "empty"
749   "altered doc" "altered vars")
750
751 (deftest :oodml/update-instance/7
752     (flet ((print-loc (l)
753              (format nil "~a: ~a"
754                      (slot-value l 'node-id) (slot-value l 'title)))
755            (print-subloc (sl)
756              (format nil "~a: ~a"
757                      (slot-value sl 'node-id) (slot-value sl 'loc))))
758         (with-dataset *ds-nodes*
759       (values
760         (print-loc loc2)
761         (print-subloc subloc2)
762         (progn
763           (clsql:update-records [node]
764                                 :av-pairs '(([title] "altered title"))
765                                 :where [= [node-id] 9])
766           (clsql:update-slot-from-record loc2 'title)
767           (print-loc loc2))
768         (progn
769           (clsql:update-records [subloc]
770                                 :av-pairs '(([loc] "altered loc"))
771                                 :where [= [subloc-id] 11])
772           (clsql:update-slot-from-record subloc2 'loc)
773           (print-subloc subloc2)))))
774   "9: location-2" "11: second subloc"
775   "9: altered title" "11: altered loc")
776
777 (deftest :oodml/do-query/1
778     (with-dataset *ds-employees*
779       (let ((result '()))
780         (clsql:do-query ((e) [select 'employee :order-by [emplid]])
781           (push (slot-value e 'last-name) result))
782         result))
783   ("Putin" "Yeltsin" "Gorbachev" "Chernenko" "Andropov" "Brezhnev" "Kruschev"
784            "Trotsky" "Stalin" "Lenin"))
785
786 (deftest :oodml/do-query/2
787     (with-dataset *ds-employees*
788       (let ((result '()))
789         (clsql:do-query ((e c) [select 'employee 'company
790                                        :where [= [slot-value 'employee 'last-name]
791                                                  "Lenin"]])
792           (push (list (slot-value e 'last-name) (slot-value c 'name))
793                 result))
794         result))
795   (("Lenin" "Widgets Inc.")))
796
797 (deftest :oodml/map-query/1
798     (with-dataset *ds-employees*
799       (clsql:map-query 'list #'last-name [select 'employee :order-by [emplid]]))
800   ("Lenin" "Stalin" "Trotsky" "Kruschev" "Brezhnev" "Andropov" "Chernenko"
801            "Gorbachev" "Yeltsin" "Putin"))
802
803 (deftest :oodml/map-query/2
804     (with-dataset *ds-employees*
805       (clsql:map-query 'list #'(lambda (e c) (list (slot-value e 'last-name)
806                                                    (slot-value c 'name)))
807                        [select 'employee 'company :where [= [slot-value 'employee 'last-name]
808                                                             "Lenin"]]))
809   (("Lenin" "Widgets Inc.")))
810
811 (deftest :oodml/iteration/3
812     (with-dataset *ds-employees*
813       (loop for (e) being the records in
814             [select 'employee :where [< [emplid] 4] :order-by [emplid]]
815             collect (slot-value e 'last-name)))
816   ("Lenin" "Stalin" "Trotsky"))
817
818
819 (deftest :oodml/cache/1
820     (with-dataset *ds-employees*
821       (progn
822         (setf (clsql-sys:record-caches *default-database*) nil)
823         (let ((employees (select 'employee)))
824           (every #'(lambda (a b) (eq a b))
825                  employees (select 'employee)))))
826   t)
827
828 (deftest :oodml/cache/2
829     (with-dataset *ds-employees*
830       (let ((employees (select 'employee)))
831         (equal employees (select 'employee :flatp t))))
832   nil)
833
834 (deftest :oodml/refresh/1
835     (with-dataset *ds-employees*
836       (let ((addresses (select 'address)))
837         (equal addresses (select 'address :refresh t))))
838   t)
839
840 (deftest :oodml/refresh/2
841     (with-dataset *ds-employees*
842       (let* ((addresses (select 'address :order-by [addressid] :flatp t :refresh t))
843              (city (slot-value (car addresses) 'city)))
844         (clsql:update-records [addr]
845                               :av-pairs '((city_field "A new city"))
846                               :where [= [addressid] (slot-value (car addresses) 'addressid)])
847         (let* ((new-addresses (select 'address :order-by [addressid] :refresh t :flatp t))
848                (new-city (slot-value (car addresses) 'city))
849                )
850           (clsql:update-records [addr]
851                                 :av-pairs `((city_field ,city))
852                                 :where [= [addressid] (slot-value (car addresses) 'addressid)])
853           (values (equal addresses new-addresses)
854                   city
855                   new-city))))
856   t "Leningrad" "A new city")
857
858 (deftest :oodml/refresh/3
859     (with-dataset *ds-employees*
860       (let* ((addresses (select 'address :order-by [addressid] :flatp t)))
861         (values
862           (equal addresses (select 'address :refresh t :flatp t))
863           (equal addresses (select 'address :flatp t)))))
864   nil nil)
865
866 (deftest :oodml/refresh/4
867     (with-dataset *ds-employees*
868       (let* ((addresses (select 'address :order-by [addressid] :flatp t :refresh t))
869              (*db-auto-sync* t))
870         (make-instance 'address :addressid 1000 :city "A new address city")
871         (let ((new-addresses (select 'address :order-by [addressid] :flatp t :refresh t)))
872           (delete-records :from [addr] :where [= [addressid] 1000])
873           (values
874             (length addresses)
875             (length new-addresses)
876             (eq (first addresses) (first new-addresses))
877             (eq (second addresses) (second new-addresses))))))
878   2 3 t t)
879
880
881 (deftest :oodml/uoj/1
882     (with-dataset *ds-employees*
883       (progn
884         (let* ((dea-list (select 'deferred-employee-address :caching nil :order-by ["ea_join" aaddressid]
885                                  :flatp t))
886                (dea-list-copy (copy-seq dea-list))
887                (initially-unbound (every #'(lambda (dea) (not (slot-boundp dea 'address))) dea-list)))
888           (update-objects-joins dea-list)
889           (values
890             initially-unbound
891             (equal dea-list dea-list-copy)
892             (every #'(lambda (dea) (slot-boundp dea 'address)) dea-list)
893             (every #'(lambda (dea) (typep (slot-value dea 'address) 'address)) dea-list)
894             (mapcar #'(lambda (dea) (slot-value (slot-value dea 'address) 'addressid)) dea-list)))))
895   t t t t (1 1 2 2 2))
896
897 ;; update-object-joins needs to be fixed for multiple keys
898 #+ignore
899 (deftest :oodml/uoj/2
900     (progn
901       (clsql:update-objects-joins (list company1))
902       (mapcar #'(lambda (e)
903                   (slot-value e 'ecompanyid))
904               (company-employees company1)))
905   (1 1 1 1 1 1 1 1 1 1))
906
907 (deftest :oodml/big/1
908     (with-dataset *ds-big*
909       (let ((objs (clsql:select 'big :order-by [i] :flatp t)))
910         (values
911           (length objs)
912           (do ((i 0 (1+ i))
913                (max (expt 2 60))
914                (rest objs (cdr rest)))
915               ((= i (length objs)) t)
916             (let ((obj (car rest))
917                   (index (1+ i)))
918               (unless (and (eql (slot-value obj 'i) index)
919                            (eql (slot-value obj 'bi) (truncate max index)))
920                 (print index)
921                 (describe obj)
922                 (return nil)))))))
923   555 t)
924
925 (deftest :oodml/db-auto-sync/1
926     (with-dataset *ds-employees*
927       (values
928         (progn
929           (make-instance 'employee :emplid 20 :groupid 1
930                          :last-name "Ivanovich")
931           (select [last-name] :from [employee] :where [= [emplid] 20]
932                   :flatp t :field-names nil))
933         (let ((*db-auto-sync* t))
934           (make-instance 'employee :emplid 20 :groupid 1
935                          :last-name "Ivanovich")
936           (prog1 (select [last-name] :from [employee] :flatp t
937                          :field-names nil
938                          :where [= [emplid] 20])
939             (delete-records :from [employee] :where [= [emplid] 20])))))
940   nil ("Ivanovich"))
941
942 (deftest :oodml/db-auto-sync/2
943     (with-dataset *ds-employees*
944       (values
945         (let ((instance (make-instance 'employee :emplid 20 :groupid 1
946                                        :last-name "Ivanovich")))
947           (setf (slot-value instance 'last-name) "Bulgakov")
948           (select [last-name] :from [employee] :where [= [emplid] 20]
949                   :flatp t :field-names nil))
950         (let* ((*db-auto-sync* t)
951                (instance (make-instance 'employee :emplid 20 :groupid 1
952                                         :last-name "Ivanovich")))
953           (setf (slot-value instance 'last-name) "Bulgakov")
954           (prog1 (select [last-name] :from [employee] :flatp t
955                          :field-names nil
956                          :where [= [emplid] 20])
957             (delete-records :from [employee] :where [= [emplid] 20])))))
958   nil ("Bulgakov"))
959
960 (deftest :oodml/db-auto-sync/3
961     (with-dataset *ds-nodes*
962       (values
963         (progn
964           (make-instance 'theme :title "test-theme" :vars "test-vars"
965                          :doc "test-doc")
966           (select [node-id] :from [node] :where [= [title] "test-theme"]
967                   :flatp t :field-names nil))
968         (let ((*db-auto-sync* t))
969           (make-instance 'theme :title "test-theme" :vars "test-vars"
970                          :doc "test-doc")
971           (prog1 (select [title] :from [node] :where [= [title] "test-theme"]
972                          :flatp t :field-names nil)
973             (delete-records :from [node] :where [= [title] "test-theme"])
974             (delete-records :from [setting] :where [= [vars] "test-vars"])
975             (delete-records :from [theme] :where [= [doc] "test-doc"])))))
976   nil ("test-theme"))
977
978 (deftest :oodml/db-auto-sync/4
979     (with-dataset *ds-nodes*
980       (values
981         (let ((inst (make-instance 'theme
982                                    :title "test-theme" :vars "test-vars"
983                                    :doc "test-doc"))
984               (*print-circle* nil))
985           (setf (slot-value inst 'title) "alternate-test-theme")
986           (format nil "~a ~a ~a ~a"
987                   (or (select [title] :from [node]
988                               :where [= [title] "test-theme"]
989                               :flatp t :field-names nil) "NIL")
990                   (or (select [vars] :from [setting]
991                               :where [= [vars] "test-vars"]
992                               :flatp t :field-names nil) "NIL")
993                   (or (select [doc] :from [theme]
994                               :where [= [doc] "test-doc"]
995                               :flatp t :field-names nil) "NIL")
996                   (or (select [title] :from [node]
997                               :where [= [title] "alternate-test-theme"]
998                               :flatp t :field-names nil) "NIL")))
999         (let* ((*db-auto-sync* t)
1000                (inst (make-instance 'theme
1001                                     :title "test-theme" :vars "test-vars"
1002                                     :doc "test-doc")))
1003           (setf (slot-value inst 'title) "alternate-test-theme")
1004           (prog1
1005               (format nil "~a ~a ~a ~a"
1006                       (or (select [title] :from [node]
1007                                   :where [= [title] "test-theme"]
1008                                   :flatp t :field-names nil) "NIL")
1009                       (or (select [vars] :from [setting]
1010                                   :where [= [vars] "test-vars"]
1011                                   :flatp t :field-names nil) "NIL")
1012                       (or (select [doc] :from [theme]
1013                                   :where [= [doc] "test-doc"]
1014                                   :flatp t :field-names nil) "NIL")
1015                       (or (select [title] :from [node]
1016                                   :where [= [title] "alternate-test-theme"]
1017                                   :flatp t :field-names nil) "NIL"))
1018             (delete-records :from [node] :where [= [title] "alternate-test-theme"])
1019             (delete-records :from [setting] :where [= [vars] "test-vars"])
1020             (delete-records :from [theme] :where [= [doc] "test-doc"])))))
1021   "NIL NIL NIL NIL"
1022   "NIL (test-vars) (test-doc) (alternate-test-theme)")
1023
1024 (deftest :oodml/setf-slot-value/1
1025     (with-dataset *ds-employees*
1026       (let* ((*db-auto-sync* t)
1027              (instance (make-instance 'employee :emplid 20 :groupid 1)))
1028         (prog1
1029             (setf
1030              (slot-value instance 'first-name) "Mikhail"
1031              (slot-value instance 'last-name) "Bulgakov")
1032           (delete-records :from [employee] :where [= [emplid] 20]))))
1033   "Bulgakov")
1034
1035 (deftest :oodml/float/1
1036     (with-dataset *ds-employees*
1037       (let* ((emp1 (car (select 'employee
1038                                 :where [= [slot-value 'employee 'emplid]
1039                                           1]
1040                                 :flatp t
1041                                 :caching nil)))
1042              (height (slot-value emp1 'height)))
1043         (prog1
1044             (progn
1045               (setf (slot-value emp1 'height) 1.0E0)
1046               (clsql:update-record-from-slot emp1 'height)
1047               (= (car (clsql:select [height] :from [employee]
1048                                     :where [= [emplid] 1]
1049                                     :flatp t
1050                                     :field-names nil))
1051                  1))
1052           (setf (slot-value emp1 'height) height)
1053           (clsql:update-record-from-slot emp1 'height))))
1054   t)
1055
1056 (deftest :oodml/float/2
1057     (with-dataset *ds-employees*
1058       (let* ((emp1 (car (select 'employee
1059                                 :where [= [slot-value 'employee 'emplid]
1060                                           1]
1061                                 :flatp t
1062                                 :caching nil)))
1063              (height (slot-value emp1 'height)))
1064         (prog1
1065             (progn
1066               (setf (slot-value emp1 'height) 1.0S0)
1067               (clsql:update-record-from-slot emp1 'height)
1068               (= (car (clsql:select [height] :from [employee]
1069                                     :where [= [emplid] 1]
1070                                     :flatp t
1071                                     :field-names nil))
1072                  1))
1073           (setf (slot-value emp1 'height) height)
1074           (clsql:update-record-from-slot emp1 'height))))
1075   t)
1076
1077 (deftest :oodml/float/3
1078     (with-dataset *ds-employees*
1079       (let* ((emp1 (car (select 'employee
1080                                 :where [= [slot-value 'employee 'emplid]
1081                                           1]
1082                                 :flatp t
1083                                 :caching nil)))
1084              (height (slot-value emp1 'height)))
1085         (prog1
1086             (progn
1087               (setf (slot-value emp1 'height) 1.0F0)
1088               (clsql:update-record-from-slot emp1 'height)
1089               (= (car (clsql:select [height] :from [employee]
1090                                     :where [= [emplid] 1]
1091                                     :flatp t
1092                                     :field-names nil))
1093                  1))
1094           (setf (slot-value emp1 'height) height)
1095           (clsql:update-record-from-slot emp1 'height))))
1096   t)
1097
1098 (deftest :oodml/float/4
1099     (with-dataset *ds-employees*
1100       (let* ((emp1 (car (select 'employee
1101                                 :where [= [slot-value 'employee 'emplid]
1102                                           1]
1103                                 :flatp t
1104                                 :caching nil)))
1105              (height (slot-value emp1 'height)))
1106         (prog1
1107             (progn
1108               (setf (slot-value emp1 'height) 1.0D0)
1109               (clsql:update-record-from-slot emp1 'height)
1110               (= (car (clsql:select [height] :from [employee]
1111                                     :where [= [emplid] 1]
1112                                     :flatp t
1113                                     :field-names nil))
1114                  1))
1115           (setf (slot-value emp1 'height) height)
1116           (clsql:update-record-from-slot emp1 'height))))
1117   t)
1118
1119 (deftest :oodml/float/5
1120     (with-dataset *ds-employees*
1121       (let* ((emp1 (car (select 'employee
1122                                 :where [= [slot-value 'employee 'emplid]
1123                                           1]
1124                                 :flatp t
1125                                 :caching nil)))
1126              (height (slot-value emp1 'height)))
1127         (prog1
1128             (progn
1129               (setf (slot-value emp1 'height) 1.0L0)
1130               (clsql:update-record-from-slot emp1 'height)
1131               (= (car (clsql:select [height] :from [employee]
1132                                     :where [= [emplid] 1]
1133                                     :flatp t
1134                                     :field-names nil))
1135                  1))
1136           (setf (slot-value emp1 'height) height)
1137           (clsql:update-record-from-slot emp1 'height))))
1138   t)
1139 ))
1140
1141
1142
1143 #.(clsql:restore-sql-reader-syntax-state)