 (defn- lhs-upserts [old-indeces i ks vs join-fn])
 (defn- lhs-deletes [old-indeces i ks vs join-fn])
 
-(defn- lhs-view [indeces lhs-pk-key lhs-fk-keys join-fn joined-model]
+(defn- lhs-view [indeces lhs-pk-key lhs-fk-keys join-fn join-pk joined-model]
   (reify
    View
    ;; singleton changes
-   (on-upsert [_ upsertion] ((swap*! indeces lhs-upsert lhs-pk-key lhs-fk-keys upsertion join-fn joined-model) []) nil) ;TODO - pass in views to notifier
-   (on-delete [_ deletion]  ((swap*! indeces lhs-delete  lhs-pk-key lhs-fk-keys deletion join-fn joined-model) []) nil) ;TODO - pass in views to notifier
+   (on-upsert [_ upsertion] ((swap*! indeces lhs-upsert lhs-pk-key lhs-fk-keys upsertion join-fn join-pk joined-model) []) nil) ;TODO - pass in views to notifier
+   (on-delete [_ deletion]  ((swap*! indeces lhs-delete  lhs-pk-key lhs-fk-keys deletion join-fn join-pk joined-model) []) nil) ;TODO - pass in views to notifier
    ;; batch changes
    (on-upserts [_ upsertions] (swap! indeces lhs-upserts lhs-fk-keys upsertions join-fn) nil)
    (on-deletes [_ deletions]  (swap! indeces lhs-deletes lhs-fk-keys deletions join-fn) nil)))
 
 ;; TODO: return a pair - first is notification fn, second is new-indeces - use swap*! to apply
 
-(defn- rhs-upsert [old-indeces i rhs-pk-key rhs-fk-key lhs-fk-keys rhs join-fn joined-model]
+(defn- rhs-upsert [old-indeces i rhs-pk-key rhs-fk-key lhs-fk-keys rhs join-fn join-pk joined-model]
   (let [fk (rhs-fk-key rhs)
 	new-indeces (rhs-assoc old-indeces i rhs-pk-key fk rhs)
 	lhs-indeces (first old-indeces)

;;--------------------------------------------------------------------------------
;; this layer encapsulates access to both lhs and rhs at the same time...

(defn- derive-joins [rhs-indeces lhs-fk-keys lhs join-fn]
  (map
   (fn [rhses] (let [join (apply join-fn lhs rhses)] [(:name join) join])) ;TODO - pass in join-pk
   (permute [[]] (rhses-get rhs-indeces lhs-fk-keys lhs))))

;;--------------------------------------------------------------------------------

(defn- lhs-upsert [old-indeces lhs-pk-key lhs-fk-keys lhs join-fn joined-model]
  (let [new-indeces (lhs-assoc old-indeces lhs-pk-key lhs-fk-keys lhs)
	join-pairs (derive-joins (second new-indeces) lhs-fk-keys lhs join-fn)
	joins (vals (reduce conj {} join-pairs))]
    [new-indeces (fn [_] (on-upserts joined-model joins))]))

(defn- lhs-delete [old-indeces lhs-pk-key lhs-fk-keys lhs join-fn joined-model]
  (let [new-indeces (lhs-dissoc old-indeces lhs-pk-key lhs-fk-keys lhs)
	join-pairs (derive-joins (second new-indeces) lhs-fk-keys lhs join-fn)
	joins (vals (reduce conj {} join-pairs))]
    [new-indeces (fn [_] (on-deletes joined-model joins))]))


	rhs-indeces (second new-indeces)
	joins (mapcat
	       (fn [lhs] 
		   (let [join-pairs (derive-joins rhs-indeces lhs-fk-keys lhs join-fn join-pk)]
		     (vals (reduce conj {} join-pairs))))
	       lhses)]
    [new-indeces (fn [_] (on-upserts joined-model joins))]
    ))

;;; TODO - ugly, slow, ...
(defn- rhs-delete [old-indeces i rhs-pk-key rhs-fk-key lhs-fk-keys rhs join-fn join-pk joined-model]
  (let [fk (rhs-fk-key rhs)
	old-rhs-indeces (second old-indeces)
	lhs-indeces (first old-indeces)
	lhses (lhses-get lhs-indeces i fk)
	old-joins (mapcat
		   (fn [lhs] (vals (reduce conj {} (derive-joins old-rhs-indeces lhs-fk-keys lhs join-fn join-pk))))
		   lhses)
	new-indeces (rhs-dissoc old-indeces i rhs-pk-key fk rhs)
	new-rhs-indeces (second new-indeces)
	new-joins (mapcat
		   (fn [lhs] (vals (reduce conj {} (derive-joins new-rhs-indeces lhs-fk-keys lhs join-fn join-pk))))
		   lhses)
	joins (remove (fn [i] (contains? (apply hash-set new-joins) i)) old-joins)
	]
