cayenne-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Aristedes Maniatis <...@ish.com.au>
Subject new fluent API
Date Wed, 15 Apr 2015 06:57:52 GMT
As a practice exercise to see how the new API works on a real system, I migrated an app completely
over to the new syntax. There were about 150 queries to change (it is a small app), and each
one only took about a minute to re-enter and visually check.

The new syntax is dramatically easier to read. I hope this will translate in the long term
to fewer bugs.

A couple of real world syntax issues raised themselves and I thought I'd bring them up here
for review. This is all real code in a real app.


1. Before

List<SupportPassword> oldPasswords = ObjectSelect.query(SupportPassword.class).
     where(SupportPassword.EXPIRES_ON.lt(new Date())).
     select(context);

The main lack of clarity here is "lt". Is it worth having an alias "before" for "lt"?

      where(SupportPassword.EXPIRES_ON.before(new Date())).

I don't know whether we need the clutter in the API, but in my brain that makes it much easier
to read.




2. Lots of AND

List<Contact> users = ObjectSelect.query(Contact.class).
		where(Contact.EMAIL_ADDRESS.eq(email).
			andExp(Contact.COLLEGE.eq(college)).
			andExp(Contact.GIVEN_NAME.eq(firstName)).
			andExp(Contact.LAST_NAME.eq(lastName))).
		select(context);

You can easily get lost in all those brackets, especially for more complex expressions than
above. Would it make sense to write this:

List<Contact> users = ObjectSelect.query(Contact.class).
	where(Contact.EMAIL_ADDRESS.eq(email).
	where(Contact.COLLEGE.eq(college)).
	where(Contact.GIVEN_NAME.eq(firstName)).
	where(Contact.LAST_NAME.eq(lastName))).
	select(context);

That would require this:

	public ObjectSelect<T> where(Expression expression) {
		if (this.where == null) {
			this.where = expression;
		} else {
			this.where = this.where.andExp(expression);
		}
		return this;
	}


If we look to Rails for ideas, they chain multiple "where" instructions with an implied AND.
That can be very convenient when you construct a query in one place, and then add additional
restrictive qualifiers onto it in other parts of the code or in conditionals.

query = ObjectSelect.query(Contact.class).
	where(Contact.EMAIL_ADDRESS.eq(email).
	where(Contact.COLLEGE.eq(college));
if (firstName != null) {
	query = query.where(Contact.GIVEN_NAME.eq(firstName)).
			where(Contact.LAST_NAME.eq(lastName)));
}
List<Contact> users = query.select(context);



Also, and probably more importantly, ordering like this makes sense:

List<Contact> users = query.order(Contact.GIVEN_NAME.asc()).order(Contact.LAST_NAME.asc()).select(context);

where we want to create two levels of sort. So, we don't always want instructions to replace
previous ones but to add onto them. Similarly we might add several prefetches to a query which
are additive.



Thoughts?


Ari

-- 
-------------------------->
Aristedes Maniatis
ish
http://www.ish.com.au
Level 1, 30 Wilson Street Newtown 2042 Australia
phone +61 2 9550 5001   fax +61 2 9550 4001
GPG fingerprint CBFB 84B4 738D 4E87 5E5C  5EFA EF6A 7D2E 3E49 102A

Mime
View raw message