{"id":13725538,"url":"https://github.com/terkelg/sqliterally","last_synced_at":"2025-04-06T09:09:07.861Z","repository":{"id":35125936,"uuid":"134201450","full_name":"terkelg/sqliterally","owner":"terkelg","description":"Lightweight SQL query builder","archived":false,"fork":false,"pushed_at":"2022-03-24T12:00:06.000Z","size":63,"stargazers_count":262,"open_issues_count":7,"forks_count":12,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-30T08:08:01.606Z","etag":null,"topics":["mysql","node","node-pg","parameterized","postgres","postgresql","query","query-builder","sql","template-literals"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/terkelg.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":".github/funding.yml","license":"license","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":"terkelg"}},"created_at":"2018-05-21T01:14:38.000Z","updated_at":"2025-02-11T21:57:50.000Z","dependencies_parsed_at":"2022-08-08T05:15:38.631Z","dependency_job_id":null,"html_url":"https://github.com/terkelg/sqliterally","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/terkelg%2Fsqliterally","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/terkelg%2Fsqliterally/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/terkelg%2Fsqliterally/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/terkelg%2Fsqliterally/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/terkelg","download_url":"https://codeload.github.com/terkelg/sqliterally/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247457802,"owners_count":20941906,"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":["mysql","node","node-pg","parameterized","postgres","postgresql","query","query-builder","sql","template-literals"],"created_at":"2024-08-03T01:02:26.516Z","updated_at":"2025-04-06T09:09:07.838Z","avatar_url":"https://github.com/terkelg.png","language":"JavaScript","readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"logo.png\" alt=\"sqliterally\" height=\"100\" /\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://npmjs.org/package/sqliterally\"\u003e\n    \u003cimg src=\"https://badgen.now.sh/npm/v/sqliterally\" alt=\"version\" /\u003e\n  \u003c/a\u003e\n\t\u003ca href=\"https://github.com/terkelg/sqliterally/actions\"\u003e\n\t\t\u003cimg src=\"https://github.com/terkelg/sqliterally/workflows/CI/badge.svg\" alt=\"integration status\" /\u003e\n\t\u003c/a\u003e\n  \u003ca href=\"https://npmjs.org/package/sqliterally\"\u003e\n    \u003cimg src=\"https://badgen.now.sh/npm/dm/sqliterally\" alt=\"downloads\" /\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cb\u003eComposable and safe parameterized queries using tagged template literals\u003c/b\u003e\n\u003c/p\u003e\n\n\u003cbr\u003e\n\nSQLiterally makes it easy to compose safe parameterized SQL queries using template literals. Clauses are automatically arranged which means you can re-use, subquery and append new clauses as you like – order doesn't matter. All queries are well formatted and ready to be passed directly to [`node-pg`](https://github.com/brianc/node-postgres) and [`mysql`](https://github.com/mysqljs/mysql).\n\nUse SQLiterally as a lightweight alternative to extensive query builders like [`Knex.js`](http://knexjs.org/) or when big ORMs are over-kill.\n\n\u003e **OBS**: _SQLiterally provides a lot of freedom by design and it's not meant to reduce the SQL learning curve. It won't prevent you from writing incorrect queries._\n\n## Features\n\n* Build queries programmatically\n* Works directly with [`node-pg`](https://github.com/brianc/node-postgres) and [`mysql`](https://github.com/mysqljs/mysql)\n* Supports nested sub-queries\n* Queries are parametrized  to protect against SQL injections\n* Write SQL as you like with no restrictions using string literals\n* Produces well-formatted queries with line breaks\n* Lightweight with **no dependencies**!\n\nThis module exposes two module definitions:\n\n* **ES Module**: `dist/sqliterally.mjs`\n* **CommonJS**: `dist/sqliterally.js`\n\n\n## Installation\n\n```\nnpm install sqliterally --save\n```\n\n## Usage\n\nThe module exposes two functions:\n * [**sql**](#sqlstring): Use this to construct any query. Useful for complex SQL scripts or when you know the full query and all you need is a parameterized query object.\n * [**query**](#query): Use this to programmatically compose parameterized queries. Useful for constructing queries as you go.\n\n ```js\nimport {sql, query} from 'sqliterally';\n\nlet movie = 'Memento', year = 2001;\n\nsql`SELECT director FROM movies WHERE title = ${movie}`;\n// =\u003e {\n//  text: 'SELECT director FROM movies WHERE title = $1'\n//  sql =\u003e 'SELECT director FROM movies WHERE title = ?'\n//  values =\u003e ['Memento']\n// }\n\nlet q = query\n    .select`director`\n    .select`year`\n    .from`movies`\n    .where`title = ${movie}`\n    .limit`5`;\n\nif (year) q = q.where`year \u003e= ${year}`;\nif (writers) q = q.select`writers`;\n\nq.build();\n// =\u003e {\n//  text: `SELECT director, year FROM movies WHERE title = $1 AND year \u003e= $2 LIMIT 5'\n//  sql =\u003e 'SELECT director, year FROM movies WHERE title = ? AND year \u003e= ? LIMIT 5'\n//  values =\u003e ['Memento', 2001]\n// }\n```\n\n## API\n\n### sql\\`string\\`\n\nReturns: `Object`\n\nThe string can contain nested SQLiterally `query` and `sql` objects.\nIndexes and values are taken care of automatically.\n\nYou can pass this directly to [`node-pg`](https://github.com/brianc/node-postgres) and [`mysql`](https://github.com/mysqljs/mysql).\n\n```js\nlet name = 'Harry Potter';\nlet max = 10, min = 0;\n\nsub = sql`age \u003e ${min} AND age \u003c ${max}`;\nsql`SELECT * FROM x WHERE name = ${name} OR (${sub}) LIMIT 2`;\n// =\u003e {\n//  text: 'SELECT * FROM x WHERE name = $1 OR (age \u003e $2 OR age \u003c $3) LIMIT 2',\n//  sql: 'SELECT * FROM x WHERE name = ? OR (age \u003e ? OR age \u003c ?) LIMIT 2',\n//  values: ['Harry Potter', 0, 10]\n// }\n\nlet script = sql`\nCREATE OR REPLACE FUNCTION update_modified_column()\nRETURNS TRIGGER AS $$\nBEGIN\n    NEW.modified = now();\n    RETURN NEW;\nEND;\n$$ language 'plpgsql';\n`\n// =\u003e { text: 'CREATE OR REPL...', sql: 'CREATE OR REPL...' values: [] }\n```\n\n#### text\n\nType: `String`\n\nGetter that returns the parameterized string for [Postgres](https://github.com/brianc/node-postgres).\n\n\n#### sql\n\nType: `String`\n\nGetter that returns the parameterized string for [MySQL](https://github.com/mysqljs/mysql).\n\n\n#### values\n\nType: `Array`\n\nGetter that returns the corresponding values in order.\n\n\n### query\n\nBuild a query by adding clauses. The order in which clauses are added doesn't matter. The final output is sorted and returned in the correct order no matter what order you call the methods in.\n\nYou can nest as many `query` and `sql` as you like. You don't have to build sub-queries before nesting them.\n\n`query` is immutable and all method calls return a new instance. This means you can build up a base query and re-use it. For example, with conditional where clauses or joins.\n\n\u003e **OBS:** If you call a method multiple times, the values are concatenated in the same order you called them.\n\n```js\nlet age = 13, limit = 10, page = 1, paginate = false;\n\nlet sub = query\n    .select`id`\n    .from`customers`\n    .where`salary \u003e 45000`;\n\nlet main = query\n    .select`*`\n    .from`customers`\n    .where`age \u003e '${age}'`\n    .where`id IN (${sub})`;\n\nmain = paginate ? main.limit`${limit} OFFSET ${limit * page}` : main;\n\nmain.build();\n```\n\n#### build(delimiter?)\n\nConstructs the final query and returns a [`sql`](#sql) query object ready for [`node-pg`](https://github.com/brianc/node-postgres) and [`mysql`](https://github.com/mysqljs/mysql).\n\n\u003e You can still append to the returned `sql` object or use it as a sub-query. You don't have to call `.build()` when nesting queries – there's no reason to call build before you need the parameterized string and values.\n\n##### delimiter\n\nType: `String`\u003cbr\u003e\nDefault: `\\n`\n\nChange the delimiter used to combine clauses. The default is a line break.\n\n#### select\\`string\\`\n\nReturns: `query`\n\nAll `.select` calls get reduced and joined with `, ` on `.build()`.\n\n```js\nquery.select`*`.build()\n// =\u003e SELECT *\nquery.select`cat`.select`zebra`.build()\n// =\u003e SELECT cat, zebra\nquery.select`cat, dog`.select`zebra`.build()\n// =\u003e SELECT cat, dog, zebra\nquery.select`something`.select`5 * 3 AS result`.build()\n// =\u003e SELECT something, 5 * 3 AS result\n```\n\n\n#### update\\`string\\`\n\nReturns: `query`\n\nCalling `.update` more than once result in the clause being overwritten.\n\n```js\nquery.update`film`.build()\n// =\u003e UPDATE film\nquery.update`film`.update`books`.build()\n// =\u003e UPDATE books\n```\n\n#### set\\`string\\`\n\nReturns: `query`\n\nAll `.set` calls get reduced and joined with `, ` on `.build()`.\n\n```js\nquery.set`a = b`.build()\n// =\u003e SET a = b\nquery.set`a = b`.set`z = y`.build()\n// =\u003e SET a = b, z = y\n```\n\n#### from\\`string\\`\n\nReturns: `query`\n\nCalling `.from` more than once result in the clause being overwritten.\n\n```js\nquery.from`film`.build()\n// =\u003e FROM film\nquery.from`film AS f`.build()\n// =\u003e FROM film AS f\nquery.from`film`.from`books`.build()\n// =\u003e FROM books\n```\n\n#### join\\`string\\`\n\nReturns: `query`\n\n```js\nquery.join`c ON d`.build()\n// =\u003e JOIN c ON d\nquery.join`a ON b.id`.join`c ON d`.build()\n// =\u003e JOIN a ON b.id\\nJOIN c ON d\n```\n\n#### leftJoin\\`string\\`\n\n```js\nquery.leftJoin`c ON d`.build()\n// =\u003e LEFT JOIN c ON d\nquery.leftJoin`a ON b.id`.leftJoin`c ON d`.build()\n// =\u003e LEFT JOIN a ON b.id\\nLEFT JOIN c ON d\n```\n\n#### where\\`string\\`\n\nReturns: `query`\n\nAll `.where` calls get reduced and joined with ` AND ` on `.build()`.\n\n```js\nquery.where`a \u003c b`.build()\n// =\u003e WHERE a \u003c b\nquery.where`a \u003c b`.where`z = y`.build()\n// =\u003e WHERE a \u003c b AND z = y\nquery.where`a = z OR a = y`.build()\n// =\u003e WHERE a = z OR a = y\n```\n\n#### orWhere\\`string\\`\n\nReturns: `query`\n\nAll `.orWhere` calls get reduced and joined with ` OR ` on `.build()`.\n\n```js\nquery.orWhere`a \u003c b`.build()\n// =\u003e WHERE a \u003c b\nquery.orWhere`a \u003c b`.orWhere`z = y`.build()\n// =\u003e WHERE a \u003c b OR z = y\n```\n\n#### having\\`string\\`\n\nReturns: `query`\n\nAll `.having` calls get reduced and joined with ` AND ` on `.build()`.\n\n```js\nquery.having`MAX (list_price) \u003e 4000`\n// =\u003e HAVING MAX (list_price) \u003e 4000\nquery.having`MAX (list_price) \u003e 4000`.having`MIN (list_price) \u003c 500`\n// =\u003e HAVING MAX (list_price) \u003e 4000 AND MIN (list_price) \u003c 500'\n```\n\n#### orHaving\\`string\\`\n\nReturns: `query`\n\nAll `.orHaving` calls get reduced and joined with ` OR ` on `.build()`.\n\n```js\nquery.orHaving`MAX (list_price) \u003e 4000`\n// =\u003e HAVING MAX (list_price) \u003e 4000\nquery.orHaving`MAX (list_price) \u003e 4000`.orHaving`MIN (list_price) \u003c 500`\n// =\u003e HAVING MAX (list_price) \u003e 4000 OR MIN (list_price) \u003c 500'\n```\n\n#### groupBy\\`string\\`\n\nReturns: `query`\n\nAll `.groupBy` calls get reduced and joined with `, ` on `.build()`.\n\n```js\nquery.groupBy`a, b`.groupBy`c`.groupBy`d`.build()\n// =\u003e GROUP BY a, b, c, d\n```\n\n#### orderBy\\`string\\`\n\nReturns: `query`\n\nAll `.orderBy` calls get reduced and joined with `, ` on `.build()`.\n\n```js\nquery.orderBy`a, b`.orderBy`COUNT(c) DESC`.orderBy`d`.build()\n// =\u003e ORDER BY a, b, COUNT(c) DESC, d\n```\n\n#### limit\\`string\\`\n\nReturns: `query`\n\nCalling `.limit` more than once result on the clause being overwritten.\n\n```js\nquery.limit`5`.build()\n// =\u003e LIMIT 5\nquery.limit`5 OFFSET 2`.build()\n// =\u003e LIMIT 5 OFFSET 2\nquery.limit`5`.limit`10`.build()\n// =\u003e LIMIT 10\n```\n\n#### returning\\`string\\`\n\nReturns: `query`\n\nAll `.returning` calls get reduced and joined with `, ` on `.build()`.\n\n```js\nquery.returning`a, b`.returning`c`.returning`d`.build()\n// =\u003e RETURNING a, b, c, d\n```\n\n#### lockInShareMode\n\nReturns: `query`\n\nGetter method. Multiple invocations get ignored.\n\n```js\nquery.lockInShareMode.build()\n// =\u003e LOCK IN SHARE MODE\nquery.select`*`.from`x`.lockInShareMode.build()\n// =\u003e SELECT * FROM x LOCK IN SHARE MODE\n```\n\n#### forUpdate\n\nReturns: `query`\n\nGetter method. Multiple invocations get ignored.\n\n```js\nquery.forUpdate.build()\n// =\u003e FOR UPDATE\nquery.select`*`.from`x`.forUpdate.build()\n// =\u003e SELECT * FROM x FOR UPDATE\nquery.select`*`.from`x`.lockInShareMode.forUpdate.build()\n// =\u003e SELECT * FROM x LOCK IN SHARE MODE FOR UPDATE\n```\n\n## Credit\n\nThis module is inspired by [sql-concat](https://github.com/TehShrike/sql-concat) but with a different implementation, support for Postgres, single queries and with a reduced API.\n\nThe `sql` function and merge algorithm are based on [prepare-sql](https://github.com/hyperdivision/prepare-sql).\n\n\n## License\n\nMIT © [Terkel Gjervig](https://terkel.com)\n","funding_links":["https://github.com/sponsors/terkelg"],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fterkelg%2Fsqliterally","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fterkelg%2Fsqliterally","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fterkelg%2Fsqliterally/lists"}