{"id":18851390,"url":"https://github.com/xnerhu/sql-next","last_synced_at":"2025-04-14T09:52:42.485Z","repository":{"id":57368262,"uuid":"220973317","full_name":"xnerhu/sql-next","owner":"xnerhu","description":"🔎 Mysql client for Node.js with json queries and modern api.","archived":false,"fork":false,"pushed_at":"2023-07-17T19:04:13.000Z","size":117,"stargazers_count":9,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-27T23:11:23.948Z","etag":null,"topics":["javascript","js","json","mysql","nodejs","nosql","sql","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/xnerhu.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["xnerhu"],"patreon":"xnerhu"}},"created_at":"2019-11-11T12:08:44.000Z","updated_at":"2022-05-31T04:20:19.000Z","dependencies_parsed_at":"2024-11-08T03:34:48.020Z","dependency_job_id":"0cce108d-ec16-409c-90bd-a49ccabda43f","html_url":"https://github.com/xnerhu/sql-next","commit_stats":{"total_commits":30,"total_committers":1,"mean_commits":30.0,"dds":0.0,"last_synced_commit":"b98b655b63fbdc078faca6c4969d6d7ce15b7f0b"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xnerhu%2Fsql-next","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xnerhu%2Fsql-next/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xnerhu%2Fsql-next/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xnerhu%2Fsql-next/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xnerhu","download_url":"https://codeload.github.com/xnerhu/sql-next/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248860029,"owners_count":21173339,"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":["javascript","js","json","mysql","nodejs","nosql","sql","typescript"],"created_at":"2024-11-08T03:34:40.740Z","updated_at":"2025-04-14T09:52:42.458Z","avatar_url":"https://github.com/xnerhu.png","language":"TypeScript","readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://wexond.net/public/sql-next-logo.png\" width=\"512\"\u003e\n\n  \u003cbr /\u003e\n\n[![Travis](https://img.shields.io/travis/xnerhu/sql-next.svg?style=flat-square)](https://travis-ci.org/xnerhu/sql-next.svg)\n[![NPM](https://img.shields.io/npm/v/sql-next.svg?style=flat-square)](https://www.npmjs.com/package/sql-next)\n[![NPM](https://img.shields.io/npm/dm/sql-next?style=flat-square)](https://www.npmjs.com/package/sql-next)\n[![Discord](https://discordapp.com/api/guilds/307605794680209409/widget.png?style=shield)](https://discord.gg/P7Vn4VX)\n[![Github](https://img.shields.io/github/followers/xnerhu.svg?style=social\u0026label=Follow)](https://github.com/xnerhu)\n\n\u003c/div\u003e\n\nSQL-next is a wrapper around [node-mysql](https://github.com/mysqljs/mysql), which provides MongoDB like queries and promise-based api.\n\n\u003ca href=\"https://www.patreon.com/bePatron?u=21429620\"\u003e\n  \u003cimg src=\"https://c5.patreon.com/external/logo/become_a_patron_button@2x.png\" width=\"160\"\u003e\n\u003c/a\u003e\n\n### Features\n\n- JSON queries\n- Protection from sql-injection\n- Selectors _(not yet done)_\n- Promise based api\n\nCheckout [roadmap](https://github.com/xnerhu/sql-next/projects/1) to see what's coming.\n\n## Installing\n\n```bash\n$ npm install sql-next\n```\n\n## Quick start\n\nAn example of finding an item:\n\n```ts\nimport { Client, IConfig } from 'sql-next';\n\nconst config: IConfig = {\n  host: 'example.com',\n  user: 'username',\n  password: '123',\n  port: 8080,\n};\n\ninterface Item {\n  _id: number;\n  header: string;\n  body: string;\n}\n\nasync function init() {\n  const client = new Client();\n\n  await client.connect(config);\n\n  console.log('Connected!');\n\n  const db = client.db('name');\n  const table = db.table\u003cItem\u003e('tests');\n\n  const item = await table.findOne({ _id: 2 });\n\n  console.log(item);\n}\n\ninit();\n```\n\nOutput:\n\n```js\n{\n  _id: 2,\n  header: 'Hello world!',\n  body: 'Lorem ipsum...',\n}\n```\n\n## API\n\nClass `Client`:\n\n- [`Client.connect`](#clientConnect)\n- [`Client.close`](#clientClose)\n- [`Client.db`](#clientDb)\n- [`Client.switchUser`](#clientSwitchUser)\n- [`Client.query`](#clientQuery)\n\nClass `Database`:\n\n- [`Database.tables`](#databaseTables)\n- [`Database.table`](#databaseTable)\n\nClass `Table`:\n\n- [`Table.find`](#tableFind)\n- [`Table.findOne`](#tableFindOne)\n- [`Table.count`](#tableCount)\n- [`Table.insertOne`](#tableInsertOne)\n- [`Table.insert`](#tableInsert)\n- [`Table.update`](#tableUpdate)\n\nInterfaces:\n\n- [`IConfig`](#config)\n- [`ISSLConfig`](#sslConfig)\n- [`IQueryFilter`](#queryFilter)\n- [`IQuerySelector`](#querySelector)\n- [`IQueryOptions`](#queryOptions)\n\n## Other\n\n- [`Advanced filtering`](#advancedFiltering)\n\n### Class `Client`\n\n#### Methods\n\n\u003ca name=\"clientConnect\"\u003e\u003c/a\u003e\n\n- `Client.connect(config: string | IConfig)`\n  \u003cbr /\u003e\n  Connects to mysql server.\n  \u003cbr /\u003e\n\n  ```js\n  import { Client } from 'sql-next';\n\n  const client = new Client();\n\n  try {\n    await client.connect({\n      host: 'example.com',\n      user: 'username',\n      password: '123',\n      port: 8080,\n    });\n\n    console.log('Connected!');\n  } catch (error) {\n    console.log('Failed to connect!', error);\n  }\n  ```\n\n\u003ca name=\"clientClose\"\u003e\u003c/a\u003e\n\n- `Client.close()`\n  \u003cbr /\u003e\n  Closes connection.\n  \u003cbr /\u003e\n\n  ```js\n  await client.close();\n\n  console.log('Closed!');\n  ```\n\n\u003ca name=\"clientDb\"\u003e\u003c/a\u003e\n\n- `Client.db(name: string): Database`\n  \u003cbr /\u003e\n  Returns a new database instance that shares the same connection with `Client`.\n  \u003cbr /\u003e\n\n  ```js\n  const client = new Client();\n  const db = client.db('users');\n  ```\n\n\u003ca name=\"clientSwitchUser\"\u003e\u003c/a\u003e\n\n- `Client.switchUser(config: ConnectionOptions)`\n  \u003cbr /\u003e\n  Reconnects with new user credentials.\n  \u003cbr /\u003e\n\n  ```js\n  const client = new Client();\n\n  client.switchUser({\n    user: 'seconduser',\n    password: 'password',\n  });\n  ```\n\n\u003ca name=\"clientQuery\"\u003e\u003c/a\u003e\n\n- `Client.query\u003cT\u003e(sql: string): Promise\u003cT\u003e`\n  \u003cbr /\u003e\n  Performs a raw query globally.\n  \u003cbr /\u003e\n\n  ```js\n  const client = new Client();\n  const news = await client.query('SELECT * from `test`.`news`');\n  ```\n\n### Class `Database`\n\n#### Methods\n\n\u003ca name=\"databaseTables\"\u003e\u003c/a\u003e\n\n- `Database.tables(): Promise\u003cstring[]\u003e`\n  \u003cbr /\u003e\n  Returns a list of tables in a database.\n  \u003cbr /\u003e\n\n  ```js\n  import { Client } from 'sql-next';\n\n  const client = new Client();\n  const db = client.db('test');\n  const tables = await db.tables();\n\n  console.log(tables); // ['users', 'news', ...]\n  ```\n\n\u003ca name=\"databaseTable\"\u003e\u003c/a\u003e\n\n- `Database.table\u003cT\u003e(name: string): Table\u003cT\u003e`\n  \u003cbr /\u003e\n  Returns a new table instance that shares the same connection with `Client`.\n  \u003cbr /\u003e\n\n  ```js\n  import { Client } from 'sql-next';\n\n  const client = new Client();\n  const db = client.db('test');\n  const table = db.table('news');\n\n  const news = await table.find();\n\n  console.log(news); // [{_id: 1, title: 'lorem ipsum'}, ...]\n  ```\n\n#### Properties\n\n- `Database.name`\n\n### Class `Table\u003cT\u003e`\n\n#### Methods\n\n\u003ca name=\"tableFind\"\u003e\u003c/a\u003e\n\n- `Table.find(filter?: IQueryFilter\u003cT\u003e, options?: IQueryOptions): Promise\u003cT[]\u003e`\n  \u003cbr /\u003e\n  Fetches multiple items from a table. You can also set an offset or a limit, by setting `options`. See **todo** for advanced filtering.\n  \u003cbr /\u003e\n\n  ```js\n  const table = db.table('news');\n\n  const news = await table.find({ _authorId: 2 }, { offset: 2, limit: 10 });\n  ```\n\n\u003ca name=\"tableFindOne\"\u003e\u003c/a\u003e\n\n- `Table.findOne(filter?: IQueryFilter\u003cT\u003e): Promise\u003cT[]\u003e`\n  \u003cbr /\u003e\n  Returns a single item from a table. See **todo** for advanced filtering.\n  \u003cbr /\u003e\n\n  ```js\n  const table = db.table('news');\n\n  const item = await table.findOne({ _id: 11 });\n  ```\n\n\u003ca name=\"tableCount\"\u003e\u003c/a\u003e\n\n- `Table.count(filter?: IQueryFilter\u003cT\u003e): Promise\u003cnumber\u003e`\n  \u003cbr /\u003e\n  Counts items in a table.\n  \u003cbr /\u003e\n\n  ```js\n  const table = db.table('news');\n\n  const count = await table.count();\n\n  console.log(count); // 141\n  ```\n\n\u003ca name=\"tableInsert\"\u003e\u003c/a\u003e\n\n- `Table.insert(items: T[]): Promise\u003cT[]\u003e`\n  \u003cbr /\u003e\n  Inserts multiple items to a table and returns each of them with replaced `_id` property.\n  \u003cbr /\u003e\n\n  ```js\n  const table = db.table('news');\n\n  const [first, second] = await table.insert([\n    { title: 'Hello world!' },\n    { title: 'Lorem ipsum' },\n  ]);\n\n  console.log(first._id, second._id); // 1, 2\n  ```\n\n\u003ca name=\"tableInsertOne\"\u003e\u003c/a\u003e\n\n- `Table.insertOne(items: T): Promise\u003cT\u003e`\n  \u003cbr /\u003e\n  Inserts a single item with replaced `_id` property, coresponding to added record.\n  \u003cbr /\u003e\n\n  ```js\n  const table = db.table('news');\n\n  const data = await table.insertOne({ title: 'Cooking tips' });\n\n  console.log(data); // { _id: 3, title: 'Cooking tips' }\n  ```\n\n\u003ca name=\"tableUpdate\"\u003e\u003c/a\u003e\n\n- `Table.update(filter: IQueryFilter\u003cT\u003e, update: IUpdateItem\u003cT\u003e): Promise\u003cT\u003e`\n  \u003cbr /\u003e\n  Updates every items matching `filter` and replaces their fields with `update`.\n  \u003cbr /\u003e\n\n  ```js\n  table.update({ _id: 1 }, { content: 'Hello world!' });\n  ```\n\n#### Properties\n\n- `Table.name`\n\n\u003ca name=\"config\"\u003e\u003c/a\u003e\n\n### Interface `IConfig`\n\n```ts\ninterface IConfig {\n  user?: string;\n  password?: string;\n  port?: number;\n  ssl?: ISSLConfig;\n  charset?: string;\n  insecureAuth?: boolean;\n  socketPath?: string;\n  debug?: boolean | string[];\n  bigNumberStrings?: boolean;\n  connectTimeout?: number;\n  dateStrings?: boolean | ('TIMESTAMP' | 'DATETIME' | 'DATE')[];\n  host?: string;\n  localAddress?: string;\n  supportBigNumbers?: boolean;\n  timeout?: number;\n  timezone?: number;\n  trace?: boolean;\n}\n```\n\n\u003ca name=\"sslConfig\"\u003e\u003c/a\u003e\n\n### Interface `ISSLConfig`\n\n```ts\nimport { SecureContextOptions } from 'tls';\n\nexport type ISSLConfig =\n  | string\n  | (SecureContextOptions \u0026 {\n      rejectUnauthorized?: boolean;\n    });\n```\n\n\u003ca name=\"queryFilter\"\u003e\u003c/a\u003e\n\n### Interface `IQueryFilter`\n\n```ts\nexport type IQueryFilter\u003cT\u003e = {\n  [P in keyof T]?: Partial\u003cT[P]\u003e | RegExp;\n} \u0026\n  IQuerySelector\u003cT\u003e;\n```\n\nIt means that for a type you pass, it will make every key optional and property as original or a regex expression. Also it will include selectors like `$or`.\n\n\u003ca name=\"querySelector\"\u003e\u003c/a\u003e\n\n### Interface `IQuerySelector`\n\n```ts\nexport interface IQuerySelector\u003cT\u003e {\n  $or?: IQueryFilter\u003cT\u003e[];\n```\n\n\u003ca name=\"queryOptions\"\u003e\u003c/a\u003e\n\n### Interface `IQueryOptions`\n\n```ts\nexport interface IQueryOptions {\n  limit?: number;\n  offset?: number;\n```\n\n## Other\n\n\u003ca name=\"advancedFiltering\"\u003e\u003c/a\u003e\n\n### Advanced filtering\n\nLet's say we want to find a group of items with `_authorId` field equals to _2_.\n\nWe can do it like this:\n\n```ts\nconst table = db.table('news');\n\ntable.find({ _authorId: 2 });\n```\n\nAnd what if we want `_categoryId` to be _1_.\n\n```ts\ntable.find({\n  _authorId: 2,\n  _categoryId: 1,\n});\n```\n\nYou can see, that combining properties together works as **AND** selector.\n\nThere are other selectors as well.\n\n#### `$or`\n\nThis will search for the items with `_authorId` = _2_ and `_categoryId` = _1_ or _2_.\n\n```ts\ntable.find({\n  _authorId: 2,\n  $or: [{ _categoryId: 1 }, { _categoryId: 2 }],\n});\n```\n","funding_links":["https://github.com/sponsors/xnerhu","https://patreon.com/xnerhu","https://www.patreon.com/bePatron?u=21429620"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxnerhu%2Fsql-next","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxnerhu%2Fsql-next","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxnerhu%2Fsql-next/lists"}