Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Provide multiple implementations for a Clojure protocol

Tags:

clojure

I have a namespace that exposes common data-related functions (get-images, insert-user). I then have two database backends that have those same functions and implement them differently. They implement the interface as it were. Each backend is contained within a namespace.

I can't seem to be able to find a good solution on how to accomplish this.

I tried dynamically loading the ns but no luck. Once you do (:require [abc :as x]), the x isn't a real value.

I tried using defprotocol and deftype but that's all kinds of weird because the functions in the deftype need to be imported, too and that messes everything up for me.

Is there some idiomatic solution to this?

like image 838
Honza Pokorny Avatar asked Feb 14 '23 14:02

Honza Pokorny


1 Answers

I don't see why protocols are not sufficient?

In ns data.api:

(ns data.api)
(defprotocol DB
  (get-images [this]) 
  (insert-user [this]))

In ns data.impl1:

(ns data.impl1
  (:require [data.api :refer :all]))

(defrecord Database1 [connection-params]
  DB
  (get-images [_] ...)
  (insert-user [_] ...))

Same thing in ns data.impl2.

Then when you go to use a particular db, just create the correct record:

(ns data.user
  (:require [data.api :refer :all])
            [data.impl1 :refer (->Database1)])

(defn use-db []
  (let [db1 (->Database1 {})]
    (get-images db1)))
like image 139
Alex Miller Avatar answered Mar 06 '23 21:03

Alex Miller