Dan Diephouse on Thursday, July 21, 2011

Introducing Mule Query Language

9

Working with web APIs, local APIs and different data formats and structures is too damn hard. You have to write painful verbose code to:

  • Query Web and work with the data
  • Enrich and join data from external with local
  • Compose RESTful services from existing services
  • Version services and data formats
  • Merge data from different sources into a common data format
  • Sort through sets of data

We’d like to introduce an easier way that will hopefully change the way that you write applications: Mule Query Language. It’s a LINQ-inspired language that allows you to filter, join and transform data from Mule messages, Cloud Connectors, Spring beans – or any other object – in very concise query statements.

We think that the best way to illustrate this is a few examples. While you look, imagine how many more lines of code this would take if you didn’t have .

The Basics

MQL statements allow you to query, transform, and join data. Let’s take a look at a couple basic examples.

Filter objects from a Collection of user objects.

from users where division = 'Engineering' and company = 'MuleSoft'

Transform an existing object into a Map/POJO. This expression creates a new Map with a name property from the firstName and lastName properties on the user object.

from users as u select new { name = u.firstName + ' ' + u.lastName }

You can also create new POJOs from existing objects:

from users as u select new(com.acme.UserSummary) {
  name = u.firstName + ' ' + u.lastName
}

Join data from another source. This will call store.getPurchases and join the data into a new object for each user in the query.

from users as u
  join store.getPurchases(u.id) as storePurchases
  select new { name = u.name, purchases = storePurchases }

Now, let’s take a look at how we can put this to use!

Query the Web

Combine the above with Cloud connectors, and you can query the web to do things like merge data from different services into a common format. This example shows two queries which merge the data from Twitter and Yammer into a common format.

Here twitter and yammer are Cloud Connectors inside of Mule. We can create new objects using the “select” statement and set properties on these new objects by referring to the yammer and twitter objects. We can then return this merged data inside of Mule in the JSON format.

Join Data Across the Web

Join information from Cloud Connectors, like Salesforce, with your local data sources:

This example shows how you can combine data from your local user data base with the company name and phone number from Salesforce.

Compose new RESTful services

Create an instant RESTful JSON service from a query of your Spring bean or Cloud Connector. This will run your query and return the result as a set of JSON objects which you can expose to customers or to your frontend:


9 Responses to “Introducing Mule Query Language”

Arul July 21st, 2011, 11:17 am

Dan,

Very interesting project!

I am trying to query the POJOs as shown in your example. The query result collection does not contain User, instead it returns Query$1 and fails in ClassCastException when iterating the result collection. Here is the code:

List users = new ArrayList();
users.add(new User(“Dan”, “Diephouse”, “MuleSoft”, “Engineering”));
users.add(new User(“Joe”, “Sales”, “MuleSoft”, “Sales”));
Map context = new HashMap();
context.put(“users”, users);
Collection result = Query.execute(“from users where division = ‘Engineering’”, context);
for(User user : result) {
System.out.println(user);
}

Exception in thread “main” java.lang.ClassCastException: com.mulesoft.mql.Query$1 cannot be cast to mqldemo.User
at mqldemo.Test.main(Test.java:26)

Any clues what could be wrong here?

-Arul

Dan Diephouse July 21st, 2011, 12:24 pm

Hi Arul, Very sorry for that issue that you ran into. It was a release screw up (that’s why it’s 0.9 not 1.0 :-) ). I’ve pushed a new 0.9.1 release which has the Query engine fixed and modified our tests to be more strict about the results.

Arul July 21st, 2011, 3:15 pm

Awesome. It works now! Thanks Dan for fixing this so quickly.

Franco Gasperino July 21st, 2011, 9:43 pm

Extremely interesting.

srini February 23rd, 2012, 7:05 pm

MQL order by clause not actually ordering the result-set.
i am playing with this to see , if we can use in our application.

Any links to documentation on query sytax would be more helpful.

List users = new ArrayList();
users.add(new User(“Dan”, “Dan.Diephouse@gmail.com”,2,13000 , address));
address = new Address(“International pkway”,”Atlatna”,”GA”,”USA”);
users.add(new User(“Joe”, “Joe.Sales@yahoo.com”, 1,14000, address));
users.add(new User(“John”, “John@yahoo.com”, 1,16000, address));
users.add(new User(“Scott”, “scott@yahoo.com”, 1,15000, address));
users.add(new User(“Andy”, “andy@abc.com”, 1,7000, address));

Query query = new QueryBuilder()
.as(“p”)
.orderby(“income”)
// .max(3)
.where(eq(property(“companyId”), 1))
.select(newObject()
.set(“name”, “name”)
.set(“income”, “income”)
.set(“email”, “email”)).build();

Collection result1 = query.execute(users);

srini konakanchi February 24th, 2012, 6:04 pm

Got it . Looked at the mql source code. We have a bug ( typo ) in OrderByComparator class.

Object r1 = MVEL.executeExpression(expression, o1.get(queryBuilder.getAs()), o1); Object r2 = MVEL.executeExpression(expression, o1.get(queryBuilder.getAs()), o1);

should be Object r2 = MVEL.executeExpression(expression, o1.get(queryBuilder.getAs()), o2);

srini konakanchi February 24th, 2012, 7:18 pm

Another error – when the result set is not hashmap.

Exception in thread “main” java.lang.ClassCastException: com.mql.test.User cannot be cast to java.util.Map
at com.mulesoft.mql.impl.OrderByComparator.compare(OrderByComparator.java:11)
at java.util.Arrays.mergeSort(Arrays.java:1270)
at java.util.Arrays.sort(Arrays.java:1210)
at java.util.Collections.sort(Collections.java:159)
at com.mulesoft.mql.Query.order(Query.java:214)
at com.mulesoft.mql.Query.execute(Query.java:189)

List persons = getPersons();

Query query = new QueryBuilder()
// .where(and(eq(property(“division”), “Sales”),
// eq(property(“firstName”), “Joe”)))
.orderby(“income”)
.max(3)
.build();

Collection result = query.execute(persons);

srini konakanchi February 24th, 2012, 7:49 pm

Got it , Need couple of fixes in OrderByComparator.

Timothee July 19th, 2012, 2:42 pm

Hi Dan,

MQL looks great. I was wondering it is possible to use it in MuleStudio (CE 3.3), or only with Maven.

Thanks,
Timothee

Leave a Comment