             (set! end? true)
             (.search this 1)))))
 
-;; TODO treeterator (key-ix->needed? , key-ix->produced?)
-
 (defn intersection [iterators]
+  (assert (> (alength iterators) 0))
+  (assert (every? #(= (.-key-len (aget iterators 0)) (.-key-len %)) iterators))
   (if (> (alength iterators) 1)
     (if (some #(.-end? %) iterators)
       (Intersection. iterators true)
-      (let [intersection (Intersection. (into-array (sort-by #(.key %) key-compare iterators)) false)]
+      (let [intersection (Intersection. (into-array (sort-by #(.key %) key-compare iterators)) false (.-key-len (aget iterators 0)))]
         (.search intersection 0)
         intersection))
     (aget iterators 0)))
 
-(defn iter-seq [iterator]
-  (let [results #js []]
-    (while (false? (.-end? iterator))
-      (.push results (.key iterator))
-      (.next iterator))
-    results))
-
-(deftype Join [^:mutable key-ix iterators key-ix->intersection key-ix->iterator->present? ^:mutable end?]
+;; works on tries
+(deftype Join [^:mutable key-ix iterators key-ix->intersection key-ix->iterator->present? ^:mutable end? key-len]
   Object
   (key [this]
        (when (false? end?)
          (.key (aget key-ix->intersection key-ix))))
+  (val [this]
+       (when (false? end?)
+         (.val (aget key-ix->intersection key-ix))))
   (maintain [this]
             (set! end? (.-end? (aget key-ix->intersection key-ix))))
   (next [this]

            (.reset (aget iterators i))))
        (.maintain this))))

(defn join [trees num-vars tree->vars]
  (assert (> num-vars 0))
  (dotimes [i (alength trees)]
    (let [tree-vars (aget tree->vars i)]
      (assert (== (alength tree-vars) (.key-len (aget trees i))))
      (dotimes [j (alength tree-vars)]
        (assert (< (aget tree-vars j) num-vars)))))
  (let [iterators (amap trees i _ (iterator (aget trees i)))
        var->trees #js []
        var->tree->present? #js []
        var->intersection #js []]
    (dotimes [i num-vars]
      (.push var->trees #js [])
      (let [tree->present? #js []]
        (.push var->tree->present? tree->present?)
        (dotimes [j (alength trees)]
          (.push tree->present? false))))
    (dotimes [tree (alength trees)]
      (let [tree-vars (aget trees tree)]
        (dotimes [j (alength tree-vars)]
          (let [var (aget tree-vars j)]
            (.push (aget var->trees var) tree)
            (aset var->tree->present? var tree true)))))
    (dotimes [i num-vars]
      (.push var->intersection i (intersection (aget var->trees i))))
    (let [join (Join. 0 iterators var->intersection var->tree->present? false)]
      (.maintain join)
      join)))

;; TESTS


  (reset [this]
         (.reset iterator)))

(defn trieterator [iterator]
  (Trieterator. iterator (least-key (.-key-len iterator)) nil -1 0 (.-end? it) (.-key-len iterator)))

;; works on trees
(deftype Intersection [iterators ^:mutable end? key-len]
  Object
  (key [this]
       (when (false? end?)
