+(defun %select-objects (type select-fn query)
+ (mapcar (curry 'make-object-from-plist type)
+ (apply select-fn (intern (format nil "*"))
+ (if (string-equal (first query) :from)
+ query
+ (append `(:from ,type) query)))))
+
+(defun select-objects (type &rest query)
+ (%select-objects type #'select query))
+
+(defun select-only-n-objects (n type &rest query)
+ (let ((fields (if (eq :fields (car query))
+ (loop
+ :for cons :on (cdr query)
+ :if (not (keywordp (car cons)))
+ :collect (car cons) into fields
+ :else :do
+ (setf query cons)
+ (return (nreverse (print fields)))
+ :finally
+ (setf query cons)
+ (return (nreverse (print fields))))
+
+ (list (intern "*")))))
+ (let ((results
+ (%query
+ (print `(:limit (:select
+ ,@fields
+ ,@(if (string-equal (first query) :from)
+ (print query)
+ (append `(:from ,type) query)))
+ ,n)))))
+ (if (eql 1 n)
+ (make-object-from-plist type (first results))
+ (mapcar (curry 'make-object-from-plist type) results)))))
+
+(defun make-object-from-plist (type plist)
+ (let* ((class (find-class type))
+ (object (make-instance class))
+ (slotds (class-slots class)))
+
+ (loop
+ :for (key val) :on plist :by #'cddr
+ :do
+ (dolist (slotd (remove key slotds
+ :key #'slot-definition-column-name
+ :test-not #'string-equal))
+
+ (setf (slot-value-using-class class object slotd) val))
+ :finally (return (reinitialize-instance object)))))
+
+(defun make-object (type &rest plist)
+ (make-object-from-plist type plist))
+