{"id":13452488,"url":"https://github.com/Schniz/cuery","last_synced_at":"2025-03-23T19:34:23.966Z","repository":{"id":66364986,"uuid":"61943422","full_name":"Schniz/cuery","owner":"Schniz","description":"A composable SQL query builder using template literals :sparkles:","archived":false,"fork":false,"pushed_at":"2019-03-31T09:22:26.000Z","size":237,"stargazers_count":219,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-10T16:52:00.505Z","etag":null,"topics":[],"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/Schniz.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}},"created_at":"2016-06-25T13:00:40.000Z","updated_at":"2025-03-02T17:31:28.000Z","dependencies_parsed_at":"2023-02-20T16:01:14.405Z","dependency_job_id":null,"html_url":"https://github.com/Schniz/cuery","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Schniz%2Fcuery","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Schniz%2Fcuery/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Schniz%2Fcuery/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Schniz%2Fcuery/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Schniz","download_url":"https://codeload.github.com/Schniz/cuery/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245159438,"owners_count":20570387,"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":[],"created_at":"2024-07-31T07:01:25.626Z","updated_at":"2025-03-23T19:34:23.666Z","avatar_url":"https://github.com/Schniz.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# Cuery - Composable SQL Querying [![CircleCI status](https://circleci.com/gh/Schniz/cuery.svg?style=svg)](https://circleci.com/gh/Schniz/cuery)\n\n\u003e A composable SQL query builder based inspired by\n\u003e [styled-components :nail_care:](https://styled-components.com) :sparkles:\n\n:dancer: Replace weird `$1` or `?` in your queries with simple functions!\n\n:star: PostgreSQL and MySQL support!\n\n:lock: Type safety (and autocompletion) with TypeScript\n\n## Why\n\nIn 2016, I wrote a blog post about\n[composing SQL queries](https://medium.com/@galstar/composable-sql-in-javascript-db51d9cae017)\nand published this library as a reference. The years passed, and there are much\ncooler ways of doing it, so this is the new way - using template literals.\n\n# Installation\n\nFor PostgreSQL users:\n\n```bash\nyarn add cuery pg\n# or\nnpm install --save cuery pg\n```\n\nFor MySQL users:\n\n```bash\nyarn add cuery mysql\n# or\nnpm install --save cuery mysql\n```\n\n# API\n\nImport the modules for the database you use:\n\n- `cuery/pg` for PostgreSQL\n- `cuery/mysql` for MySQL\n\nBoth modules export the same two basic functions:\n\n### `sql\u003cInput, Output\u003e` template literal\n\nThe `sql\u003cInput, Output\u003e` template literal is meant for constructing an SQL query. It accepts functions, that will be acted as \"getters\" from the object you supply to the execute function, and compose other SQL queries too.\n\nThe two generics are meant for type safety, so you would declare your input and output types co-located with your query, just like a function: `(input: Input) =\u003e Output`.\n\nIt returns an SQL query, that later can be `execute`d with the options needed, such as a `pool` (or a `connection` in MySQL)\n\n```ts\nconst returnsNumber = sql\u003c\n  {}, // Takes no parameters as input\n  { age: number }\n\u003e` // Returns a number as output\n  SELECT 27 AS age\n`;\n\nconst takesNumberAndReturnsIt = sql\u003c\n  { age: number }, // Takes a number as input\n  { age: number }\n\u003e` // Returns a number as output\n  SELECT ${p =\u003e p.age} AS age\n`;\n\n(await takesNumberAndReturnsIt.execute({ age: 27 }, { pool: new Pg.Pool() }))[0]\n  .age === 27;\n```\n\n### `createSqlWithDefaults(defaults)`\n\nThis function returns an `sql\u003cInput, Output\u003e` template literal function, that defaults to a specific execute options.\nNormally, it would be stored in a specific file in your project, that contains the information about the database connection, so you won't need to pass it all around your application.\n\n```ts\nconst sql = createSqlWithDefaults({ pool: new Pg.Pool() });\nconst query = sql\u003c{}, { age: number }\u003e`SELECT 27 AS age`;\n(await query.execute({}))[0].age === 27;\n```\n\n### `raw`\n\nThis function is a helper function to say that the primitive passed into this function should be stringified and be added \"as is\" to the query. This is unsafe by nature, but when used correctly can have good implications like generating table names.\n\n```ts\nsql\u003c{}, {}\u003e`SELECT 27 AS ${raw(\"age\")}`;\n```\n\n# Usage\n\n### PostgreSQL\n\n```ts\nimport { sql } from \"cuery/pg\";\n\nconst usersQuery = sql`SELECT name, age FROM users`;\nconst usersWithNameQuery = sql\u003c{ name: string }, { name: string; age: number }\u003e`\n  SELECT name, age FROM (${usersQuery})\n  WHERE name = ${params =\u003e params.name}\n`;\n\n// pool = new Pg.Pool()\n\nconst rows = await usersWithNameQuery.execute({ name: \"John\" }, { pool });\nrows[0].age; // Type safe!\n```\n\n### MySQL\n\n```ts\nimport { sql } from \"cuery/mysql\";\n\nconst usersQuery = sql`SELECT name, age FROM users`;\nconst usersWithNameQuery = sql\u003c{ name: string }, { name: string; age: number }\u003e`\n  SELECT name, age FROM (${usersQuery})\n  WHERE name = ${params =\u003e params.name}\n`;\n\n// connection = create a new mysql connection\n\nconst rows = await usersWithNameQuery.execute({ name: \"John\" }, { connection });\nrows[0].age; // Type safe!\n```\n\n## Transformations\n\nYou can declare helper methods that do magic on your queries, like `limit`:\n\n```ts\nfunction limit\u003cInput, Output\u003e(query: Query\u003cInput, Output\u003e) {\n  return sql\u003cInput \u0026 { limit: Number; offset: Number }, Output\u003e`\n    SELECT *\n    FROM (${query}) LIMITED__QUERY__${raw(Math.floor(Math.random() * 99999))}\n    LIMIT ${p =\u003e p.limit}\n    OFFSET ${p =\u003e p.offset}\n  `;\n}\n\n// then you can just compose your queries!\n\nconst users = sql\u003c\n  {},\n  { name: string; age: number }\n\u003e`SELECT name, age FROM users`;\nconst usersWithLimit = limit(users);\nexecute(usersWithLimit, { limit: 10, offset: 10 }); // start with offset of 10, then take 10 records.\n```\n\n# Running tests\n\n```bash\ndocker run --rm -d -p 5432:5432 -e POSTGRES_PASSWORD=password postgres:10\ndocker run --rm -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=password mysql:5.7\nnpm test\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSchniz%2Fcuery","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSchniz%2Fcuery","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSchniz%2Fcuery/lists"}