{"id":36541912,"url":"https://github.com/mw-experts/rsql","last_synced_at":"2026-01-12T05:47:49.777Z","repository":{"id":43005030,"uuid":"245979605","full_name":"mw-experts/rsql","owner":"mw-experts","description":"Complete and thoroughly tested parser for RSQL/FIQL written in Typescript(Javascript). Tool for filtering array of objects using RSQL/FIQL. Built with zero dependencies.","archived":false,"fork":false,"pushed_at":"2023-07-18T21:12:50.000Z","size":845,"stargazers_count":13,"open_issues_count":4,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-11T09:31:07.746Z","etag":null,"topics":["filter","fiql","javascript","nodejs","parser","rsql","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/mw-experts.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}},"created_at":"2020-03-09T08:21:10.000Z","updated_at":"2024-06-27T02:03:21.000Z","dependencies_parsed_at":"2023-02-06T12:00:39.485Z","dependency_job_id":null,"html_url":"https://github.com/mw-experts/rsql","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/mw-experts/rsql","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mw-experts%2Frsql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mw-experts%2Frsql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mw-experts%2Frsql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mw-experts%2Frsql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mw-experts","download_url":"https://codeload.github.com/mw-experts/rsql/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mw-experts%2Frsql/sbom","scorecard":{"id":669686,"data":{"date":"2025-08-11","repo":{"name":"github.com/mw-experts/rsql","commit":"801c6475ff6226caaa75da265a92611de9144cfb"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.9,"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":"Code-Review","score":0,"reason":"Found 1/23 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":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","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":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/validate.yml:1","Info: no jobLevel write permissions found"],"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":"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":"Pinned-Dependencies","score":2,"reason":"dependency not pinned by hash detected -- score normalized to 2","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/validate.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/mw-experts/rsql/validate.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/validate.yml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/mw-experts/rsql/validate.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/validate.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/mw-experts/rsql/validate.yml/main?enable=pin","Info:   0 out of   3 GitHub-owned GitHubAction dependencies pinned","Info:   1 out of   1 npmCommand dependencies pinned"],"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":"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":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"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":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"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 10 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":0,"reason":"19 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-4wf5-vphf-c2xc","Warn: Project is vulnerable to: GHSA-jgrx-mgxx-jf9v","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-hc6q-2mpp-qw7j","Warn: Project is vulnerable to: GHSA-4vvj-4cpr-p986","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q"],"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-21T19:31:47.407Z","repository_id":43005030,"created_at":"2025-08-21T19:31:47.408Z","updated_at":"2025-08-21T19:31:47.408Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28335269,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T00:36:25.062Z","status":"online","status_checked_at":"2026-01-12T02:00:08.677Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["filter","fiql","javascript","nodejs","parser","rsql","typescript"],"created_at":"2026-01-12T05:47:49.678Z","updated_at":"2026-01-12T05:47:49.768Z","avatar_url":"https://github.com/mw-experts.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RSQL / FIQL tools\n\nComplete and thoroughly tested parser for RSQL/FIQL written in Typescript(Javascript).\nTools to work with RSQL: matcher, filter, converter to SQL.\nBuilt with zero dependencies.\n\n## Installing\n\n```sh\nnpm install @mw-experts/rsql\n```\n\nor\n\n```sh\nyarn add @mw-experts/rsql\n```\n\n## Usage\n\n### Import library\n\nImport library as CommonJS module:\n```\nconst rsql = require('@mw-experts/rsql');\n```\n\nImport library as ES6 module:\n```\nimport { RsqlMatcher } from '@mw-experts/rsql';\nimport { RsqlFilter } from '@mw-experts/rsql';\nimport { RsqlToSqlConverter } from '@mw-experts/rsql';\n```\nor\n```\nimport * as rsql from '@mw-experts/rsql';\n```\n\nImport library as standalone script in a browser:\n```\n\u003cscript src=\"../node_modules/@mw-experts/rsql/dist/rsql-browser.js\"\u003e\u003c/script\u003e\n```\n\n## About RSQL / FIQL\n\nRSQL is a query language for parametrized filtering of entries in RESTful APIs.\n\nIt’s based on [FIQL](http://tools.ietf.org/html/draft-nottingham-atompub-fiql-00) (Feed Item Query Language)\nan URI-friendly syntax for expressing filters across the entries in an Atom Feed.\n\nThe simplicity of RSQL and its capability to express complex queries in a compact and HTTP URI-friendly way\nmakes it a good candidate for becoming a generic query language for searching REST endpoints.\n\nFor example, you can query your resource like this:\n\n`/movies?search=name==\"Kill Bill\";year=gt=2003`\n\nor\n\n`/movies?search=director.lastName==Nolan and year\u003e=2000`.\n\nRSQL introduces simple and composite operators which can be used to build basic and complex queries.\n\n### Basic operators:\n\n| Basic Operator | Description         |\n|----------------|---------------------|\n| ==             | Equal To            |\n| !=             | Not Equal To        |\n| =gt=           | Greater Than        |\n| \u003e              | Greater Than        |\n| =ge=           | Greater Or Equal To |\n| \u003e=             | Greater Or Equal To |\n| =lt=           | Less Than           |\n| \u003c              | Less Than           |\n| =le=           | Less Or Equal To    |\n| \u003c=             | Less Or Equal To    |\n| =in=           | In                  |\n| =out=          | Not in              |\n| =includes-all= | Includes all        |\n| =includes-one= | Includes one        |\n\nThese operators can be used to do all sort of simple queries, for example:\n\n* name==Fero: find all people whose name is Fero\n* street!=Darna: find all people who do not live at Darna\n* age=gt=10: find all people older than 10 (exclusive)\n* age\u003e10: find all people older than 10 (exclusive)\n* age=ge=10: find all people older than 10 (inclusive)\n* age\u003e=10: find all people older than 10 (inclusive)\n* house=lt=3: find all people who have less than 3 houses\n* house\u003c3: find all people who have less than 3 houses\n* house=le=3: find all people who have less than or 3 houses\n* house\u003c=3: find all people who have less than or 3 houses\n* name=in=(Fero,Jane) find all people whose name is Fero or Jane\n* name=out=(Alex,Mike) find all people whose name is not Alex or Mike\n* list=includes-all=(item1,item2) find all records where list is array and includes item1 and item2\n* list=includes-one=(item1,item2) find all records where list is array and includes item1 or item2\n\n### Composite operators:\n\n| Composite Operator   | Description         |\n|----------------------|---------------------|\n| ;                    | Logical AND         |\n| and                  | Logical AND         |\n| ,                    | Logical OR          |\n| or                   | Logical OR          |\n\nThese operators can be used to join the simple queries and build more involved queries which can be as complex as required.\nHere are some examples:\n\n* age=gt=10;age=lt=20: find all people older than 10 and younger than 20\n* age=gt=10 and age=lt=20: find all people older than 10 and younger than 20\n* age=lt=5,age=gt=30: find all people younger than 5 or older than 30\n* age\u003c5 or age\u003e30: find all people younger than 5 or older than 30\n* age=gt=10;age=lt=20;name=in=(Fero,Jane): find all people older than 10 and younger than 20 with names either Fero or Jane.\n\n### Fields and Values\n\n#### Fields can only consist of next regexp symbols: **[\\w-.]** (A-Za-z0-9_-.)\n\n* field.name==value\n* field-name==value\n* field_name==value\n* FieldName==value\n* FIELD_NAME_777==value\n\n#### Values can only consist of next regexp symbols:\n\n* in double quotes - space, any unicode letter, any unicode number, `_`, `-`, `.`, `'`, `(`, `)`\n* in single quotes - space, any unicode letter, any unicode number, `_`, `-`, `.`, `\"`, `(`, `)`\n* without quotes - any unicode letter, any unicode number, `_`, `-`, `.`\n* with == or != operators you can also use asterisk `*` as a wildcard\n\n### Ordering\n\nBy default, operators evaluated from left to right.\nHowever, a parenthesized expression can be used to change the precedence.\n\n* age=lt=20;(name==Fero,name==Jane): find all people younger than 20 with names either Fero or Jane.\n\n## Convert RSQL to SQL\n\n```\nconst rsqlStr = 'name==\"Kill Bill\",year=ge=2000';\nlet result;\n\ntry {\n  result = rsql.RsqlToSqlConverter.getInstance().convert(rsqlStr);\n} catch (e) {\n  console.warn(e);\n}\n\nconsole.log(result);\n\n// will output:\n// (\"name\" = 'Kill Bill' OR \"year\" \u003e= '2000')\n```\n\nYou can have different field names wrapper, for example if you use Mysql.\nJust pass a second argument to `convert` method like this:\n\n```\nconst rsqlStr = 'name==\"Kill Bill\",year=ge=2000';\nlet result;\n\ntry {\n  result = rsql.RsqlToSqlConverter.getInstance().convert(rsqlStr, '`');\n} catch (e) {\n  console.warn(e);\n}\n\nconsole.log(result);\n\n// will output:\n// (`name` = 'Kill Bill' OR `year` \u003e= '2000')\n```\n\n* \"=includes-all=\", \"=includes-one=\" operators are not supported in RsqlToSqlConverter\n* Not included in browser bundle\n\n## Filter array of objects\n\n```\nconst data = [\n  { name: 'Kill Bill', year: 2006 },\n  { name: 'Terminator', year: 1998 },\n  { name: 'Matrix', year: 2000 },\n];\n\nconst rsqlStr = 'name==\"Kill Bill\",year=ge=2000';\nlet result = [];\n\ntry {\n  result = rsql.RsqlFilter.getInstance().filter(rsqlStr, data);\n} catch (e) {\n  console.warn(e);\n}\n\nconsole.log(result);\n\n// will output:\n// [\n//  { name: 'Kill Bill', year: 2006 },\n//  { name: 'Matrix', year: 2000 },\n// ]\n```\n\n#### You can ask for deep nested properties using dot separator - `someObj.prop`, or array notation - `someList[0].prop`:\n\n```\nconst data = [\n    {\n        deep: {\n            nested: {\n                field: 777\n            }\n        },\n        list: [1, 2, 3]\n    }\n]\n\nconst rsql = 'deep.nested.field==777';\nconst rsql = 'list[1]==2';\n```\n\n## Match item\n\n```\nconst data = { name: 'Matrix', year: 2000 };\n\nconst rsqlStr = 'name==\"Kill Bill\";year=ge=2000';\n\ntry {\n  result = rsql.RsqlMatcher.getInstance().match(rsqlStr, data);\n} catch (e) {\n  console.warn(e);\n}\n\nconsole.log(result);\n\n// will output: false\n```\n\n\nValue part of matching expression also can be used as path to value, example:\n\n```\nconst data = [\n    {\n        deep: {\n            nested: {\n                field: 2\n            }\n        },\n        list: [1, 2, 3]\n    }\n]\n\nconst rsqlStr = 'deep.nested.field==list[1]';\n\ntry {\n  result = rsql.RsqlMatcher.getInstance().match(rsqlStr, data);\n} catch (e) {\n  console.warn(e);\n}\n\nconsole.log(result);\n\n// will output: true\n```\n\n## Match many items\n\ntypescript version:\n\n```\nconst rsqlStr = 'name==\"Kill Bill\";year=ge=2000';\n\nconst tokens: Token\u003cRsqlTokenType\u003e[] = RsqlTokenizer.getInstance().tokenize(rsqlStr);\nconst ast: RsqlAstRootNode = RsqlParser.getInstance().parse(tokens);\nconst matcher: RsqlMatcher = RsqlMatcher.getInstance();\n\ntry {\n  result1 = matcher.matchWithPreparedAst(ast, { name: 'Matrix', year: 2000 });\n  result2 = matcher.matchWithPreparedAst(ast, { name: 'Kill Bill', year: 2021 });\n} catch (e) {\n  console.warn(e);\n}\n\nconsole.log(result1);\n// will output: false\n\nconsole.log(result2);\n// will output: true\n```\n\njavascript version:\n\n```\nconst rsqlStr = 'name==\"Kill Bill\";year=ge=2000';\n\nconst tokens = rsql.RsqlTokenizer.getInstance().tokenize(rsqlStr);\nconst ast = rsql.RsqlParser.getInstance().parse(tokens);\nconst matcher = rsql.RsqlMatcher.getInstance();\n\ntry {\n  result1 = matcher.matchWithPreparedAst(ast, { name: 'Matrix', year: 2000 });\n  result2 = matcher.matchWithPreparedAst(ast, { name: 'Kill Bill', year: 2021 });\n} catch (e) {\n  console.warn(e);\n}\n\nconsole.log(result1);\n// will output: false\n\nconsole.log(result2);\n// will output: true\n```\n\n#### Filter and Matcher is case-insensitive\n\n* `name==Marina` and `name==marina` will give the same results - Marina, marina \n\n#### Usage of wildcard\n\nYou can use wildcard `*` in `==` and `!=` operators. Example:\n* `name==Ma*` find all items where name starts from `Ma` - Marina, Maxim, Maria \n* `value==*de*` find all items where value starts and ends with any symbols - Made, abcdefg \n\n#### Comparison rules:\n\n* \"==\", \"!=\" before comparison data converts to string\n* \"=gt=\", \"\u003e\", \"=ge=\", \"\u003e=\", \"=lt=\", \"\u003c\", \"=le=\", \"\u003c=\" before comparison data converts to number\n* \"=in=\", \"=out=\" before comparison data converts to string\n* \"=includes-all=\", \"=includes-one=\" before comparison data converts to array of strings\n\n## Authors\n\n* **Andrey Korovin** - [misticwonder](https://github.com/misticwonder)\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE.md](https://github.com/mw-experts/rsql/blob/main/LICENSE) file for details\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmw-experts%2Frsql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmw-experts%2Frsql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmw-experts%2Frsql/lists"}