I'm trying to write some clojure which builds up a data-structure that will be valid clojure code as well. (note I'm not building a macro here: just a function that happens to return clojure code).
Here's my working bit:
(defn create-clause [ property operator value ]
(list (symbol operator) (symbol property) (symbol value))
)
(create-clause "b" "<" "5")
So this creates a 'clause' like this:
(< b 5)
And this works.
What I want to do is end up with something like this:
(and (= AccountType "current") (< Balance 0))
I can chain up a couple of clauses manually like this:
(list 'and (create-clause "a" "=" "current") (create-clause "b" "<" "0"))
Which results in:
(and (= a "current") (< b 0))
But I want a function that takes my 3-string arguments "property" "operator" "value" , creates the clause and results in a combined 'and' list of all the clauses which can be evaluated (assume the symbols are bound in a 'let' of course...)
EDIT: Got a bit closer but still no cigar....
Slightly refactored the func - so it now takes a single argument of a list , rather than 3 separate arguments:
(defn create-clause [ [ property operator value ] ]
(list (symbol operator) (symbol property) (symbol value))
)
(create-clause [ "b" "<" "5" ] )
Now using a loop/recur - and I can nearly get what I need:
(list 'and (loop [ input [ "a" "<" "10" , "b" "<" "5" ] output [] ]
(if (= (count input) 0) output
(recur (drop 3 input) (conj output (create-clause(take 3 input)))))))
The result of the above is:
(and [(< a 10) (< b 5)]) ; wrong - don't want that internal vector wrapper...
EDIT #2:
So I'm thinking I have accumulate the result somewhere in my loop - so I might was well stick to using the vector as above (but dropping the (list 'and...) ) - but then I should be able to apply something to the result of it which will have the effect of turning this something like this structure:
[ (= 1 1) (= 1 1) ]
Into this structure:
(and (= 1 1) (= 1 1))
But now I'm stuck again.....
EDIT #3:
Ok , I got there - I have ended up with an unholy mess - but at least it works and I can start refactoring now !
(conj (seq (loop [ input [ "AccountType" "=" "current" , "Balance" "<" 5 ] output [] ]
(if (= (count input) 0) output
(recur (drop 3 input) (conj output (create-clause(take 3 input))))))) 'and)
(and (= AccountType "current") (< Balance 5))