All Projects → dungba88 → libra

dungba88 / libra

Licence: MIT license
Java Predicate, supports SQL-like syntax

Programming Languages

java
68154 projects - #9 most used programming language
ANTLR
299 projects

Projects that are alternatives of or similar to libra

antlr4-tool
A useful Antlr4 tool with full TypeScript support
Stars: ✭ 34 (+13.33%)
Mutual labels:  antlr4
de9im
DE-9IM spatial predicate library implemented in Javascript.
Stars: ✭ 22 (-26.67%)
Mutual labels:  predicates
yahdl
A programming language for FPGAs.
Stars: ✭ 20 (-33.33%)
Mutual labels:  antlr4
speedy-antlr-tool
Generate an accelerator extension that makes your Antlr parser in Python super-fast!
Stars: ✭ 22 (-26.67%)
Mutual labels:  antlr4
java-ast
Java Parser for JavaScript/TypeScript (based on antlr4ts)
Stars: ✭ 58 (+93.33%)
Mutual labels:  antlr4
tiinvo
Functions for tacit programming and functional types for TypeScript and JavaScript.
Stars: ✭ 36 (+20%)
Mutual labels:  predicates
Java-AgentSpeak
LightJason - AgentSpeak(L++) for Java
Stars: ✭ 21 (-30%)
Mutual labels:  antlr4
Antlr4
ANTLR (ANother Tool for Language Recognition) is a powerful parser generator for reading, processing, executing, or translating structured text or binary files.
Stars: ✭ 11,227 (+37323.33%)
Mutual labels:  antlr4
snowstar
Here lies the code for the Snow* programming language, currently being rewritten.
Stars: ✭ 31 (+3.33%)
Mutual labels:  antlr4
kolasu
Kotlin Language Support – AST Library
Stars: ✭ 45 (+50%)
Mutual labels:  antlr4
xqdoc
An Antlr4 implementation of xqDoc for XQuery
Stars: ✭ 14 (-53.33%)
Mutual labels:  antlr4
Profane
Scripting language for derps
Stars: ✭ 18 (-40%)
Mutual labels:  antlr4
ANTLR4ParseTreeVisualizer
Visual Studio debugging visualizer, and .NET visualization controls, for ANTLR4 parse trees
Stars: ✭ 59 (+96.67%)
Mutual labels:  antlr4
MPL
A language to generate command blocks for Minecraft 1.9 and higher
Stars: ✭ 18 (-40%)
Mutual labels:  antlr4
bsl-parser
Коллекция парсеров языка 1С (BSL) в формате ANTLR4.
Stars: ✭ 23 (-23.33%)
Mutual labels:  antlr4
robots.txt
🤖 robots.txt as a service. Crawls robots.txt files, downloads and parses them to check rules through an API
Stars: ✭ 13 (-56.67%)
Mutual labels:  antlr4
parcera
Grammar-based Clojure(script) parser
Stars: ✭ 100 (+233.33%)
Mutual labels:  antlr4
predicates-rs
Boolean-valued predicate functions in Rust
Stars: ✭ 103 (+243.33%)
Mutual labels:  predicates

libra

Maven Central Javadocs Build Status Coverage Status

Libra is a Java package for creating and evaluating predicate. Java-based and SQL-like predicate are both supported. For SQL predicates, it is using ANTLR to parse the string against a predefined grammar. The Java-based predicates are implementation of Specification pattern and support numeric/text/collection related conditions.

install

Libra can be easily installed with Maven:

<dependency>
    <groupId>org.dungba</groupId>
    <artifactId>joo-libra</artifactId>
    <version><!-- latest version. see above --></version>
</dependency>

how to use

By default, you can simply use SqlPredicate class for all the functionality, which supports satisfiedBy method to perform the evaluation. A PredicateContext needs to be passed to the method.

PredicateContext context = new PredicateContext(customer);
SqlPredicate predicate = new SqlPredicate("customer.age > 50 AND customer.isResidence is true");
predicate.satisfiedBy(context);

You can optionally check for syntax errors:

if (predicate.hasError()) {
    predicate.getCause().printStackTrace();
}

or throw the exception if any

predicate.checkForErrorAndThrow();

from 2.0.0 you can retrieve the raw value instead of letting Libra convert it to boolean

PredicateContext context = new PredicateContext(customer);
SqlPredicate predicate = new SqlPredicate("customer.asset - customer.liability");
Object rawValue = predicate.calculateLiteralValue(context);

grammar

Libra supports the following syntax for SQL predicates:

  • Logic operators: and, or and not
  • Comparison operators: >, >=, <, <=, =, ==, !=, is, is not
  • Parenthesises
  • List and string operators: contains (for both list and string) and matches (only for string)
  • Array indexing: a[0] (this cannot be used to evaluate a Map)
  • String literals, single quoted, e.g: 'John'
  • Numeric literals: 1, 1.0
  • Boolean literals: true, false
  • Other literals: null, undefined, empty
  • Variables: alphanumerics, _, . (to denote nested object) and [, ] (to denote array index), must starts with alphabet characters.
  • List: {1, 2, 3}. Empty list { } is also supported.
  • Function: functionName(arg1, arg2...) It's also possible to configure custom function in PredicateContext. Built-in functions: sqrt, avg, sum, min, max, len.
  • Stream matching: See below
  • Subset filtering: See below

stream matching

Libra 2.0.0 supports stream-like matching, similar to anyMatch, allMatch and noneMatch. The syntax is:

ANY <indexVariableName> IN <listVariableName> SATISFIES <expression>
ALL <indexVariableName> IN <listVariableName> SATISFIES <expression>
NONE <indexVariableName> IN <listVariableName> SATISFIES <expression>

listVariableName is the name of the list variable you want to perform matching on. indexVariableName is the name of the temporary variable used in each loop. For example: ANY $job IN jobs satisfies $job.salary > 1000 will try to find out if there is ANY element in jobs which its salary property is greater than 1000. Starting from Libra 2.1.0 the temporary variable name must be started with $.

subset filtering

Libra 2.1.0 supports subset filtering from list:

WITH <indexVariableName> IN <listVariableName> SATISFIES <expression>

For example WITH $job IN jobs satisfies $job.salary > 1000 will returns a list of jobs which the salary attribute is greater than 1000.

You can also transform the returned list element using transformation expression:

For example: $job.salary WITH $job IN jobs satisfies $job.salary > 1000 will returns a list of salary that is greater than 1000 from the job list.

examples

Some examples of SQL predicates:

name is 'John' and age > 27
employments contains 'LEGO assistant' and name is 'Anh Dzung Bui'
experiences >= 4 or (skills contains 'Java' and projects is not empty)
avg(4, 5, 6) is 5

More examples can be seen inside the test cases

quirks and limitations

Some special cases or limitations are covered here:

  • Literals, if stand alone in their own branch, will be converted into predicate according to their types:
    • String & list literals will be considered as true if and only they are not null and not empty
    • Number literals will be considered as true if and only they are not null and not zero
    • null will always be considered as false
  • If literals are compared with any other type, the comparison will be as normal
    • 0 is false will be evaluated as false, since 0 and false have different type
  • Variables, if stand alone in their own branch, will be converted into predicate according to their types:
    • String & list variables will be considered as true if and only if they are not null and not empty
    • Number variables will be considered as true if and only if they are not null and not zero
    • Boolean variables will be considered as their own values
    • null variables will always be considered as false
  • When comparing number, they will be converted into BigDecimal, so 0.0, 0 or 0L are all equal

optimizers

Libra currently supports a simple Constant Folding optimization. It will reduces constant-only conditional branches into a single branch. To enable the optimizations, use OptimizedAntlrSqlPredicateParser as below:

SqlPredicate predicate = new SqlPredicate(predicateString, new OptimizedAntlrSqlPredicateParser());

This will take more time to compile the SQL but will reduce evaluation time.

extends

The SqlPredicate class allows you to use your own SqlPredicateParser:

SqlPredicate predicate = new SqlPredicate(predicateString, new MyPredicateParser());

you can implement SqlPredicateParser, or extend the AbstractAntlrSqlPredicateParser to use your own grammar. For the former, the interface has only one method public Predicate parse(String predicate) throws MalformedSyntaxException, so you can even use lambda expression to construct it, like:

SqlPredicate predicate = new SqlPredicate(predicateString, predicate -> {
   return something; 
});

or use method reference:

SqlPredicate predicate = new SqlPredicate(predicateString, this::parseSql);

performance considerations

It is better to cache the parsed version of sql and if possible, try to load all of them at startup. If you keep the SqlPredicate objects, they will contain the parsed predicate to be reused.

The runtime evaluation is quite fast (2 millions ops/sec with Java object or 5 millions ops/sec with Map). You can also consider using Map because it's significantly faster.

license

This library is distributed under MIT license. See LICENSE

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].