Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

transform and changing pick! to pick #71

Closed
wants to merge 1 commit into from

2 participants

@ninjudd
Collaborator

Hey Lau,

I'm submitting this as a pull request even though I could commit it directly because I want you to take a look and sign off first.

I added a transform method to RTable that lets you specify a transform function to be executed after deref. I also implmented pick using it based on the conversation we had in #clojureql. The transform function will also be really useful for other data transformations that have to be done in Clojure. i.e:

;; i just want a list of emails for all users
@(transform users #(map :email %))

;; several fields are json, and i need to parse them when records are loaded
@(transform records #(map parse-json %))

Transforms are also composable:

;; only parse and return the first record
@(-> records (transform #(map parse-json %)) (transform first))

I'm pretty excited about this feature as it is going to clean up a lot of our code and make ClojureQL even easier for our engineers to use.

Let me know if you have any questions.

Cheers,
:justin

@bendlas
Collaborator

Committed as 7584a38

@bendlas bendlas closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 1, 2011
  1. @ninjudd

    add transform method for modifying results on deref. implement pick u…

    ninjudd authored
    …sing it. add tests for all of this.
This page is out of date. Refresh to see the latest.
Showing with 52 additions and 18 deletions.
  1. +25 −18 src/clojureql/core.clj
  2. +27 −0 test/clojureql/test/integration.clj
View
43 src/clojureql/core.clj
@@ -135,15 +135,12 @@
(modify \"TOP 5\")) ; MSSqls special LIMIT syntax
(-> (table :one) distinct)")
- (pick! [this kw]
- "For queries where you know only a single result will be returned,
- pick calls the keyword on that result. You can supply multiple keywords
- in a collection. Returns nil for no-hits, throws
- an exception on multiple hits.
-
+ (transform [this fn]
+ "Transforms results using fn when deref or with-results is called.
+ The pick helper function is implemented using this.
Ex. (-> (table :users)
- (select (where (= :id 5))) ; We know this will only match 1 row
- (pick :email))")
+ (select (where (= :id 5)))
+ (transform #(map :email %))")
(conj! [this records]
"Inserts record(s) into the table
@@ -194,7 +191,7 @@
(defrecord RTable [cnx tname tcols restriction renames joins
grouped-by pre-scope scope order-by modifiers
- combinations having]
+ combinations having transform]
clojure.lang.IDeref
(deref [this]
(apply-on this doall))
@@ -202,15 +199,16 @@
Relation
(apply-on [this f]
(with-cnx cnx
- (with-results* (compile this cnx) f)))
+ (with-results* (compile this cnx)
+ (fn [results]
+ (f (if transform
+ (transform results)
+ results))))))
- (pick! [this kw]
- (let [results @this]
- (if (or (= 1 (count results)) (empty? results))
- (if (coll? kw)
- (map (first results) kw)
- (kw (first results)))
- (throw (Exception. "Multiple items in resultsetseq, keyword lookup not possible")))))
+ (transform [this fn]
+ (if transform
+ (assoc this :transform (comp fn transform))
+ (assoc this :transform fn)))
(select [this clause]
(if (and (has-aggregate? this) (seq grouped-by))
@@ -421,7 +419,7 @@
(let [connection-info (if (fn? connection-info)
(connection-info)
connection-info)]
- (RTable. connection-info table-name [:*] nil nil nil nil nil nil nil nil nil nil))))
+ (RTable. connection-info table-name [:*] nil nil nil nil nil nil nil nil nil nil nil))))
(defmacro declare-tables
"Given a connection info map (or nil) and as list
@@ -442,3 +440,12 @@
"Returns true if tinstance is an instnce of RTable"
[tinstance]
(instance? clojureql.core.RTable tinstance))
+
+(defn pick [table kw]
+ (transform table
+ (fn [results]
+ (if (or (= 1 (count results)) (empty? results))
+ (if (coll? kw)
+ (map (first results) kw)
+ (kw (first results)))
+ (throw (Exception. "Multiple items in resultsetseq, keyword lookup not possible"))))))
View
27 test/clojureql/test/integration.clj
@@ -183,3 +183,30 @@
[:name :as :dupe]])]
(is (= (map :name @users)
(map :dupe @tbl)))))
+
+(database-test test-transform
+ (is (= @(transform users #(map (juxt :id :name) %))
+ '([1 "Lau Jensen"] [2 "Christophe"] [3 "sthuebner"] [4 "Frank"]))))
+
+(database-test test-transform-and-with-results
+ (with-results [names (transform users #(map :name %))]
+ (is (= names
+ '("Lau Jensen" "Christophe" "sthuebner" "Frank")))))
+
+(database-test test-pick
+ (is (= @(-> (select users (where (= :id 4)))
+ (pick :name))
+ "Frank")))
+
+(database-test test-composing-transforms
+ (is (= @(-> users
+ (transform #(map (juxt :id :name) %))
+ (transform first))
+ [1 "Lau Jensen"])))
+
+(database-test test-transform-with-join
+ (is (= @(-> users
+ (transform #(map (juxt :name :wage) %))
+ (join (transform salary first) ; this transform will be ignored
+ (where (= :users.id :salary.id))))
+ '(["Lau Jensen" 100] ["Christophe" 200] ["sthuebner" 300] ["Frank" 400]))))
Something went wrong with that request. Please try again.