ANN: ClojureQL 1.0.0 finally released as public beta

30 views
Skip to first unread message

LauJensen

unread,
Nov 18, 2010, 2:10:16 PM11/18/10
to Clojure
Hi gents,

For those of you who have followed the development
of ClojureQL over the past 2.5 years you'll be excited
to know that ClojureQL is as of today being released
as 1.0.0 beta1.

That means that the significant primitives from Relational
Algebra are all in place and functional. The documentation
is there and I've even made a screencast in order to get
you guys started.

Personally Im excited about this version because it really
does change the way you work with a database. Queries
are incredibly composable!

For more information, please checkout this blogpost +
screencast:
http://bestinclass.dk/index.clj/2010/11/clojureql--1.0.0-now-in-beta.html

Best regards,
Lau

Stuart Campbell

unread,
Nov 18, 2010, 7:11:47 PM11/18/10
to clo...@googlegroups.com
Looks great! Can't wait to try it out!

Cheers,
Stuart

MarkH

unread,
Nov 18, 2010, 7:47:31 PM11/18/10
to Clojure
> screencast:http://bestinclass.dk/index.clj/2010/11/clojureql--1.0.0-now-in-beta....
>
> Best regards,
> Lau

Great stuff Lau. I enjoyed the screencast.

Jeff Rose

unread,
Nov 19, 2010, 4:23:33 AM11/19/10
to Clojure
Looks great, I'm giving it a try now. FYI, the github link in your
post is the private URL so it won't work for anyone but you.

-Jeff
> screencast:http://bestinclass.dk/index.clj/2010/11/clojureql--1.0.0-now-in-beta....
>
> Best regards,
> Lau

Sam Aaron

unread,
Nov 19, 2010, 4:28:33 PM11/19/10
to clo...@googlegroups.com
Looks really good. Great work,

Sam

---
http://sam.aaron.name

> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en

James Reeves

unread,
Nov 21, 2010, 2:44:53 PM11/21/10
to clo...@googlegroups.com
I've just been playing around with ClojureQL, and I'm very impressed
at how clean, elegant and idiomatic the syntax is. So far this is the
best SQL library I've come across - for any language.

- James

Mark Engelberg

unread,
Nov 21, 2010, 3:21:23 PM11/21/10
to clo...@googlegroups.com
ClojureQL is all about queries, right?  As far as I can tell, it provides no abstraction for creating tables, specifying indices, etc., correct?

LauJensen

unread,
Nov 23, 2010, 5:34:32 AM11/23/10
to Clojure
@Mark: Thanks! :)

@Jeff: Thanks a lot. Link is fixed now.

@Sam: Thanks!

@James: Wow - I should put that in my resume, thanks a lot !

@Mark E:
Half right.

ClojureQL has a major focus on queries as they are the largest
part of our interaction with databases. However it piggy-backs
on contrib.sql and the functions provided there for creating tables,
dropping them etc are well suited for the job, so simply use those.

ClojureQL also has conj!, disj! and update-in! for manipulating
tables.

And finally, I've just refurbished the compiler so that its not a
25 line beast of a recursive machine that automatically spawns
subselects for aggregates, limit/offset and predicates:

cql.core> (to-sql (-> (table {} :users)
(join (table {} :salary)
(where (= :users.id :salary.id)))
(outer-join (take (table :wages)
5) :left :id)
(join (select (table :test) (where (> :id
5))) (where (= :test.id :users.id)))
(project [:users.id :salary.wage])
(select (where (= :test.id :wages.id)))))

SELECT users.id,salary.wage,wages_subselect.*,test_subselect.* FROM
users
JOIN salary ON (users.id = salary.id) LEFT OUTER JOIN
(SELECT wages.* FROM wages LIMIT 5) AS wages_subselect USING(id)
JOIN (SELECT test.* FROM test WHERE (id > 5)) AS test_subselect ON
(test_subselect.id = users.id) WHERE (test_subselect.id =
wages_subselect.id)"

There are probably still a few minor quirks (what you see above is
fresh from the REPL),
but if nobody sues me in the next month and if I manage to
automatically paramterize all
queries 1.0.0 FINAL should be just up ahead.

Thanks to all who have tried this out already,
Lau

Wilson MacGyver

unread,
Nov 23, 2010, 10:57:07 AM11/23/10
to clo...@googlegroups.com
On Tue, Nov 23, 2010 at 5:34 AM, LauJensen <lau.j...@bestinclass.dk> wrote:
> And finally, I've just refurbished the compiler so that its not a
> 25 line beast of a recursive machine that automatically spawns
> subselects for aggregates, limit/offset and predicates:
>
> cql.core> (to-sql (-> (table {} :users)
>                            (join (table {} :salary)
>                                  (where (= :users.id :salary.id)))
>                            (outer-join (take (table :wages)
> 5) :left :id)
>                            (join (select (table :test) (where (> :id
> 5))) (where (= :test.id :users.id)))
>                            (project [:users.id :salary.wage])
>                            (select (where (= :test.id :wages.id)))))
>
> SELECT users.id,salary.wage,wages_subselect.*,test_subselect.* FROM
> users
> JOIN salary ON (users.id = salary.id) LEFT OUTER JOIN
> (SELECT wages.* FROM wages LIMIT 5) AS wages_subselect USING(id)
> JOIN (SELECT test.* FROM test WHERE (id > 5)) AS test_subselect ON
> (test_subselect.id = users.id) WHERE (test_subselect.id =
> wages_subselect.id)"
>

Great work. Has the updated version been pushed to clojars yet? Or do I
need to git pull and build manually?

--
Omnem crede diem tibi diluxisse supremum.

LauJensen

unread,
Nov 23, 2010, 5:01:53 PM11/23/10
to Clojure
@Wilson,

Normally I release the jar to clojars when I implement some major
change
of interest to the public, but the compiler above didn't not get
released
due to forgetfulness on my part!

I was reworking the predicate compiler into a very fancy record which
does automated parameterization of all predicates and wanted to
include this as well. It turned out quite nice, as the (toString)
interface
made most of the old code work:

cql.predicates> (where (or (= :x 5) (< 10 :y 5)))
#:cql.predicates.APredicate{:stmt ["(( ? = ? ) OR ( ? < ?
< ? ))"], :env ["x" 5 10 "y" 5]}
cql.predicates> (str *1)
"(( ? = ? ) OR ( ? < ? < ? ))"
cql.predicates> (:env *2)
["x" 5 10 "y" 5]

I hope to release this very shortly as its the final building block
needed
for 1.0.0 FINAL - Injection protection.

Lau

On Nov 23, 4:57 pm, Wilson MacGyver <wmacgy...@gmail.com> wrote:

Luke VanderHart

unread,
Nov 23, 2010, 7:56:35 PM11/23/10
to Clojure
Lau,

This is really impressive, and I can't wait to experiment with it.

That said, I'm curious as to what good use cases for this would be,
and what it's motivation is. SQL is already a highly specialized DSL
for slinging around relational data that most developers are already
pretty good with. I'm wondering how useful it is to have a separate
relational DSL. Is this motivated by the same "everything in Clojure"
philosophy (like Hiccup or Scriptjure)? Not that there's anything
wrong with that... I'm just curious as to use cases.

Or does it confer some other benefit over SQL besides being Clojure?
The only thing I see is the ability to reuse and compose fragments of
relational logic. Unarguably, that is very cool, but off the top of my
head I can't think of any particular benefit it would give, at least
in my apps. 99% of my database interaction is a fixed set of CRUD
operations, which (unless I'm missing something) would be just as easy
to write in SQL directly.

Thanks,
-Luke
> screencast:http://bestinclass.dk/index.clj/2010/11/clojureql--1.0.0-now-in-beta....
>
> Best regards,
> Lau

LauJensen

unread,
Nov 24, 2010, 3:37:07 AM11/24/10
to Clojure
Hi Luke,

Thanks!

Initially CQL0.1 was motivated by "everything in Clojure" which was
the driving design principle behind the first version of CQL. When
I scrapped that project (for reasons you can read on my blog) I
instead turned my attention towards Relational Algebra as this
gives you unique ways to compose and express your queries, in
my opinion far superior to the SQL language itself.

Example from our test suite: Lets say you want to define a table
which computes an aggregate on a column, ex counting pictures
by user id and then join those stats to your users table. In CQL
you will (hopefully) intuitively write:

(let [photo-counts (-> (table :photos)
(aggregate [[:count/* :as :cnt]]
[:id])))]
(-> (table :users)
(join photo-counts (= {:users.id :photos.id}))

I think thats really as simple as you can express that join operation.
However for the SQL to work/be efficient, you need to detect when
a join benefits from spawning subselects and ClojureQL handles this
for you completely transparently, so if you execute the above
statement
the following is actually generated and run:

"SELECT users.*,photos_aggregation.cnt FROM users
LEFT OUTER JOIN
(SELECT photos.user_id,count(photos.*) AS cnt FROM photos GROUP BY
user_id)
AS photos_aggregation ON (users.user_id = photos_aggregation.user_id)"

And notice how your reference to :id in photos is automatically
aliased
to photos_aggregation. There are SQL statements which are truely
complex
and it takes a long time to master SQL and get comfortable with such
queries.
It is my ambition that ClojureQL will take away that complexity while
still
generating the most efficient SQL statements possible. The
implications for
Q/A on your projects will be substantial I hope.

And even if I was only doing CRUD - I'd prefer to do it (and have my
developers do it)
in Clojure, which is guaranteed to compile to correct SQL.

Answers your question?

Lau

Luke VanderHart

unread,
Nov 24, 2010, 3:31:59 PM11/24/10
to Clojure
Thanks... I think I do see the benefit. I'll certainly give it a try
and see if I can get the feel of it.

One question... You say it generates optimized SQL. Does it take the
DBMS into account? I know the performance profiles of various SQL
idioms vary widely between MySQL and Oracle, for example - what may be
better as a subselect on one may sometimes be better as a join on
another.

Thanks so much for the detailed answer...

-Luke

Mike Meyer

unread,
Nov 24, 2010, 3:40:44 PM11/24/10
to clo...@googlegroups.com
On Wed, 24 Nov 2010 00:37:07 -0800 (PST)
LauJensen <lau.j...@bestinclass.dk> wrote:

You just touched on an idiom I see fairly often here that bugs me. I'm
not intentionally singling you - or CQL! - out for this, but you made
a comment that sets up my question perfectly.

> (let [photo-counts (-> (table :photos)
> (aggregate [[:count/* :as :cnt]] [:id])))]
> (-> (table :users)
> (join photo-counts (= {:users.id :photos.id}))
>
> I think thats really as simple as you can express that join operation.

Um, I can see two macros that, if expanded in place, would result in a
simpler expression (assuming that CQL doesn't redefine ->):

(let [photo-counts (aggregate (table :photos) [[:count/* :as :cnt]] [:id])]
(join (table :users) photo-counts (= {:users.id :photos.id})))

I also fixed the parens - I think. I removed one after [:id], and it
seems like two were missing at the end as well.

Ok, I understand why you would use -> if you're threading through
multiple forms. I don't know that I like it, but I can at least
understand it. But when it's only one form? In the best case - when
the form is a symbol, as in (-> 1 inc) - it just wastes three
characters to reverse the form and argument. More often - for example
(-> 1 (+ 2)) - it also adds another level of parenthesis, which I
thought most people considered a hindrance to comprehension.

Could someone explain where this urge to write (-> expr (func arg))
instead of (func expr arg) comes from?

<mike
--
Mike Meyer <m...@mired.org> http://www.mired.org/consulting.html
Independent Network/Unix/Perforce consultant, email for more information.

O< ascii ribbon campaign - stop html mail - www.asciiribbon.org

Laurent PETIT

unread,
Nov 24, 2010, 3:57:01 PM11/24/10
to clo...@googlegroups.com


2010/11/24 Mike Meyer <mwm-keyword-goo...@mired.org>


Maybe the lack of refactoring tools: expressions starting big, then some pieces are refactored out, but not totally ?
I know my code looks like this sometimes, and I have to go back to it to remove these remaining (-> a b).

LauJensen

unread,
Nov 24, 2010, 4:38:39 PM11/24/10
to Clojure
No problem Luke.

ClojureQL does not take the backend in to account. This is the one
feature from the old CQL that I didn't want to carry over because it
would be impossible for me to cater to all backends. If you hit
specific problems, let me know and I'll see what we can do.

We adhere to SQL92 and test everything on MySQL and Postgres. If
you're in a situation where thats not good enough, its always possible
to supply part of your expression as a string.

I just implemented the final piece before 1.0.0 FINAL today, which is
a predicate compiler that captures the environment and automatically
paramterizes all predicates. To help spread such lightweight news
snippets Ive put up this tumblr in case anybody's interested:
http://laujensen.tumblr.com

Lau

Daniel Werner

unread,
Nov 24, 2010, 4:51:09 PM11/24/10
to clo...@googlegroups.com
On 24 November 2010 21:40, Mike Meyer

<mwm-keyword-goo...@mired.org> wrote:
> Could someone explain where this urge to write (-> expr (func arg))
> instead of (func expr arg) comes from?

I like to use -> and ->> because they allow me to add more steps to
the "pipeline" as needed, without requiring ever more deeply nested
parentheses. Of course, the examples you cited were intentionally
trivial, but in a setting where you either have many consecutive
transformations on a piece of data, or you *expect* that these
transformations will grow numerous in the future, threading can help
keep the visual and cognitive complexity down. One could probably say
it makes nested s-exprs more scalable ;-)

Interestingly, in languages that prefer dot (.) method call notation
instead of prefix notation, the issue hasn't ever come up for me
because one generally doesn't have a choice. Take Pythons SQLAlchemy
as an example:

Customer.query.filter_by(validated=True).group_by('customer_gender').add_column(func.count()).values(Customer.customer_id)

Pretty neat, isn't it? The threading operators nicely introduce this
style of writing into the world of prefix notation.

Mike Meyer

unread,
Nov 24, 2010, 5:26:59 PM11/24/10
to clo...@googlegroups.com
On Wed, 24 Nov 2010 22:51:09 +0100
Daniel Werner <daniel....@googlemail.com> wrote:

> On 24 November 2010 21:40, Mike Meyer
> <mwm-keyword-goo...@mired.org> wrote:
> > Could someone explain where this urge to write (-> expr (func arg))
> > instead of (func expr arg) comes from?
>
> I like to use -> and ->> because they allow me to add more steps to
> the "pipeline" as needed, without requiring ever more deeply nested
> parentheses. Of course, the examples you cited were intentionally
> trivial

Those cases weren't "intentionally trivial", they were the
point. What's the motive for using -> when there's only one form after
the expression? I get why you'd do it with two or more forms - it
reduces the nesting, and reading left-to right follows the evaluation
order. But with just one form it's liable to have the opposite effect
on nesting, and it makes the evaluation order read zig-zag.

Laurent PETIT

unread,
Nov 24, 2010, 5:35:06 PM11/24/10
to clo...@googlegroups.com


2010/11/24 Mike Meyer <mwm-keyword-goo...@mired.org>

On Wed, 24 Nov 2010 22:51:09 +0100
Daniel Werner <daniel....@googlemail.com> wrote:

> On 24 November 2010 21:40, Mike Meyer
> <mwm-keyword-goo...@mired.org> wrote:
> > Could someone explain where this urge to write (-> expr (func arg))
> > instead of (func expr arg) comes from?
>
> I like to use -> and ->> because they allow me to add more steps to
> the "pipeline" as needed, without requiring ever more deeply nested
> parentheses. Of course, the examples you cited were intentionally
> trivial

Those cases weren't "intentionally trivial", they were the
point. What's the motive for using -> when there's only one form after
the expression? I get why you'd do it with two or more forms - it
reduces the nesting, and reading left-to right follows the evaluation
order. But with just one form it's liable to have the opposite effect
on nesting, and it makes the evaluation order read zig-zag.

I don't know.

-?> could have its use, since it would prevent throwing a NullPointerException if the receiver is null, but plain -> .. ?

Brenton

unread,
Nov 24, 2010, 5:42:12 PM11/24/10
to Clojure
> ClojureQL does not take the backend in to account. This is the one
> feature from the old CQL that I didn't want to carry over because it
> would be impossible for me to cater to all backends. If you hit
> specific problems, let me know and I'll see what we can do.
>
> We adhere to SQL92 and test everything on MySQL and Postgres. If
> you're in a situation where thats not good enough, its always possible
> to supply part of your expression as a string.

Lau

Off the top of my head, I know that the LIMIT syntax for SQL Server is
totally different. A lot of the apps that I write end up getting
deployed using Oracle and SQL Server. If you plan for CQL to be widely
used I think you will need to take backends into account. You don't
need to implement them all yourself, but you should provide a way so
that others can implement them when they need to.

Brenton

LauJensen

unread,
Nov 25, 2010, 2:28:01 AM11/25/10
to Clojure
Hi Brenton,

Yes the OFFSET/LIMIT syntax differs from backend to backend. However
in some instances (like MySQL/PostgreSQL) they have ensured
compatability so that the same statement will run on several DBs
although the syntax might not be considered 'native'. For something
like Oracle there actually isnt a syntax for LIMIT so instead they do
something like

SELECT * FROM (
SELECT
ROW_NUMBER() OVER (ORDER BY key ASC) AS rownumber,
columns
FROM tablename
)
WHERE rownumber <= n

But as you can see it would be trivial to express this in terms of
ClojureQL:

(defn oracle-take
[tname limit]
(-> (table (str "(SELECT ROW_NUMBER() OVER (ORDER BY key ASC)"
" AS rownumber,columns"
" FROM " (to-tablename tname) ")"))
(select (where (<= :rownumber limit)))
(project ["*"])))

(to-sql (oracle-table :users 10))
["SELECT * FROM (SELECT ROW_NUMBER() OVER (ORDER BY key ASC) AS
rownumber,columns FROM users) WHERE (rownumber <= ?)" 10]

From the outset it has been my ambition to make ClojureQL extremely
composable and as far as possible allow users to directly insert
strings into the query to allow for backend specific customization.
The entire design-plan of this customization is not yet thought out so
input is welcomed. To me, flexibility and leaving with the power to
the user is the key to wide adoption across various backends.

Lau

Saul Hazledine

unread,
Nov 25, 2010, 3:43:31 AM11/25/10
to Clojure
On Nov 25, 8:28 am, LauJensen <lau.jen...@bestinclass.dk> wrote:
> ClojureQL:
>
> (defn oracle-take
>   [tname limit]
>   (-> (table (str "(SELECT ROW_NUMBER() OVER (ORDER BY key ASC)"
>                   " AS rownumber,columns"
>                   " FROM " (to-tablename tname) ")"))
>       (select (where (<= :rownumber limit)))
>       (project ["*"])))
>
> (to-sql (oracle-table :users 10))
> ["SELECT * FROM (SELECT ROW_NUMBER() OVER (ORDER BY key ASC) AS
> rownumber,columns FROM users) WHERE (rownumber <= ?)" 10]
>
> From the outset it has been my ambition to make ClojureQL extremely
> composable and as far as possible allow users to directly insert
> strings into the query to allow for backend specific customization.
> The entire design-plan of this customization is not yet thought out so
> input is welcomed. To me, flexibility and leaving with the power to
> the user is the key to wide adoption across various backends.
>

My experience would agree with this assumption. I looked at the
original Clojure QL for use with H2 but didn't want to put in the
effort of writing a H2 driver to TEST a library that I may want to
use. If I can play with the library and I like it, its then no problem
at all to write some small workarounds for the non-standard behaviour
of the database I'm using.

Ideally though, it would be nice if workarounds for various databases
were added to the library as the appear - so in this example I can
call oracle-take without having to write it myself.

Saul

Shantanu Kumar

unread,
Nov 25, 2010, 3:51:38 AM11/25/10
to Clojure
Database dialect independence may be a useful thing to have for
ClojureQL, so that users can work based on intent rather than syntax.
Consider something like this (just an idea):

;; by default in ClojureQL
;; make-sql92-handler is a factory fn for a protocol
(def *dialect-handler* (make-sql92-handler))


;; somewhere in an app
(binding [cql/*dialect-handler* (make-oracle-handler)]
;; do usual stuff
..)

This kind of a structure may allow others to write dialect handlers
for different databases as contrib and ClojureQL can stay as the
composable core. Databases that do not support all of SQL-92
constructs can throw a FeatureNotAvailable exception when an
unsupported intent is asked for.

Regards,
Shantanu

rickmode

unread,
Nov 25, 2010, 12:14:48 PM11/25/10
to Clojure
Allowing implementation-specific and optimized SQL only via strings
and not via a mechanism within ClojureQL allows its use in specific
applications but effectively prevents use for libraries and
frameworks. Indirect use of ClojureQL could yield unacceptable
performance with no elegant fix.

LauJensen

unread,
Nov 25, 2010, 1:27:02 PM11/25/10
to Clojure
There's some valuable food for thought in this thread.

My major problem with support various backends is the amount of work
thats involved. Every single backend needs to play nice with all the
primitives defined in Relational Algebra and that are implemented in
ClojureQL. I believe that the SQL92 standard takes us very far down
the middle road, but I realize that it wont take us all the way.

ClojureQL is actually two sets of primitives. Firstly its the RA stuf
(select, project, join, etc) and then internally there is a number of
primitives defined which help translate the RTable record into a query
string. At the highest level only two functions need to be changed in
order to effectively replace the entire compiler: to-sql and build-
join. These call each other to build complex queries. If these were
supplied as plugins, I think most backends could be fully supported
simply by providing these two methods. They are not trivial however,
so anybody interested in contributing should check out whats already
there.

Still thinking this through but the input is appreciated!

Lau

Brenton

unread,
Nov 26, 2010, 12:29:50 PM11/26/10
to Clojure
Lau,

I agree that it is a lot of work and no one person can do it all well.
I think that the main thing that needs to happen at this point is that
you, as the brains behind ClojureQL, should spend a little time
thinking about the best way for people to contribute back end
implementations. Maybe there is something that can be done to CQL to
make this easy. For example, maybe we add a "dialect" key to the
database connection map and then have the functions which will need
change be multimethods which dispatch on that key (dispatching on the
classname or subprotocol may not always be good enough. For example,
newer versions of SQL Server may provide better optimizations.). This
will allow others to have a path for implementing new back ends as
they need them and not be that much additional work for you. It could
also be designed so that people can provide back end implementations
as separate projects so that they don't even need to be included in
ClojureQL.

I'm sure you will come up with something on par with the rest of
ClojureQL.

Great work! I didn't like the first ClojureQL but I love it now. Now I
have to figure out how what to do with Carte.

Brenton

Janico Greifenberg

unread,
Nov 27, 2010, 1:05:52 PM11/27/10
to clo...@googlegroups.com
First of all, thank you for this awesome library.

I'm experimenting with ClojureQL for accessing Postgis, the spacial
extender for Postgres. To improve the ClojureQL for this use case, it
would be useful to have a way to add custom predicates. For example to
find all places whose location column intersect with a polygon, you
can use a query like this:

SELECT * FROM place WHERE ST_Intersects(location,
ST_GeographyFromText('SRID=4326;POLYGON((33 38,34 38,34 39,33 39,33
38))'))

It would be nice, if I could write that as

(-> places (select (where (st-intersects :location polygon))))

Is there a way to do this (or something similar) in ClojureQL or is it
planned for a future version?

Janico

LauJensen

unread,
Nov 30, 2010, 6:00:35 AM11/30/10
to Clojure
@Brenton,

Thanks a lot for the vote of confidence :) I will do my best to try
and make some kind of elegant design solution for this. Your
suggestions are great!

@Janico:

Since we allow strings as arguments to most functions, I think you
could simple express it like so:

clojureql.core> (defn st-intersects [loc poly]
(format "ST_Intersects(%s,
ST_GeographyFromText('SRID=4326;POLYGON((%s))')"
(name loc)
(join-str ", " poly)))
#'clojureql.core/st-intersects
clojureql.core> (-> (table :place)
(select (where (st-intersects :location [15, 20,
25, 30])))
to-sql)
["SELECT place.* FROM place WHERE ST_Intersects(location,
ST_GeographyFromText('SRID=4326;POLYGON((15, 20, 25, 30))')"]

Would that work for you?

Lau

On Nov 27, 7:05 pm, Janico Greifenberg <j...@acm.org> wrote:
> First of all, thank you for this awesome library.
>
> I'm experimenting withClojureQLfor accessing Postgis, the spacial
> extender for Postgres. To improve theClojureQLfor this use case, it
> would be useful to have a way to add custom predicates. For example to
> find all places whose location column intersect with a polygon, you
> can use a query like this:
>
> SELECT * FROM place WHERE ST_Intersects(location,
> ST_GeographyFromText('SRID=4326;POLYGON((33 38,34 38,34 39,33 39,33
> 38))'))
>
> It would be nice, if I could write that as
>
> (-> places (select (where (st-intersects :location polygon))))
>
> Is there a way to do this (or something similar) inClojureQLor is it
> planned for a future version?
>
> Janico
>
> On Thu, Nov 25, 2010 at 7:27 PM, LauJensen <lau.jen...@bestinclass.dk> wrote:
> > There's some valuable food for thought in this thread.
>
> > My major problem with support various backends is the amount of work
> > thats involved. Every single backend needs to play nice with all the
> > primitives defined in Relational Algebra and that are implemented in
> >ClojureQL. I believe that the SQL92 standard takes us very far down
> > the middle road, but I realize that it wont take us all the way.
>
> >ClojureQLis actually two sets of primitives. Firstly its the RA stuf
> > (select, project, join, etc) and then internally there is a number of
> > primitives defined which help translate the RTable record into a query
> > string. At the highest level only two functions need to be changed in
> > order to effectively replace the entire compiler: to-sql and build-
> > join. These call each other to build complex queries. If these were
> > supplied as plugins, I think most backends could be fully supported
> > simply by providing these two methods. They are not trivial however,
> > so anybody interested in contributing should check out whats already
> > there.
>
> > Still thinking this through but the input is appreciated!
>
> > Lau
>
> > On Nov 25, 6:14 pm, rickmode <rickm...@gmail.com> wrote:
> >> Allowing implementation-specific and optimized SQL only via strings
> >> and not via a mechanism withinClojureQLallows its use in specific
> >> applications but effectively prevents use for libraries and
> >> frameworks. Indirect use ofClojureQLcould yield unacceptable
> >> > > >ClojureQLdoes not take the backend in to account. This is the one

Janico Greifenberg

unread,
Nov 30, 2010, 12:59:13 PM11/30/10
to clo...@googlegroups.com
On Tue, Nov 30, 2010 at 12:00 PM, LauJensen <lau.j...@bestinclass.dk> wrote:
> @Janico:
>
> Since we allow strings as arguments to most functions, I think you
> could simple express it like so:
>
> clojureql.core> (defn st-intersects [loc poly]
>                      (format "ST_Intersects(%s,
> ST_GeographyFromText('SRID=4326;POLYGON((%s))')"
>                              (name loc)
>                              (join-str ", " poly)))
> #'clojureql.core/st-intersects
> clojureql.core> (-> (table :place)
>                    (select (where (st-intersects :location [15, 20,
> 25, 30])))
>                    to-sql)
> ["SELECT place.* FROM place WHERE ST_Intersects(location,
> ST_GeographyFromText('SRID=4326;POLYGON((15, 20, 25, 30))')"]
>
> Would that work for you?

Yes, that works nicely. Thank you. I didn't realize you could use a
function that returns a string as a predicate.

Janico

Reply all
Reply to author
Forward
0 new messages