non-persistent type), and transform in getFromSet/writeToStatement, rather than
operate on T (the persistent type) and transform in
getFromObject/writeToObject.
This makes the newly added test in TransformTest work, rather than fail, as it
did previously.
safely be stored, but if rehydrated into a Set then an EnumSet would
be created and that can't store nulls.
So, check to see if the encoded String has any nulls in it and
have the builder create a HashSet instead.
so that partially constructed queries can be reused without any special care
being taken by the caller. I also switched to the use of a functional list
internally to make this whole process more pleasant and efficient.
versions with the repository.
Why, Maven, do you not offer an option to not go searching numerous sources on
the Internet every time I run a build? (And then timing out when some of those
sources are behind firewalls and I'm not running vpn at the moment.) Indeed,
why would that not be the default?
pojos which hold the results of the query. The caller can decide if they want
to use the magic of selectInto(), and be careful not to screw up the types and
order of their pojo fields, or they can boil up some plates and create a
builder for their pojo, which will be type-checked, soup to nuts.
only on a matching public constructor. This version is not type-safe, but I'll
also be adding an additional mechanism to do selections like this that uses a
type-safe builder approach, which comes at the cost of a healthy dose of
boilerplate code.
This uncovered a lot of loose geese as far as the database was concerned, which
necessitated turning a bunch of functions which had specific type into
functions which have type Number.
In general, I made the Funcs/StringFuncs/MathFuncs factory methods provide an
expression typed Number and I left the underlying SQLExpression derivations
able to be more precisely typed. So if you know that your database does not
magically promote an integer column to long when calling sum() on it, you can
force a more specific type. But really, I don't see why you would go to the
trouble. You can just call intValue() on your result and get the int you were
looking for regardless of what the database thought it would be fun to provide.
I also fixed a few HSQLDB variants (average -> avg, round(a) -> round(a, 0),
etc.) and made notes about a few things that just plain don't work in HSQLDB.
Awesome! Fortunately they're things like log-base-10, rather than more critical
functionality.
exception. I'm tempted to reinstate the NoSuchElement exception for a load()
that attempts to project fields from the selected rows, but I think it makes
more sense for a load() which aggregates over zero rows to return null than to
throw a NoSuchElement exception.
Some examples:
int max = _repo.from(TestRecord.class).load(Funcs.max(TestRecord.RECORD_ID));
List<Tuple2<String,Integer>> data = _repo.from(EnumKeyRecord.class).
groupBy(EnumKeyRecord.NAME).ascending(EnumKeyRecord.NAME).
select(EnumKeyRecord.NAME, Funcs.count(EnumKeyRecord.TYPE));
Still no caching integration, but the ratio of utility over boilerplate is
high.
least on something that was Comparable, but unfortunately, the numeric type's
only shared supertype is Number and that is not comparable.
If I require Number, then you can't do greatest(timestamp, timestamp), and if I
require Comparable, then you can't do greatest(int, double) because the
compiler can't unify those types to something that is Comparable.
I could require that you only compare apples with apples (i.e. greatest(int,
int) or greatest(double, double)), but databases will happily compare
greatest(int, double) and people are going to want to do that. I could
introduce some sort of numeric conversion expressions, but I think that's
getting too deeply into the realm of type safety for type safety's sake.
fast-and-looseness by propagating types through foo.eq(bar) expressions,
foo.lessThan(bar) expressions and the like.
This means a few things stopped working, like
StringFuncs.length(MyRecord.BYTE_ARRAY_FIELD), but now there's
Funcs.arrayLength() for that. Also Date functions are looser than I'd like
because there's no supertype between sql.Date and sql.Timestamp (to express a
date having type) and sql.Timestamp and sql.Time (to express a time having
type). So you can still do some foot shooting with those methods, but it's
hardly worth crying over since the foot shooting range was fully open for
business prior to this.
MSOY fixes coming presently. ProjectX fixes shortly thereafter.
List<Tuple2<Integer,EnumKeyRecord.Type>> jdata =
_repo.from(TestRecord.class).
join(TestRecord.NAME, EnumKeyRecord.NAME).
select(TestRecord.RECORD_ID, EnumKeyRecord.TYPE);
This should eliminate the need for pesky one-off computed records when doing
ad-hoc joins.