{"id":23213127,"url":"https://github.com/liitfr/relational-reselect","last_synced_at":"2026-05-02T06:41:35.258Z","repository":{"id":34463616,"uuid":"182591165","full_name":"liitfr/relational-reselect","owner":"liitfr","description":"🤝 A declarative way to express queries with reselect","archived":false,"fork":false,"pushed_at":"2023-01-03T20:17:45.000Z","size":1567,"stargazers_count":2,"open_issues_count":16,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-14T01:04:49.642Z","etag":null,"topics":["immutablejs","join","redux","relational-algebra","relationship","reselect","selector"],"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/liitfr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-04-21T23:06:09.000Z","updated_at":"2019-08-31T14:21:47.000Z","dependencies_parsed_at":"2023-01-15T07:14:43.435Z","dependency_job_id":null,"html_url":"https://github.com/liitfr/relational-reselect","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liitfr%2Frelational-reselect","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liitfr%2Frelational-reselect/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liitfr%2Frelational-reselect/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liitfr%2Frelational-reselect/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/liitfr","download_url":"https://codeload.github.com/liitfr/relational-reselect/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247339158,"owners_count":20923014,"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":["immutablejs","join","redux","relational-algebra","relationship","reselect","selector"],"created_at":"2024-12-18T19:14:32.054Z","updated_at":"2026-05-02T06:41:35.210Z","avatar_url":"https://github.com/liitfr.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# relational-reselect\n\n[![Build Status](https://travis-ci.org/liitfr/relational-reselect.svg?branch=master)](https://travis-ci.org/liitfr/relational-reselect)\n[![Coverage Status](https://coveralls.io/repos/github/liitfr/relational-reselect/badge.svg?branch=master)](https://coveralls.io/github/liitfr/relational-reselect?branch=master)\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/7112f798a4e247c78d531d54a7468837)](https://app.codacy.com/app/liitfr/relational-reselect?utm_source=github.com\u0026utm_medium=referral\u0026utm_content=liitfr/relational-reselect\u0026utm_campaign=Badge_Grade_Dashboard)\n![npm bundle size](https://img.shields.io/bundlephobia/min/relational-reselect.svg)\n![NPM](https://img.shields.io/npm/l/relational-reselect.svg)\n![npm](https://img.shields.io/npm/v/relational-reselect.svg)\n\nWith its decarative style, this library aims to facilitate creation of complex selectors on a normalized store that imposes to perform joins, lookups, relationships, or whatever you call it !\n\n```js\nimport { createSelector } from 'reselect';\nimport Query from 'relational-reselect';\n\n// my selectors\nconst a = createSelector(\n  aSelector,\n  aFn,\n);\nconst b = createSelector(\n  bSelector,\n  bFn,\n);\nconst c = createSelector(\n  cSelector,\n  cFn,\n);\n\n// define my query\nconst myQuery = new Query()\n  .from(a, 'a')\n  .leftJoin(b, 'b')\n  .on(row =\u003e row.getIn(['a', 'id']) === row.getIn(['b', 'aRef']))\n  .leftJoin(c, 'c')\n  .on(row =\u003e row.getIn(['c', 'id']) \u003e= row.getIn(['a', 'cId']));\n\n// get generated selector\nconst mySelector = myQuery.get();\n\n// or directly run it\nconst myData = myQuery.run(state);\n```\n\nother examples are available on dedicated [CodeSandbox](https://codesandbox.io/s/427q264yv0)\n\n## Install\n\n```js\nnpm install --save relational-reselect\n```\n\n## How to write a query ?\n\n![State Machine diagram](./docs/state.jpg?raw=true 'State Machine diagram')\n\n## API\n\n### Query bloc\n\n#### `new Query()`\n\nCreate a new query\n\n#### `get(): Selector`\n\ngenerate selector for this query\n\n#### `run(state: State): Collection`\n\nrun this query (= execute its selector) and return result\n\n### Select bloc\n\n#### `select(selectSpec: SpecificationForTuple): Select`\n\nOptional operation if you need to process data coming from From bloc.\n\n### From bloc\n\nIn this bloc, any `dataSource` can be a selector (a simple one or a `reselect` one) or another valid query if you need to nest them.\n`Aliases` are required for naming `dataSources`, except when you use `except`, `intersect`, and `union` joins\n\n#### `from(dataSource: DataSource, alias: string): From`\n\nRequired operation.\n\n#### Joins\n\nOptional operation. You can join as much data sources as you want as long as you specify how to join them.\nSupported join types are :\n\n- `innerJoin(dataSource: DataSource, alias: string): IncompleteJoin`\n- `leftJoin(dataSource: DataSource, alias: string): IncompleteJoin`\n- `rightJoin(dataSource: DataSource, alias: string): IncompleteJoin`\n- `fullJoin(dataSource: DataSource, alias: string): IncompleteJoin`\n- `except(dataSource: DataSource): CompleteJoin`\n- `intersect(dataSource: DataSource): CompleteJoin`\n- `union(dataSource: DataSource): CompleteJoin`\n- `cartesian(dataSource: DataSource, alias: string): CompleteJoin`\n\nIncomplete joins need to be completed with a `on(specification: SpecificationForMatchingTuple): CompleteJoin`\n\n### Where bloc\n\n#### `where(whereSpec: SpecificationForMatchingTuple): Where`\n\nOptional operation. This filter will be applied over data coming from From or Select (if exists) bloc\n\n### Ordering bloc\n\n#### `orderBy(orderBySpec: SpecificationForOrderingTuples): OrderBy`\n\nOptional operation. This sort will be applied over data coming from From, or Select (if exists), or Where (if exists) bloc\n\n### Grouping bloc\n\nTODO !\n\n### Specification Types\n\n```\ntype Tuple = Map\u003cstring, any\u003e;\ntype SpecificationForTuple = (tuple: Tuple) =\u003e Tuple;\ntype SpecificationForMatchingTuple = (tuple: Tuple) =\u003e boolean;\ntype SpecificationForOrderingTuples = (left: Tuple, right: Tuple) =\u003e number;\n```\n\n## Class Diagram\n\n![Class diagram](./docs/class.jpg?raw=true 'Class diagram')\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliitfr%2Frelational-reselect","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fliitfr%2Frelational-reselect","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliitfr%2Frelational-reselect/lists"}