{"id":15020864,"url":"https://github.com/arjunsumarlan/typeorm-query-builder-wrapper","last_synced_at":"2025-10-26T14:30:59.242Z","repository":{"id":54616449,"uuid":"316879387","full_name":"arjunsumarlan/typeorm-query-builder-wrapper","owner":"arjunsumarlan","description":"Easy Wrapper for TypeORM Query Builder","archived":false,"fork":false,"pushed_at":"2021-02-09T03:10:02.000Z","size":350,"stargazers_count":22,"open_issues_count":0,"forks_count":5,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-31T20:16:05.879Z","etag":null,"topics":["orm","postgresql","typeorm","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/arjunsumarlan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-11-29T05:00:05.000Z","updated_at":"2024-04-15T06:52:02.000Z","dependencies_parsed_at":"2022-08-13T21:40:40.919Z","dependency_job_id":null,"html_url":"https://github.com/arjunsumarlan/typeorm-query-builder-wrapper","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arjunsumarlan%2Ftypeorm-query-builder-wrapper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arjunsumarlan%2Ftypeorm-query-builder-wrapper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arjunsumarlan%2Ftypeorm-query-builder-wrapper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arjunsumarlan%2Ftypeorm-query-builder-wrapper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arjunsumarlan","download_url":"https://codeload.github.com/arjunsumarlan/typeorm-query-builder-wrapper/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238347422,"owners_count":19456928,"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":["orm","postgresql","typeorm","typescript"],"created_at":"2024-09-24T19:55:46.802Z","updated_at":"2025-10-26T14:30:53.906Z","avatar_url":"https://github.com/arjunsumarlan.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  Easy Wrapper for TypeORM Query Builder\n  \u003cbr\u003e\n  \u003cbr\u003e\n  \u003cimg src=\"https://badgen.net/npm/v/yarn\"\u003e\n  \u003cimg src=\"https://badgen.net/npm/node/next\"\u003e\n  \u003cimg src=\"https://badgen.net/badge/icon/typescript?icon=typescript\u0026label\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/license-MIT-green.svg\"\u003e\n  \u003cbr\u003e\n  \u003cbr\u003e\n\u003c/p\u003e\n\n# TypeORM Query Builder Wrapper\n[TypeORM](https://github.com/typeorm/typeorm) is one of ORM that can run in NodeJS, Browser, Cordova, PhoneGap, Ionic, React Native, NativeScript, Expo, and Electron platforms and can be used with TypeScript and JavaScript. To use TypeORM to create connection, entities, etc, please visit this [link](https://github.com/typeorm/typeorm/blob/master/README.md). One of the great feature in TypeORM is Query Builder, that you can build query with builder pattern so you can write query with flexible and elegant syntax without to know more about SQL knowledge, to use Query Builder please visit this [link](https://github.com/typeorm/typeorm/blob/master/docs/select-query-builder.md). But, its Query Builder have a weakness that you have to write query with RAW that allow you to make a mistakes, typos, and of course reduce the elegancy of it. So, this library allows you to use TypeORM Query Builder in very easy, safe way, and of course more elegant. This library was inspired by [TypeORM LINQ Repository](https://github.com/IRCraziestTaxi/typeorm-linq-repository)\n\n## Features\n\n* Currently it supports for SQL Database, especially PostgreSQL\n* TypeScript and JavaScript support\n* Produced code is performant, flexible, clean and maintainable\n\n\n## Installation\n\n\n1. Install the yarn package:\n\n    `yarn add typeorm typeorm-query-builder-wrapper --save`\n\n2. You need to install `reflect-metadata` shim:\n\n    `npm install reflect-metadata --save`\n\n    and import it somewhere in the global place of your app (for example in `app.ts`):\n\n    `import \"reflect-metadata\";`\n\n3. You may need to install node typings:\n\n    `npm install @types/node --save-dev`\n\n4. Install a database driver:\n\n    * for **PostgreSQL** or **CockroachDB**\n\n        `npm install pg --save`\n\n\n### TypeScript configuration\n\n\nAlso, make sure you are using TypeScript version **3.3** or higher,\nand you have enabled the following settings in `tsconfig.json`:\n\n```json\n\"emitDecoratorMetadata\": true,\n\"experimentalDecorators\": true,\n```\n\nYou may also need to enable `es6` in the `lib` section of compiler options, or install `es6-shim` from `@types`.\n\n### TypeORM\n\n\nPlease visit [this](https://github.com/typeorm/typeorm#quick-start) to setup what needs and how to use TypeORM.\n\n## Usage\n\n\n* [QueryBuilder](#querybuilder)\n* [Instantiate a QueryBuilder](#instantiate-a-querybuilder)\n* [Adding `Filter` and `Pagination`](#adding-filter-and-pagination)\n* [Adding `SELECT` expression](#adding-select-expression)\n* [Adding `WHERE` expression](#adding-where-expression)\n* [Adding `HAVING` expression](#adding-having-expression)\n* [Adding `DISTINCT ON` expression](#adding-distinct-on-expression)\n* [Adding `GROUP BY` expression](#adding-group-by-expression)\n* [Joining relations](#joining-relations)\n* [Inner and left joins](#inner-and-left-joins)\n* [Getting the generated query](#getting-the-generated-query)\n* [Getting raw results](#getting-raw-results)\n* [Streaming result data](#streaming-result-data)\n* [Set locking](#set-locking)\n* [Using subqueries](#using-subqueries)\n\n## `QueryBuilder`\n\n`QueryBuilder` is one of the most powerful features of TypeORM -\nit allows you to build SQL queries using elegant and convenient syntax,\nexecute them and get automatically transformed entities.\n\nAssume that you have `User Entity` like this:\n\n```typescript\nimport { BaseEntity, Column, Entity, PrimaryGeneratedColumn, UpdateDateColumn, CreateDateColumn, } from 'typeorm';\n\n@Entity('users')\nexport class User extends BaseEntity {\n    @PrimaryGeneratedColumn('uuid')\n    id: string;\n\n    @Column({\n        type: 'boolean',\n        name: 'is_deleted',\n        default: false\n    })\n    isDeleted: boolean;\n\n    @CreateDateColumn({\n        type: 'timestamp',\n        name: 'create_date_time',\n        default: () =\u003e 'CURRENT_TIMESTAMP',\n    })\n    createDateTime: Date;\n\n    @Column({ type: 'uuid', name: 'create_user_id' })\n    createUserId: string;\n\n    @Column('character varying', {\n        nullable: false,\n        length: 255,\n        name: 'name',\n    })\n    name: string;\n\n    @Column('character varying', {\n        nullable: false,\n        length: 255,\n        name: 'username',\n    })\n    username: string;\n\n    @Column('character varying', {\n        nullable: false,\n        length: 500,\n        name: 'password',\n        select: false,\n    })\n    password: string;\n}\n```\n\nSimple example of `QueryBuilder`:\n\n```typescript\n// Instantiate QueryBuilder\nconst qb = new QueryBuilder(User, {\n      page: 1,\n      limit: 10,\n      order: '^name',\n      name_contains: 'Roy',\n      username: 'roygrindelwald',\n      createDateTime__gte: '2020-11-15T00:00:00.000Z',\n      createDateTime__lt: '2020-11-25T00:00:00.000Z',\n    }, 't1');\n\n// Mapping filter field (Whitelist).\nqb.fieldResolverMap['name_contains'] = 't1.name';\nqb.fieldResolverMap['username'] = 't1.username';\nqb.fieldResolverMap['createDateTime__gte'] = 't1.create_date_time';\nqb.fieldResolverMap['createDateTime__lt'] = 't1.create_date_time';\n\n// Have to be after mapping.\nqb.applyFilterPagination();\n\n// Select fields.\nqb.selectRaw(\n    ['t1.id', 'id'],\n    ['t1.name', 'fullName'],\n    ['t1.username', 'username'],\n    ['t1.email', 'email'],\n);\n\nqb.andWhere(\n    e =\u003e e.isDeleted,\n    w =\u003e w.isFalse(),\n);\n\n// Execute the query\nconst data = await qb.exec();\n```\n\nIt builds the following SQL query:\n\n```sql\nSELECT \n    t1.id AS id,\n    t1.name AS fullName,\n    t1.username AS username,\n    t1.email AS email\nFROM users t1 \nWHERE \n    t1.name = 'Roy'\n    AND t1.username = 'roygrindelwald'\n    AND t1.create_date_time \u003e= '2020-11-15T00:00:00.000Z'\n    AND t1.create_date_time \u003c '2020-11-25T00:00:00.000Z'\n    AND t1.is_deleted = 'false'\nORDER BY t1.name ASC \nLIMIT 10\n```\n\nand returns you a list instance of `User`:\n\n```\n[\n    User {\n        id: \"8cca9676-32a4-11eb-adc1-0242ac120002\",\n        fullName: \"Roy Grindelwald\",\n        username: \"roygrindelwald\",\n        email: \"roygrindelwald@gmail.com\"\n    }\n]\n```\n\n## Instantiate a QueryBuilder\n\n\n```typescript\nimport { QueryBuilder } from 'typeorm-query-builder-wrapper';\nimport { User } from './model/user.entity';\n\nconst qb = new QueryBuilder(User, {\n      page: 1,\n      limit: 10,\n      order: '^name',\n      name_contains: 'Roy',\n      username: 'roygrindelwald',\n      createDateTime__gte: '2020-11-15T00:00:00.000Z',\n      createDateTime__lt: '2020-11-25T00:00:00.000Z',\n    }, 't1');\n```\n\nThere are 3 arguments of `QueryBuilder` constructor:\n\n* `Entity` - used to apply entity to `QueryBuilder`.\n* `QueryObject` - used to construct filter and pagination in `QueryBuilder`. Example:\n\n    ```typescript\n    {\n      page: 1,\n      limit: 10,\n      order: '^name',\n      name_contains: 'Roy',\n      username: 'roygrindelwald',\n      createDateTime__gte: '2020-11-15T00:00:00.000Z',\n      createDateTime__lt: '2020-11-25T00:00:00.000Z',\n    }\n    ```\n\n    It is contains these options:\n\n    | Option | Default | Behaviour | Example |\n    | --- | :---: | --- | --- |\n    page | __1__ | Return entries for page `page` | `page: 2`\n    limit | __10__ | Return entries for page `page` paginated by size `limit` | `limit: 25`\n    order | - | Order for fields:\u003cbr\u003e`^`: Ascendant \u003cbr\u003e `-`: Descendant | `order: '^foo,-name,^surname'`\n\n    And for the field of entity, it follows these rules:\n\n    | Lookup | Behaviour | Example |\n    | --- | --- | --- |\n    __matches__ | Return entries that match with value | `foo: 'raul'`\n    __contains__ | Return entries that contains value | `foo__contains: 'ryo'`\n    __startswith__ | Return entries that starts with value | `foo__startswith: 'r'`\n    __endswith__ | Return entries that ends with value | `foo__endswith: 'dev'`\n    __isnull__ | Return entries with null value | `foo__isnull`\n    __lt__ | Return entries with value less than or equal to provided | `foo__lt: 18`\n    __lte__ | Return entries with value less than provided | `foo__lte: 18`\n    __gt__ | Returns entries with value greater than provided | `foo__gt: 18`\n    __gte__ | Return entries with value greater than or equal to provided | `foo__gte: 18`\n    __in__ | Return entries that match with values in list | `foo__in: 'admin,common'`\n    __between__ | Return entries in range | `foo__between: [1, 27]`\n\n* `Alias` - used to define alias for main table.\n\n\n## Adding `Filter` and `Pagination`\n\nMost of the time when you develop an application, you need pagination functionality. This is used if you have pagination, page slider, or infinite scroll components in your application.\n\nTo do this, it is very simple, you only need define `page` and `limit` in `QueryObject` when you instantiate `QueryBuilder`, for example:\n\n```typescript\nqb.applyFilterPagination();\n```\n\nit will add ORDER and LIMIT query into SQL raw query like this:\n\n```sql\nORDER BY t1.name ASC \nLIMIT 10\n```\n\nIf you have `filters` for your list, you have to mapping the fields to make a whitelist for the filter and also to map field of `entity` to field of `QueryObject`, for example:\n\n```typescript\nqb.fieldResolverMap['name_contains'] = 't1.name';\nqb.fieldResolverMap['username'] = 't1.username';\nqb.fieldResolverMap['createDateTime__gte'] = 't1.create_date_time';\nqb.fieldResolverMap['createDateTime__lt'] = 't1.create_date_time';\n```\n\nit will add WHERE query into SQL raw query like this:\n\n```sql\nWHERE \n    t1.name = 'Roy'\n    AND t1.username = 'roygrindelwald'\n    AND t1.create_date_time \u003e= '2020-11-15T00:00:00.000Z'\n    AND t1.create_date_time \u003c '2020-11-25T00:00:00.000Z'\n```\n\n`WARNING !!` YOU HAVE TO MAPPING BEFORE APPLY TO FILTER PAGINATION\n\nThen the complete of filter and pagination is:\n\n```typescript\nqb.fieldResolverMap['name_contains'] = 't1.name';\nqb.fieldResolverMap['username'] = 't1.username';\nqb.fieldResolverMap['createDateTime__gte'] = 't1.create_date_time';\nqb.fieldResolverMap['createDateTime__lt'] = 't1.create_date_time';\n\nqb.applyFilterPagination();\n```\nAnd the complete result:\n\n```sql\nWHERE \n    t1.name = 'Roy'\n    AND t1.username = 'roygrindelwald'\n    AND t1.create_date_time \u003e= '2020-11-15T00:00:00.000Z'\n    AND t1.create_date_time \u003c '2020-11-25T00:00:00.000Z'\nORDER BY t1.name ASC \nLIMIT 10\n```\n\n\n## Adding `SELECT` expression\n\nTo select fields in table, you can use SELECT query. In `QueryBuilder`, you can use `selectRaw` method.\nIt has one argument is a list of fields with its alias. Example:\n\n```typescript\nqb.selectRaw(\n    ['t1.id', 'id'],\n    ['t1.name', 'name'],\n    ['t1.username', 'username'],\n    ['t1.email', 'email'],\n);\n```\n\nWhich will result in the following sql query:\n\n```sql\nSELECT\n    t1.id AS id,\n    t1.name AS fullName,\n    t1.username AS username,\n    t1.email AS email\nFROM users t1\n```\n\nIn this SQL query, `users` is the table name, and `t1` is an alias we assign to this table.\n\n## Adding `WHERE` expression\n\nAdding a `WHERE` expression is as easy as:\n\n```typescript\nqb.andWhere(\n    e =\u003e e.isDeleted,\n    w =\u003e w.isFalse(),\n);\n```\n\nWhich will produce:\n\n```sql\nWHERE t1.is_deleted = 'false'\n```\n\nIf `WHERE` expression it reach for the first time, then `AND` or `OR` will be removed to avoid error. So the result will not be like this:\n\n```sql\nWHERE AND t1.is_deleted = 'false'\n```\n\nYou can add `AND` into an existing `WHERE` expression:\n\n```typescript\nqb.andWhere(\n    e =\u003e e.isDeleted,\n    w =\u003e w.isFalse(),\n);\nqb.andWhere(\n    e =\u003e e.name,\n    w =\u003e w.equals('Roy Grindelwald'),\n);\n```\n\nWhich will produce the following SQL query:\n\n```sql\nWHERE \n    t1.is_deleted = 'false'\n    AND t1.name = 'Roy Grindelwald'\n```\n\nYou can add `OR` into an existing `WHERE` expression:\n\n```typescript\nqb.andWhere(\n    e =\u003e e.isDeleted,\n    w =\u003e w.isFalse(),\n);\nqb.orWhere(\n    e =\u003e e.username,\n    w =\u003e w.equals('roygrindelwald'),\n);\n```\n\nWhich will produce the following SQL query:\n\n```sql\nWHERE \n    t1.is_deleted = 'false'\n    OR t1.username = 'roygrindelwald'\n```\n\nThey have 2 arguments.\n\nFirst argument is called `Property Selector`, which return the selected property or field, example `e.username`, `e` is entity of main table which is `User`, user has `username` field, then `e.username` will give you an output of field `username` from `User` entity. it also can select from `User` relation, assume `User` has relation to `Product` with entity name `product`. `NOTE!` you have to mapping `Product` entity first in `User` entity class, or vice versa, depends on your need. So, if you want select one of field of `Product` entity, you can do like this:\n\n```typescript\nqb.andWhere(\n    e =\u003e e.product.productCode,\n    w =\u003e w.equals('2ABC5'),\n);\n```\n\nSecond argument is called `Operator`, which return the operator used in `WHERE` expression like `=`, `!=`, `IN`, `IS NULL`, etc.\n\nThe list of oprator:\n\n| Operator | Behaviour | Example |\n| --- | --- | --- |\n__equals__ | Return entries that match with value | `w.equals('foo')`\n__notEquals__ | Return entries that not match with value | `w.notEquals('foo')`\n__contains__ | Return entries that contains value | `w.contains('foo')`\n__beginsWith__ | Return entries that starts with value | `w.beginsWith('foo')`\n__endsWith__ | Return entries that ends with value | `w.endsWith('foo')`\n__isNotNull__ | Return entries with not null value | `w.isNotNull()`\n__isNull__ | Return entries with null value | `w.isNull()`\n__greaterThan__ | Returns entries with value greater than provided | `w.greaterThan(100)`\n__greaterThanOrEqual__ | Return entries with value greater than or equal to provided | `w.greaterThanOrEqual(100)`\n__lessThan__ | Return entries with value less than or equal to provided | `w.lessThan(100)`\n__lessThanOrEqual__ | Return entries with value less than provided | `w.lessThanOrEqual(100)`\n__in__ | Return entries that match with values in list | `w.in(['foo', 'bar'])`\n__notIn__ | Return entries that not match with values in list | `w.notIn(['foo', 'bar'])`\n\n\nYou can add a complex `WHERE` expression into an existing `WHERE` like `Brackets` in `TypeORM`\n\n```typescript\nqb.andWhere(\n    e =\u003e e.isDeleted,\n    w =\u003e w.isFalse(),\n);\nqb.andWhereIsolated(q =\u003e\n    q.andWhere(\n        e =\u003e e.product.productCode,\n        w =\u003e w.isNotNull(),\n    ).orWhere(\n        e =\u003e e.name,\n        w =\u003e w.equals('Roy'),\n    ),\n);\n```\n\nIt has 1 argument that has type of `QueryBuilder` like `Sub Query`.\n\nWhich will produce the following SQL query:\n\n```sql\nWHERE \n    t1.is_deleted = 'false'\n    AND (\n        t2.product_code = '2ABC'\n        OR t1.name = 'Roy Grindelwald'\n    )\n```\n\nYou can combine as many `AND` and `OR` expressions as you need.\n\nNote: be careful with `orWhere` - if you use complex expressions with both `AND` and `OR` expressions,\nkeep in mind that they are stacked without any pretences.\nSometimes you'll need to create a where string instead, and avoid using `orWhere`.\n\n## Adding `HAVING` expression\n\nAdding a `HAVING` expression is easy as:\n\n```typescript\nqb.andHaving(\n    e =\u003e e.isDeleted,\n    w =\u003e w.isTrue(),\n);\n```\n\nWhich will produce following SQL query:\n\n```sql\nHAVING t1.is_deleted = 'true'\n```\n\nThe rules of play is same as `WHERE` expression.\nBut it is not support yet for complex having.\n\n## Adding `DISTINCT ON` expression\nWhen using both distinct-on with an order-by expression, the distinct-on expression must match the leftmost order-by.\nThe distinct-on expressions are interpreted using the same rules as order-by. Please note that, using distinct-on without an order-by expression means that the first row of each set is unpredictable.\n\nAdding a `DISTINCT ON` expression is easy as:\n\n```typescript\nqb.setDistinctOn(\n    e =\u003e e.id,\n    e =\u003e e.name,\n);\n```\n\nWhich will produce:\n\n```sql\nSELECT DISTINCT ON (t1.id, t1.name) ... FROM users t1 ORDER BY t1.id\n```\n\n## Adding `GROUP BY` expression\n\nAdding a `GROUP BY` expression is easy as:\n\n```typescript\nqb.groupBy(\n    e =\u003e e.id,\n    e =\u003e e.name,\n);\n```\n\nWhich will produce the following SQL query:\n\n```sql\nGROUP BY t1.id, t1.name\n```\n\nIf you use `.groupBy` more than once you'll override all previous `GROUP BY` expressions.\n\n## Joining relations\n\nLet's say you have the following entities:\n\n```typescript\nimport {Entity, PrimaryGeneratedColumn, Column, OneToMany} from \"typeorm\";\nimport {Photo} from \"./Photo\";\n\n@Entity()\nexport class User {\n\n    @PrimaryGeneratedColumn()\n    id: number;\n\n    @Column()\n    name: string;\n\n    @OneToMany(type =\u003e Photo, photo =\u003e photo.user)\n    photos: Photo[];\n}\n```\n\n```typescript\nimport {Entity, PrimaryGeneratedColumn, Column, ManyToOne} from \"typeorm\";\nimport {User} from \"./User\";\n\n@Entity()\nexport class Photo {\n\n    @PrimaryGeneratedColumn()\n    id: number;\n\n    @Column()\n    url: string;\n\n    @ManyToOne(type =\u003e User, user =\u003e user.photos)\n    user: User;\n}\n```\n\nNow let's say you want to load user \"Timber\" with all of his photos:\n\n```typescript\nconst qb = new QueryBuilder(User, {}, 't1');\nqb.selectRaw(\n    ['t1.id', 'id'],\n    ['t1.name', 'name'],\n    ['t2.url', 'url'],\n);\nqb.leftJoin(\n    e =\u003e e.photos,\n    't2',\n    j =\u003e\n        j.andWhere(\n            e =\u003e e.isDeleted,\n            w =\u003e w.isFalse(),\n        ),\n);\nqb.andWhere(\n      e =\u003e e.name,\n      w =\u003e w.equals('Timber'),\n);\n```\n\nThis will generate following sql query:\n\n```sql\nSELECT \n    t1.id AS id\n    t1.name AS name\n    t2.url AS url\nFROM users t1\nLEFT JOIN photos t2 ON t2.user = t1.id AND t2.is_deleted = 'false'\nWHERE t1.name = 'Timber'\n```\n\nYou'll get the following result:\n\n```typescript\n[\n    {\n        id: 1,\n        name: \"Timber\",\n        url: \"me-with-chakram.jpg\",\n    },\n    {\n        id: 1,\n        name: \"Timber\",\n        url: \"me-with-trees.jpg\",\n    }\n]\n```\n\n## Inner and left joins\n\nIf you want to use `INNER JOIN` instead of `LEFT JOIN` just use `.innerJoin` instead:\n\n```typescript\nqb.innerJoin(\n    e =\u003e e.photos,\n    't2',\n    j =\u003e\n        j.andWhere(\n            e =\u003e e.isDeleted,\n            w =\u003e w.isFalse(),\n        ),\n);\n```\n\nThis will generate:\n\n```sql\nSELECT \n    t1.id AS id\n    t1.name AS name\n    t2.url AS url\nFROM users t1\nINNER JOIN photos t2 ON t2.user = t1.id AND t2.is_deleted = 'false'\nWHERE t1.name = 'Timber'\n```\n\nThe difference between `LEFT JOIN` and `INNER JOIN` is that `INNER JOIN` won't return a user if it does not have any photos.\n`LEFT JOIN` will return you the user even if it doesn't have photos.\nTo learn more about different join types, refer to the [SQL documentation](https://msdn.microsoft.com/en-us/library/zt8wzxy4.aspx).\n\n\n## Getting the generated query\n\nSometimes you may want to get the SQL query generated by `QueryBuilder`.\nTo do so, use `getQuery` or `getSql`:\n\n```typescript\nconst sql = qb.selectRaw(\n    ['t1.id', 'id'],\n    ['t1.name', 'name'],\n    ['t1.username', 'username'],\n    ['t1.email', 'email'],\n).andWhere(\n    e =\u003e e.isDeleted,\n    w =\u003e w.isFalse(),\n).getQuery();\n```\n\n## Getting raw results\n\nTo get raw data, you use `exec`.\nExamples:\n\n```typescript\nconst data = await qb.selectRaw(\n    ['t1.id', 'id'],\n    ['t1.name', 'name'],\n    ['t1.username', 'username'],\n    ['t1.email', 'email'],\n).andWhere(\n    e =\u003e e.isDeleted,\n    w =\u003e w.isFalse(),\n).exec();\n```\n\n## Streaming result data\n\nYou can use `stream` which returns you a stream.\nStreaming returns you raw data and you must handle entity transformation manually:\n\n```typescript\nconst fileName = `User_${new Date().getTime()}.csv`;\n\n// response is writeable output\nresponse.setHeader(\n    'Content-disposition',\n    `attachment; filename=${fileName}`,\n);\nresponse.writeHead(200, { 'Content-Type': 'text/csv' });\nresponse.flushHeaders();\n\n// To set header of CSV\nresponse.write(`User ID, Name, URL\\n`);\n\nconst qb = new QueryBuilder(User, {}, 't1');\n\nqb.selectRaw(\n    ['t1.id', 'id'],\n    ['t1.name', 'name'],\n    ['t2.url', 'url'],\n);\nqb.leftJoin(\n    e =\u003e e.photos,\n    't2',\n    j =\u003e\n        j.andWhere(\n            e =\u003e e.isDeleted,\n            w =\u003e w.isFalse(),\n        ),\n);\nqb.andWhere(\n      e =\u003e e.name,\n      w =\u003e w.equals('Timber'),\n);\n\nawait qb.stream(response, this.transformer);\n```\n\nThe transformer looks like this:\n\n```typescript\ntransformer(doc) {\n    const values = [\n        doc.id,\n        doc.name,\n        doc.url,\n    ];\n\n    return `${values.join(',')} \\n`;\n}\n```\n\nIt will stream raw results into csv format (for this example) in your user's browser.\n\n\n## Set locking\n\nQueryBuilder supports both optimistic and pessimistic locking.\nTo use pessimistic read locking use the following method:\n\n```typescript\nqb.setLock(\"pessimistic_read\");\n```\n\nTo use pessimistic write locking use the following method:\n\n```typescript\nqb.setLock(\"pessimistic_write\");\n```\n\nTo use dirty read locking use the following method:\n\n```typescript\nqb.setLock(\"dirty_read\");\n```\n\nTo use optimistic locking use the following method:\n\n```typescript\nqb.setLock(\"optimistic\", version);\n```\n\nOptimistic locking works in conjunction with both `@Version` and `@UpdatedDate` decorators from `TypeORM`.\n\n## Using subqueries\n\nYou can easily create subqueries. Subqueries are supported in `SELECT` and `FROM` expressions. Next will be supported in `WHERE` and `JOIN` expressions.\nExample:\n\n```typescript\nqb.selectSubQuery(User, 'user', subQuery =\u003e\n    subQuery.selectRaw(\n        ['user.name', 'name'],\n        ['user.username', 'username'],\n    )\n    .andWhere(\n        'user.is_deleted',\n        w =\u003e w.isFalse()\n    )\n);\n```\n\nexample for `FROM`:\n\n```typescript\nqb.from(User, 'user', subQuery =\u003e {\n    return subQuery.selectRaw(\n        ['user.name', 'name'],\n        ['user.username', 'username'],\n    )\n    .andWhere(\n        'user.is_deleted',\n        w =\u003e w.isFalse()\n    );\n});\n```\n\nexample for `WHERE`:\n\n```typescript\nqb.from(User, 'user', subQuery =\u003e {\n    return subQuery.selectRaw(\n      ['t1.id', 'id'],\n      ['t1.username', 'username'],\n    ).andWhere(\n      e =\u003e e.username,\n      (w, subQuery) =\u003e {\n        w.in(\n          subQuery\n            .selectRaw(['user.username', 'username'])\n            .from(User, 'user')\n            .andWhere(\n              e =\u003e e.isDeleted,\n              w =\u003e w.isFalse(),\n            )\n            .getQuery()\n        )\n      },\n    ).orWhere(\n      e =\u003e e.username,\n      (w, subQuery) =\u003e {\n        w.notIn(\n          subQuery\n            .selectRaw(['user.username', 'username'])\n            .from(User, 'user')\n            .andWhere(\n              e =\u003e e.isDeleted,\n              w =\u003e w.isFalse(),\n            )\n            .getQuery()\n        )\n      },\n    );\n});\n```\n\nexample for `JOIN`:\n\n```typescript\nqb.from(User, 'user', subQuery =\u003e {\n    return subQuery.selectRaw(\n      ['t1.id', 'id'],\n      ['t1.name', 'name'],\n      ['t2.branchName', 'branch'],\n    )\n    .innerJoinSubQuery(\n      subQuery =\u003e {\n        return subQuery\n          .selectRaw(\n            ['branch.user_id', 'userId'],\n            ['branch.branch_name', 'branchName'],\n          )\n          .from(Branch, 'branch')\n          .andWhere(\n            e =\u003e e.isDeleted,\n            w =\u003e w.isFalse(),\n          )\n      },\n      't2',\n      j =\u003e j.andWhere(\n        't2.userId',\n        w =\u003e w.equalsWithField('t1.id'),\n      )\n    );\n});\n```\n\n## TODOS:\n\n* Support for MongoDB and other DB\n* Support for GraphQL\n* \n\n## Samples\n\nTake a look at the samples in [sample](https://github.com/arjunsumarlan/typeorm-query-builder-wrapper/tree/master/sample) for examples of usage.\n\n\n## Contributing\n\nLearn about contribution [here](https://github.com/arjunsumarlan/typeorm-query-builder-wrapper/blob/master/CONTRIBUTING.md) and how to setup your development environment [here](https://github.com/arjunsumarlan/typeorm-query-builder-wrapper/blob/master/DEVELOPER.md).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farjunsumarlan%2Ftypeorm-query-builder-wrapper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farjunsumarlan%2Ftypeorm-query-builder-wrapper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farjunsumarlan%2Ftypeorm-query-builder-wrapper/lists"}