Skip to content

Instantly share code, notes, and snippets.

@quephird
Last active February 20, 2016 17:42
Show Gist options
  • Save quephird/4d3dac813b61ce477778 to your computer and use it in GitHub Desktop.
Save quephird/4d3dac813b61ce477778 to your computer and use it in GitHub Desktop.
Inspired by some code I read this past week.
;; After seeing some code whereby a suite of function implementations for CRUD operations
;; for a set of object types were exactly the same except for the entity in question,
;; I wondered if there was a way to somehow share implementations. It's not quite OO
;; inheritance but this seems to do the job; I have no idea if this is considered
;; idiomatic Clojure code.
(ns fun-with-protocols-and-records)
;; Based on http://david-mcneil.com/post/1475458103/implementation-inheritance-in-clojure
;;
;; This example illustrates how to pass things other than the record type itself
;; to the protocol functions.
;; Create a base record type representing an object
;; that can map to a datanase table, identified
;; by the table and db parameters.
(defrecord Entity [table db])
;; This defines a protocol that establishes
;; the set of CRUD operations that must be implemented.
(defprotocol Persistable
(find [entity id])
(update [entity id attrs])
(insert [entity attrs]))
;; This defines a baseline set of implementations.
(def crud-ops
{:find (fn [entity id]
(str "Found a " (:table entity) " with id " id " in " (:db entity) "."))
:update (fn [entity id attrs]
(str "Updated attributes " attrs " of a " (:table entity) " with id " id " in " (:db entity) "."))
:insert (fn [entity attrs]
(str "Inserted a new " (:table entity) " with attributes " attrs " in " (:db entity) "."))})
;; This provides the implementations above to the protocol,
;; and associates them with the Entity record type.
(extend Entity
Persistable
crud-ops)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Create some entities
(def person (Entity. :person :oracle-instance))
(def address (Entity. :address :postgress-instance))
;; Do some CRUD ops and see that they "touch" different
;; tables and databases even though it's the same API calls
;; for each record type.
(find person 42)
(insert address {:street "123 Main Street" :city "New York" :state-code "NY"})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment