 ;; a really clever impl might start lazy and become agressive during serialisation..
 (defn- ^ABC join-abc [^A a ^B b ^C c]
   (->ABC
-   (keyword (apply str (interpose "-" (list (name (:name a)) (name (:name b)) (name (:name c))))))
-   (+ (* 1000 (:version a)) (* 100 (:version b)) (* 10 (:version c)))
+   [(:name a) (:name b) (:name c)]
+   [ (:version a) (:version b) (:version c)]
    (:data b)
    (:data c)))
 
+(defn- abc-more-recent-than? [[a1 b1 c1][a2 b2 c2]]
+  (or (and (> a1 a2) (>= b1 b2) (>= c1 c2))
+      (and (> b1 b2) (>= a1 a2) (>= c1 c2))
+      (and (> c1 c2) (>= a1 a2) (>= b1 b2))))
+
 (deftest test-join-abc
-  (is (= (->ABC :a1-b1-c1 0 "b-data" "c-data") 
+  (is (= (->ABC [:a1 :b1 :c1] [0 0 0] "b-data" "c-data") 
 	 (join-abc (->A :a1 0 :b :c)(->B :b1 0 :b "b-data")(->C :c1 0 :c "c-data")))))
 
 (deftest test-permute

  Object
  (^String toString [_] (str name)))

(defrecord ABC [name ^int version b-data c-data]
  Object
  (^String toString [_] (str name)))


    ;; join - lhs - a1
    (on-upsert as a1)
    (is (= [[{:b [a1]}{:c [a1]}]{:b [b1]} {:c [c1]}] (data join)))
    (is (= {[:a1 :b1 :c1] (->ABC [:a1 :b1 :c1] [0 0 0] "b1-data" "c1-data")} (data joined-model)))

    ;; join - new rhs - b2
    (on-upsert bs b2)
    (is (= [[{:b [a1]}{:c [a1]}]{:b [b1 b2]} {:c [c1]}] (data join)))
    (is (= {
	   [:a1 :b1 :c1] (->ABC [:a1 :b1 :c1] [0 0 0] "b1-data" "c1-data")
	   [:a1 :b2 :c1] (->ABC [:a1 :b2 :c1] [0 0 0] "b2-data" "c1-data")}
	   (data joined-model)))

    ;; join - new rhs - c2
    (on-upsert cs c2)
    (is (= [[{:b [a1]}{:c [a1]}]{:b [b1 b2]} {:c [c1 c2]}] (data join)))
    (is (= {
	   [:a1 :b1 :c1] (->ABC [:a1 :b1 :c1] [0 0 0] "b1-data" "c1-data")
	   [:a1 :b2 :c1] (->ABC [:a1 :b2 :c1] [0 0 0] "b2-data" "c1-data")
	   [:a1 :b1 :c2] (->ABC [:a1 :b1 :c2] [0 0 0] "b1-data" "c2-data")
	   [:a1 :b2 :c2] (->ABC [:a1 :b2 :c2] [0 0 0] "b2-data" "c2-data")
	   }
	   (data joined-model)))
    ;; join - new lhs - a2
    (on-upsert as a2)
    (is (= [[{:b [a1 a2]}{:c [a1 a2]}]{:b [b1 b2]} {:c [c1 c2]}] (data join)))
    (is (= {
	   [:a1 :b1 :c1] (->ABC [:a1 :b1 :c1] [0 0 0] "b1-data" "c1-data")
	   [:a1 :b2 :c1] (->ABC [:a1 :b2 :c1] [0 0 0] "b2-data" "c1-data")
	   [:a1 :b1 :c2] (->ABC [:a1 :b1 :c2] [0 0 0] "b1-data" "c2-data")
	   [:a1 :b2 :c2] (->ABC [:a1 :b2 :c2] [0 0 0] "b2-data" "c2-data")
	   [:a2 :b1 :c1] (->ABC [:a2 :b1 :c1] [0 0 0] "b1-data" "c1-data")
	   [:a2 :b2 :c1] (->ABC [:a2 :b2 :c1] [0 0 0] "b2-data" "c1-data")
	   [:a2 :b1 :c2] (->ABC [:a2 :b1 :c2] [0 0 0] "b1-data" "c2-data")
	   [:a2 :b2 :c2] (->ABC [:a2 :b2 :c2] [0 0 0] "b2-data" "c2-data")
	   }
	   (data joined-model)))
    ;; what about amend-in/out ?
