Skip to content

Instantly share code, notes, and snippets.

@camsaul
Created June 13, 2019 17:07
Show Gist options
  • Save camsaul/81bc81338726d4e618b8a36ce7433ff9 to your computer and use it in GitHub Desktop.
Save camsaul/81bc81338726d4e618b8a36ce7433ff9 to your computer and use it in GitHub Desktop.
Mongo driver ideas
(defn- normalize-details [details]
(let [{:keys [dbname host port user pass ssl authdb tunnel-host tunnel-user tunnel-pass additional-options]
:or {port 27017, pass "", ssl false}} details
;; ignore empty :user and :pass strings
user (when (seq user)
user)
pass (when (seq pass)
pass)
authdb (if (seq authdb)
authdb
dbname)]
{:host host
:port port
:user user
:authdb authdb
:pass pass
:dbname dbname
:ssl ssl
:additional-options additional-options}))
(defn- srv-connection-info
"Docstring goes here"
[{:keys [host port user authdb pass dbname ssl additional-options]}]
(let [conn-opts (connection-options-builder :ssl? ssl, :additional-options additional-options)
authdb (if (seq authdb)
authdb
dbname)
conn-str (format "mongodb+srv://%s:%s@%s/%s" user pass host authdb)]
{:type :srv
:uri (MongoClientURI. conn-str conn-opts)}))
(defn- normal-connection-info
"Docstring goes here"
[{:keys [host port user authdb pass dbname ssl additional-options]}]
(let [server-address (mg/server-address host port)
credentials (when user
(mcred/create user authdb pass))
^MongoClientOptions$Builder opts (connection-options-builder :ssl? ssl, :additional-options additional-options)]
{:type :normal
:server-address server-address
:options (-> opts .build)}))
(defn- fqdn?
"A very simple way to check if a hostname is fully-qualified:
Check if there are exactly two periods in the name."
[host]
(= 2 (-> host frequencies (get \.))))
(defn- details->mongo-connection-info [{:keys [host], :as details}]
((if (fqdn? host)
srv-connection-info
normal-connection-info) details))
(defmulti ^:private connect
"Connect to MongoDB using Mongo `connection-info`, return a tuple of `[mongo-client db]`, instances of `MongoClient`
and `DB` respectively."
{:arglists '([connection-info])}
:type)
(defmethod connect :srv
[{:keys [^MongoClientURI uri]}]
(let [mongo-client (MongoClient. uri)]
(if-let [db-name (.getDatabase uri)]
[mongo-client (.getDB conn db-name)]
(throw
(IllegalArgumentException.
(str (trs "No database name specified in URI. Monger requires a database to be explicitly configured.")))))))
(defmethod connect :normal
[:keys [server-address options]]
(let [do-connect (partial mg/connect server-address options)
mongo-client (if credentials
(do-connect credentials)
(do-connect))]
[mongo-client (mg/get-db mongo-client dbname)]))
(defn -with-mongo-connection
"Run `f` with a new connection (bound to `*mongo-connection*`) to `database`. Don't use this directly; use
`with-mongo-connection`."
[f database]
(let [details (database->details database)]
(ssh/with-ssh-tunnel [details-with-tunnel details]
(let [connection-info (details->mongo-connection-info (normalize-details details-with-tunnel))
[mongo-client db] (connect connection-info)]
(log/debug (u/format-color 'cyan (trs "Opened new MongoDB connection.")))
(try
(binding [*mongo-connection* db]
(f *mongo-connection*))
(finally
(mg/disconnect mongo-client)
(log/debug (u/format-color 'cyan (trs "Closed MongoDB connection.")))))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment