MLang (Model Language) is FOAM’s domain-specific language for queries, predicates, and expressions that works consistently across Java and JavaScript.
The examples below use a hypothetical Employee model with name, age, status, role, salary, department and createdDate properties.
In Java, use static imports from foam.mlang.MLang:
import static foam.mlang.MLang.*;
// Basic predicates
Predicate p1 = EQ(Employee.NAME, "John");
Predicate p2 = GT(Employee.AGE, 25);
Predicate p3 = AND(p1, p2);
Predicate p4 = OR(EQ(Employee.STATUS, "ACTIVE"), IN(Employee.ROLE, Arrays.asList("ADMIN", "MANAGER")));
// Aggregation sinks
Sink countSink = COUNT();
Sink sumSink = SUM(Employee.SALARY);
Sink groupBySink = GROUP_BY(Employee.DEPARTMENT, COUNT());
// Using with DAO
dao.where(AND(GT(Employee.AGE, 18), EQ(Employee.STATUS, "ACTIVE")))
.orderBy(DESC(Employee.CREATED_DATE))
.select(countSink);
In JavaScript, implement the Expressions mixin or use ExpressionsSingleton:
// Option 1: Implement Expressions mixin
foam.CLASS({
name: 'MyController',
implements: ['foam.mlang.Expressions'],
methods: [
async function loadEmployees() {
return (await this.dao.where(
this.AND(
this.GT(Employee.AGE, 25),
this.EQ(Employee.STATUS, 'ACTIVE')
)
).select()).array;
}
]
});
// Option 2: Use ExpressionsSingleton
const M = foam.mlang.ExpressionsSingleton.create();
// Basic predicates
const p1 = M.EQ(Employee.NAME, 'John');
const p2 = M.GT(Employee.AGE, 25);
const p3 = M.AND(p1, p2);
const p4 = M.OR(M.EQ(Employee.STATUS, 'ACTIVE'), M.IN(Employee.ROLE, ['ADMIN', 'MANAGER']));
// Aggregation sinks
const countSink = M.COUNT();
const sumSink = M.SUM(Employee.SALARY);
const groupBySink = M.GROUP_BY(Employee.DEPARTMENT, M.COUNT());
// Using with DAO
const results = await dao.where(
M.AND(M.GT(Employee.AGE, 18), M.EQ(Employee.STATUS, 'ACTIVE'))
).orderBy(M.DESC(Employee.CREATED_DATE))
.select(countSink);
MLang also supports mathematical formulas:
// JavaScript formula examples
const E = foam.mlang.ExpressionsSingleton.create();
// Basic arithmetic
E.ADD(1, 2, 3, 4, 5).f() === 15
E.SUB(9, 1, 2, 3, 4).f() === -1
E.MUL(1, 2, 3, 4, 5).f() === 120
// Nested formulas
E.DIV(1, E.ADD(2, E.MUL(3, E.SUB(4, 5)))).f() === -1
MLang integrates with FOAM’s query parsers to convert strings to predicates:
// Java SimpleQueryParser
SimpleQueryParser parser = new SimpleQueryParser(Employee.getOwnClassInfo());
Predicate predicate = parser.parseString("age>25 AND status=ACTIVE");
// JavaScript QueryParser
const parser = foam.parse.QueryParser.create({ of: Employee });
const predicate = parser.parseString('age>25 AND status=ACTIVE');
Expressions mixin provides convenient shorthand methods for all MLang operationsEmployee.NAME) which provides type safety and introspectionFUNC in JavaScript, though they can’t be optimized by the DAO like standard MLang predicates