Coverage report: /home/ati/workspace/perec/persistence/store.lisp
Kind | Covered | All | % |
expression | 497 | 513 | 96.9 |
branch | 45 | 46 | 97.8 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
6
(defparameter *lazy-collections* #f
7
"True means slot-value-using-class will by default return lazy collections.")
9
(defstruct unbound-value)
11
(defparameter +unbound-slot-value+
13
"This value is used to signal unbound slot value returned from database.")
15
(defmethod make-load-form ((instance unbound-value) &optional environment)
16
(declare (ignore environment))
17
'(make-unbound-value))
19
(defun unbound-slot-value-p (value)
20
(eq +unbound-slot-value+ value))
22
;;;;;;;;;;;;;;;;;;;;;;;;;
23
;;; RDBMS slot restorers
25
(defun restore-slot-value (slot rdbms-values)
26
"Provides convenient access to the arguments in the debugger."
27
(declare (optimize (debug 3)))
28
(funcall (reader-of slot) rdbms-values))
30
(defun restore-slot-set (object slot)
31
"Restores the non lazy list without local side effects from the database."
32
(mapcar #'object-reader
33
(select-records (oid-columns-of (table-of slot))
34
(list (name-of (table-of slot)))
35
(id-column-matcher-where-clause object (id-column-of slot)))))
37
(defun restore-1-n-association-end-set (object slot)
38
"Restores the non lazy list association end value without local side effects from the database."
39
(restore-slot-set object slot))
41
(defun restore-m-n-association-end-set (object slot)
42
"Restores the non lazy list association end value without local side effects from the database."
43
(bind ((other-slot (other-association-end-of slot)))
44
(mapcar #'object-reader
45
(select-records (columns-of slot)
46
(list (name-of (table-of slot)))
47
(id-column-matcher-where-clause object (id-column-of other-slot))))))
49
(defun restore-slot (object slot)
50
"Restores a single slot without local side effects from the database."
52
(cond ((and (typep slot 'persistent-association-end-effective-slot-definition)
53
(eq (association-kind-of (association-of slot)) :1-1)
54
(secondary-association-end-p slot))
55
(restore-slot-value slot
57
(select-records +oid-column-names+
58
(list (name-of (table-of slot)))
60
(sql-identifier :name (id-column-of slot)))))))
61
((and (typep slot 'persistent-association-end-effective-slot-definition)
62
(eq (association-kind-of (association-of slot)) :1-n)
63
(eq (cardinality-kind-of slot) :n))
64
(if *lazy-collections*
65
(make-instance 'persistent-1-n-association-end-set-container :object object :slot slot)
66
(restore-1-n-association-end-set object slot)))
67
((and (typep slot 'persistent-association-end-effective-slot-definition)
68
(eq (association-kind-of (association-of slot)) :m-n))
69
(if *lazy-collections*
70
(make-instance 'persistent-m-n-association-end-set-container :object object :slot slot)
71
(restore-m-n-association-end-set object slot)))
72
((set-type-p (normalized-type-of slot))
73
(if *lazy-collections*
74
(make-instance 'persistent-slot-set-container :object object :slot slot)
75
(restore-slot-set object slot)))
77
;; TODO enters and fails with #<DWIM-META-MODEL::EFFECTIVE-PROPERTY-AND-COMPUTED-EFFECTIVE-SLOT-DEFINITION-AND-PERSISTENT-EFFECTIVE-SLOT-DEFINITION FULL-NAME {F7BED59}>
80
(select-records (columns-of slot)
81
(list (name-of (table-of slot)))
82
(id-column-matcher-where-clause object)))))
83
(restore-slot-value slot record))))
86
(defun restore-prefetched-slots (object &optional (allow-missing #f))
87
"Restores all prefetched slots at once without local side effects from the database. Executes a single select statement."
88
(if-bind slots (prefetched-slots-of (class-of object))
89
(bind ((tables (delete-duplicates (mapcar #'table-of slots)))
92
(select-records (mapcan (lambda (slot)
93
(mapcar (lambda (column)
94
(sql-column-alias :table (name-of (table-of slot)) :column column))
97
(mapcar #L(sql-table-alias :name (name-of !1) :alias (name-of !1)) tables)
99
(sql-= (sql-column-alias :table (name-of (first tables)) :column +id-column-name+)
100
(sql-literal :type +oid-id-sql-type+ :value (id-of object)))
101
(mapcar #L(sql-= (sql-column-alias :table (name-of (first tables)) :column +id-column-name+)
102
(sql-column-alias :table (name-of !1) :column +id-column-name+))
104
(assert (or record allow-missing))
107
(iter (for i first 0 then (+ i (length (columns-of slot))))
109
(collect (restore-slot-value slot (nthcdr i record))))
112
(defun restore-all-slots (object)
113
"Restores all slots wihtout local side effects from the database."
114
(bind (((values prefetched-slot-values prefetched-slots) (restore-prefetched-slots object))
115
(non-prefetched-slots (non-prefetched-slots-of (class-of object))))
116
(values (append prefetched-slot-values (mapcar #L(restore-slot object !1) non-prefetched-slots))
117
(append prefetched-slots non-prefetched-slots))))
119
;;;;;;;;;;;;;;;;;;;;;;
120
;;; RDBMS slot storers
122
(defun store-slot-value (slot slot-value)
123
"Provides convenient access to the arguments in the debugger."
124
(declare (optimize (debug 3)))
125
(funcall (writer-of slot) slot-value))
127
(defun delete-slot-set (object slot)
128
(update-records (name-of (table-of slot))
131
(id-column-matcher-where-clause object (id-column-of slot))))
133
(defun store-slot-set (object slot value)
134
"Stores the non lazy list without local side effects into the database."
135
(delete-slot-set object slot)
137
(update-records (name-of (table-of slot))
139
(object-writer object)
140
(id-column-list-matcher-where-clause value))))
142
(defun store-1-n-association-end-set (object slot value)
143
"Stores the non lazy list association end value without local side effects into the database."
144
(store-slot-set object slot value))
146
(defun delete-m-n-association-end-set (object slot)
147
(delete-records (name-of (table-of slot))
148
(id-column-matcher-where-clause object (id-column-of slot))))
150
(defun insert-into-m-n-association-end-set (object slot value)
151
(bind ((other-slot (other-association-end-of slot)))
152
(insert-records (name-of (table-of slot))
153
(append (columns-of slot) (columns-of other-slot))
154
(append (object-writer value) (object-writer object)))))
156
(defun store-m-n-association-end-set (object slot value)
157
"Stores the non lazy list association end value without local side effects into the database."
158
(delete-m-n-association-end-set object slot)
160
(mapc #L(insert-into-m-n-association-end-set object slot !1) value)))
162
(defun store-slot (object slot value)
163
"Stores a single slot without local side effects into the database."
164
(cond ((and (typep slot 'persistent-association-end-effective-slot-definition)
165
(eq (association-kind-of (association-of slot)) :1-1)
166
(secondary-association-end-p slot))
167
(when-bind other-object (slot-value-using-class (class-of object) object slot)
168
(bind ((other-slot (other-effective-association-end-for (class-of other-object) slot)))
169
(store-slot other-object other-slot nil)))
171
(bind ((other-slot (other-effective-association-end-for (class-of value) slot)))
172
(store-slot value other-slot object))))
173
((and (typep slot 'persistent-association-end-effective-slot-definition)
174
(eq (association-kind-of (association-of slot)) :1-n)
175
(eq (cardinality-kind-of slot) :n))
177
(persistent-p object))
178
(store-1-n-association-end-set object slot value)))
179
((and (typep slot 'persistent-association-end-effective-slot-definition)
180
(eq (association-kind-of (association-of slot)) :m-n))
182
(persistent-p object))
183
(store-m-n-association-end-set object slot value)))
184
((set-type-p (normalized-type-of slot))
185
(store-slot-set object slot value))
187
(when-bind columns (columns-of slot)
188
(update-records (name-of (table-of slot))
190
(store-slot-value slot value)
191
(id-column-matcher-where-clause object))))))
193
(defun store-prefetched-slots (object)
194
"Stores all prefetched slots without local side effects into the database. Executes one insert statement for each table."
195
(bind ((prefetched-slots (prefetched-slots-of (class-of object)))
196
(tables (delete-duplicates (mapcar #'table-of prefetched-slots))))
197
(dolist (table tables)
198
(bind ((slots (collect-if #L(eq (table-of !1) table) prefetched-slots))
199
(slot-values (mapcar #L(cached-slot-boundp-or-value-using-class (class-of object) object !1) slots))
200
(oid-columns (oid-columns-of table))
201
(columns (mappend #'columns-of slots))
202
(oid-values (oid-values object))
203
(rdbms-values (mappend #L(store-slot-value !1 !2) slots slot-values)))
204
(if (persistent-p object)
205
(update-records (name-of table) columns rdbms-values (id-column-matcher-where-clause object))
206
(insert-records (name-of table) (append oid-columns columns) (append oid-values rdbms-values)))))
207
(unless (persistent-p object)
208
(dolist (table (set-difference (data-tables-of (class-of object)) tables))
209
(insert-records (name-of table) (oid-columns-of table) (oid-values object))))))
211
(defun store-all-slots (object)
212
"Stores all slots wihtout local side effects into the database."
213
(store-prefetched-slots object)
214
(mapc #L(store-slot object !1 (cached-slot-boundp-or-value-using-class (class-of object) object !1))
215
(non-prefetched-slots-of (class-of object))))
220
(defun id-column-matcher-where-clause (object &optional (id-name +id-column-name+))
221
(sql-binary-operator :name '=
222
:left (sql-identifier :name id-name)
223
:right (sql-literal :type +oid-id-sql-type+ :value (id-of object))))
225
(defun id-column-list-matcher-where-clause (values &optional (id-name +id-column-name+))
226
(sql-binary-operator :name 'in
227
:left (sql-identifier :name id-name)
228
:right (mapcar (lambda (value)
229
(sql-literal :type +oid-id-sql-type+ :value (id-of value)))