{"id":15295951,"url":"https://github.com/ktorzpersonal/purescript-ifrit","last_synced_at":"2025-12-12T04:17:29.972Z","repository":{"id":57271519,"uuid":"83154632","full_name":"KtorZPersonal/purescript-ifrit","owner":"KtorZPersonal","description":"An SQL -\u003e NoSQL compiler for data aggregation","archived":false,"fork":false,"pushed_at":"2017-04-02T17:36:06.000Z","size":995,"stargazers_count":12,"open_issues_count":2,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-10-22T16:37:35.035Z","etag":null,"topics":["aggregation","compiler","mapreduce","mongodb","nosql","pipeline","sql"],"latest_commit_sha":null,"homepage":"","language":"PureScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KtorZPersonal.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":"2017-02-25T18:54:55.000Z","updated_at":"2019-12-11T14:55:24.000Z","dependencies_parsed_at":"2022-08-31T00:41:15.599Z","dependency_job_id":null,"html_url":"https://github.com/KtorZPersonal/purescript-ifrit","commit_stats":null,"previous_names":["ktorz/purescript-ifrit"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KtorZPersonal%2Fpurescript-ifrit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KtorZPersonal%2Fpurescript-ifrit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KtorZPersonal%2Fpurescript-ifrit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KtorZPersonal%2Fpurescript-ifrit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KtorZPersonal","download_url":"https://codeload.github.com/KtorZPersonal/purescript-ifrit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248760916,"owners_count":21157455,"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":["aggregation","compiler","mapreduce","mongodb","nosql","pipeline","sql"],"created_at":"2024-09-30T18:08:44.153Z","updated_at":"2025-12-12T04:17:29.911Z","avatar_url":"https://github.com/KtorZPersonal.png","language":"PureScript","readme":"![](.github/ifrit.png)\n\nIfrit ![](https://travis-ci.org/KtorZ/purescript-ifrit.svg?style=flat-square) ![](https://img.shields.io/badge/license-MPL_2.0-blue.svg?style=flat-square) [![](https://img.shields.io/badge/doc-javascript-red.svg?style=flat-square)](https://ktorz.github.io/purescript-ifrit) [![](https://img.shields.io/badge/doc-purescript-c5c5c5.svg?style=flat-square)](https://pursuit.purescript.org/packages/purescript-ifrit)\n=========\n\n# Overview\n\n## What \u0026 Why ?\n\nIfrit is a **compiler from SQL to NoSQL** for data aggregation. NoSQL databases are great at\nmodelling structured, unstructured and polymorphic data and usually offer powerful map-reduce\nbased API when it comes to data aggregation. However, it is truly challenging to leverage those\nAPI in a web service. \n\nIn a nutshell, Ifrit:\n\n- Offers **aggegation capabilities** to any API via a neat and well-known syntax\n- Ensures the **semantic correctness** of a request\n- **Embraces security** concerns by clearly defining the scope of each request\n- Produces an **easy-to-use output**, without any dependencies or pre-requisite setup\n- Has a **small fingerprint** on your integration and performances\n\n# Getting started\n\n## Installation\n\n```\nnpm install ifrit\n```\n\n## Usage\n\n```js\nconst Ifrit = require(\"../dist\")\nconst mongodb = require(\"mongodb\")\nconst schema = require(\"./schema.json\")\n\n/*\n * Names and classes of the first two good guys, ordered by age\n */\nconst query = `\n    SELECT name, details.biographical.class AS class, details.biographical.age AS age\n    WHERE NOT(bad_guy) AND details.physical.gender = \"male\"\n    ORDER BY details.biographical.age\n    LIMIT 2\n`\n\nmongodb.MongoClient\n    .connect(\"mongodb://localhost:27017/ifrit\")\n    .then((db) =\u003e {\n        return db\n            .collection(\"mages\")\n            .aggregate(Ifrit.compile.mongodb(schema, query))\n            .toArray()\n    })\n    .then(console.log)\n    .catch(console.err)\n\n```\n\n## Documentation\n\nIfrit is available as a Node.js module as well as a PureScript module. The JavaScript\ndocumentation is accessible on [github pages](https://ktorz.github.io/purescript-ifrit). A\ndocumentation for PureScript is published on\n[pursuit](https://pursuit.purescript.org/packages/purescript-ifrit/).\n\n## Examples \n\nDifferent scenarios are available on the repository in the `examples` folder. Here's a\nsummary of all examples:\n\n#### schema\n\n[schema](examples/schema.json)\n\n```json\n{\n    \"name\": \"string\",\n    \"bad_guy\": \"boolean\",\n    \"details\": {\n        \"biographical\": {\n            \"age\": \"number\",\n            \"class\": \"string\"\n        },\n        \"physical\": {\n            \"gender\": \"string\",\n            \"height\": \"number\"\n        }\n    },\n    \"spells\": [{\n        \"name\": \"string\",\n        \"power\": \"number\"\n    }]\n}\n```\n\n#### Bad guys' names\n\n[example 001](examples/001.js)\n\n```sql\nSELECT name\nWHERE bad_guy = true\n```\n\n#### Minimal age of female mages\n\n[example 002](examples/002.js)\n\n```sql\nSELECT name, MIN(details.biographical.age) AS min_age\nWHERE details.physical.gender = \"female\"\nGROUP BY NULL\n```\n\n#### Average power for mages under 170cm, by class\n\n[example 003](examples/003.js)\n\n```sql\nSELECT AVG(spells_power) AS power\nFROM (\n    SELECT AVG(spells.power), details.biographical.class AS class\n    WHERE details.physical.height \u003c 170\n)\nGROUP BY class\n```\n\n#### Names and classes of the first two good guys, ordered by age\n\n[example 004](examples/004.js)\n\n```sql\nSELECT name, details.biographical.class AS class, details.biographical.age AS age\nWHERE NOT(bad_guy) AND details.physical.gender = \"male\"\nORDER BY details.biographical.age\nLIMIT 2\n```\n\n#### Names and average size of the first three females order by height\n\n[example 005](examples/005.js)\n\n```sql\nSELECT name, AVG(details.physical.height)\nWHERE details.physical.gender = \"female\"\nGROUP BY NULL\nORDER BY details.physical.height\nLIMIT 3\n```\n\n# How it works \n\nIfrit builds an Abstract Syntax Tree (AST) which represents only syntactycally correct\nrequests. Then, it generates a request corresponding to a specific driver. So far, MongoDB is\nthe only target driver available.\n\n```\n       _                                                                                    __\n        \\                                                                                  /\n         \\   +----------+         +-----------+        +----------+        +----------+   /\n    SQL   = =| tokenize +---------\u003e   parse   +--------\u003e  verify  +--------\u003e generate |= =   NoSQL\n         /   +----------+         +-----------+        +----------+        +----------+   \\\n       _/                                                                                  \\__\n                                                                                       \n```\n\n## Example (MongoDB)\n\n**input**\n```sql\nSELECT COUNT(_id) AS nb_txs WHERE amount \u003e 1000 GROUP BY account.currency\n```\n\n**output**\n```json\n[\n    {\n        \"$match\": {\n            \"amount\": {\n                \"$gt\": 1000\n            }\n        }\n    },\n    {\n        \"$group\": {\n            \"_id\": \"$account.currency\",\n            \"nb_txs\": {\n                \"$sum\": 1\n            }\n        }\n    }\n]\n```\n\n## Schema definition\n\nIfrit acts on a single collection at a time and does not support joins. Therefore, a schema is\nrequired in order to verify the request (semantically and security wise). Schemas are defined\nas JSON objects in a declarative syntaxe.\n\nIfrit supports the following primitive types: `number`, `string`, `boolean` and `null`. Arrays\nand objects can be declared by nesting primitive types in JSON arrays `[]` or objects `{}`. \n\n\u003e Ifrit can only see what's defined in a schema. The compilation will fail if the request tries\n\u003e to use or select a field not present in the schema. This can be used to control the scope of\n\u003e what elements are accessible via the query.\n\n#### Example:\n\n```json\n{\n    \"amount\": \"number\",\n    \"account\": {\n        \"country\": \"string\",\n        \"currency\": \"string\"\n    },\n    \"items\": [{\n        \"price\": \"number\",\n        \"description\": \"string\"\n    }]\n}\n```\n\n\n## SQL language support\n\ntype        | support\n--------    | --------\nprojection  | `SELECT, AS, FROM`\ngrouping    | `GROUP BY`\nfiltering   | `WHERE, LIMIT, OFFSET`\nsorting     | `ORDER BY, DESC, ASC`\noperators   | `AND, OR, NOT, =, !=, \u003e, \u003c`\n\nfunction | applicable type\n-------- | ----------------\nAVG      | number\nCOUNT    | any\nMAX      | number\nMIN      | number\nSUM      | number\n\n\u003e ⚠ Ifrit relies on a strict order of clauses ⚠\n\u003e  \n\u003e - (1) `SELECT`\n\u003e - (2) `FROM`\n\u003e - (3) `WHERE`\n\u003e - (4) `GROUP BY`\n\u003e - (5) `ORDER BY`\n\u003e - (6) `(ASC | DESC)`\n\u003e - (7) `LIMIT`\n\u003e - (8) `OFFSET`\n\n#### Differences with SQL\n\n- Ifrit is case-sensitive, e.g. `AS != as`, `NULL != null`, etc.\n\n- Ifrit doesn't support the `*` selector.\n\n- `ORDER BY` can't be use with `NULL`.\n\n- Ifrit can't `JOIN` from other collections, the `FROM` can only be used to defined derived\n  tables, i.e, define a multi-level pipeline of map / reduce operations.\n\n- Aggregation functions can be applied to numbers when used with `GROUP BY` or directly to\n  array of numbers when apply without. Ifrit also supports nested notation for array of objects\n  (e.g.  `SELECT AVG(items.price)`).\n\n- When no alias is specified, the property of the output schema is named after the selector.\n  (with MongoDB, `.` in names are replaced with `_`).\n\n\n\n# Benchmark\n\nOn a classic i7 quad-core, 16Gb DDR5 RAM / Ubuntu 16.04\n\n```\nSELECT age \n\u003e 9,795 ops/sec ±0.40% (91 runs sampled)\n\nSELECT class AS klass, COUNT(bonus)\n\u003e 4,791 ops/sec ±0.83% (90 runs sampled)\n\nSELECT AVG(age) GROUP BY class\n\u003e 5,754 ops/sec ±0.58% (94 runs sampled)\n\nSELECT is_master WHERE age \u003e 14 AND age \u003c 20\n\u003e 4,586 ops/sec ±0.65% (93 runs sampled)\n\nSELECT AVG(power) AS avg_pow FROM (SELECT AVG(spells.power), age) WHERE age \u003e 18 GROUP BY NULL \n\u003e 2,378 ops/sec ±0.63% (93 runs sampled)\n```\n\n# Changelog \n\n### Roadmap\n\n- Support for `*` joker in select\n- Augment support for binary \u0026 unary operators\n- Augment support for projections \u0026 aggregations functions\n- Support basic arithmetic in projections \u0026 aggregations\n\n### 2017-04-02 | 0.1.0 \n\n- Support for the following keyword:\n    - `SELECT`\n    - `FROM`\n    - `WHERE`\n    - `GROUP BY`\n    - `ORDER BY`\n    - `(ASC | DESC)`\n    - `LIMIT`\n    - `OFFSET`\n\n- Support for the following boolean operators:\n    - `AND`\n    - `OR`\n\n- Support for the following binary operators:\n    - `\u003e`\n    - `\u003c`\n    - `=`\n    - `!=`\n\n- Support for the following unary operators:\n    - `NOT`\n\n- Support for the following functions (projections \u0026 aggregations):\n    - `AVG`\n    - `COUNT`\n    - `MAX`\n    - `MIN`\n    - `SUM`\n\n- Support for aliases inside SELECT\n- Support for nested objects\n- Support for derived tables\n\n# Compatibility\n\n| Driver  | Version |\n| ------  | ------- |\n| MongoDB | ~3.4    |\n\n# Credits\n\n- Chibi Ifrit by [capsicum](http://capsicum.deviantart.com/)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fktorzpersonal%2Fpurescript-ifrit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fktorzpersonal%2Fpurescript-ifrit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fktorzpersonal%2Fpurescript-ifrit/lists"}