{"id":37421591,"url":"https://github.com/dungba88/libra","last_synced_at":"2026-01-16T06:06:57.451Z","repository":{"id":75614847,"uuid":"110289100","full_name":"dungba88/libra","owner":"dungba88","description":"Java Predicate, supports SQL-like syntax","archived":false,"fork":false,"pushed_at":"2025-05-28T18:06:24.000Z","size":459,"stargazers_count":37,"open_issues_count":3,"forks_count":4,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-10-31T00:38:19.320Z","etag":null,"topics":["antlr4","predicates","sql-predicates"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dungba88.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-11-10T20:21:51.000Z","updated_at":"2024-08-29T10:03:45.000Z","dependencies_parsed_at":"2024-11-13T15:53:03.232Z","dependency_job_id":"0e351d26-1420-43f9-af73-5bb600dca362","html_url":"https://github.com/dungba88/libra","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/dungba88/libra","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dungba88%2Flibra","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dungba88%2Flibra/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dungba88%2Flibra/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dungba88%2Flibra/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dungba88","download_url":"https://codeload.github.com/dungba88/libra/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dungba88%2Flibra/sbom","scorecard":{"id":359736,"data":{"date":"2025-08-11","repo":{"name":"github.com/dungba88/libra","commit":"14ca069d585f2d756099f69c4e4c5dfb2acc3bfd"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.6,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 1/26 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact joo-libra-2.0.0 not signed: https://api.github.com/repos/dungba88/libra/releases/13589258","Warn: release artifact 2.0.0-rc1 not signed: https://api.github.com/repos/dungba88/libra/releases/13392259","Warn: release artifact 1.0.3 not signed: https://api.github.com/repos/dungba88/libra/releases/8749225","Warn: release artifact joo-libra-2.0.0 does not have provenance: https://api.github.com/repos/dungba88/libra/releases/13589258","Warn: release artifact 2.0.0-rc1 does not have provenance: https://api.github.com/repos/dungba88/libra/releases/13392259","Warn: release artifact 1.0.3 does not have provenance: https://api.github.com/repos/dungba88/libra/releases/8749225"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 5 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":9,"reason":"1 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-wxr5-93ph-8wr9"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-18T10:30:57.472Z","repository_id":75614847,"created_at":"2025-08-18T10:30:57.472Z","updated_at":"2025-08-18T10:30:57.472Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28477632,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T03:13:13.607Z","status":"ssl_error","status_checked_at":"2026-01-16T03:11:47.863Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["antlr4","predicates","sql-predicates"],"created_at":"2026-01-16T06:06:56.311Z","updated_at":"2026-01-16T06:06:57.438Z","avatar_url":"https://github.com/dungba88.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# libra\n\n[![Maven Central](https://img.shields.io/maven-central/v/org.dungba/joo-libra.svg)](http://mvnrepository.com/artifact/org.dungba/joo-libra)\n[![Javadocs](http://javadoc.io/badge/org.dungba/joo-libra.svg)](http://javadoc.io/doc/org.dungba/joo-libra)\n[![Build Status](https://travis-ci.org/dungba88/libra.svg?branch=master)](https://travis-ci.org/dungba88/libra)\n[![Coverage Status](https://coveralls.io/repos/github/dungba88/libra/badge.svg?branch=master\u0026maxAge=86400)](https://coveralls.io/github/dungba88/libra?branch=master)\n\nLibra 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.\n\n## install\n\nLibra can be easily installed with Maven:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.dungba\u003c/groupId\u003e\n    \u003cartifactId\u003ejoo-libra\u003c/artifactId\u003e\n    \u003cversion\u003e\u003c!-- latest version. see above --\u003e\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## how to use\n\nBy 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.\n\n```java\nPredicateContext context = new PredicateContext(customer);\nSqlPredicate predicate = new SqlPredicate(\"customer.age \u003e 50 AND customer.isResidence is true\");\npredicate.satisfiedBy(context);\n```\n\nYou can optionally check for syntax errors:\n```java\nif (predicate.hasError()) {\n    predicate.getCause().printStackTrace();\n}\n```\n\nor throw the exception if any\n```java\npredicate.checkForErrorAndThrow();\n```\n\nfrom `2.0.0` you can retrieve the raw value instead of letting Libra convert it to boolean\n```java\nPredicateContext context = new PredicateContext(customer);\nSqlPredicate predicate = new SqlPredicate(\"customer.asset - customer.liability\");\nObject rawValue = predicate.calculateLiteralValue(context);\n```\n\n## grammar\n\nLibra supports the following syntax for SQL predicates:\n\n- Logic operators: `and`, `or` and `not`\n- Comparison operators: \u003e, \u003e=, \u003c, \u003c=, =, ==, !=, `is`, `is not`\n- Parenthesises\n- List and string operators: `contains` (for both list and string) and `matches` (only for string)\n- Array indexing: `a[0]` (this cannot be used to evaluate a `Map`)\n- String literals, single quoted, e.g: `'John'`\n- Numeric literals: `1`, `1.0`\n- Boolean literals: `true`, `false`\n- Other literals: `null`, `undefined`, `empty`\n- Variables: alphanumerics, `_`, `.` (to denote nested object) and `[`, `]` (to denote array index), must starts with alphabet characters.\n- List: `{1, 2, 3}`. Empty list `{ }` is also supported. \n- Function: `functionName(arg1, arg2...)` It's also possible to configure custom function in `PredicateContext`. Built-in functions: `sqrt`, `avg`, `sum`, `min`, `max`, `len`.\n- Stream matching: See below\n- Subset filtering: See below\n\n**stream matching**\n\nLibra `2.0.0` supports stream-like matching, similar to `anyMatch`, `allMatch` and `noneMatch`. The syntax is:\n\n```\nANY \u003cindexVariableName\u003e IN \u003clistVariableName\u003e SATISFIES \u003cexpression\u003e\nALL \u003cindexVariableName\u003e IN \u003clistVariableName\u003e SATISFIES \u003cexpression\u003e\nNONE \u003cindexVariableName\u003e IN \u003clistVariableName\u003e SATISFIES \u003cexpression\u003e\n```\n\n`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 \u003e 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 `$`.\n\n**subset filtering**\n\nLibra `2.1.0` supports subset filtering from list:\n\n```\nWITH \u003cindexVariableName\u003e IN \u003clistVariableName\u003e SATISFIES \u003cexpression\u003e\n```\n\nFor example `WITH $job IN jobs satisfies $job.salary \u003e 1000` will returns a list of jobs which the `salary` attribute is greater than 1000.\n\nYou can also transform the returned list element using transformation expression:\n\nFor example: `$job.salary WITH $job IN jobs satisfies $job.salary \u003e 1000` will returns a list of *salary* that is greater than 1000 from the job list.\n\n**examples**\n\nSome examples of SQL predicates:\n\n```\nname is 'John' and age \u003e 27\nemployments contains 'LEGO assistant' and name is 'Anh Dzung Bui'\nexperiences \u003e= 4 or (skills contains 'Java' and projects is not empty)\navg(4, 5, 6) is 5\n```\n\nMore examples can be seen inside the [test cases](https://github.com/dungba88/libra/tree/master/src/test/java/org/joo/libra/test)\n\n## quirks and limitations\n\nSome special cases or limitations are covered here:\n- Literals, if stand alone in their own branch, will be converted into predicate according to their types:\n  + String \u0026 list literals will be considered as `true` if and only they are *not null* and *not empty*\n  + Number literals will be considered as `true` if and only they are *not null* and *not zero*\n  + `null` will always be considered as `false`\n- If literals are compared with any other type, the comparison will be as normal\n  + `0 is false` will be evaluated as `false`, since `0` and `false` have different type\n- Variables, if stand alone in their own branch, will be converted into predicate according to their types:\n  + String \u0026 list variables will be considered as `true` if and only if they are *not null* and *not empty*\n  + Number variables will be considered as `true` if and only if they are *not null* and *not zero*\n  + Boolean variables will be considered as their own values\n  + `null` variables will always be considered as `false`\n- When comparing number, they will be converted into `BigDecimal`, so `0.0`, `0` or `0L` are all equal\n\n## optimizers\n\nLibra currently supports a simple [Constant Folding](https://en.wikipedia.org/wiki/Constant_folding) optimization. It will reduces constant-only conditional branches into a single branch. To enable the optimizations, use `OptimizedAntlrSqlPredicateParser` as below:\n\n```java\nSqlPredicate predicate = new SqlPredicate(predicateString, new OptimizedAntlrSqlPredicateParser());\n```\n\nThis will take more time to compile the SQL but will reduce evaluation time.\n\n## extends\n\nThe `SqlPredicate` class allows you to use your own `SqlPredicateParser`:\n\n```java\nSqlPredicate predicate = new SqlPredicate(predicateString, new MyPredicateParser());\n```\n\nyou 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:\n\n```java\nSqlPredicate predicate = new SqlPredicate(predicateString, predicate -\u003e {\n   return something; \n});\n```\n\nor use method reference:\n\n```java\nSqlPredicate predicate = new SqlPredicate(predicateString, this::parseSql);\n```\n\n## performance considerations\n\nIt 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.\n\nThe 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.\n\n## license\n\nThis library is distributed under MIT license. See [LICENSE](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdungba88%2Flibra","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdungba88%2Flibra","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdungba88%2Flibra/lists"}