{"id":15069803,"url":"https://github.com/sangupta/gather","last_synced_at":"2025-09-12T18:50:32.649Z","repository":{"id":21733891,"uuid":"92934824","full_name":"sangupta/gather","owner":"sangupta","description":"Run SQL queries on Java objects in a collection","archived":false,"fork":false,"pushed_at":"2022-04-22T05:03:58.000Z","size":132,"stargazers_count":38,"open_issues_count":4,"forks_count":4,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-24T14:45:53.818Z","etag":null,"topics":["dynamic-queries","hoc-queries","in-memory","java","java-collections","sql","sql-query"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sangupta.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-05-31T10:29:16.000Z","updated_at":"2024-06-06T09:22:25.000Z","dependencies_parsed_at":"2022-08-07T10:01:10.027Z","dependency_job_id":null,"html_url":"https://github.com/sangupta/gather","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sangupta%2Fgather","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sangupta%2Fgather/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sangupta%2Fgather/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sangupta%2Fgather/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sangupta","download_url":"https://codeload.github.com/sangupta/gather/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248256818,"owners_count":21073600,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["dynamic-queries","hoc-queries","in-memory","java","java-collections","sql","sql-query"],"created_at":"2024-09-25T01:44:47.578Z","updated_at":"2025-04-10T16:53:28.040Z","avatar_url":"https://github.com/sangupta.png","language":"Java","readme":"# Gather\n\n[![Build Status](https://img.shields.io/travis/sangupta/gather.svg)](https://travis-ci.org/sangupta/gather)\n[![Coverage Status](https://img.shields.io/coveralls/sangupta/gather.svg)](https://coveralls.io/github/sangupta/gather?branch=master)\n[![License](https://img.shields.io/github/license/sangupta/gather.svg)](https://opensource.org/licenses/Apache-2.0)\n[![Maven Central](https://img.shields.io/maven-central/v/com.sangupta/gather.svg)](https://maven-badges.herokuapp.com/maven-central/com.sangupta/gather)\n\n`Gather` is an ultra-lightweight, 37KB, no dependencies library to fire SQL like queries on Java collections\nand arrays. The data is not inserted into any in-memory database, nor any index is created. The query is matched\nagainst all the objects (could be different types as well) against the provided query. Useful to run ad-hoc\nqueries and aggregation functions, say on XML/JSON/CSV and more.\n\nThe library is tested on the following JDK versions:\n\n* Oracle JDK 9\n* Oracle JDK 8\n* Oracle JDK 7\n\n## Table of Contents\n\n* [Usecases](#usecases)\n* [Usage Examples](#usage-examples)\n* [Composed Objects and Keys](#composed-objects-and-keys)\n* [Features](#features)\n* [Roadmap](#roadmap)\n* [Clause chaining and Evaluation](#clause-chaining-and-evaluation)\n* [Performance](#performance)\n* [Downloads](#downloads)\n* [Release Notes](#release-notes)\n* [Versioning](#versioning)\n* [License](#license)\n\n## Usecases\n\nThe library is useful in the following scenarios:\n\n* Run ad-hoc queries during development to debug data-sets and tweak DB queries\n* Run ad-hoc queries on production data via some admin interface\n* Query on objects of different types in one-shot, say `List\u003cObject\u003e` than `List\u003cEmployee\u003e`\n* Works with JDK 9, 8, 7 and legacy code\n\n\n## Usage Examples\n\n```java\nList\u003cEmployee\u003e employees = this.employeeService.getAllEmployeesFromDatabase();\n\n// prepare a query\nGather query = Gather.where(\"age\").greaterThan(50).and(\"status\").is(\"active\");\n\n// fire query\nList\u003cEmployee\u003e filtered = query.find(employees);\n\n// reuse the query for another collection\nList\u003cManager\u003e managers = this.employeeService.getAllManagersFromDatabase();\n\nList\u003cManager\u003e filteredManagers = query.find(managers);\n\n// null check operations\nquery = Gather.where(\"name\").isNull();\nquery = Gather.where(\"name\").isNotNull();\n\n// not operator\nquery = Gather.where(\"name\").not().is(\"sandeep\");\n\n// find instances that have a property\n// one of the two ways can be employed\ngather = Gather.where(\"name\").existsProperty();\ngather = Gather.hasProperty(\"name\");\n\n// query if an attribute which is a collection or an array contains a given value\n// converting between various primitive value types is supported\ngather = Gather.where(\"someFloatArray\").has(new Double(123));\n\n// run over collections as well\ngather = Gather.where(\"collection\").has(objectInstance);\n\n// find a single instance\nquery.findOne(employees);\n\n// find limited instances\nquery.find(employees, 5);\n\n// find 5 instances, but skip the first 10 instances\nquery.find(employees, 5, 10);\n\n// count the number of results rather than accumulating them\n// this is much faster and memory efficient\nint numResults = query.count(employees);\n```\n\n## Composed Objects and Keys\n\n`Gather` supports composed objects and keys in the `where` clause based on them. For example: the\nfollowing query will search all objects in the collection/array called `children` which have an `age`\nattribute and its value is less than `40`.\n\n```java\nGather query = Gather.where(\"children.age\").lessThan(10);\n\nquery.find(employees);\n\npublic class Employee {\n\n  public List\u003cChild\u003e children;\n\n}\n\npublic class Child {\n\n  public int age;\n\n}\n```\n\n## Features\n\n* Gathering operations\n  * `find` - find all matching objects, with options to skip elements and/or limit number of matches\n  * `findOne` - find the first matching object\n  * `count` - count the total number of matching objects\n  * `aggregate` - run a custom aggregator on a collection/array for a given field\n* Supported operations\n  * `is` - equals match\n  * `isIgnoreCase` - equals match ignoring case on strings\n  * `isNull` - check if a property is null\n  * `isNotNull` - check if a property is not null\n  * `like` - wildcard match on strings\n  * `regex` - Java regular expression match on strings\n  * `has` - check if value is contained in a collection or an array\n  * `hasAll` - check if all values are contained in a collection or an array\n  * `hasAny` - check if any of the value are present in a collection or an array\n  * `not` - negate the match expression\n  * `existsProperty` - check if property exists on object\n  * `notExistsProperty` - check if property does not exists on object\n  * `lessThan` - if a value is less than property value\n  * `lessThanOrEquals` - if a value is equal or less than property value\n  * `greaterThan` - if a value is greater than property value\n  * `greaterThanOrEquals` - if a value is equal or greater than property value\n* Boolean operations supported\n  * `and` - Boolean AND between two clauses\n  * `or` - Boolean OR between two clauses\n* Aggregation operations\n  * `averageAsLong` - find average value of a field which has no decimal part\n  * `averageAsDouble` - find average value of a field which has a decimal part\n  * `minAsLong` - find minimum value of a field which has no decimal part\n  * `minAsDouble` - find minimum value of a field which has a decimal part\n  * `maxAsLong` - find maximum value of a field which has no decimal part\n  * `maxAsDouble` - find maximum value of a field which has a decimal part\n  * `sumAsLong` - find total sum of value of a field which has no decimal part\n  * `sumAsDouble` - find total sum of value of a field which has a decimal part\n  * `unique` - find the number of unique objects from the result set\n  * `count` - count objects in a collection/array which have a given field\n\n## RoadMap\n\n* Support for `uniqueAs(\"someKey\", String.class)` to return `Set\u003cString\u003e` than `Set\u003cObject\u003e`\n* Support for `groupBy(\"someKey\")` to return a `Map\u003cObject, List\u003cObject\u003e\u003e`\n\n## Clause chaining and Evaluation\n\nWhen more than one clause is added to the query and Boolean operations like `AND` or `OR` are used\nto connect them, the evaluation happens from left to right. The first clause is evaluated first and\nthen the result is boolean `AND`/`OR` with the result of next clause depending on connecting operation\ntype.\n\nFor example:\n\n```java\nGather.where(\"name\").like(\"sandeep*\").and(\"age\").lessThan(50).or(\"status\").is(\"active\");\n```\n\nThe evaluation happens in the order:\n\n```java\nboolean first = evaluate(\"name like 'sandeep*'\");\nboolean second = evaluate(\"age \u003c 50\");\nboolean third = evaluate(\"status == 'active'\");\nreturn first \u0026 second | third;\n```\n\n## Performance\n\nPerformance numbers and percentage changes (compared to previous run). Values are operations-per-second.\nAn operation is a query fired over a million objects created randomly for a `LIKE` clause and a `GREATER THAN`\nclause.\n\n| Version  |   Date Run   | `LIKE` clause | %age change | Numeric `GREATER THAN` clause | %age change |\n|----------|--------------|---------------|-------------|-------------------------------|-------------|\n|  1.0.0   | 10 Jan 2018  |     3.240     |     n/a     |        3.215                  |      n/a    |\n|  1.2.0   | 10 Jan 2018  |     4.160     |     +28     |        5.792                  |      +80    |\n| Snapshot | 10 Jan 2018  |     5.322     |     +28     |        5.735                  |      +0     |\n\nTest Machine specs:\n\n```\nMacbook Pro (2017)\n2.9GHz Intel i7\n16GB RAM\nOS X 10.12.6\nOracle JDK 1.8.0_131\nTests run from inside Eclipse Oxygen.2 (4.7.2) release\n```\n\nJMH options used were:\n\n```\n# JMH version: 1.19\n# VM version: JDK 1.8.0_131, VM 25.131-b11\n# VM invoker: /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/bin/java\n# VM options: -Dfile.encoding=UTF-8\n# Warmup: 5 iterations, 1 s each\n# Measurement: 20 iterations, 1 s each\n# Timeout: 10 min per iteration\n# Forks: 5\n# Threads: 1 thread, will synchronize iterations\n# Benchmark mode: Throughput, ops/time\n```\n\n**Caveat:** Your mileage may vary.\n\n## Downloads\n\nThe latest stable release of the library can be downloaded via the Maven Central using the following coordinates:\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.sangupta\u003c/groupId\u003e\n  \u003cartifactId\u003egather\u003c/artifactId\u003e\n  \u003cversion\u003e1.2.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\nThe current/latest development snapshot `JAR` can be obtained using `JitPack.io` as:\n\nAdd the following repository to Maven,\n\n```xml\n\u003crepository\u003e\n  \u003cid\u003ejitpack.io\u003c/id\u003e\n  \u003curl\u003ehttps://jitpack.io\u003c/url\u003e\n\u003c/repository\u003e\n```\n\nThen add the dependency as,\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.github.sangupta\u003c/groupId\u003e\n    \u003cartifactId\u003egather\u003c/artifactId\u003e\n    \u003cversion\u003e-SNAPSHOT\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Release Notes\n\n**Snapshot**\n\n* Improve performance of `wildcard` matches\n\n**1.2.0 (21 Dec 2017)**\n\n* Query on `object arrays` than just `Collections`\n* Added caching to improve performance\n* Updated for newer OSSRH release guidelines\n* Updated `javadocs` and copyright headers\n\n**1.0.0 (09 Jun 2017)**\n\n* First stable release\n\n\n## Versioning\n\nFor transparency and insight into our release cycle, and for striving to maintain\nbackward compatibility, `gather` will be maintained under the Semantic\nVersioning guidelines as much as possible.\n\nReleases will be numbered with the follow format:\n\n```\n\u003cmajor\u003e.\u003cminor\u003e.\u003cpatch\u003e\n```\n\nAnd constructed with the following guidelines:\n\n* Breaking backward compatibility bumps the major\n* New additions without breaking backward compatibility bumps the minor\n* Bug fixes and misc changes bump the patch\n\nFor more information on SemVer, please visit http://semver.org/.\n\n## License\n\n```\n gather: SQL queries for Java collections\n Copyright (c) 2017-2018, Sandeep Gupta\n\n https://sangupta.com/projects/gather\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n      http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsangupta%2Fgather","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsangupta%2Fgather","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsangupta%2Fgather/lists"}