diff --git a/README b/README deleted file mode 100644 index c52d6a0..0000000 --- a/README +++ /dev/null @@ -1,149 +0,0 @@ -h1. Relational Algebra for Clojure - -h2. Description - -Implementation of the relational operators: project, select (restrict), -rename, crossproduct, various joins, union, difference and intersection. - -See example code at the bottom of hoeck/rel/reflection.clj - -To use it in clojure, include this directiory to your -classpath and then simply type (use 'hoeck.rel.reflection). - -Needs also some -"clojure.contrib":http://code.google.com/p/clojure-contrib/ modules -and "lazymap":http://bitbucket.org/kotarak/lazymap from kotarak. - -h2. Some examples using the reflection relations - -* Load the hoeck.rel library -
-
-user> (use 'hoeck.rel.reflection)
-
-
-
-* Print all accessible relations in a map rel-name -> fields
-
-
-user> (with-relations (pprint (into {} (field-map (relations) :relation :field))))
-{:publics (:ns :name :varname),
- :namespace (:name),
- :interfaces (:class :interface),
- :methods (:returntype :returns-array :modifiers :arity :class :name),
- :imports (:ns :class :name),
- :jars (:jar :time :compressed-size :path :comment :name :directory :size),
- :interns (:ns :name :varname),
- :classpaths (:path),
- :files (:time :path :name :directory :size),
- :method-args (:arity :position :class :method :type),
- :classes (:super :class :type :modifiers),
- :refers (:ns :name :varname),
- :aliases (:ns :name :alias)}
-
-
-
-* Private definitions in the hoeck.rel.reflection namespace
-
-
-user> (with-relations (project (select (difference :interns :publics)
- (= ~ns 'hoeck.rel.reflection))
- :name))
-#{{:name classnames-from-ns }
- {:name method-args }
- {:name class-interfaces }
- {:name path->package }
- {:name read-files-from-jar }
- {:name class-methods }
- {:name without-dotclass }
- {:name classnames-from-files}
- {:name class-tuple }
- {:name find-classnames }
- {:name classnames-from-jars }}
-
-
-
-* Relation of all files on the classpath, ordered by size
-
-
-user> (with-relations
- (order-by
- (project :files [(/ ~size 1000.0) :size-in-kb] :name :path)
- :size-in-kb
- '>))
-#{{:size-in-kb 43800.36, :name "rt.jar", :path "C:\\Programme\\Java\\jre6\\lib"}
- {:size-in-kb 6592.915, :name "charsets.jar", :path "C:\\Programme\\Java\\jre6\\lib"}
- ...}
-
-
-
-* Relations are first-class citizens
-
-
-user> (with-relations (def java-lang-classes (select :classes (rlike "^java\\.lang\\.[A-Z].*" ~class))))
-#'hoeck.rel.reflection/java-lang-classes
-
-user> (defn without-inner-classes [classes-rel]
- (select classes-rel (rlike "[^\\$]*" ~class)))
-#'hoeck.rel.reflection/without-inner-classes
-
-
-
-* The number of classes in the java.lang package
-
-
-user> (count (without-inner-classes java-lang-classes))
-108
-
-
-
-* All inner classes in the java.lang package
-(takes some time to compute, calculates all indexes over the :classes relation due to my poor difference implementation)
-
-
-user> (count (difference java-lang-classes (without-inner-classes java-lang-classes)))
-48
-
-
-
-* Number of implemented interfaces
-
-
-user> (with-relations (count (project :interfaces :interface)))
-2035
-
-
-
-* Total number of interfaces
-
-
-user> (with-relations (count (select :classes (= ~type :interface))))
-2580
-
-
-
-* Classes (directly) implementing clojure.lang.IFn
-
-
-user> (with-relations (-> (select :interfaces
- (= 'clojure.lang.IFn ~interface))
- (field-seq :class)
- (pprint)))
-(hoeck.mapped_map.MappedMap
- hoeck.magicmap.MagicMap
- clojure.lang.AFn
- clojure.lang.Keyword
- clojure.lang.Ref
- clojure.lang.Var)
-
-
-
-h2. TODO
-
-* ant build script
-* function-join
-* datalog (iris and/or clojure.contrib.datalog)
-* sql backend
-* index-aware select
-* more index types: sorted-index, none
-* other backends, query-by-example, constraints, query-compiler
diff --git a/README.textile b/README.textile
index f52d834..12146c4 100644
--- a/README.textile
+++ b/README.textile
@@ -25,15 +25,12 @@ Include the generated rel.jar in your classpath
h2. Some examples using the reflection relations
* Load the hoeck.rel library
-
-
+
user> (use 'hoeck.rel.reflection)
-
-
+
* Print all accessible relations in a map rel-name -> fields
-
-
+
user> (with-relations (pprint (into {} (field-map (relations) :relation :field))))
{:publics (:ns :name :varname),
:namespace (:name),
@@ -48,12 +45,10 @@ user> (with-relations (pprint (into {} (field-map (relations) :relation :field))
:classes (:super :class :type :modifiers),
:refers (:ns :name :varname),
:aliases (:ns :name :alias)}
-
-
+
* Private definitions in the hoeck.rel.reflection namespace
-
-
+
user> (with-relations (project (select (difference :interns :publics)
(= ~ns 'hoeck.rel.reflection))
:name))
@@ -68,12 +63,10 @@ user> (with-relations (project (select (difference :interns :publics)
{:name class-tuple }
{:name find-classnames }
{:name classnames-from-jars }}
-
-
+
* Relation of all files on the classpath, ordered by size
-
-
+
user> (with-relations
(order-by
(project :files [(/ ~size 1000.0) :size-in-kb] :name :path)
@@ -82,57 +75,45 @@ user> (with-relations
#{{:size-in-kb 43800.36, :name "rt.jar", :path "C:\\Programme\\Java\\jre6\\lib"}
{:size-in-kb 6592.915, :name "charsets.jar", :path "C:\\Programme\\Java\\jre6\\lib"}
...}
-
-
+
* Relations are first-class citizens
-
-
+
user> (with-relations (def java-lang-classes (select :classes (rlike "^java\\.lang\\.[A-Z].*" ~class))))
#'hoeck.rel.reflection/java-lang-classes
user> (defn without-inner-classes [classes-rel]
(select classes-rel (rlike "[^\\$]*" ~class)))
#'hoeck.rel.reflection/without-inner-classes
-
-
+
* The number of classes in the java.lang package
-
-
+
user> (count (without-inner-classes java-lang-classes))
108
-
-
+
* All inner classes in the java.lang package
(takes some time to compute, calculates all indexes over the :classes relation due to my poor difference implementation)
-
-
+
user> (count (difference java-lang-classes (without-inner-classes java-lang-classes)))
48
-
-
+
* Number of implemented interfaces
-
-
+
user> (with-relations (count (project :interfaces :interface)))
2035
-
-
+
* Total number of interfaces
-
-
+
user> (with-relations (count (select :classes (= ~type :interface))))
2580
-
-
+
* Classes (directly) implementing clojure.lang.IFn
-
-
+
user> (with-relations (-> (select :interfaces
(= 'clojure.lang.IFn ~interface))
(field-seq :class)
@@ -143,8 +124,7 @@ user> (with-relations (-> (select :interfaces
clojure.lang.Keyword
clojure.lang.Ref
clojure.lang.Var)
-
-
+
h2. TODO:
diff --git a/hoeck/rel/operators.clj b/hoeck/rel/operators.clj
index 399564c..9550259 100644
--- a/hoeck/rel/operators.clj
+++ b/hoeck/rel/operators.clj
@@ -56,6 +56,7 @@
(defmulti join join-dispatch) ;; natural-join
(defmulti outer-join join-dispatch) ;; right-outer-join
(defmulti full-outer-join join-dispatch)
+(defmulti fjoin op-dispatch-fn) ;; m
(defmulti union two-op-dispatch-fn)
(defmulti difference two-op-dispatch-fn)
diff --git a/hoeck/rel/structmaps.clj b/hoeck/rel/structmaps.clj
index 8504d4f..3225907 100644
--- a/hoeck/rel/structmaps.clj
+++ b/hoeck/rel/structmaps.clj
@@ -52,7 +52,6 @@
(next keys)))
ret)))
-
;; index tools
(defn- index-lookup
@@ -355,6 +354,8 @@
(magic-map a (fn ([] (keys b))
([k] (get b k)))))
+;;; joins
+
(defmethod join :clojure [R r S s]
(let [index-Ss (find (index S) s)
join-tuple (fn [r-tup] (let [friends (get (val index-Ss) (r-tup r))]
@@ -375,6 +376,14 @@
(is (= (set (fields j)) (set (concat (fields R) (filter #(not= :id %) (fields S))))) "joined fields")
(is (= (clean-index (index j)) (make-index j (fields j))) "index"))))
+(defmethod fjoin [R f] ;; much like project with an expression, but allows 1..n joins instead of 1..1 only
+ ;; f must return a seq of tuples or nil
+ (let []
+ (Relation (merge ^R {:fields (fields R) ()}) {}
+ {'seq _
+ 'get _
+ 'count _})))
+
(defmethod xproduct :clojure [R S]
(let [cross-tuple (fn [r-tup] (map #(merge r-tup %) S))]
(Relation. (merge ^S ^R {:fields (concat (fields R) (fields S))