Skip to content

Commit

Permalink
Add clojure.set/join (#431)
Browse files Browse the repository at this point in the history
  • Loading branch information
PEZ authored Dec 9, 2023
1 parent adae713 commit 0e843d6
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

[Squint](https://github.com/squint-cljs/squint): ClojureScript syntax to JavaScript compiler

## Unreleased

- Add `clojure.set/join`

## 0.4.77 (2023-12-09)

- Add `clojure.set` functions `select`, `rename-keys`, `rename`, `project`, and `map-invert` ([@PEZ](https://github.com/PEZ))
Expand Down
23 changes: 23 additions & 0 deletions src/squint/set.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,27 @@ export function map_invert(xmap) {
return {};
}
return core.reduce_kv((m, k, v) => core.assoc_BANG_(m, v, k), core.empty(xmap), xmap);
}

export function join(xrel, yrel, kmap) {
if (kmap === undefined) { // natural join
if (core.seq(xrel) && core.seq(yrel)) {
const ks = intersection(core.set(core.keys(core.first(xrel))), core.set(core.keys(core.first(yrel))));
const [r, s] = core.count(xrel) <= core.count(yrel) ? [xrel, yrel] : [yrel, xrel];
const idx = core.group_by(core.juxt(...ks), r);
return core.reduce((ret, x) => {
const found = core.get(idx, core.juxt(...ks)(x));
return found ? core.reduce((acc, y) => core.conj(acc, core.merge(y, x)), ret, found) : ret;
}, new Set(), s);
} else {
return new Set();
}
} else { // arbitrary key mapping
const [r, s, k] = core.count(xrel) <= core.count(yrel) ? [xrel, yrel, map_invert(kmap)] : [yrel, xrel, kmap];
const idx = core.group_by(core.juxt(...core.vals(k)), r);
return core.reduce((ret, x) => {
const found = core.get(idx, core.juxt(...core.keys(k))(x));
return found ? core.reduce((acc, y) => core.conj(acc, core.merge(y, x)), ret, found) : ret;
}, new Set(), s);
}
}
51 changes: 50 additions & 1 deletion test/squint/compiler_test.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -2015,13 +2015,62 @@
(set/map-invert {})
(set/map-invert {:a 1, :b 2, :c 3})
(set/map-invert (new js/Map [[:a 1] [:d 3]]))]" {:repl true
:context :return})
:context :return})
vs (js/eval (wrap-async js))]
(let [expected [{}
{}
{1 :a 2 :b 3 :c}
(new js/Map (clj->js [[1 :a] [3 :d]]))]
pairs (map vector expected vs)]
(doseq [[expected s] pairs]
(is (eq expected s) (str "expected vs actual:"
(util/inspect expected) (util/inspect s)))))))
(testing "join"
(p/let [js (compiler/compile-string "(ns foo (:require [clojure.set :as set]))
[(set/join #{ {:a 1} {:a 2} } #{ {:b 1} {:b 2} })
(set/join #{ {:name \"betsy\" :owner \"brian\" :kind \"cow\"}
{:name \"jake\" :owner \"brian\" :kind \"horse\"}
{:name \"josie\" :owner \"dawn\" :kind \"cow\"} }
#{ {:kind \"cow\" :personality \"stoic\"}
{:kind \"horse\" :personality \"skittish\"} })
(set/join #{ {:name \"betsy\" :owner \"brian\" :kind \"cow\"}
{:name \"jake\" :owner \"brian\" :kind \"horse\"}
{:name \"josie\" :owner \"dawn\" :kind \"cow\"} }
#{ {:species \"cow\" :personality \"stoic\"}
{:species \"horse\" :personality \"skittish\"} }
{:kind :species})]" {:repl true
:context :return})
vs (js/eval (wrap-async js))]
(let [set (fn [& xs] (new js/Set xs))
expected [(set #js {:a 1, :b 1} #js {:a 1, :b 2} #js {:a 2, :b 1} #js {:a 2, :b 2})
(set #js {:name "betsy", :owner "brian", :kind "cow", :personality "stoic"}
#js {:name "jake", :owner "brian", :kind "horse", :personality "skittish"}
#js {:name "josie", :owner "dawn", :kind "cow", :personality "stoic"})
(set #js {:name "betsy", :owner "brian", :kind "cow", :species "cow", :personality "stoic"}
#js {:name "jake", :owner "brian", :kind "horse", :species "horse", :personality "skittish"}
#js {:name "josie", :owner "dawn", :kind "cow", :species "cow", :personality "stoic"})]
pairs (map vector expected vs)]
(doseq [[expected s] pairs]
(is (eq expected s) (str "expected vs actual:"
(util/inspect expected) (util/inspect s)))))))
(testing "join-renaming-keys"
(p/let [js (compiler/compile-string "(ns foo (:require [clojure.set :as set]))
[(set/project
(set/join #{{:user-id 2, :name \"jake\", :age 28, :type \"company\"}
{:user-id 3, :name \"amanda\", :age 63, :type \"personal\"}
{:user-id 1, :name \"john\", :age 22, :type \"personal\"}}
(set/rename #{{:acc-id 2, :user-id 2, :amount 1200, :type \"saving\"}
{:acc-id 3, :user-id 1, :amount 850.1, :type \"debit\"}
{:acc-id 1, :user-id 1, :amount 300.45, :type \"saving\"}}
{:type :atype}))
[:user-id :acc-id :type :atype])]" {:repl true
:context :return})
vs (js/eval (wrap-async js))]
(let [set (fn [& xs] (new js/Set xs))
expected [(set #js {:user-id 1, :acc-id 1, :type "personal", :atype "saving"}
#js {:user-id 2, :acc-id 2, :type "company", :atype "saving"}
#js {:user-id 1, :acc-id 3, :type "personal", :atype "debit"})]
pairs (map vector expected vs)]
(doseq [[expected s] pairs]
(is (eq expected s) (str "expected vs actual:"
(util/inspect expected) (util/inspect s))))))))
Expand Down

0 comments on commit 0e843d6

Please sign in to comment.