{"id":23512776,"url":"https://github.com/baethon/kex","last_synced_at":"2025-04-19T12:18:06.768Z","repository":{"id":46200078,"uuid":"259882627","full_name":"baethon/kex","owner":"baethon","description":"ORM-less for Knex","archived":false,"fork":false,"pushed_at":"2023-01-11T03:55:37.000Z","size":401,"stargazers_count":17,"open_issues_count":3,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2023-03-03T15:17:34.546Z","etag":null,"topics":["knex","knexjs","models","query-builder"],"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/baethon.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2020-04-29T09:32:08.000Z","updated_at":"2021-11-08T10:41:32.000Z","dependencies_parsed_at":"2023-02-09T01:16:44.574Z","dependency_job_id":null,"html_url":"https://github.com/baethon/kex","commit_stats":null,"previous_names":[],"tags_count":null,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baethon%2Fkex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baethon%2Fkex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baethon%2Fkex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baethon%2Fkex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/baethon","download_url":"https://codeload.github.com/baethon/kex/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":231237746,"owners_count":18345795,"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":["knex","knexjs","models","query-builder"],"created_at":"2024-12-25T13:19:25.612Z","updated_at":"2024-12-25T13:19:26.311Z","avatar_url":"https://github.com/baethon.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Node.js CI](https://github.com/baethon/kex/workflows/Node.js%20CI/badge.svg?branch=master)\n[![npm version](https://badge.fury.io/js/%40baethon%2Fkex.svg)](https://badge.fury.io/js/%40baethon%2Fkex)\n\n# @baethon/kex\n\nKex is a query extension for [Knex](https://knexjs.org/). It uses the concept of \"model\" from ORMs like [Lucid](https://github.com/adonisjs/lucid), or [Laravel Eloquent](https://laravel.com/docs/7.x/eloquent) restricted only to make queries. It has support for scopes, plugins, relations, and many more.\n\n## Installation\n\nInstall the package:\n\n```\nnpm i @baethon/kex\n```\n\nSet up Kex instance:\n\n```js\nconst knex = require('knex')({ /* ... */ })\nconst { Kex } = require('@baethon/kex')\n\nconst kex = new Kex({ knex })\n```\n\nCreate first model:\n\n```js\nconst User = kex.createModel('User')\n```\n\n## Making queries\n\nKex models uses the Knex query builder. To start the query, use `query()` method:\n\n```js\nconst usersList = await User.query()\n```\n\nThe query object is chainable:\n\n```js\nconst activeUsers = await User.query()\n  .where({ active: true })\n```\n\nIn some cases, you can omit the `query()` method and start chaining using following methods:\n\n- `where()`\n- `whereIn()`\n- `insert()`\n- `returning()`\n\n```js\nconst activeUsers = await User.where({ active: true })\n```\n\nUnlike Knex, the models don't create a query when using other methods (e.g. `andWhere()`).\n\n## Creating new records\n\n```js\nawait User.insert({ name: 'Jon' })\n```\n\nAs in Knex, you should use `returning()` when you want to receive the returning fields:\n\n```js\nconst [id] = await User.returning('id')\n  .insert({ name: 'Jon' })\n```\n\n## Updating records\n\n```js\nUser.where({ active: true })\n  .update({ active: false })\n  \n// to make an update of a single item you can use\n// following query\nUser.find(userId)\n  .update({ active: true })\n```\n\n## Scopes\n\n[Scope](https://github.com/baethon/kex/wiki/Scopes) is a function that alters the query. You can chain them as other query methods.\n\nScopes are declared when creating a model:\n\n```js\nconst User = kex.createModel('User', {\n  scopes: {\n    active (qb) {\n      qb.where('active', true)\n    }\n  }\n})\n\nconst activeUsers = await User.query()\n  .active()\n```\n\nScopes can be used in the callbacks of `where()`:\n\n```js \nconst usersList = await User.where(qb =\u003e {\n  qb.active()\n    .orWhere('role', 'admin')\n})\n```\n\n## Global scopes\n\n[Global scope](https://github.com/baethon/kex/wiki/Scopes#global-scopes) is very similar to the regular scope. The main difference is that it's applied automatically to every query.\n\n```js \nconst User = kex.createModel('User', {\n  globalScopes: {\n    active (qb) {\n      qb.where('active', true)\n    }\n  }\n})\n\nconst activeUsers = await User.query()\n```\n\nIt's possible to ignore the scope using `withoutGlobalScope()`, or `withoutGlobalScopes()` method:\n\n```js\nconst usersList = await User.query()\n  .withoutGlobalScope('active')\n  // alternative syntax:\n  // .withoutGlobalScopes(['active'])\n```\n\n## Other\n\nKex supports many other things:\n\n- [plugins](https://github.com/baethon/kex/wiki/Plugins)\n- [soft-deletes](https://github.com/baethon/kex/wiki/Soft-deletes)\n- [timestamps](https://github.com/baethon/kex/wiki/Timestamps)\n- [relations](https://github.com/baethon/kex/wiki/Relations)\n- [query utilities](https://github.com/baethon/kex/wiki/Query-utilities)\n\n## Conventions\n\nKex uses naming conventions taken from Lucid, or Eloquent:\n\n- the table name is a snake_case version of the pluralized model name (e.g. `users`)\n- the primary key is always `id`\n- foreign keys (used in relations) are snake_case version of a table name (in singular form) postfixed with `_id` (e.g. `user_id`)\n- the pivot table is a snake_case version of related table names (in singular form) joined in alphabetical order (e.g. `tag_user`)\n\nThe naming is fully customizable.\n\n## Motivation\n\nFull-blown ORMs offer fantastic features. Yet sometimes, it might be overkill for your application. What I needed is a customizable DBAL which wouldn't make too much magic behind the scenes. I wanted something like Knex, yet a little more robust.\n\nKex gives you the feeling of an ORM. However, it makes sure not to interfere with your work. Build a query and fetch the results. That's all. Don't worry about hydrated objects, results collections, or anything like that.\n\n## Testing\n\nThe test suite is a combination of unit tests and integration tests. The latter use by default an SQLite database, however, you can (and sometimes must) choose a different database backend.\n\nTo run tests:\n\n```\nyarn test\n```\n\nRunning a single test suite with:\n\n```\nyarn test tests/path/to/test-file.test.js\n```\n\n### Using different database backend\n\nYou need to install client dependency:\n\n- `mysql` for MySQL database\n- `pg` for PostgreSQL database\n\nThen, start the database and set env variables. The test suite supports two env variables:\n\n- `DB_CLIENT` (either `mysql` or `pg`)\n- `DB_URL` (e.g. `mysql://user:passwd@host:3306/db_name`)\n\n```\nDB_CLIENT=mysql DB_URL=mysql://user:passwd@host:3306/db_name yarn test\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbaethon%2Fkex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbaethon%2Fkex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbaethon%2Fkex/lists"}