A TL;DR update on this in case anyone else has similar issues. Short
version - seriously consider congomongo, clutch etc.

Part 1 - The Past
==========

After some thinking, I headed towards deftype, to provide a level of
abstraction atop clojureql.

Queries can be incrementally refined like this (REPL example from book
namespace):

(-> (where (= :id "blah"))
    (select ["title", "binding"])
    (page 3))

and similar from within a model named namespace. More complicated
cases can be dealt with like this say, for a search:

(book/search {:keyword "beer"})

=>

(defmulti query-refine (fn [query [key val]] key))

(defmethod query-refine :keyword [query [_ keyword]]
  (where query (matches keyword)))

(defn search [search]
  (reduce query-refine (all) search))

This would get "all" books as a ClojureQL query, then refine as
appropriate.

Each function would return a new value of my type (key functions like
"all" and "where" bootstrap the type), until finally the type was
consumed as a seq. The type at any point contained the refined query
thus far, plus any metadata (a real map when I left it). The deftype
implemented seq by deref-ing the ClojureQL query and returning the
results.

A function like "page" above refines the query (to set the limit and
offset) and also adds it's own metadata to the type (a total function
to fetch the total result count via another refined query). The
pagination view code plucks it's total out later for display.

The namespace functions were created in each model namespace via
macro, so they hid the tiresome config of each "model". At this point
I discovered clj_record, which was trying to solve similar aims,
however I was totally onboard with composable ClojureQL queries at
this point, and so only the namespace building caught my eye.

Part 2 - The Present
============

It was actually working like a charm, showing promise if Active Record
is what you absolutely need, but I've since been able to gain the
possibility of changing data storage, and generally rebooting the app
to a large degree!

And so I've been hacking out some congomongo based code, which appears
to give me far less impedance mismatch. From 32 tables, I've boiled it
down to 6 collections. Many of the current tables are there to keep
relationships that are ideally nested anyway, and some are for unused
features I'll cull in the reboot, or push out to 3rd party platforms.
There is only one collection so far where a single rarely-updated
field might need to be stored redundantly, and I think that might
disappear when the full-text search implementation changes to
something like Lucene / Solr (redundancy desired there anyway).

In my controllers I've gone back to pretty simple code, and have been
striving to avoid nurturing much notion of model namespaces at all
(keeping namespaces function based, not one-per-model based). Aside
from the queries and associations, those namespaces dealt with
validation (Valip), but I think by-field-name validation could work
for me (my sector fields are always market sectors, my country fields
always ISO based etc). Will see how that pans out, but I'm very
pleasantly surprised thus far.

So it was pretty cool when I saw Rich's Strangeloop presentation
yesterday, as I've really felt like I've been battling this complexity
demon recently. I do feel like I'm winning now though.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to