-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathunserialization.lisp
78 lines (66 loc) · 3.28 KB
/
unserialization.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
(in-package :schemata)
;; Unserialization
(defgeneric unserialize-with-schema (schema data format))
(defmethod unserialize-with-schema ((schema object-schema) input format)
"Unserializes an schema object
Args: - object (list) : An schema object
- input (assoc-list) : An association list with values.
Probably obtained from parse-api-input.
See: parse-api-input (function)"
(let ((unserializer (object-unserializer schema))
(object-class (object-class schema)))
(cond
(unserializer (funcall unserializer input))
(object-class (unserialize-schema-object-to-class schema input object-class format))
(t input))))
(defun unserialize-schema-object-to-class (object input class format)
(unless (trivial-types:association-list-p input)
(validation-error "Not an object data: ~s" input))
(let ((instance (allocate-instance (find-class class))))
(loop for attribute in (object-attributes object)
do (let ((attribute-input (assoc (string (attribute-name attribute))
input
:test #'equalp
:key #'string)))
(cond
((and (not attribute-input)
(not (attribute-optional-p attribute)))
(validation-error "~A not provided" (attribute-name attribute)))
(attribute-input
(let ((attribute-value (unserialize-schema-attribute attribute (cdr attribute-input) format)))
(setf (slot-value instance (or (attribute-slot attribute)
(attribute-name attribute)))
attribute-value))))))
(initialize-instance instance)
instance))
(defun unserialize-schema-attribute (attribute input format)
(let ((unserializer (attribute-unserializer attribute)))
(if unserializer
(funcall unserializer)
(unserialize-with-schema (attribute-type attribute) input format))))
(defmethod unserialize-with-schema ((schema type-schema) data format)
(unserialize-with-type (schema-type schema) data format))
(defmethod unserialize-with-schema ((schema schema-reference-schema) data format)
(unserialize-with-schema (referenced-schema schema) data format))
(defmethod unserialize-with-schema ((schema list-of-schema) data format)
(loop for elem in (the list data)
collect (unserialize-with-schema (elements-schema schema) elem format)))
(defgeneric unserialize-with-type (type input format)
(:method (type input format)
(coerce input type))
(:method ((type (eql 'cl:integer)) input format)
(if (integerp input)
input
(parse-integer input)))
(:method ((type (eql 'boolean)) input format)
(if (stringp input)
(let ((true-strings (list "true" "t" "yes" "on"))
(false-strings (list "false" "f" "no" "off")))
(assert (member input (append true-strings false-strings) :test #'equalp)
nil "Invalid boolean ~A" input)
(member input true-strings :test #'equalp))
(not (null input))))
(:method ((type (eql 'cl:keyword)) input format)
(if (stringp input)
(intern (string-upcase input) :keyword)
(the keyword input))))