 (defn for-experiment-named [q exp]
   (for-experiment q (subselect experiments (fields "id") (where {:file exp}))))
 
+(defn exp-by-name [exp]
+  (let [[{id :ID}]
+        (select experiments (fields "id") (where {:file exp}))]
+    id))
+
+; XXX expand model for probes/genes??
 (defn with-genes [q genes]
   (fields (where q {:probes.name [in genes]}) [:probes.name :gene]))
 
 (defn do-select [q]
   (exec q))
+
+; merge bin number and bin offset for a sample.
+(defn- merge-bin-off [sample]
+  (let [{i :I} sample]
+    (assoc sample :bin (quot i bin-size) :off (rem i bin-size))))
+
+(defn- bin-mapping [order {off :off sample :SAMPLE}]
+  [off (order sample)])
+
+(defn- pick-samples-fn [order [bin samples]]
+  [bin (partial ashuffle-float
+                (map (partial bin-mapping order) samples))])
+
+; Take an ordered list of requested samples, a list of samples (with indexes) in the
+; experiment, and generate fns to copy values from a score bin to an output array.
+; Returns one function for each score bin in the request.
+
+(defn- pick-samples-fns [s-req s-exp]
+  (let [order (zipmap s-req (range))
+        by-bin (group-by :bin s-exp)]
+    (apply hash-map (mapcat (partial pick-samples-fn order) by-bin))))
+
+; Take map of bin copy fns, list of scores rows, and a map of output arrays,
+; copying the scores to the output arrays via the bin copy fns.
+(defn- build-score-arrays [rows bfns out]
+  (dorun (map (fn [{i :I scores :EXPSCORES gene :GENE}]
+                ((bfns i) (out gene) scores))
+              rows))
+  out)
+
+(defn- col-arrays [columns n]
+  (zipmap columns (repeatedly (partial float-array n))))
+
+; XXX Need to fill in NAN for unknown samples.
+(defn genomic-read-req [req]
+  (let [{samples 'samples table 'table columns 'columns} req
+        eid (exp-by-name table)
+        s-in-exp (map merge-bin-off (exp-samples-in-list eid samples))
+        bins (map :bin s-in-exp)
+        bfns (pick-samples-fns samples s-in-exp)]
+
+    (-> (select-scores)
+        (for-experiment eid)
+        (with-genes columns)
+        (with-bins bins)
+        (do-select)
+        (build-score-arrays bfns (col-arrays columns (count samples))))))
+
+; doall is required so the seq is evaluated in db context.
+; Otherwise lazy map may not be evaluted until the context is lost.
+(defn genomic-source [reqs]
+  (doall (map #(update-in % ['data] merge (genomic-read-req %)) reqs)))
 
 (defn create[]
   (kdb/transaction

      (clear-by-exp exp)
      (delete experiments (where {:id exp})))))

(kdb/defdb cavmdb db)
(kconf/set-delimiters "`") ; for h2

; execute a sequence of sql statements
(defn- exec-statements [stmts]
  (dorun (map (partial exec-raw cavmdb) stmts)))

; TODO look up N
(defn- dataset-transform [ds]

                        `i` INT NOT NULL,
                        PRIMARY KEY(`eid`, `sid`))"])


;
; Table models
;

(declare probes scores experiments samples exp_samples)

(defentity cohorts
  (has-many experiments {:fk :cid})
