(Fluent) Query (Interface) to Support Or/And/Nested-Expressions

46 views
Skip to first unread message

Scott Hernandez

unread,
Sep 1, 2010, 4:56:19 PM9/1/10
to mor...@googlegroups.com
We have gone back and forth on this before, and we will probably go another round now, but before we get to that (to be fluent or not) let us talk about adding support for "or" (and soon "and") and nested expressions.

At the moment we had "or" support by basically by-passing the validation (both checking names and the value/type of the param) of the query and using a DBObject/List. It would be nice to support "or" queries directly in our query interface. (http://code.google.com/p/morphia/source/browse/trunk/morphia/src/test/java/com/google/code/morphia/TestQuery.java#276)

We have a new patch (http://code.google.com/p/morphia/issues/detail?id=104) that offers support by letting you do this:

1.)

Query<Asset> query = ds.createQuery(AssetState.class);

OrBuilder<Asset> or = query.or();

or.add().field("name").equal("asset-1"); 
or.add().field("name").equal("asset-2"); 
or.add().field("name").equal("asset-3");

//or

2.)

List<Query<Asset>> queries = new ArrayList<Query<Asset>>();

queries.add(ds.createQuery(AssetState.class).field("name").equal("asset-1"));
queries.add(ds.createQuery(AssetState.class).field("name").equal("asset-2"));
queries.add(ds.createQuery(AssetState.class).field("name").equal("asset-3"));

query.or(queries)

I'm not so keen on 2 since it isn't quite correct; There are options in a query you can't use in an "or" (like limit/skip/sort) and you can't mix and match different types either.
Number 1 feel a lot like 3 below...

We have discussed something like this before:

3.)
query.startOr().field(...).oper(..).field(...).oper(...).endOr()




One of design constraints/features I have been pushing is that errors are caught (during validation) on the line that you specify the parameters to query, not when you "run" it.

"and" will be implemented in whatever fashion "or" is, and will still be the default; unless people thing that should change -- the default that is.

The next question is how to support nested expressions in general. Maybe some of the discussion out of this will lead there.

Thoughts? Choose an option (1/2/3) or do you have other idea?

Uwe Schäfer

unread,
Sep 2, 2010, 3:32:13 AM9/2/10
to mor...@googlegroups.com
On 09/01/2010 10:56 PM, Scott Hernandez wrote:

> 2.)
>
> List<Query<Asset>> queries = new ArrayList<Query<Asset>>();
> queries.add(ds.createQuery(AssetState.class).field("name").equal("asset-1"));
> queries.add(ds.createQuery(AssetState.class).field("name").equal("asset-2"));

is my fav, but you´re right saying

> There are options in
> a query you can't use in an "or" (like limit/skip/sort) and you can't
> mix and match different types either.

So what if we had a dedicated class for criteria gained from the query
(so that it has the type info)

Query q = createQuery(Foo.class);
Criteria c = q.crit();
c.and( c.field("deleted").equal(false) );
c.or(
c.field("published").equal(true) ,
c.field("draft").equal(true)
)

one painpoint is that c.field(x).equal(y) is no longer automatically
added to the query. to fail fast we could keep track of orphaned
(created but unused) criteria, and fail/warn.

we could still keep
q.field("foo").equal("bar")

for the 90% usecase, which would then be basically the same than

q.crit().and(q.crit().field("foo").equal("bar"));

i do not think anyone really wants to define a query with or/and groups
in one line.

cu uwe

Norman Elton

unread,
Sep 2, 2010, 8:09:19 AM9/2/10
to mor...@googlegroups.com
As the author of said patch, I'll chime in with my two cents :)

>> I'm not so keen on 2 since it isn't quite correct

I did not like loading up a Collection either, it's a pretty dirty
hack. It was designed as a proof-of-concept before I started on method
#1, my preferred.

You mentioned that the criteria clauses are dirty, since they support
things like limiting and sorting. These obviously should only be
applicable at the "top-level" query. This applies to both of my
suggested methods:

or.add().limit(12)

... is clearly invalid. This could be solved by applying an interface
(Filterable?) to Query, then having add() return this interface. Under
the covers, you'd still be dealing with a full Query object, but only
given permission to use the filtering methods.

I also like Uwe's suggestion, but am not sure how difficult it would
be to implement. I'd certainly be willing to give it a shot.

Thoughts?

Norman

Uwe Schäfer

unread,
Sep 2, 2010, 10:20:42 AM9/2/10
to mor...@googlegroups.com
On 09/02/2010 02:09 PM, Norman Elton wrote:

Hi Norman

> I also like Uwe's suggestion, but am not sure how difficult it would
> be to implement. I'd certainly be willing to give it a shot.

isn´t particularly hard to do. i did similar stuff (a criteria API) for
JPA before, which could serve as an example (which is far more complex
due to supporting aliases and joins)

cu uwe

Norman Elton

unread,
Sep 2, 2010, 1:09:31 PM9/2/10
to mor...@googlegroups.com
> isn´t particularly hard to do. i did similar stuff (a criteria API) for JPA
> before, which could serve as an example (which is far more complex due to
> supporting aliases and joins)

I like your idea best. If you've got time to take a stab at it, go for
it. Otherwise let me know and I'll see what I can whip up. I would
just need to research how the validation stuff works to make sure
everything places nicely together.

Norman

Reply all
Reply to author
Forward
0 new messages