Age | Commit message (Collapse) | Author |
|
Now it takes a third "projection" argument in which one can perform aggregate
function over the existing fields. The fields of the resulting query are the
union of the grouping fields and the projected fields (with the projected
fields taking precedence).
If you try to project a field without applying some sort of function to it then
you'll get an exception, but at the moment no function calls are actually
validated as aggregate functions (in order to do so we'd need a knowledge of
all the aggregate functions, which isn't possible in general).
|
|
Previously the union/intersection operations didn't work when you tried to
select/project/sort/drop/whatever on them. Now they just automatically
introduce a subquery, which means that they can be used in other operations
automatically. (There is a potential for a minor decrease in query speed, but I
think it's worthwhile to maintain the abstraction.)
|
|
When queries were being created their internal aliases were defaulting to the
same as their external table names. This would normally have been fine, but in
the case of a rename the simplistic implementation of table renames was leading
to the external name being changed too.
The solution: generate a (unique) random internal name for the table. That way
the rename operation will only rename the unique internal name, not the
constant external name (it would also, in theory, reduce the need for renames,
but that optimisation probably isn't really worth doing for expected work
loads).
|
|
The ambiguous field error message used to specify that it was a case where
multiple tables were present, but that's not always true. If you're trying to
work on a query that has been "subqueried" then you'll also get the error
(arguably that should have a different error message, but I'll come back to
that later).
|
|
The `having` function duplicated the intended functionality of `select`, but in
a bad way. It only applied to a restricted case, and its existence meant that
`select` provided an escape-hatch with which we could cause some unexpected
behaviour. By consolidating the two functions into `select` we remove the
escape hatch as well as simplify the model.
Selection on grouped queries may now introduce a new subquery, but only in
situations where the behaviour is unpredictable (ie. selecting on non-grouped
attributes).
|
|
|
|
Essentially just prefixes a subobject name in front of all fields in a query,
with a dot separating the new prefix and the original name.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Add take and drop functionality to the queries, so now you can use the take and
drop functions in a similar way to how they work on seqs in clojure.
Move jdbc interface stuff into clojure-sql.jdbc, so if you're using jdbc you
can include it yourself. (If you're not using jdbc then it shouldn't bother
you).
Given the default compilation target is actually postgres, document that.
|
|
Fix compilation of cross joins.
Remove the sort clauses on queries when they become subqueries in joins because
then the sorting means nothing (although when take/drop stuff is added the sort
will be relevant, so we'll see about that).
Favour the left side of a join, which is mostly only relevant for the outer
join case (and technically it's not quite right for full-outer joins, maybe,
but I'll get to that later).
|
|
`sort-by` is now called `sort`. This is just because I think it makes more
sense and nothing more.
Grouping has been added with `group` and `having`. They behave as you'd expect
from SQL, except that joining with a table which has a `group` or `having`
clause will move that query in as a subquery. I wasn't sure how else to ensure
their composition, so this way maintains the semantics (which is the most
important part) at the potential cost of some efficiency in performing the
query. I'm not sure that there exists a more general solution. I would assume
not.
The join stuff has been fixed a bit (some valid renames were rejected as
invalid) and standardised a bit (exceptions are now more similar). A bunch of
things have been added to the join stuff as a result of the above grouping
things, too. A bunch of changes all around, basically.
The compiler has also had a few small changes made to it, and has been enhanced
to support the grouping stuff.
|
|
|
|
|
|
It should generally be usable at this point. It should generate the queries
correctly (including join order and stuff) and approximately properly do
things. The type of join stuff still hasn't been finished, but if the code were
left as-is it would still be possible to get whatever you wanted out of it, I
think.
Basically: lots of work has been done and we're approaching something more
usable.
|
|
Flip around field/table aliases, do joins a bit differently. They're my main
aims at the moment! I'll also add a preprocessor for the compiler to massage it
into a nicer form there.
I discovered that joins can be done with a pretty sweet syntax in SQL:
(tableA LEFT JOIN tableB) RIGHT JOIN tableC
This is pretty much perfect for my purposes.
Flipping alias maps just makes more sense and removes a whole bunch of
`flip-map` calls that would be unnecessary if the aliases were the other way
around. The user-facing side of the DSL will be left unchanged, though. The
user provides an `{old-name new-name}` map and internally we convert that into
`{new-name old-name}`. Like magic.
I'm also adding a bunch more tests. Hopefully that will make things more likely
to work for long periods of time.
Peace out!
|
|
The recursive calls to `resolve-fields` were not being made due to programmer
error. This has been fixed, so now the field resolution stuff should work
properly again.
This is really highlighting the need for better testing. Get on that!
|
|
The compiler's been simplified a bit by breaking out the `writer` stuff into
its own namespace and by generally making the monadic stuff better. It's all
hidden behind a nice, simple, `clojure-sql.compiler/compile` function now. Call
that and you'll get back what you need. (Internally it's a writer monad which
is really modelled as a state monad with the only operation able to be
performed on the state being `tell`.)
Subqueries are now handled by the DSL in such a way as to not blow up
everything. Subqueries have no support for referencing values in the
superquery, though, so their utility is quite limited at present. Thinking
about how to do subqueries properly may be difficult.
|
|
The query namespace really only exists because I didn't want to put it in dsl,
but I couldn't put it in core without a circular dependency.
Users should only have to :require core to do things, though. It just aliases
other stuff to make that work.
|