Full Code of nestjsx/crud for AI

master d6d3c4ebd844 cached
201 files
379.5 KB
103.0k tokens
486 symbols
1 requests
Download .txt
Showing preview only (427K chars total). Download the full file or copy to clipboard to get everything.
Repository: nestjsx/crud
Branch: master
Commit: d6d3c4ebd844
Files: 201
Total size: 379.5 KB

Directory structure:
gitextract_rxpb3oso/

├── .eslintignore
├── .eslintrc.js
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── Bug_report.md
│   │   └── Feature_request.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── release.yml
│       └── tests.yml
├── .gitignore
├── .husky/
│   └── pre-commit
├── .prettierrc.json
├── .yarnrc
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── docker-compose.yml
├── integration/
│   ├── crud-typeorm/
│   │   ├── app.module.ts
│   │   ├── auth.guard.ts
│   │   ├── base-entity.ts
│   │   ├── companies/
│   │   │   ├── companies.controller.ts
│   │   │   ├── companies.module.ts
│   │   │   ├── companies.service.ts
│   │   │   ├── company.entity.ts
│   │   │   ├── index.ts
│   │   │   ├── requests/
│   │   │   │   ├── create-company.dto.ts
│   │   │   │   └── index.ts
│   │   │   └── responses/
│   │   │       ├── get-company-response.dto.ts
│   │   │       └── index.ts
│   │   ├── constants.ts
│   │   ├── devices/
│   │   │   ├── device.entity.ts
│   │   │   ├── devices.controller.ts
│   │   │   ├── devices.module.ts
│   │   │   ├── devices.service.ts
│   │   │   ├── index.ts
│   │   │   └── response/
│   │   │       ├── delete-device-response.dto.ts
│   │   │       └── index.ts
│   │   ├── main.ts
│   │   ├── notes/
│   │   │   ├── index.ts
│   │   │   ├── note.entity.ts
│   │   │   ├── notes.controller.ts
│   │   │   ├── notes.module.ts
│   │   │   ├── notes.service.ts
│   │   │   ├── requests/
│   │   │   │   ├── create-note.dto.ts
│   │   │   │   └── index.ts
│   │   │   └── responses/
│   │   │       ├── get-note-response.dto.ts
│   │   │       └── index.ts
│   │   ├── orm.config.ts
│   │   ├── orm.mysql.ts
│   │   ├── orm.postgres.ts
│   │   ├── orm.yaml
│   │   ├── projects/
│   │   │   ├── index.ts
│   │   │   ├── my-projects.controller.ts
│   │   │   ├── project.entity.ts
│   │   │   ├── projects.controller.ts
│   │   │   ├── projects.module.ts
│   │   │   ├── projects.service.ts
│   │   │   ├── user-project.entity.ts
│   │   │   └── user-projects.service.ts
│   │   ├── seeds.ts
│   │   ├── users/
│   │   │   ├── index.ts
│   │   │   ├── me.controller.ts
│   │   │   ├── user.entity.ts
│   │   │   ├── users.controller.ts
│   │   │   ├── users.module.ts
│   │   │   └── users.service.ts
│   │   ├── users-licenses/
│   │   │   ├── index.ts
│   │   │   ├── license.entity.ts
│   │   │   └── user-license.entity.ts
│   │   └── users-profiles/
│   │       ├── index.ts
│   │       └── user-profile.entity.ts
│   └── shared/
│       └── https-exception.filter.ts
├── jest.config.js
├── lerna.json
├── mrepo.json
├── package.json
├── packages/
│   ├── crud/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── constants.ts
│   │   │   ├── crud/
│   │   │   │   ├── crud-routes.factory.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── reflection.helper.ts
│   │   │   │   ├── serialize.helper.ts
│   │   │   │   ├── swagger.helper.ts
│   │   │   │   └── validation.helper.ts
│   │   │   ├── decorators/
│   │   │   │   ├── crud-auth.decorator.ts
│   │   │   │   ├── crud.decorator.ts
│   │   │   │   ├── feature-action.decorator.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── override.decorator.ts
│   │   │   │   ├── parsed-body.decorator.ts
│   │   │   │   └── parsed-request.decorator.ts
│   │   │   ├── enums/
│   │   │   │   ├── crud-actions.enum.ts
│   │   │   │   ├── crud-validation-groups.enum.ts
│   │   │   │   └── index.ts
│   │   │   ├── index.ts
│   │   │   ├── interceptors/
│   │   │   │   ├── crud-base.interceptor.ts
│   │   │   │   ├── crud-request.interceptor.ts
│   │   │   │   ├── crud-response.interceptor.ts
│   │   │   │   └── index.ts
│   │   │   ├── interfaces/
│   │   │   │   ├── auth-options.interface.ts
│   │   │   │   ├── base-route.interface.ts
│   │   │   │   ├── create-many-dto.interface.ts
│   │   │   │   ├── crud-controller.interface.ts
│   │   │   │   ├── crud-global-config.interface.ts
│   │   │   │   ├── crud-options.interface.ts
│   │   │   │   ├── crud-request.interface.ts
│   │   │   │   ├── dto-options.interface.ts
│   │   │   │   ├── get-many-default-response.interface.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── model-options.interface.ts
│   │   │   │   ├── params-options.interface.ts
│   │   │   │   ├── query-options.interface.ts
│   │   │   │   ├── routes-options.interface.ts
│   │   │   │   └── serialize-options.interface.ts
│   │   │   ├── module/
│   │   │   │   ├── crud-config.service.ts
│   │   │   │   └── index.ts
│   │   │   ├── services/
│   │   │   │   ├── crud-service.abstract.ts
│   │   │   │   └── index.ts
│   │   │   ├── types/
│   │   │   │   ├── base-route-name.type.ts
│   │   │   │   ├── index.ts
│   │   │   │   └── query-filter-option.type.ts
│   │   │   └── util.ts
│   │   ├── test/
│   │   │   ├── __fixture__/
│   │   │   │   ├── dto/
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── test-create.dto.ts
│   │   │   │   │   └── test-update.dto.ts
│   │   │   │   ├── exception.filter.ts
│   │   │   │   ├── models/
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── test-serialize-2.model.ts
│   │   │   │   │   ├── test-serialize.model.ts
│   │   │   │   │   └── test.model.ts
│   │   │   │   ├── response/
│   │   │   │   │   ├── delete-model-response.dto.ts
│   │   │   │   │   ├── get-many-model-response.dto.ts
│   │   │   │   │   ├── get-model-response.dto.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── recover-model-response.dto.ts
│   │   │   │   └── services/
│   │   │   │       ├── index.ts
│   │   │   │       ├── test-serialize.service.ts
│   │   │   │       └── test.service.ts
│   │   │   ├── crud-config.service.global.spec.ts
│   │   │   ├── crud-config.service.spec.ts
│   │   │   ├── crud-request.interceptor.spec.ts
│   │   │   ├── crud-service.abstract.spec.ts
│   │   │   ├── crud.decorator.base.spec.ts
│   │   │   ├── crud.decorator.exclude.spec.ts
│   │   │   ├── crud.decorator.options.spec.ts
│   │   │   ├── crud.decorator.override.spec.ts
│   │   │   ├── crud.decorator.soft.spec.ts
│   │   │   ├── crud.dto.options.spec.ts
│   │   │   ├── crud.serialize.options.spec.ts
│   │   │   └── feature-action.decorator.spec.ts
│   │   └── tsconfig.json
│   ├── crud-request/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── exceptions/
│   │   │   │   ├── index.ts
│   │   │   │   └── request-query.exception.ts
│   │   │   ├── index.ts
│   │   │   ├── interfaces/
│   │   │   │   ├── create-query-params.interface.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── params-options.interface.ts
│   │   │   │   ├── parsed-request.interface.ts
│   │   │   │   └── request-query-builder-options.interface.ts
│   │   │   ├── request-query.builder.ts
│   │   │   ├── request-query.parser.ts
│   │   │   ├── request-query.validator.ts
│   │   │   └── types/
│   │   │       ├── index.ts
│   │   │       ├── request-param.types.ts
│   │   │       └── request-query.types.ts
│   │   ├── test/
│   │   │   ├── request-query.builder.spec.ts
│   │   │   ├── request-query.parser.spec.ts
│   │   │   └── request.query.validator.spec.ts
│   │   └── tsconfig.json
│   ├── crud-typeorm/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── index.ts
│   │   │   └── typeorm-crud.service.ts
│   │   ├── test/
│   │   │   ├── __fixture__/
│   │   │   │   ├── companies.service.ts
│   │   │   │   ├── devices.service.ts
│   │   │   │   ├── notes.service.ts
│   │   │   │   ├── projects.service.ts
│   │   │   │   └── users.service.ts
│   │   │   ├── a.params-options.spec.ts
│   │   │   ├── b.query-params.spec.ts
│   │   │   ├── c.basic-crud.spec.ts
│   │   │   └── d.crud-auth.spec.ts
│   │   └── tsconfig.json
│   └── util/
│       ├── README.md
│       ├── package.json
│       ├── src/
│       │   ├── checks.util.ts
│       │   ├── index.ts
│       │   ├── obj.util.ts
│       │   └── types/
│       │       ├── class.type.ts
│       │       ├── index.ts
│       │       └── object-literal.type.ts
│       ├── test/
│       │   ├── checks.util.spec.ts
│       │   └── obj.util.spec.ts
│       └── tsconfig.json
├── tsconfig.eslint.json
├── tsconfig.jest.json
├── tsconfig.json
└── tslint.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .eslintignore
================================================


================================================
FILE: .eslintrc.js
================================================
module.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    project: 'tsconfig.eslint.json',
    sourceType: 'module',
  },
  plugins: ['@typescript-eslint/eslint-plugin'],
  extends: ['plugin:@typescript-eslint/eslint-recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
  root: true,
  env: {
    node: true,
    jest: true,
  },
  ignorePatterns: ['.eslintrc.js'],
  rules: {
    '@typescript-eslint/interface-name-prefix': 'off',
    '@typescript-eslint/explicit-function-return-type': 'off',
    '@typescript-eslint/no-explicit-any': 'off',
    '@typescript-eslint/no-empty-function': 'off',
    '@typescript-eslint/no-non-null-assertion': 'off',
    '@typescript-eslint/no-var-requires': 'off',
    'lines-between-class-members': ['error', 'always'],
    'padded-blocks': ['error', 'never'],
    semi: ['error', 'always'],
    quotes: ['error', 'single', { avoidEscape: true }],
    'max-len': ['error', { code: 150, comments: 200 }],
    'comma-dangle': ['error', 'always-multiline'],
    '@typescript-eslint/no-namespace': 'off',
    '@typescript-eslint/member-ordering': [
      'error',
      {
        default: [
          'signature',
          'public-static-field',
          'protected-static-field',
          'private-static-field',
          'public-instance-field',
          'protected-instance-field',
          'private-instance-field',
          'public-abstract-field',
          'protected-abstract-field',
          'private-abstract-field',
          'public-constructor',
          'protected-constructor',
          'private-constructor',
          'public-static-method',
          'protected-static-method',
          'private-static-method',
          'public-instance-method',
          'protected-instance-method',
          'private-instance-method',
          'public-abstract-method',
          'protected-abstract-method',
          'private-abstract-method',
        ],
      },
    ],
  },
};


================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: nestjsx
ko_fi: # Replace with a single Ko-fi username
tidelift: npm/@nestjsx/crud
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with a single custom sponsorship URL


================================================
FILE: .github/ISSUE_TEMPLATE/Bug_report.md
================================================
---
name: "\U0001F41B Bug Report"
about: "If something isn't working as expected \U0001F914."
title: ''
labels: 'type: potential issue'
assignees: ''
---

## Bug Report

## Current behavior

<!-- Describe how the issue manifests. -->

## Input Code

<!-- REPL or Repo link if applicable: -->

```ts
const your = (code) => here;
```

## Expected behavior

<!-- A clear and concise description of what you expected to happen (or code). -->

## Possible Solution

<!--- Only if you have suggestions on a fix for the bug -->

## Environment

<pre><code>
Package version: X.Y.Z
<!-- Check whether this is still an issue in the most recent package(s) version -->
 
For Tooling issues:
- Node version: XX  <!-- run `node --version` -->
- Platform:  <!-- Mac, Linux, Windows -->
- Database <!-- MySQL, Postgres, etc. (with version) -->

Others:
<!-- Anything else relevant?  Operating system version, IDE, ... -->
</code></pre>

## Repository with minimal reproduction


================================================
FILE: .github/ISSUE_TEMPLATE/Feature_request.md
================================================
---
name: "\U0001F680 Feature Request"
about: "I have a suggestion \U0001F63B!"
title: ''
labels: 'type: enhancement'
assignees: ''
---

## Feature Request

## Is your feature request related to a problem? Please describe.

<!-- A clear and concise description of what the problem is. Ex. I have an issue when [...] -->

## Describe the solution you'd like

<!-- A clear and concise description of what you want to happen. Add any considered drawbacks. -->

## Teachability, Documentation, Adoption, Migration Strategy

<!-- If you can, explain how users will be able to use this and possibly write out a version the docs. Maybe a screenshot or design? -->

## What is the motivation / use case for changing the behavior?

<!-- Describe the motivation or the concrete use case. -->


================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
## PR Checklist

Please check if your PR fulfills the following requirements:

- [ ] The commit message was generated by `yarn commit`
- [ ] Tests for the changes have been added (for bug fixes / features)

## PR Type

What kind of change does this PR introduce?

<!-- Please check the one that applies to this PR using "x". -->

```
[ ] Bugfix
[ ] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] Tests
[ ] Release
[ ] CI related changes
[ ] Other... Please describe:
```

## What is the current behavior?

<!-- Please describe the current behavior that you are modifying, or link to a relevant issue. -->

Issue Number: N/A

## What is the new behavior?

## Does this PR introduce a breaking change?

```
[ ] Yes
[ ] No
```

<!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. -->

## Other information


================================================
FILE: .github/workflows/release.yml
================================================
name: Release

on:
  pull_request:
    types: [closed]

jobs:
  release:
    if: github.event.pull_request.merged && startsWith(github.head_ref, 'release')
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2
        with:
          fetch-depth: '0'

      - name: Set NPM Token
        uses: actions/setup-node@v2
        with:
          registry-url: https://registry.npmjs.org
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

      - name: Install
        run: yarn boot

      - name: Build
        run: yarn build

      - name: Run Tests
        run: yarn test

      - name: Get Latest Tag
        id: get_latest_tag
        uses: actions-ecosystem/action-get-latest-tag@v1

      - name: Parse Latest Git Tag
        id: parse_latest_tag
        run: |
          TAG=$(echo ${{ steps.get_latest_tag.outputs.tag }} | cut -d 'v' -f 2)
          echo "::set-output name=tag::${TAG}"

      - name: Get Next Tag Semver
        id: get_next_tag_semver
        uses: WyriHaximus/github-action-next-semvers@v1
        with:
          version: ${{ steps.parse_latest_tag.outputs.tag }}

      - name: Define Publishing Strategy
        id: lerna_strategy
        run: |
          MREPO_LERNA_STRATEGY=$(cat lerna.json | npx jase version)
          echo "MREPO_LERNA_STRATEGY=${MREPO_LERNA_STRATEGY}" >> $GITHUB_ENV

      - name: Define Current Version
        run: |
          echo ${{ env.MREPO_LERNA_STRATEGY }}
          if [ "${{ env.MREPO_LERNA_STRATEGY }}" = "independent" ]; then
            CURRENT_VERSION=${{ steps.get_next_tag_semver.outputs.v_minor }}
            DIST_TAG=$(cat lerna.json | npx jase distTag)
          else
            CURRENT_VERSION=$(cat lerna.json | npx jase version)
            [[ $CURRENT_VERSION =~ "-" ]] && DIST_TAG=$(echo $CURRENT_VERSION | cut -d '-' -f 2 | cut -d '.' -f 1) || DIST_TAG="latest"
            CURRENT_VERSION=v$CURRENT_VERSION
          fi

          echo $CURRENT_VERSION
          echo $DIST_TAG

          echo "CURRENT_VERSION=${CURRENT_VERSION}" >> $GITHUB_ENV
          echo "DIST_TAG=${DIST_TAG}" >> $GITHUB_ENV

      - name: Ensure Latest Git Tag
        uses: mukunku/tag-exists-action@v1.0.0
        id: checkTag
        with:
          tag: ${{ env.CURRENT_VERSION }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Create Git Tag
        if: steps.checkTag.outputs.exists == 'false'
        uses: negz/create-tag@v1
        with:
          version: ${{ env.CURRENT_VERSION }}
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Create Release
        if: steps.checkTag.outputs.exists == 'false'
        uses: actions/create-release@v1
        with:
          tag_name: ${{ env.CURRENT_VERSION }}
          release_name: ${{ env.CURRENT_VERSION }}
          body: |
            ${{ github.event.pull_request.body }}
          draft: false
          prerelease: false
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Publish Packages to NPM Registry
        if: steps.checkTag.outputs.exists == 'false'
        run: |
          lerna publish from-package --no-git-reset --no-verify-access --yes --registry https://registry.npmjs.org --dist-tag ${{ env.DIST_TAG }}
          git update-index --assume-unchanged ./packages/**/package.json
        env:
          GH_TOKEN: ${{ secrets.NPM_TOKEN }}
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

      - name: Create a Comment
        uses: actions/github-script@0.8.0
        with:
          github-token: ${{secrets.GITHUB_TOKEN}}
          script: |
            github.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: 'Packages with version [${{ env.CURRENT_VERSION }}](https://github.com/${{ github.repository }}/releases/tag/${{ env.CURRENT_VERSION }}) have been released 🎉'
            })


================================================
FILE: .github/workflows/tests.yml
================================================
name: Tests

on:
  push:
    branches: [master]
  pull_request:
    branches: [master]

  workflow_dispatch:

jobs:
  test:
    runs-on: ubuntu-latest
    env:
      COMPOSE_FILE: ./docker-compose.yml

    steps:
      - uses: actions/checkout@v2

      - name: build docker db
        run: docker-compose up -d

      - name: install
        run: yarn boot

      - name: build
        run: yarn build

      - name: check docker
        run: docker-compose up -d

      - name: tests
        run: yarn test:coverage

      - name: Coveralls Parallel
        uses: coverallsapp/github-action@master
        with:
          github-token: ${{ secrets.github_token }}
          flag-name: run-${{ matrix.test_number }}
          parallel: true

  coverage:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - name: Coveralls coverage
        uses: coverallsapp/github-action@master
        with:
          github-token: ${{ secrets.github_token }}
          parallel-finished: true


================================================
FILE: .gitignore
================================================
# dependencies
/**/node_modules
yarn-error.log
npm-debug.log

# IDE
/.idea
/.awcache
/.vscode

# misc
.DS_Store
lerna-debug.log
.npmrc
.nvmrc

# tests
/coverage
/.nyc_output

# dist
packages/**/lib
packages/**/tsconfig.tsbuildinfo
.mrepo


================================================
FILE: .husky/pre-commit
================================================
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn lint && yarn format


================================================
FILE: .prettierrc.json
================================================
{
  "printWidth": 120,
  "singleQuote": true,
  "trailingComma": "all",
  "arrowParens": "always"
}


================================================
FILE: .yarnrc
================================================
save-prefix ""


================================================
FILE: CHANGELOG.md
================================================
## [4.6.2] - 2020-05-14

### Bug Fixes

- **typeorm** - fixed selected fields on joins [#510](https://github.com/nestjsx/crud/issues/510)). Kudos to @jbrousseau for finding this bug

## [4.6.1] - 2020-05-08

### Bug Fixes

- **typeorm** - fixed query generation when a column display name differs from its name in db [#401](https://github.com/nestjsx/crud/issues/401)). Kudos to @farhad2161 for finding this bug

## [4.6.0] - 2020-05-07

### Features

- **crud**/**typeorm** - added `select` (boolean) to `join` options which allows to join relation but not select it ([#218](https://github.com/nestjsx/crud/issues/218))

### Bug Fixes

- **typeorm** - fixed column identifier for MySQL ([#401](https://github.com/nestjsx/crud/issues/401))
- **typeorm** - fixed nested relations aliases, filtering, sorting ([#419](https://github.com/nestjsx/crud/issues/419), [#450](https://github.com/nestjsx/crud/issues/450), [#267](https://github.com/nestjsx/crud/issues/267), [#385](https://github.com/nestjsx/crud/issues/385))

## [4.5.0] - 2020-05-01

### Improvements

- **crud** - added enum support for params Swagger. Kudos to @tbrannam

### Bug Fixes

- **crud** - fixed auth property definition. Kudos to @lafeuil
- **typeorm** - fixed request generation with aliases ([#321](https://github.com/nestjsx/crud/issues/321), [#401](https://github.com/nestjsx/crud/issues/401)). Kudos to @joennlae

## [4.4.5] - 2020-04-18

## Deps

- **crud** fixted imports

## [4.4.4] - 2020-04-18

### Deps

- **dev** fixted lerna

## [4.4.3] - 2020-04-18

### Bug Fixes

- **crud** fixed returning `pageCount` in some cases ([#465](https://github.com/nestjsx/crud/pull/465))
- **typeorm** fixed critical bug with possible SQL injections when using query `?sort=` (big kudos to João Maurício)
- **typeorm** fixed filter conditions for LIKE/iLIKE operators ([#395](https://github.com/nestjsx/crud/pull/395))

## [4.4.2] - 2020-03-17

### Bug Fixes

- **crud** fixed custom routes params caused by NestJs v7 breaking changes ([#443](https://github.com/nestjsx/crud/issues/443))

## [4.4.1] - 2019-12-28

### Bug Fixes

- **crud** fixed `CrudRequestInterceptor` validation status code from 500 to 400 ([#374](https://github.com/nestjsx/crud/issues/374), [#247](https://github.com/nestjsx/crud/issues/247))

## [4.4.0] - 2019-12-27

### Features

- **crud** added `serialize` to the global options

## [4.3.0] - 2019-12-21

### Features

- **crud** added `dto` to the `CrudOptions` ([#132](https://github.com/nestjsx/crud/issues/132))
- **crud** added `serialize` to the `CrudOptions`
- **crud** added `search` query param and a new search condition api
- **crud** added new condition operators: `$eqL`, `$neL`, `$startsL`, `$endsL`, `$contL`, `$exclL`, `$inL`, `$notinL` for case insensitive queries ([#77](https://github.com/nestjsx/crud/issues/77))
- **crud** added `@crudAuth()` class decorator for authorized requests

### Improvements

- **crud** `CrudRequestInterceptor` can be used for both crud and non-crud controllers or for custom routes within crud controller
- **crud** support `@nestjs/swagger` major versions: v3 and v4 ([#340](https://github.com/nestjsx/crud/issues/340))
- **crud** added `returnShallow` option to the `CrudOptions.routes` `createOneBase`, `updateOneBase`, `replaceOneBase` methods ([#158](https://github.com/nestjsx/crud/issues/158))
- **crud** added `alias` to the `CrudOptions.join` ([#350](https://github.com/nestjsx/crud/issues/55))
- **crud** added `alwaysPaginate` to the `CrudOptions.query`, can be used globally as well ([#213](https://github.com/nestjsx/crud/issues/213))
- **crud** `CrudOptions.query.filter` can be a function that returns transformed `search` object
- **crud** added `disabled` for an objects withing `CrudOptions.params`
- **request** query builder: now uses [qs](https://www.npmjs.com/package/qs) package
- **request** query builder: `filter` and `or` methods can accept array of filter objects
- **typeorm** changed visibility of all methods ([#226](https://github.com/nestjsx/crud/issues/226))
- **typeorm** use `ILIKE` for PostgreSQL ([#212](https://github.com/nestjsx/crud/issues/212))

### Bug Fixes

- **crud** swagger: fixed response models ([#350](https://github.com/nestjsx/crud/issues/350))
- **crud** swagger: fixed query params ([#196](https://github.com/nestjsx/crud/issues/196))
- **crud** swagger: fixed renamed params ([#283](https://github.com/nestjsx/crud/issues/283))
- **crud** swagger: fixed swagger method decoration on overridden methods
- **crud** query parser: fixed parsing integers when it's a big int
- **typeorm** fixed load embedded entities ([#138](https://github.com/nestjsx/crud/issues/138))
- **typeorm** fixed left join issues ([#31](https://github.com/nestjsx/crud/issues/31), [#98](https://github.com/nestjsx/crud/issues/98))
- **typeorm** fixed composite key joins ([#238](https://github.com/nestjsx/crud/issues/238))
- **typeorm** fixed entity events ([#51](https://github.com/nestjsx/crud/issues/51))
- **typeorm** all methods return entity instances ([#259](https://github.com/nestjsx/crud/issues/259))

## [4.2.0] - 2019-07-26

### Features

- **crud** added support for older versions of `UUID` ([#186])

### Bug Fixes

- **crud** fixed `BulkDto` swagger description ([#159])
- **crud** fixed `CrudRequestInterceptor` request parsing
- **requests** added `@nestjsx/util` as a dependency ([#184])
- **requests** fixed condition operators mapping ([#148])
- **requests** fixed ISO date string validation ([#161])
- **typeorm** fixed filtering and sorting by nested fields ([#105])
- **typeorm** fixed `too many nested levels` exception ([#87])
- **typeorm** fixed pagination `pageCount` ([#179])

### Deps

- **dev** updated deps

## [4.1.0] - 2019-06-27

### Features

- **crud** added `PUT` request handling ([#107])
- **requests** added creating request builder with params ([#131])
- **requests** improved query params naming parsing ([#101])

### Bug Fixes

- **crud** set decorators after Swagger so metadata can be overwritten
- **requests** added support for ISO-8610 date strings

## [4.0.1] - 2019-06-21

### Bug Fixes

- **requests** fixed query parser to properly accept numbers and booleans ([#97])

## [4.0.0] - 2019-06-12

### BREAKING CHANGES

- **crud:** changed `CrudOptions` ([docs](https://github.com/nestjsx/crud/wiki/Controllers#options))
- **crud:** remove decorators: `@ParsedOptions`, `@ParsedParams`, `@ParsedQuery`. Add decorator `@ParsedRequest` instead.
- **crud:** change interfaces
- **services:** remove `RestfulOptions` from services
- **services:** changed base abstract class

### Features

- **repo:** refactor to monorepository
- **docs:** new [documentation](https://github.com/nestjsx/crud/wiki)
- **packages:** totally refactor `@nestjsx/crud` to be service (ORM) agnostic
- **packages:** add `@nestjsx/crud-typeorm` ([docs](https://github.com/nestjsx/crud/wiki/ServiceTypeorm))
- **packages:** add `@nestjsx/crud-request` ([docs](https://github.com/nestjsx/crud/wiki/Requests#description), [#53])
- **crud:** add global options ([docs](https://github.com/nestjsx/crud/wiki/Controllers#global-options), [#64])
- **crud:** add eager relations option ([#54], [#67])

### Bug Fixes

- several fixes

[4.6.2]: https://github.com/nestjsx/crud/compare/v4.6.1...v4.6.2
[4.6.1]: https://github.com/nestjsx/crud/compare/v4.6.0...v4.6.1
[4.6.0]: https://github.com/nestjsx/crud/compare/v4.5.0...v4.6.0
[4.5.0]: https://github.com/nestjsx/crud/compare/v4.4.5...v4.5.0
[4.4.5]: https://github.com/nestjsx/crud/compare/v4.4.4...v4.4.5
[4.4.4]: https://github.com/nestjsx/crud/compare/v4.4.3...v4.4.4
[4.4.3]: https://github.com/nestjsx/crud/compare/v4.4.2...v4.4.3
[4.4.2]: https://github.com/nestjsx/crud/compare/v4.4.1...v4.4.2
[4.4.1]: https://github.com/nestjsx/crud/compare/v4.4.0...v4.4.1
[4.4.0]: https://github.com/nestjsx/crud/compare/v4.3.0...v4.4.0
[4.3.0]: https://github.com/nestjsx/crud/compare/v4.2.0...v4.3.0
[4.2.0]: https://github.com/nestjsx/crud/compare/v4.1.0...v4.2.0
[4.1.0]: https://github.com/nestjsx/crud/compare/v4.0.1...v4.1.0
[4.0.1]: https://github.com/nestjsx/crud/compare/v4.0.0...v4.0.1
[4.0.0]: https://github.com/nestjsx/crud/compare/v.3.2.0...v4.0.0
[#97]: https://github.com/nestjsx/crud/issues/97
[#53]: https://github.com/nestjsx/crud/issues/53
[#64]: https://github.com/nestjsx/crud/issues/64
[#54]: https://github.com/nestjsx/crud/issues/54
[#67]: https://github.com/nestjsx/crud/issues/67
[#107]: https://github.com/nestjsx/crud/issues/107
[#131]: https://github.com/nestjsx/crud/issues/131
[#101]: https://github.com/nestjsx/crud/issues/101
[#186]: https://github.com/nestjsx/crud/pull/186
[#184]: https://github.com/nestjsx/crud/issues/184
[#148]: https://github.com/nestjsx/crud/issues/148
[#105]: https://github.com/nestjsx/crud/issues/105
[#87]: https://github.com/nestjsx/crud/issues/87
[#159]: https://github.com/nestjsx/crud/issues/159
[#161]: https://github.com/nestjsx/crud/issues/161
[#179]: https://github.com/nestjsx/crud/issues/179


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.

## Our Standards

Examples of behavior that contributes to creating a positive environment
include:

- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members

Examples of unacceptable behavior by participants include:

- The use of sexualized language or imagery and unwelcome sexual attention or
  advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic
  address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Our Responsibilities

Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

## Scope

This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at mihon4ik@gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.

Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq


================================================
FILE: LICENSE
================================================
(The MIT License)

Copyright (c) 2018-Present Michael Yali <mihon4ik@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

================================================
FILE: README.md
================================================
[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://vshymanskyy.github.io/StandWithUkraine/)

<div align="center">
  <h1>:point_right:<a href="https://github.com/nestjsx/crud/issues/784">You can help NestJs CRUD
  </a></h1>
</div>

<div align="center">
  <h1>CRUD</h1>
</div>
<div align="center">
  <strong>for RESTful APIs built with NestJs</strong>
</div>

<br />

<div align="center">
  <a href="https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md">
    <img src="https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg" alt="StandWithUkraine" />
  </a>
  <a href="https://travis-ci.org/nestjsx/crud">
    <img src="https://github.com/nestjsx/crud/workflows/Tests/badge.svg" alt="Build" />
  </a>
  <a href="https://coveralls.io/github/nestjsx/crud?branch=master">
    <img src="https://coveralls.io/repos/github/nestjsx/crud/badge.svg" alt="Coverage" />
  </a>
  <a href="https://github.com/nestjsx/crud/blob/master/LICENSE">
    <img src="https://img.shields.io/github/license/nestjsx/crud.svg" alt="License" />
  </a>
  <a href="https://www.npmjs.com/package/@nestjsx/crud">
    <img src="https://img.shields.io/npm/v/@nestjsx/crud.svg" alt="npm version" />
  </a>
  <a href="https://www.npmjs.com/org/nestjsx">
    <img src="https://img.shields.io/npm/dm/@nestjsx/crud.svg" alt="npm downloads" />
  </a>
  <a href="http://makeapullrequest.com">
    <img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square" alt="PRs welcome" />
  </a>
  <a href="https://github.com/marmelab/awesome-rest#nodejs">
    <img src="https://raw.githubusercontent.com/nestjsx/crud/master/img/awesome-rest.svg?sanitize=true" alt="Awesome REST" />
  </a>
  <a href="#individuals" alt="Sponsors on Open Collective">
    <img src="https://opencollective.com/nestjsx/backers/badge.svg" />
  </a>
  <a href="#organizations" alt="Sponsors on Open Collective">
    <img src="https://opencollective.com/nestjsx/sponsors/badge.svg" />
  </a> 
</div>

<div align="center">
  <sub>Built with :purple_heart: by
  <a href="https://twitter.com/MichaelYali">@MichaelYali</a> and
  <a href="https://github.com/nestjsx/crud/graphs/contributors">
    Contributors
  </a>
  <div align="center">
    :star2: :eyes: :zap: :boom:
  </div>
</div>

<br />

We believe that everyone who's working with NestJs and building some RESTful services and especially some CRUD functionality will find `@nestjsx/crud` microframework very useful.

## Features

<img align="right" src="img/crud-usage2.png" alt="CRUD usage" />

- :electric_plug: Super easy to install and start using the full-featured controllers and services :point_right:

- :octopus: DB and service agnostic extendable CRUD controllers

- :mag_right: Reach query parsing with filtering, pagination, sorting, relations, nested relations, cache, etc.

- :telescope: Framework agnostic package with query builder for a frontend usage

- :space_invader: Query, path params and DTOs validation included

- :clapper: Overriding controller methods with ease

- :wrench: Tiny config (including globally)

- :gift: Additional helper decorators

- :pencil2: Swagger documentation

## Packages

- [**@nestjsx/crud**](https://www.npmjs.com/package/@nestjsx/crud) - core package which provides `@Crud()` decorator for endpoints generation, global configuration, validation, helper decorators ([docs](https://github.com/nestjsx/crud/wiki/Controllers#description))
- [**@nestjsx/crud-request**](https://www.npmjs.com/package/@nestjsx/crud-request) - request builder/parser package which provides `RequestQueryBuilder` class for a frontend usage and `RequestQueryParser` that is being used internally for handling and validating query/path params on a backend side ([docs](https://github.com/nestjsx/crud/wiki/Requests#frontend-usage))
- [**@nestjsx/crud-typeorm**](https://www.npmjs.com/package/@nestjsx/crud-typeorm) - TypeORM package which provides base `TypeOrmCrudService` with methods for CRUD database operations ([docs](https://github.com/nestjsx/crud/wiki/ServiceTypeorm))

## Documentation

- :dart: [General Information](https://github.com/nestjsx/crud/wiki#why)
- :video_game: [CRUD Controllers](https://github.com/nestjsx/crud/wiki/Controllers#description)
- :horse_racing: [CRUD ORM Services](https://github.com/nestjsx/crud/wiki/Services#description)
- :trumpet: [Handling Requests](https://github.com/nestjsx/crud/wiki/Requests#description)

## Support

Any support is welcome. At least you can give us a star :star:

## Contributors

### Code Contributors

This project exists thanks to all the people who contribute. [[Contribute](CODE_OF_CONDUCT.md)].
<a href="https://github.com/nestjsx/crud/graphs/contributors"><img src="https://opencollective.com/nestjsx/contributors.svg?width=890&button=false" /></a>

### Financial Contributors

Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/nestjsx#backer)]

#### Individuals

<a href="https://opencollective.com/nestjsx#backers" target="_blank"><img src="https://opencollective.com/nestjsx/backers.svg?width=890&button=false"></a>

#### Organizations

Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/nestjsx#sponsor)]

<a href="https://opencollective.com/nestjsx/sponsor/0/website" target="_blank"><img src="https://opencollective.com/nestjsx/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/nestjsx/sponsor/1/website" target="_blank"><img src="https://opencollective.com/nestjsx/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/nestjsx/sponsor/2/website" target="_blank"><img src="https://opencollective.com/nestjsx/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/nestjsx/sponsor/3/website" target="_blank"><img src="https://opencollective.com/nestjsx/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/nestjsx/sponsor/4/website" target="_blank"><img src="https://opencollective.com/nestjsx/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/nestjsx/sponsor/5/website" target="_blank"><img src="https://opencollective.com/nestjsx/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/nestjsx/sponsor/6/website" target="_blank"><img src="https://opencollective.com/nestjsx/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/nestjsx/sponsor/7/website" target="_blank"><img src="https://opencollective.com/nestjsx/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/nestjsx/sponsor/8/website" target="_blank"><img src="https://opencollective.com/nestjsx/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/nestjsx/sponsor/9/website" target="_blank"><img src="https://opencollective.com/nestjsx/sponsor/9/avatar.svg"></a>

## License

[MIT](LICENSE)


================================================
FILE: docker-compose.yml
================================================
version: '3'

networks:
  nestjsx_crud:

services:
  postgres:
    # TypeORM fails with Postgres v.12
    image: postgres:11.5
    ports:
      - 5455:5432
    environment:
      POSTGRES_USER: root
      POSTGRES_PASSWORD: root
      POSTGRES_DB: nestjsx_crud
    networks:
      - nestjsx_crud

  mysql:
    platform: linux/x86_64
    image: mysql:5.7
    ports:
      - 3316:3306
    environment:
      MYSQL_DATABASE: nestjsx_crud
      MYSQL_USER: nestjsx_crud
      MYSQL_PASSWORD: nestjsx_crud
      MYSQL_ROOT_PASSWORD: nestjsx_crud

  redis:
    image: redis:alpine
    ports:
      - 6399:6379
    command: redis-server
    networks:
      - nestjsx_crud


================================================
FILE: integration/crud-typeorm/app.module.ts
================================================
import { Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
import { TypeOrmModule } from '@nestjs/typeorm';

import { AuthGuard } from './auth.guard';
import { withCache } from './orm.config';
import { CompaniesModule } from './companies/companies.module';
import { ProjectsModule } from './projects/projects.module';
import { UsersModule } from './users/users.module';
import { DevicesModule } from './devices/devices.module';
import { NotesModule } from './notes/notes.module';

@Module({
  imports: [
    TypeOrmModule.forRoot(withCache),
    CompaniesModule,
    ProjectsModule,
    UsersModule,
    DevicesModule,
    NotesModule,
  ],
  providers: [
    {
      provide: APP_GUARD,
      useClass: AuthGuard,
    },
  ],
})
export class AppModule {}


================================================
FILE: integration/crud-typeorm/auth.guard.ts
================================================
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';

import { UsersService } from './users';
import { USER_REQUEST_KEY } from './constants';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private usersService: UsersService) {}

  async canActivate(ctx: ExecutionContext): Promise<boolean> {
    const req = ctx.switchToHttp().getRequest();
    req[USER_REQUEST_KEY] = await this.usersService.findOne(1);

    return true;
  }
}


================================================
FILE: integration/crud-typeorm/base-entity.ts
================================================
import { PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn } from 'typeorm';

export class BaseEntity {
  @PrimaryGeneratedColumn()
  id?: number;

  @CreateDateColumn({ nullable: true })
  createdAt?: Date;

  @UpdateDateColumn({ nullable: true })
  updatedAt?: Date;
}


================================================
FILE: integration/crud-typeorm/companies/companies.controller.ts
================================================
import { Controller } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Crud } from '@nestjsx/crud';

import { Company } from './company.entity';
import { CompaniesService } from './companies.service';
import { serialize } from './responses';

@Crud({
  model: {
    type: Company
  },
  serialize,
  routes: {
    deleteOneBase: {
      returnDeleted: false,
    },
  },
  query: {
    alwaysPaginate: false,
    softDelete: true,
    allow: ['name'],
    join: {
      users: {
        alias: 'companyUsers',
        exclude: ['email'],
        eager: true,
      },
      'users.projects': {
        eager: true,
        alias: 'usersProjects',
        allow: ['name'],
      },
      'users.projects.company': {
        eager: true,
        alias: 'usersProjectsCompany',
      },
      projects: {
        eager: true,
        select: false,
      },
    },
  },
})
@ApiTags('companies')
@Controller('companies')
export class CompaniesController {
  constructor(public service: CompaniesService) {}
}


================================================
FILE: integration/crud-typeorm/companies/companies.module.ts
================================================
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

import { Company } from './company.entity';
import { CompaniesService } from './companies.service';
import { CompaniesController } from './companies.controller';

@Module({
  imports: [TypeOrmModule.forFeature([Company])],
  providers: [CompaniesService],
  exports: [CompaniesService],
  controllers: [CompaniesController],
})
export class CompaniesModule {}


================================================
FILE: integration/crud-typeorm/companies/companies.service.ts
================================================
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { TypeOrmCrudService } from '@nestjsx/crud-typeorm';

import { Company } from './company.entity';

@Injectable()
export class CompaniesService extends TypeOrmCrudService<Company> {
  constructor(@InjectRepository(Company) repo) {
    super(repo);
  }
}


================================================
FILE: integration/crud-typeorm/companies/company.entity.ts
================================================
import { CrudValidationGroups } from '@nestjsx/crud';
import { Entity, Column, OneToMany, PrimaryGeneratedColumn, DeleteDateColumn } from 'typeorm';
import {
  IsOptional,
  IsString,
  MaxLength,
  IsNotEmpty,
  IsNumber,
  IsEmpty,
} from 'class-validator';
import { Type } from 'class-transformer';

import { BaseEntity } from '../base-entity';
import { User } from '../users/user.entity';
import { Project } from '../projects/project.entity';

const { CREATE, UPDATE } = CrudValidationGroups;

@Entity('companies')
export class Company extends BaseEntity {
  @IsOptional({ groups: [UPDATE] })
  @IsEmpty({ groups: [CREATE] })
  @IsNumber({}, { groups: [UPDATE] })
  @PrimaryGeneratedColumn()
  id?: number;

  @IsOptional({ groups: [UPDATE] })
  @IsNotEmpty({ groups: [CREATE] })
  @IsString({ always: true })
  @MaxLength(100, { always: true })
  @Column({ type: 'varchar', length: 100, nullable: false })
  name: string;

  @IsOptional({ groups: [UPDATE] })
  @IsNotEmpty({ groups: [CREATE] })
  @IsString({ groups: [CREATE, UPDATE] })
  @MaxLength(100, { groups: [CREATE, UPDATE] })
  @Column({ type: 'varchar', length: 100, nullable: false, unique: true })
  domain: string;

  @IsOptional({ always: true })
  @IsString({ always: true })
  @Column({ type: 'text', nullable: true, default: null })
  description: string;

  @DeleteDateColumn({ nullable: true })
  deletedAt?: Date;

  /**
   * Relations
   */

  @OneToMany((type) => User, (u) => u.company)
  @Type((t) => User)
  users: User[];

  @OneToMany((type) => Project, (p) => p.company)
  projects: Project[];
}


================================================
FILE: integration/crud-typeorm/companies/index.ts
================================================
export * from './company.entity';
export * from './companies.service';


================================================
FILE: integration/crud-typeorm/companies/requests/create-company.dto.ts
================================================
import { ApiProperty } from '@nestjs/swagger';
import { IsString, MaxLength } from 'class-validator';

export class CreateCompanyDto {
  @ApiProperty({ type: 'string' })
  @IsString()
  @MaxLength(100)
  name: string;

  @ApiProperty({ type: 'string' })
  @IsString()
  @MaxLength(100)
  domain: string;

  @ApiProperty({ type: 'string' })
  @IsString()
  @MaxLength(100)
  description: string;
}


================================================
FILE: integration/crud-typeorm/companies/requests/index.ts
================================================
import { CreateCompanyDto } from './create-company.dto';

export const dto = {
  create: CreateCompanyDto,
};


================================================
FILE: integration/crud-typeorm/companies/responses/get-company-response.dto.ts
================================================
import { ApiProperty } from '@nestjs/swagger';
import { Exclude } from 'class-transformer';

export class GetCompanyResponseDto {
  @ApiProperty({ type: 'number' })
  id: string;

  @ApiProperty({ type: 'string' })
  name: string;

  @ApiProperty({ type: 'string' })
  domain: string;

  @ApiProperty({ type: 'string' })
  description: string;

  @Exclude()
  createdAt: any;

  @Exclude()
  updatedAt: any;
}


================================================
FILE: integration/crud-typeorm/companies/responses/index.ts
================================================
import { SerializeOptions } from '@nestjsx/crud';
import { GetCompanyResponseDto } from './get-company-response.dto';

export const serialize: SerializeOptions = {
  get: GetCompanyResponseDto,
};


================================================
FILE: integration/crud-typeorm/constants.ts
================================================
export const USER_REQUEST_KEY = 'user';


================================================
FILE: integration/crud-typeorm/devices/device.entity.ts
================================================
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
import { IsOptional, IsString, IsUUID } from 'class-validator';
import { CrudValidationGroups } from '@nestjsx/crud';

const { CREATE, UPDATE } = CrudValidationGroups;

@Entity('devices')
export class Device {
  @IsOptional({ always: true })
  @IsUUID('4', { always: true })
  @PrimaryGeneratedColumn('uuid')
  deviceKey: string;

  @IsOptional({ always: true })
  @IsString({ always: true })
  @Column({ type: 'text', nullable: true })
  description?: string;
}


================================================
FILE: integration/crud-typeorm/devices/devices.controller.ts
================================================
import { Controller } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Crud } from '@nestjsx/crud';

import { Device } from './device.entity';
import { DevicesService } from './devices.service';
import { serialize } from './response';

@Crud({
  model: { type: Device },
  serialize,
  params: {
    deviceKey: {
      field: 'deviceKey',
      type: 'uuid',
      primary: true,
    },
  },
  routes: {
    deleteOneBase: {
      returnDeleted: true,
    },
  },
})
@ApiTags('devices')
@Controller('/devices')
export class DevicesController {
  constructor(public service: DevicesService) {}
}


================================================
FILE: integration/crud-typeorm/devices/devices.module.ts
================================================
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

import { Device } from './device.entity';
import { DevicesService } from './devices.service';
import { DevicesController } from './devices.controller';

@Module({
  imports: [TypeOrmModule.forFeature([Device])],
  providers: [DevicesService],
  exports: [DevicesService],
  controllers: [DevicesController],
})
export class DevicesModule {}


================================================
FILE: integration/crud-typeorm/devices/devices.service.ts
================================================
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { TypeOrmCrudService } from '@nestjsx/crud-typeorm';

import { Device } from './device.entity';

@Injectable()
export class DevicesService extends TypeOrmCrudService<Device> {
  constructor(@InjectRepository(Device) repo) {
    super(repo);
  }
}


================================================
FILE: integration/crud-typeorm/devices/index.ts
================================================
export * from './device.entity';
export * from './devices.service';


================================================
FILE: integration/crud-typeorm/devices/response/delete-device-response.dto.ts
================================================
import { ApiProperty } from '@nestjs/swagger';
import { Exclude } from 'class-transformer';

export class DeleteDeviceResponseDto {
  @ApiProperty({ type: 'string' })
  deviceKey: string;

  @Exclude()
  description?: string;
}


================================================
FILE: integration/crud-typeorm/devices/response/index.ts
================================================
import { SerializeOptions } from '@nestjsx/crud';
import { DeleteDeviceResponseDto } from './delete-device-response.dto';

export const serialize: SerializeOptions = {
  delete: DeleteDeviceResponseDto,
};


================================================
FILE: integration/crud-typeorm/main.ts
================================================
import { NestFactory } from '@nestjs/core';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { CrudConfigService } from '@nestjsx/crud';
import { USER_REQUEST_KEY } from './constants';

// Important: load config before (!!!) you import AppModule
// https://github.com/nestjsx/crud/wiki/Controllers#global-options
CrudConfigService.load({
  auth: {
    property: USER_REQUEST_KEY,
  },
  routes: {
    // exclude: ['createManyBase'],
  },
});

import { HttpExceptionFilter } from '../shared/https-exception.filter';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  app.useGlobalFilters(new HttpExceptionFilter());

  const options = new DocumentBuilder()
    .setTitle('@nestjsx/crud-typeorm')
    .setDescription('@nestjsx/crud-typeorm')
    .setVersion('1.0')
    .build();
  const document = SwaggerModule.createDocument(app, options);
  SwaggerModule.setup('docs', app, document);

  await app.listen(process.env.PORT || 3000);
}

bootstrap();


================================================
FILE: integration/crud-typeorm/notes/index.ts
================================================
export * from './note.entity';
export * from './notes.service';


================================================
FILE: integration/crud-typeorm/notes/note.entity.ts
================================================
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';

@Entity('notes')
export class Note {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ name: 'revision_id', nullable: false })
  revisionId: number;
}


================================================
FILE: integration/crud-typeorm/notes/notes.controller.ts
================================================
import { Controller } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Crud } from '@nestjsx/crud';

import { Note } from './note.entity';
import { NotesService } from './notes.service';
import { dto } from './requests';
import { serialize } from './responses';

@Crud({
  model: { type: Note },
  dto,
  serialize,
  query: {
    alwaysPaginate: true,
  },
})
@ApiTags('notes')
@Controller('/notes')
export class NotesController {
  constructor(public service: NotesService) {}
}


================================================
FILE: integration/crud-typeorm/notes/notes.module.ts
================================================
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

import { Note } from './note.entity';
import { NotesService } from './notes.service';
import { NotesController } from './notes.controller';

@Module({
  imports: [TypeOrmModule.forFeature([Note])],
  providers: [NotesService],
  exports: [NotesService],
  controllers: [NotesController],
})
export class NotesModule {}


================================================
FILE: integration/crud-typeorm/notes/notes.service.ts
================================================
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { TypeOrmCrudService } from '../../../packages/crud-typeorm/src';

import { Note } from './note.entity';

@Injectable()
export class NotesService extends TypeOrmCrudService<Note> {
  constructor(@InjectRepository(Note) repo) {
    super(repo);
  }
}


================================================
FILE: integration/crud-typeorm/notes/requests/create-note.dto.ts
================================================
import { ApiProperty } from '@nestjs/swagger';
import { IsNumber } from 'class-validator';

export class CreateNoteDto {
  @ApiProperty({ type: 'number' })
  @IsNumber()
  revisionId: string;
}


================================================
FILE: integration/crud-typeorm/notes/requests/index.ts
================================================
import { CreateNoteDto } from './create-note.dto';

export const dto = {
  create: CreateNoteDto,
};


================================================
FILE: integration/crud-typeorm/notes/responses/get-note-response.dto.ts
================================================
import { ApiProperty } from '@nestjs/swagger';
import { IsNumber } from 'class-validator';

export class GetNoteResponseDto {
  @ApiProperty({ type: 'number' })
  @IsNumber()
  id: string;

  @ApiProperty({ type: 'number' })
  @IsNumber()
  revisionId: string;
}


================================================
FILE: integration/crud-typeorm/notes/responses/index.ts
================================================
import { GetNoteResponseDto } from './get-note-response.dto';

export const serialize = {
  get: GetNoteResponseDto,
};


================================================
FILE: integration/crud-typeorm/orm.config.ts
================================================
import { join } from 'path';
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
import { isNil } from '@nestjsx/util';

const type = (process.env.TYPEORM_CONNECTION as any) || 'postgres';

export const withCache: TypeOrmModuleOptions = {
  type,
  host: '127.0.0.1',
  port: type === 'postgres' ? 5455 : 3316,
  username: type === 'mysql' ? 'nestjsx_crud' : 'root',
  password: type === 'mysql' ? 'nestjsx_crud' : 'root',
  database: 'nestjsx_crud',
  synchronize: false,
  logging: !isNil(process.env.TYPEORM_LOGGING) ? !!parseInt(process.env.TYPEORM_LOGGING, 10) : true,
  entities: [join(__dirname, './**/*.entity{.ts,.js}')],
};


================================================
FILE: integration/crud-typeorm/orm.mysql.ts
================================================
import { DataSource } from 'typeorm';

exports.default = new DataSource({
  type: 'mysql',
  host: '127.0.0.1',
  port: 3316,
  username: 'nestjsx_crud',
  password: 'nestjsx_crud',
  database: 'nestjsx_crud',
  entities: ['./**/*.entity.ts'],
  migrationsTableName: 'orm_migrations',
  migrations: ['./seeds.ts'],
});


================================================
FILE: integration/crud-typeorm/orm.postgres.ts
================================================
import { DataSource } from 'typeorm';

exports.default = new DataSource({
  type: 'postgres',
  host: '127.0.0.1',
  port: 5455,
  username: 'root',
  password: 'root',
  database: 'nestjsx_crud',
  entities: ['./**/*.entity.ts'],
  migrationsTableName: 'orm_migrations',
  migrations: ['./seeds.ts'],
});


================================================
FILE: integration/crud-typeorm/orm.yaml
================================================
default:
  type: postgres
  host: 127.0.0.1
  port: 5455
  username: root
  password: root
  database: nestjsx_crud
  entities:
    - ./**/*.entity.ts
  migrationsTableName: orm_migrations
  migrations:
    - ./seeds.ts
mysql:
  type: mysql
  host: 127.0.0.1
  port: 3316
  username: nestjsx_crud
  password: nestjsx_crud
  database: nestjsx_crud
  entities:
    - ./**/*.entity.ts
  migrationsTableName: orm_migrations
  migrations:
    - ./seeds.ts


================================================
FILE: integration/crud-typeorm/projects/index.ts
================================================
export * from './project.entity';
export * from './user-project.entity';
export * from './projects.service';


================================================
FILE: integration/crud-typeorm/projects/my-projects.controller.ts
================================================
import { Controller } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Crud, CrudAuth } from '@nestjsx/crud';

import { User } from '../users/user.entity';
import { UserProject } from './user-project.entity';
import { UserProjectsService } from './user-projects.service';

@Crud({
  model: {
    type: UserProject,
  },
  params: {
    projectId: {
      field: 'projectId',
      type: 'number',
      primary: true,
    },
  },
  query: {
    join: {
      project: {
        eager: true,
      },
    },
  },
})
@CrudAuth({
  filter: (user: User) => ({
    userId: user.id,
  }),
  persist: (user: User) => ({
    userId: user.id,
  }),
})
@ApiTags('my-projects')
@Controller('my-projects')
export class MyProjectsController {
  constructor(public service: UserProjectsService) {}
}


================================================
FILE: integration/crud-typeorm/projects/project.entity.ts
================================================
import { Entity, Column, ManyToOne, ManyToMany, JoinTable, OneToMany } from 'typeorm';
import {
  IsOptional,
  IsString,
  IsNumber,
  MaxLength,
  IsDefined,
  IsBoolean,
} from 'class-validator';
import { CrudValidationGroups } from '@nestjsx/crud';

import { BaseEntity } from '../base-entity';
import { Company } from '../companies/company.entity';
import { User } from '../users/user.entity';
import { UserProject } from './user-project.entity';

const { CREATE, UPDATE } = CrudValidationGroups;

@Entity('projects')
export class Project extends BaseEntity {
  @IsOptional({ groups: [UPDATE] })
  @IsDefined({ groups: [CREATE] })
  @IsString({ always: true })
  @MaxLength(100, { always: true })
  @Column({ type: 'varchar', length: 100, nullable: false, unique: true })
  name?: string;

  @IsOptional({ always: true })
  @Column({ type: 'text', nullable: true })
  description?: string;

  @IsOptional({ always: true })
  @IsBoolean({ always: true })
  @Column({ type: 'boolean', default: true })
  isActive?: boolean;

  @IsOptional({ always: true })
  @IsNumber({}, { always: true })
  @Column({ nullable: false })
  companyId?: number;

  /**
   * Relations
   */

  @ManyToOne((type) => Company, (c) => c.projects)
  company?: Company;

  @ManyToMany((type) => User, (u) => u.projects, { cascade: true })
  @JoinTable({
    name: 'user_projects',
    joinColumn: {
      name: 'projectId',
      referencedColumnName: 'id',
    },
    inverseJoinColumn: {
      name: 'userId',
      referencedColumnName: 'id',
    },
  })
  users?: User[];

  @OneToMany((type) => UserProject, (el) => el.project, {
    persistence: false,
    onDelete: 'CASCADE',
  })
  userProjects!: UserProject[];
}


================================================
FILE: integration/crud-typeorm/projects/projects.controller.ts
================================================
import { Controller } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Crud } from '@nestjsx/crud';

import { Project } from './project.entity';
import { ProjectsService } from './projects.service';

@Crud({
  model: {
    type: Project,
  },
  params: {
    companyId: {
      field: 'companyId',
      type: 'number',
    },
    id: {
      field: 'id',
      type: 'number',
      primary: true,
    },
  },
  query: {
    join: {
      users: {},
    },
  },
})
@ApiTags('projects')
@Controller('/companies/:companyId/projects')
export class ProjectsController {
  constructor(public service: ProjectsService) {}
}


================================================
FILE: integration/crud-typeorm/projects/projects.module.ts
================================================
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

import { Project } from './project.entity';
import { UserProject } from './user-project.entity';
import { ProjectsService } from './projects.service';
import { UserProjectsService } from './user-projects.service';
import { ProjectsController } from './projects.controller';
import { MyProjectsController } from './my-projects.controller';

@Module({
  imports: [TypeOrmModule.forFeature([Project, UserProject])],
  providers: [ProjectsService, UserProjectsService],
  exports: [ProjectsService, UserProjectsService],
  controllers: [ProjectsController, MyProjectsController],
})
export class ProjectsModule {}


================================================
FILE: integration/crud-typeorm/projects/projects.service.ts
================================================
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { TypeOrmCrudService } from '@nestjsx/crud-typeorm';

import { Project } from './project.entity';

@Injectable()
export class ProjectsService extends TypeOrmCrudService<Project> {
  constructor(@InjectRepository(Project) repo) {
    super(repo);
  }
}


================================================
FILE: integration/crud-typeorm/projects/user-project.entity.ts
================================================
import { Entity, Column, ManyToOne, PrimaryColumn } from 'typeorm';

import { User } from '../users/user.entity';
import { Project } from './project.entity';

@Entity('user_projects')
export class UserProject {
  @PrimaryColumn()
  public projectId!: number;

  @PrimaryColumn()
  public userId!: number;

  @Column({ nullable: true })
  public review!: string;

  @ManyToOne(() => Project, (el) => el.userProjects, {
    persistence: false,
    onDelete: 'CASCADE',
  })
  public project: Project;

  @ManyToOne(() => User, (el) => el.userProjects, {
    persistence: false,
  })
  public user: User;
}


================================================
FILE: integration/crud-typeorm/projects/user-projects.service.ts
================================================
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { TypeOrmCrudService } from '@nestjsx/crud-typeorm';

import { UserProject } from './user-project.entity';

@Injectable()
export class UserProjectsService extends TypeOrmCrudService<UserProject> {
  constructor(@InjectRepository(UserProject) repo) {
    super(repo);
  }
}


================================================
FILE: integration/crud-typeorm/seeds.ts
================================================
import { ClassType } from '@nestjsx/util';
import { plainToClass } from 'class-transformer';
import { MigrationInterface, Repository, QueryRunner } from 'typeorm';
import { Company } from './companies';
import { Project, UserProject } from './projects';
import { Name, User } from './users';
import { License, UserLicense } from './users-licenses';
import { UserProfile } from './users-profiles';
import { Note } from './notes';

export class Seeds1544303473346 implements MigrationInterface {
  private save<T>(repo: Repository<T>, data: Partial<T>[]): Promise<T[]> {
    return repo.save(
      data.map((partial: Partial<T>) =>
        plainToClass<any, any>(repo.target as ClassType<T>, partial, {
          ignoreDecorators: true,
        }),
      ),
    );
  }

  public async up(queryRunner: QueryRunner): Promise<any> {
    const { connection } = queryRunner;

    const companiesRepo = connection.getRepository(Company);
    const projectsRepo = connection.getRepository(Project);
    const usersProfilesRepo = connection.getRepository(UserProfile);
    const usersRepo = connection.getRepository(User);
    const licensesRepo = connection.getRepository(License);
    const usersLincesesRepo = connection.getRepository(UserLicense);
    const usersProjectsRepo = connection.getRepository(UserProject);
    const notesRepo = connection.getRepository(Note);

    // companies
    await this.save(companiesRepo, [
      { name: 'Name1', domain: 'Domain1' },
      { name: 'Name2', domain: 'Domain2' },
      { name: 'Name3', domain: 'Domain3' },
      { name: 'Name4', domain: 'Domain4' },
      { name: 'Name5', domain: 'Domain5' },
      { name: 'Name6', domain: 'Domain6' },
      { name: 'Name7', domain: 'Domain7' },
      { name: 'Name8', domain: 'Domain8' },
      { name: 'Name9', domain: 'Domain9', deletedAt: new Date() },
      { name: 'Name10', domain: 'Domain10' },
    ]);

    // projects
    await this.save(projectsRepo, [
      { name: 'Project1', description: 'description1', isActive: true, companyId: 1 },
      { name: 'Project2', description: 'description2', isActive: true, companyId: 1 },
      { name: 'Project3', description: 'description3', isActive: true, companyId: 2 },
      { name: 'Project4', description: 'description4', isActive: true, companyId: 2 },
      { name: 'Project5', description: 'description5', isActive: true, companyId: 3 },
      { name: 'Project6', description: 'description6', isActive: true, companyId: 3 },
      { name: 'Project7', description: 'description7', isActive: true, companyId: 4 },
      { name: 'Project8', description: 'description8', isActive: true, companyId: 4 },
      { name: 'Project9', description: 'description9', isActive: true, companyId: 5 },
      { name: 'Project10', description: 'description10', isActive: true, companyId: 5 },
      { name: 'Project11', description: 'description11', isActive: false, companyId: 6 },
      { name: 'Project12', description: 'description12', isActive: false, companyId: 6 },
      { name: 'Project13', description: 'description13', isActive: false, companyId: 7 },
      { name: 'Project14', description: 'description14', isActive: false, companyId: 7 },
      { name: 'Project15', description: 'description15', isActive: false, companyId: 8 },
      { name: 'Project16', description: 'description16', isActive: false, companyId: 8 },
      { name: 'Project17', description: 'description17', isActive: false, companyId: 9 },
      { name: 'Project18', description: 'description18', isActive: false, companyId: 9 },
      { name: 'Project19', description: 'description19', isActive: false, companyId: 10 },
      { name: 'Project20', description: 'description20', isActive: false, companyId: 10 },
    ]);

    // user-profiles
    await this.save(usersProfilesRepo, [
      { name: 'User1' },
      { name: 'User2' },
      { name: 'User3' },
      { name: 'User4' },
      { name: 'User5' },
      { name: 'User6' },
      { name: 'User7' },
      { name: 'User8' },
      { name: 'User9' },
      { name: 'User1' },
      { name: 'User1' },
      { name: 'User1' },
      { name: 'User1' },
      { name: 'User1' },
      { name: 'User1' },
      { name: 'User1' },
      { name: 'User1' },
      { name: 'User1' },
      { name: 'User1' },
      { name: 'User2' },
    ]);

    // users
    const name: Name = { first: null, last: null };
    const name1: Name = { first: 'firstname1', last: 'lastname1' };
    await this.save(usersRepo, [
      { email: '1@email.com', isActive: true, companyId: 1, profileId: 1, name: name1 },
      { email: '2@email.com', isActive: true, companyId: 1, profileId: 2, name },
      { email: '3@email.com', isActive: true, companyId: 1, profileId: 3, name },
      { email: '4@email.com', isActive: true, companyId: 1, profileId: 4, name },
      { email: '5@email.com', isActive: true, companyId: 1, profileId: 5, name },
      { email: '6@email.com', isActive: true, companyId: 1, profileId: 6, name },
      { email: '7@email.com', isActive: false, companyId: 1, profileId: 7, name },
      { email: '8@email.com', isActive: false, companyId: 1, profileId: 8, name },
      { email: '9@email.com', isActive: false, companyId: 1, profileId: 9, name },
      { email: '10@email.com', isActive: true, companyId: 1, profileId: 10, name },
      { email: '11@email.com', isActive: true, companyId: 2, profileId: 11, name },
      { email: '12@email.com', isActive: true, companyId: 2, profileId: 12, name },
      { email: '13@email.com', isActive: true, companyId: 2, profileId: 13, name },
      { email: '14@email.com', isActive: true, companyId: 2, profileId: 14, name },
      { email: '15@email.com', isActive: true, companyId: 2, profileId: 15, name },
      { email: '16@email.com', isActive: true, companyId: 2, profileId: 16, name },
      { email: '17@email.com', isActive: false, companyId: 2, profileId: 17, name },
      { email: '18@email.com', isActive: false, companyId: 2, profileId: 18, name },
      { email: '19@email.com', isActive: false, companyId: 2, profileId: 19, name },
      { email: '20@email.com', isActive: false, companyId: 2, profileId: 20, name },
      { email: '21@email.com', isActive: false, companyId: 2, profileId: null, name },
    ]);

    // licenses
    await this.save(licensesRepo, [
      { name: 'License1' },
      { name: 'License2' },
      { name: 'License3' },
      { name: 'License4' },
      { name: 'License5' },
    ]);

    // user-licenses
    await this.save(usersLincesesRepo, [
      { userId: 1, licenseId: 1, yearsActive: 3 },
      { userId: 1, licenseId: 2, yearsActive: 5 },
      { userId: 1, licenseId: 4, yearsActive: 7 },
      { userId: 2, licenseId: 5, yearsActive: 1 },
    ]);

    // user-projects
    await this.save(usersProjectsRepo, [
      { projectId: 1, userId: 1, review: 'User project 1 1' },
      { projectId: 1, userId: 2, review: 'User project 1 2' },
      { projectId: 2, userId: 2, review: 'User project 2 2' },
      { projectId: 3, userId: 3, review: 'User project 3 3' },
    ]);

    // notes
    await this.save(notesRepo, [
      { revisionId: 1 },
      { revisionId: 1 },
      { revisionId: 2 },
      { revisionId: 2 },
      { revisionId: 3 },
      { revisionId: 3 },
    ]);
  }

  public async down(queryRunner: QueryRunner): Promise<any> {}
}


================================================
FILE: integration/crud-typeorm/users/index.ts
================================================
export * from './user.entity';
export * from './users.service';


================================================
FILE: integration/crud-typeorm/users/me.controller.ts
================================================
import { Controller } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Crud, CrudAuth } from '@nestjsx/crud';

import { User } from './user.entity';
import { UsersService } from './users.service';

@Crud({
  model: {
    type: User,
  },
  routes: {
    only: ['getOneBase', 'updateOneBase'],
  },
  params: {
    id: {
      primary: true,
      disabled: true,
    },
  },
  query: {
    join: {
      company: {
        eager: true,
      },
      profile: {
        eager: true,
      },
    },
  },
})
@CrudAuth({
  filter: (user: User) => ({
    id: user.id,
  }),
})
@ApiTags('me')
@Controller('me')
export class MeController {
  constructor(public service: UsersService) {}
}


================================================
FILE: integration/crud-typeorm/users/user.entity.ts
================================================
import {
  Entity,
  Column,
  JoinColumn,
  OneToOne,
  OneToMany,
  ManyToOne,
  ManyToMany,
  DeleteDateColumn,
} from 'typeorm';
import {
  IsOptional,
  IsString,
  MaxLength,
  IsNotEmpty,
  IsEmail,
  IsBoolean,
  ValidateNested,
} from 'class-validator';
import { Type } from 'class-transformer';
import { CrudValidationGroups } from '@nestjsx/crud';

import { BaseEntity } from '../base-entity';
import { UserProfile } from '../users-profiles/user-profile.entity';
import { UserLicense } from '../users-licenses/user-license.entity';
import { Company } from '../companies/company.entity';
import { Project } from '../projects/project.entity';
import { UserProject } from '../projects/user-project.entity';

const { CREATE, UPDATE } = CrudValidationGroups;

export class Name {
  @IsString({ always: true })
  @Column({ nullable: true })
  first: string;

  @IsString({ always: true })
  @Column({ nullable: true })
  last: string;
}

// tslint:disable-next-line:max-classes-per-file
@Entity('users')
export class User extends BaseEntity {
  @IsOptional({ groups: [UPDATE] })
  @IsNotEmpty({ groups: [CREATE] })
  @IsString({ always: true })
  @MaxLength(255, { always: true })
  @IsEmail({ require_tld: false }, { always: true })
  @Column({ type: 'varchar', length: 255, nullable: false, unique: true })
  email: string;

  @IsOptional({ groups: [UPDATE] })
  @IsNotEmpty({ groups: [CREATE] })
  @IsBoolean({ always: true })
  @Column({ type: 'boolean', default: true })
  isActive: boolean;

  @Type((t) => Name)
  @Column((type) => Name)
  name: Name;

  @Column({ nullable: true })
  profileId?: number;

  @Column({ nullable: false })
  companyId?: number;

  @DeleteDateColumn({ nullable: true })
  deletedAt?: Date;

  /**
   * Relations
   */

  @IsOptional({ groups: [UPDATE] })
  @IsNotEmpty({ groups: [CREATE] })
  @ValidateNested({ always: true })
  @Type((t) => UserProfile)
  @OneToOne((type) => UserProfile, (p) => p.user, { cascade: true })
  @JoinColumn()
  profile?: UserProfile;

  @ManyToOne((type) => Company, (c) => c.users)
  company?: Company;

  @ManyToMany((type) => Project, (c) => c.users)
  projects?: Project[];

  @OneToMany((type) => UserProject, (el) => el.user, {
    persistence: false,
    onDelete: 'CASCADE',
  })
  userProjects?: UserProject[];

  @OneToMany((type) => UserLicense, (ul) => ul.user)
  @Type((t) => UserLicense)
  @JoinColumn()
  userLicenses?: UserLicense[];
}


================================================
FILE: integration/crud-typeorm/users/users.controller.ts
================================================
import { Controller } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import {
  Crud,
  CrudController,
  CrudRequest,
  ParsedRequest,
  Override,
} from '@nestjsx/crud';

import { User } from './user.entity';
import { UsersService } from './users.service';

@Crud({
  model: {
    type: User,
  },
  params: {
    companyId: {
      field: 'companyId',
      type: 'number',
    },
    id: {
      field: 'id',
      type: 'number',
      primary: true,
    },
  },
  query: {
    softDelete: true,
    join: {
      company: {
        exclude: ['description'],
      },
      'company.projects': {
        alias: 'pr',
        exclude: ['description'],
      },
      profile: {
        eager: true,
        exclude: ['updatedAt'],
      },
    },
  },
})
@ApiTags('users')
@Controller('/companies/:companyId/users')
export class UsersController implements CrudController<User> {
  constructor(public service: UsersService) {}

  get base(): CrudController<User> {
    return this;
  }

  @Override('getManyBase')
  getAll(@ParsedRequest() req: CrudRequest) {
    return this.base.getManyBase(req);
  }
}


================================================
FILE: integration/crud-typeorm/users/users.module.ts
================================================
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

import { User } from './user.entity';
import { UserProfile } from '../users-profiles/user-profile.entity';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { MeController } from './me.controller';

@Module({
  imports: [TypeOrmModule.forFeature([User, UserProfile])],
  providers: [UsersService],
  exports: [UsersService],
  controllers: [UsersController, MeController],
})
export class UsersModule {}


================================================
FILE: integration/crud-typeorm/users/users.service.ts
================================================
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { TypeOrmCrudService } from '@nestjsx/crud-typeorm';

import { User } from './user.entity';

@Injectable()
export class UsersService extends TypeOrmCrudService<User> {
  constructor(@InjectRepository(User) repo) {
    super(repo);
  }
}


================================================
FILE: integration/crud-typeorm/users-licenses/index.ts
================================================
export * from './license.entity';
export * from './user-license.entity';


================================================
FILE: integration/crud-typeorm/users-licenses/license.entity.ts
================================================
import { Column, Entity } from 'typeorm';
import { BaseEntity } from '../base-entity';
import { IsOptional, IsString, MaxLength } from 'class-validator';

@Entity('licenses')
export class License extends BaseEntity {
  @IsOptional({ always: true })
  @IsString({ always: true })
  @MaxLength(32, { always: true })
  @Column({ type: 'varchar', length: 32, nullable: true, default: null })
  name: string;
}


================================================
FILE: integration/crud-typeorm/users-licenses/user-license.entity.ts
================================================
import { Column, Entity, ManyToOne, PrimaryColumn } from 'typeorm';
import { User } from '../users/user.entity';
import { Type } from 'class-transformer';
import { License } from './license.entity';

@Entity('user_licenses')
export class UserLicense {
  @PrimaryColumn()
  userId: number;

  @PrimaryColumn()
  licenseId: number;

  @ManyToOne((type) => User)
  @Type((t) => User)
  user: User;

  @ManyToOne((type) => License)
  @Type((t) => License)
  license: License;

  @Column()
  yearsActive: number;
}


================================================
FILE: integration/crud-typeorm/users-profiles/index.ts
================================================
export * from './user-profile.entity';


================================================
FILE: integration/crud-typeorm/users-profiles/user-profile.entity.ts
================================================
import { Entity, Column, OneToOne, DeleteDateColumn } from 'typeorm';
import { IsOptional, IsString, MaxLength } from 'class-validator';

import { BaseEntity } from '../base-entity';
import { User } from '../users/user.entity';

@Entity('user_profiles')
export class UserProfile extends BaseEntity {
  @IsOptional({ always: true })
  @IsString({ always: true })
  @MaxLength(32, { always: true })
  @Column({ type: 'varchar', length: 32, nullable: true, default: null })
  name: string;

  @DeleteDateColumn({ nullable: true })
  deletedAt?: Date;

  /**
   * Relations
   */

  @OneToOne((type) => User, (u) => u.profile)
  user?: User;
}


================================================
FILE: integration/shared/https-exception.filter.ts
================================================
import { ExceptionFilter, Catch, ArgumentsHost } from '@nestjs/common';
import { HttpException, InternalServerErrorException } from '@nestjs/common';

@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const { status, json } = this.prepareException(exception);

    response.status(status).send(json);
  }

  prepareException(exc: any): { status: number; json: object } {
    if (process.env.NODE_ENV !== 'test') {
      console.log(exc);
    }

    const error =
      exc instanceof HttpException ? exc : new InternalServerErrorException(exc.message);
    const status = error.getStatus();
    const response = error.getResponse();
    const json = typeof response === 'string' ? { error: response } : response;

    return { status, json };
  }
}


================================================
FILE: jest.config.js
================================================
/* eslint-disable @typescript-eslint/no-var-requires */

const tsconfig = require('tsconfig-extends');
const { pathsToModuleNameMapper } = require('ts-jest/utils');
const compilerOptions = tsconfig.load_file_sync('./tsconfig.jest.json', __dirname);

module.exports = {
  testEnvironment: 'node',
  setupFilesAfterEnv: ['jest-extended/all'],
  moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, {
    prefix: '<rootDir>/packages/',
  }),
  moduleFileExtensions: ['ts', 'js'],
  testRegex: '\\.spec.ts$',
  rootDir: '.',
  transform: {
    '^.+\\.ts$': 'ts-jest',
  },
  globals: {
    'ts-jest': {
      tsconfig: 'tsconfig.jest.json',
    },
  },
  coverageReporters: ['json', 'lcov', 'text-summary'],
  coverageDirectory: 'coverage',
  collectCoverageFrom: [
    'packages/**/*.ts',
    '!packages/**/*.d.ts',
    '!packages/**/index.ts',
    '!packages/**/*.interface.ts',
    '!**/node_modules/**',
    '!**/__stubs__/**',
    '!**/__fixture__/**',
    '!integration/*',
  ],
};


================================================
FILE: lerna.json
================================================
{
  "packages": [
    "packages/*"
  ],
  "npmClient": "yarn",
  "useWorkspaces": true,
  "version": "5.0.0-alpha.3",
  "command": {
    "publish": {
      "message": "chore: release"
    }
  }
}


================================================
FILE: mrepo.json
================================================
{
  "workspace": {
    "name": "packages",
    "scope": "nestjsx",
    "registry": "npm",
    "packages": [
      {
        "name": "util"
      },
      {
        "name": "crud-request"
      },
      {
        "name": "crud-typeorm"
      },
      {
        "name": "crud"
      }
    ]
  },
  "packageGenerator": {
    "subGenerators": [],
    "defaultOptions": {
      "access": "public",
      "license": "MIT",
      "authorName": "Michael Yali",
      "authorEmail": "mihon4ik@gmail.com",
      "updateTsconfig": true,
      "subGenerators": [],
      "dependencies": []
    }
  }
}


================================================
FILE: package.json
================================================
{
  "name": "@nestjsx/crud",
  "version": "4.0.0",
  "description": "Nest CRUD for RESTful APIs",
  "license": "MIT",
  "workspaces": [
    "packages/*"
  ],
  "private": true,
  "scripts": {
    "boot": "npx lerna bootstrap",
    "rebuild": "yarn clean && yarn build",
    "build": "npx mrepo build",
    "clean": "npx mrepo clean && npx rimraf ./.mrepo",
    "test": "npx mrepo test",
    "test:coverage": "yarn test:all --coverage",
    "test:coveralls": "yarn test:coverage --coverageReporters=text-lcov | coveralls",
    "test:all": "yarn test:mysql && yarn test:postgres",
    "test:postgres": "yarn db:prepare:typeorm:postgres && yarn test",
    "test:mysql": "yarn db:prepare:typeorm:mysql && TYPEORM_CONNECTION=mysql yarn test",
    "start:typeorm": "npx nodemon -w ./integration/crud-typeorm -e ts node_modules/ts-node/dist/bin.js integration/crud-typeorm/main.ts",
    "db:cli:typeorm": "cd ./integration/crud-typeorm && npx ts-node -r tsconfig-paths/register ../../node_modules/typeorm/cli.js",
    "db:sync:typeorm": "yarn db:cli:typeorm schema:sync",
    "db:drop:typeorm": "yarn db:cli:typeorm schema:drop",
    "db:seeds:typeorm": "yarn db:cli:typeorm migration:run",
    "db:prepare:typeorm:postgres": "yarn db:drop:typeorm -d=orm.postgres.ts && yarn db:sync:typeorm -d=orm.postgres.ts && yarn db:seeds:typeorm -d=orm.postgres.ts",
    "db:prepare:typeorm:mysql": "yarn db:drop:typeorm -d=orm.mysql.ts && yarn db:sync:typeorm -d=orm.mysql.ts && yarn db:seeds:typeorm -d=orm.mysql.ts",
    "format": "npx pretty-quick --pattern \"packages/**/!(*.d).ts\"",
    "lint": "npx eslint \"packages/**/!(*.d).ts\" --fix",
    "commit": "npx git-cz",
    "postinstall": "npx opencollective",
    "prepare": "npx husky install",
    "release": "mrepo release",
    "release:alpha": "yarn release prerelease --preid alpha --dist-tag alpha",
    "release:beta": "yarn release prerelease --preid beta --dist-tag beta"
  },
  "config": {
    "commitizen": {
      "path": "node_modules/cz-conventional-changelog"
    }
  },
  "collective": {
    "type": "opencollective",
    "url": "https://opencollective.com/nestjsx",
    "donation": {
      "text": "Become a partner:"
    }
  },
  "dependencies": {
    "@nestjs/common": "^9.0.0",
    "@nestjs/core": "^9.0.0",
    "@nestjs/platform-express": "^9.0.0",
    "@nestjs/swagger": "5.2.1",
    "@nestjs/testing": "^9.0.0",
    "@nestjs/typeorm": "^9.0.0",
    "@zmotivat0r/mrepo": "0.8.1",
    "class-transformer": "0.3.2",
    "class-validator": "0.13.2",
    "mysql": "2.18.1",
    "pg": "8.7.3",
    "pluralize": "8.0.0",
    "qs": "6.10.3",
    "redis": "4.0.4",
    "reflect-metadata": "0.1.13",
    "rxjs": "7.5.5",
    "swagger-ui-express": "4.3.0",
    "typeorm": "^0.3.0"
  },
  "devDependencies": {
    "@nuxtjs/opencollective": "0.2.2",
    "@types/jest": "27.4.1",
    "@types/node": "17.0.23",
    "@types/qs": "6.9.7",
    "@types/supertest": "2.0.12",
    "@typescript-eslint/eslint-plugin": "4.19.0",
    "@typescript-eslint/parser": "4.19.0",
    "commitizen": "4.2.3",
    "conventional-changelog-cli": "2.1.1",
    "coveralls": "3.1.1",
    "eslint": "7.22.0",
    "eslint-config-airbnb-base": "14.2.1",
    "eslint-config-prettier": "8.1.0",
    "eslint-plugin-import": "2.22.1",
    "husky": "7.0.4",
    "jest": "27.5.1",
    "jest-extended": "2.0.0",
    "lerna": "4.0.0",
    "nodemon": "2.0.15",
    "prettier": "2.6.1",
    "pretty-quick": "3.1.3",
    "rimraf": "3.0.2",
    "supertest": "6.2.2",
    "ts-jest": "27.1.4",
    "ts-node": "10.7.0",
    "tsconfig-extends": "1.0.1",
    "tsconfig-paths": "3.14.1",
    "typescript": "4.6.3"
  },
  "author": {
    "name": "Michael Yali",
    "email": "mihon4ik@gmail.com"
  }
}


================================================
FILE: packages/crud/README.md
================================================
<div align="center">
  <h1>CRUD (@nestjsx/crud)</h1>
</div>
<div align="center">
  <strong>for RESTful APIs built with NestJs</strong>
</div>

<br />

<div align="center">
  <a href="https://travis-ci.org/nestjsx/crud">
    <img src="https://github.com/nestjsx/crud/workflows/Tests/badge.svg" alt="Build" />
  </a>
  <a href="https://coveralls.io/github/nestjsx/crud?branch=master">
    <img src="https://coveralls.io/repos/github/nestjsx/crud/badge.svg" alt="Coverage" />
  </a>
  <a href="https://github.com/nestjsx/crud/blob/master/LICENSE">
    <img src="https://img.shields.io/github/license/nestjsx/crud.svg" alt="License" />
  </a>
  <a href="https://www.npmjs.com/package/@nestjsx/crud">
    <img src="https://img.shields.io/npm/v/@nestjsx/crud.svg" alt="npm version" />
  </a>
  <a href="https://www.npmjs.com/org/nestjsx">
    <img src="https://img.shields.io/npm/dm/@nestjsx/crud.svg" alt="npm downloads" />
  </a>
  <a href="https://npm.packagequality.com/#?package=@nestjsx%2Fcrud">
    <img src="https://npm.packagequality.com/shield/%40nestjsx%2Fcrud.svg" alt="Package Quality" />
  </a>
  <a href="https://renovatebot.com/">
    <img src="https://img.shields.io/badge/renovate-enabled-brightgreen.svg" alt="Renovate" />
  </a>
  <a href="http://makeapullrequest.com">
    <img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square" alt="PRs welcome" />
  </a>
  <a href="https://github.com/marmelab/awesome-rest#nodejs">
    <img src="https://raw.githubusercontent.com/nestjsx/crud/master/img/awesome-rest.svg?sanitize=true" alt="Awesome REST" />
  </a>
  <a href="https://github.com/juliandavidmr/awesome-nestjs#components--libraries">
    <img src="https://raw.githubusercontent.com/nestjsx/crud/master/img/awesome-nest.svg?sanitize=true" alt="Awesome Nest" />
  </a>
  <a href="https://github.com/nestjs/nest">
    <img src="https://raw.githubusercontent.com/nestjsx/crud/master/img/nest-powered.svg?sanitize=true" alt="Nest Powered" />
  </a>
  <a href="#individuals" alt="Sponsors on Open Collective">
    <img src="https://opencollective.com/nestjsx/backers/badge.svg" />
  </a>
  <a href="#organizations" alt="Sponsors on Open Collective">
    <img src="https://opencollective.com/nestjsx/sponsors/badge.svg" />
  </a> 
</div>

<div align="center">
  <sub>Built by
  <a href="https://twitter.com/MichaelYali">@MichaelYali</a> and
  <a href="https://github.com/nestjsx/crud/graphs/contributors">
    Contributors
  </a>
</div>

<br />

We believe that everyone who's working with NestJs and building some RESTful services and especially some CRUD functionality will find `@nestjsx/crud` microframework very useful.

## Features

<img align="right" src="https://raw.githubusercontent.com/nestjsx/crud/master/img/crud-usage2.png" alt="CRUD usage" />

- Super easy to install and start using the full-featured controllers and services :point_right:

- DB and service agnostic extendable CRUD controllers

- Reach query parsing with filtering, pagination, sorting, relations, nested relations, cache, etc.

- Framework agnostic package with query builder for a frontend usage

- Query, path params and DTOs validation included

- Overriding controller methods with ease

- Tiny config (including globally)

- Additional helper decorators

- Swagger documentation

## Install

```shell
npm i @nestjsx/crud class-transformer class-validator
```

## Packages

- [**@nestjsx/crud**](https://www.npmjs.com/package/@nestjsx/crud) - core package which provides `@Crud()` decorator for endpoints generation, global configuration, validation, helper decorators ([docs](https://github.com/nestjsx/crud/wiki/Controllers#description))
- [**@nestjsx/crud-request**](https://www.npmjs.com/package/@nestjsx/crud-request) - request builder/parser package which provides `RequestQueryBuilder` class for a frontend usage and `RequestQueryParser` that is being used internally for handling and validating query/path params on a backend side ([docs](https://github.com/nestjsx/crud/wiki/Requests#frontend-usage))
- [**@nestjsx/crud-typeorm**](https://www.npmjs.com/package/@nestjsx/crud-typeorm) - TypeORM package which provides base `TypeOrmCrudService` with methods for CRUD database operations ([docs](https://github.com/nestjsx/crud/wiki/ServiceTypeorm))

## Documentation

- [General Information](https://github.com/nestjsx/crud/wiki#why)
- [CRUD Controllers](https://github.com/nestjsx/crud/wiki/Controllers#description)
- [CRUD ORM Services](https://github.com/nestjsx/crud/wiki/Services#description)
- [Handling Requests](https://github.com/nestjsx/crud/wiki/Requests#description)

## Support

Any support is welcome. At least you can give us a star.

## Contributors

### Code Contributors

This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
<a href="https://github.com/nestjsx/crud/graphs/contributors"><img src="https://opencollective.com/nestjsx/contributors.svg?width=890&button=false" /></a>

### Financial Contributors

Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/nestjsx#backer)]

#### Individuals

<a href="https://opencollective.com/nestjsx#backers" target="_blank"><img src="https://opencollective.com/nestjsx/backers.svg?width=890&button=false"></a>

#### Organizations

Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/nestjsx#sponsor)]

<a href="https://opencollective.com/nestjsx/sponsor/0/website" target="_blank"><img src="https://opencollective.com/nestjsx/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/nestjsx/sponsor/1/website" target="_blank"><img src="https://opencollective.com/nestjsx/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/nestjsx/sponsor/2/website" target="_blank"><img src="https://opencollective.com/nestjsx/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/nestjsx/sponsor/3/website" target="_blank"><img src="https://opencollective.com/nestjsx/sponsor/3/avatar.svg"></a>
<a href="https://opencollective.com/nestjsx/sponsor/4/website" target="_blank"><img src="https://opencollective.com/nestjsx/sponsor/4/avatar.svg"></a>
<a href="https://opencollective.com/nestjsx/sponsor/5/website" target="_blank"><img src="https://opencollective.com/nestjsx/sponsor/5/avatar.svg"></a>
<a href="https://opencollective.com/nestjsx/sponsor/6/website" target="_blank"><img src="https://opencollective.com/nestjsx/sponsor/6/avatar.svg"></a>
<a href="https://opencollective.com/nestjsx/sponsor/7/website" target="_blank"><img src="https://opencollective.com/nestjsx/sponsor/7/avatar.svg"></a>
<a href="https://opencollective.com/nestjsx/sponsor/8/website" target="_blank"><img src="https://opencollective.com/nestjsx/sponsor/8/avatar.svg"></a>
<a href="https://opencollective.com/nestjsx/sponsor/9/website" target="_blank"><img src="https://opencollective.com/nestjsx/sponsor/9/avatar.svg"></a>

## License

[MIT](LICENSE)


================================================
FILE: packages/crud/package.json
================================================
{
  "name": "@nestjsx/crud",
  "description": "NestJs CRUD for RESTful APIs",
  "version": "5.0.0-alpha.3",
  "license": "MIT",
  "main": "lib/index.js",
  "typings": "lib/index.d.ts",
  "publishConfig": {
    "access": "public"
  },
  "files": [
    "lib"
  ],
  "repository": {
    "type": "git",
    "url": "https://github.com/nestjsx/crud.git"
  },
  "bugs": {
    "url": "https://github.com/nestjsx/crud/issues"
  },
  "keywords": [
    "typescript",
    "typeorm",
    "nest",
    "nestjs",
    "rest",
    "restful",
    "api",
    "crud",
    "crud-generator",
    "backend",
    "frameworks"
  ],
  "author": {
    "name": "Michael Yali",
    "email": "mihon4ik@gmail.com"
  },
  "scripts": {
    "build": "npx tsc -b"
  },
  "dependencies": {
    "@nestjsx/crud-request": "^5.0.0-alpha.3",
    "@nestjsx/util": "^5.0.0-alpha.3",
    "deepmerge": "^3.2.0",
    "pluralize": "^8.0.0"
  },
  "peerDependencies": {
    "class-transformer": "*",
    "class-validator": "*"
  }
}


================================================
FILE: packages/crud/src/constants.ts
================================================
export const FEAUTURE_NAME_METADATA = 'NESTJSX_FEAUTURE_NAME_METADATA';
export const ACTION_NAME_METADATA = 'NESTJSX_ACTION_NAME_METADATA';
export const OVERRIDE_METHOD_METADATA = 'NESTJSX_OVERRIDE_METHOD_METADATA';
export const PARSED_BODY_METADATA = 'NESTJSX_PARSED_BODY_METADATA';
export const PARSED_CRUD_REQUEST_KEY = 'NESTJSX_PARSED_CRUD_REQUEST_KEY';
export const CRUD_OPTIONS_METADATA = 'NESTJSX_CRUD_OPTIONS_METADATA';
export const CRUD_AUTH_OPTIONS_METADATA = 'NESTJSX_CRUD_AUTH_OPTIONS_METADATA';


================================================
FILE: packages/crud/src/crud/crud-routes.factory.ts
================================================
import { RequestMethod } from '@nestjs/common';
import { RouteParamtypes } from '@nestjs/common/enums/route-paramtypes.enum';
import {
  isFalse,
  isArrayFull,
  isObjectFull,
  isFunction,
  objKeys,
  isIn,
  isEqual,
  getOwnPropNames,
  isNil,
  isUndefined,
} from '@nestjsx/util';
import * as deepmerge from 'deepmerge';

import { R } from './reflection.helper';
import { SerializeHelper } from './serialize.helper';
import { Swagger } from './swagger.helper';
import { Validation } from './validation.helper';
import { CrudRequestInterceptor, CrudResponseInterceptor } from '../interceptors';
import { BaseRoute, CrudOptions, CrudRequest, MergedCrudOptions } from '../interfaces';
import { BaseRouteName } from '../types';
import { CrudActions, CrudValidationGroups } from '../enums';
import { CrudConfigService } from '../module';

export class CrudRoutesFactory {
  protected options: MergedCrudOptions;

  protected swaggerModels: any = {};

  constructor(protected target: any, options: CrudOptions) {
    this.options = options;
    this.create();
  }

  /* istanbul ignore next */
  static create(target: any, options: CrudOptions): CrudRoutesFactory {
    return new CrudRoutesFactory(target, options);
  }

  protected get targetProto(): any {
    return this.target.prototype;
  }

  protected get modelName(): string {
    return this.options.model.type.name;
  }

  protected get modelType(): any {
    return this.options.model.type;
  }

  protected get actionsMap(): { [key in BaseRouteName]: CrudActions } {
    return {
      getManyBase: CrudActions.ReadAll,
      getOneBase: CrudActions.ReadOne,
      createManyBase: CrudActions.CreateMany,
      createOneBase: CrudActions.CreateOne,
      updateOneBase: CrudActions.UpdateOne,
      deleteOneBase: CrudActions.DeleteOne,
      replaceOneBase: CrudActions.ReplaceOne,
      recoverOneBase: CrudActions.RecoverOne,
    };
  }

  protected create() {
    const routesSchema = this.getRoutesSchema();
    this.mergeOptions();
    this.setResponseModels();
    this.createRoutes(routesSchema);
    this.overrideRoutes(routesSchema);
    this.enableRoutes(routesSchema);
  }

  protected mergeOptions() {
    // merge auth config
    const authOptions = R.getCrudAuthOptions(this.target);
    this.options.auth = isObjectFull(authOptions) ? authOptions : {};
    if (isUndefined(this.options.auth.property)) {
      this.options.auth.property = CrudConfigService.config.auth.property;
    }
    if (isUndefined(this.options.auth.groups)) {
      this.options.auth.groups = CrudConfigService.config.auth.groups;
    }
    if (isUndefined(this.options.auth.classTransformOptions)) {
      this.options.auth.classTransformOptions = CrudConfigService.config.auth.classTransformOptions;
    }

    // merge query config
    const query = isObjectFull(this.options.query) ? this.options.query : {};
    this.options.query = { ...CrudConfigService.config.query, ...query };

    // merge routes config
    const routes = isObjectFull(this.options.routes) ? this.options.routes : {};
    this.options.routes = deepmerge(CrudConfigService.config.routes, routes, {
      arrayMerge: (a, b, c) => b,
    });

    // set params
    this.options.params = isObjectFull(this.options.params)
      ? this.options.params
      : isObjectFull(CrudConfigService.config.params)
      ? CrudConfigService.config.params
      : {};
    const hasPrimary = this.getPrimaryParams().length > 0;
    if (!hasPrimary) {
      this.options.params['id'] = {
        field: 'id',
        type: 'number',
        primary: true,
      };
    }

    // set dto
    if (!isObjectFull(this.options.dto)) {
      this.options.dto = {};
    }

    // set serialize
    const serialize = isObjectFull(this.options.serialize) ? this.options.serialize : {};
    this.options.serialize = { ...CrudConfigService.config.serialize, ...serialize };
    this.options.serialize.get = isFalse(this.options.serialize.get)
      ? false
      : this.options.serialize.get || this.modelType;
    this.options.serialize.getMany = isFalse(this.options.serialize.getMany)
      ? false
      : this.options.serialize.getMany
      ? this.options.serialize.getMany
      : isFalse(this.options.serialize.get)
      ? /* istanbul ignore next */ false
      : SerializeHelper.createGetManyDto(this.options.serialize.get, this.modelName);
    this.options.serialize.create = isFalse(this.options.serialize.create)
      ? false
      : this.options.serialize.create || this.modelType;
    this.options.serialize.update = isFalse(this.options.serialize.update)
      ? false
      : this.options.serialize.update || this.modelType;
    this.options.serialize.replace = isFalse(this.options.serialize.replace)
      ? false
      : this.options.serialize.replace || this.modelType;
    this.options.serialize.delete =
      isFalse(this.options.serialize.delete) || !this.options.routes.deleteOneBase.returnDeleted
        ? false
        : this.options.serialize.delete || this.modelType;

    R.setCrudOptions(this.options, this.target);
  }

  protected getRoutesSchema(): BaseRoute[] {
    return [
      {
        name: 'getOneBase',
        path: '/',
        method: RequestMethod.GET,
        enable: false,
        override: false,
        withParams: true,
      },
      {
        name: 'getManyBase',
        path: '/',
        method: RequestMethod.GET,
        enable: false,
        override: false,
        withParams: false,
      },
      {
        name: 'createOneBase',
        path: '/',
        method: RequestMethod.POST,
        enable: false,
        override: false,
        withParams: false,
      },
      {
        name: 'createManyBase',
        path: '/bulk',
        method: RequestMethod.POST,
        enable: false,
        override: false,
        withParams: false,
      },
      {
        name: 'updateOneBase',
        path: '/',
        method: RequestMethod.PATCH,
        enable: false,
        override: false,
        withParams: true,
      },
      {
        name: 'replaceOneBase',
        path: '/',
        method: RequestMethod.PUT,
        enable: false,
        override: false,
        withParams: true,
      },
      {
        name: 'deleteOneBase',
        path: '/',
        method: RequestMethod.DELETE,
        enable: false,
        override: false,
        withParams: true,
      },
      {
        name: 'recoverOneBase',
        path: '/recover',
        method: RequestMethod.PATCH,
        enable: false,
        override: false,
        withParams: true,
      },
    ];
  }

  protected getManyBase(name: BaseRouteName) {
    this.targetProto[name] = function getManyBase(req: CrudRequest) {
      return this.service.getMany(req);
    };
  }

  protected getOneBase(name: BaseRouteName) {
    this.targetProto[name] = function getOneBase(req: CrudRequest) {
      return this.service.getOne(req);
    };
  }

  protected createOneBase(name: BaseRouteName) {
    this.targetProto[name] = function createOneBase(req: CrudRequest, dto: any) {
      return this.service.createOne(req, dto);
    };
  }

  protected createManyBase(name: BaseRouteName) {
    this.targetProto[name] = function createManyBase(req: CrudRequest, dto: any) {
      return this.service.createMany(req, dto);
    };
  }

  protected updateOneBase(name: BaseRouteName) {
    this.targetProto[name] = function updateOneBase(req: CrudRequest, dto: any) {
      return this.service.updateOne(req, dto);
    };
  }

  protected replaceOneBase(name: BaseRouteName) {
    this.targetProto[name] = function replaceOneBase(req: CrudRequest, dto: any) {
      return this.service.replaceOne(req, dto);
    };
  }

  protected deleteOneBase(name: BaseRouteName) {
    this.targetProto[name] = function deleteOneBase(req: CrudRequest) {
      return this.service.deleteOne(req);
    };
  }

  protected recoverOneBase(name: BaseRouteName) {
    this.targetProto[name] = function recoverOneBase(req: CrudRequest) {
      return this.service.recoverOne(req);
    };
  }

  protected canCreateRoute(name: BaseRouteName) {
    const only = this.options.routes.only;
    const exclude = this.options.routes.exclude;

    // include recover route only for models with soft delete option
    if (name === 'recoverOneBase' && this.options.query.softDelete !== true) {
      return false;
    }

    if (isArrayFull(only)) {
      return only.some((route) => route === name);
    }

    if (isArrayFull(exclude)) {
      return !exclude.some((route) => route === name);
    }

    return true;
  }

  protected setResponseModels() {
    const modelType = isFunction(this.modelType)
      ? this.modelType
      : SerializeHelper.createGetOneResponseDto(this.modelName);
    this.swaggerModels.get = isFunction(this.options.serialize.get) ? this.options.serialize.get : modelType;
    this.swaggerModels.getMany =
      this.options.serialize.getMany || SerializeHelper.createGetManyDto(this.swaggerModels.get, this.modelName);
    this.swaggerModels.create = isFunction(this.options.serialize.create) ? this.options.serialize.create : modelType;
    this.swaggerModels.update = isFunction(this.options.serialize.update) ? this.options.serialize.update : modelType;
    this.swaggerModels.replace = isFunction(this.options.serialize.replace)
      ? this.options.serialize.replace
      : modelType;
    this.swaggerModels.delete = isFunction(this.options.serialize.delete) ? this.options.serialize.delete : modelType;
    this.swaggerModels.recover = isFunction(this.options.serialize.recover)
      ? this.options.serialize.recover
      : modelType;
    Swagger.setExtraModels(this.swaggerModels);
  }

  protected createRoutes(routesSchema: BaseRoute[]) {
    const primaryParams = this.getPrimaryParams().filter((param) => !this.options.params[param].disabled);

    routesSchema.forEach((route) => {
      if (this.canCreateRoute(route.name)) {
        // create base method
        this[route.name](route.name);
        route.enable = true;
        // set metadata
        this.setBaseRouteMeta(route.name);
      }

      if (route.withParams && primaryParams.length > 0) {
        route.path =
          route.path !== '/'
            ? `${primaryParams.map((param) => `/:${param}`).join('')}${route.path}`
            : primaryParams.map((param) => `/:${param}`).join('');
      }
    });
  }

  protected overrideRoutes(routesSchema: BaseRoute[]) {
    getOwnPropNames(this.targetProto).forEach((name) => {
      const override = R.getOverrideRoute(this.targetProto[name]);
      const route = routesSchema.find((r) => isEqual(r.name, override));

      if (override && route && route.enable) {
        // get metadata
        const interceptors = R.getInterceptors(this.targetProto[name]);
        const baseInterceptors = R.getInterceptors(this.targetProto[override]);
        const baseAction = R.getAction(this.targetProto[override]);
        const operation = Swagger.getOperation(this.targetProto[name]);
        const baseOperation = Swagger.getOperation(this.targetProto[override]);
        const swaggerParams = Swagger.getParams(this.targetProto[name]);
        const baseSwaggerParams = Swagger.getParams(this.targetProto[override]);
        const responseOk = Swagger.getResponseOk(this.targetProto[name]);
        const baseResponseOk = Swagger.getResponseOk(this.targetProto[override]);
        // set metadata
        R.setInterceptors([...baseInterceptors, ...interceptors], this.targetProto[name]);
        R.setAction(baseAction, this.targetProto[name]);
        Swagger.setOperation({ ...baseOperation, ...operation }, this.targetProto[name]);
        Swagger.setParams([...baseSwaggerParams, ...swaggerParams], this.targetProto[name]);
        Swagger.setResponseOk({ ...baseResponseOk, ...responseOk }, this.targetProto[name]);
        this.overrideParsedBodyDecorator(override, name);
        // enable route
        R.setRoute(route, this.targetProto[name]);
        route.override = true;
      }
    });
  }

  protected enableRoutes(routesSchema: BaseRoute[]) {
    routesSchema.forEach((route) => {
      if (!route.override && route.enable) {
        R.setRoute(route, this.targetProto[route.name]);
      }
    });
  }

  protected overrideParsedBodyDecorator(override: BaseRouteName, name: string) {
    const allowed = ['createManyBase', 'createOneBase', 'updateOneBase', 'replaceOneBase'] as BaseRouteName[];
    const withBody = isIn(override, allowed);
    const parsedBody = R.getParsedBody(this.targetProto[name]);

    if (withBody && parsedBody) {
      const baseKey = `${RouteParamtypes.BODY}:1`;
      const key = `${RouteParamtypes.BODY}:${parsedBody.index}`;
      const baseRouteArgs = R.getRouteArgs(this.target, override);
      const routeArgs = R.getRouteArgs(this.target, name);
      const baseBodyArg = baseRouteArgs[baseKey];
      R.setRouteArgs(
        {
          ...routeArgs,
          [key]: {
            ...baseBodyArg,
            index: parsedBody.index,
          },
        },
        this.target,
        name,
      );

      /* istanbul ignore else */
      if (isEqual(override, 'createManyBase')) {
        const paramTypes = R.getRouteArgsTypes(this.targetProto, name);
        const metatype = paramTypes[parsedBody.index];
        const types = [String, Boolean, Number, Array, Object];
        const toCopy = isIn(metatype, types) || /* istanbul ignore next */ isNil(metatype);

        /* istanbul ignore else */
        if (toCopy) {
          const baseParamTypes = R.getRouteArgsTypes(this.targetProto, override);
          const baseMetatype = baseParamTypes[1];
          paramTypes.splice(parsedBody.index, 1, baseMetatype);
          R.setRouteArgsTypes(paramTypes, this.targetProto, name);
        }
      }
    }
  }

  protected getPrimaryParams(): string[] {
    return objKeys(this.options.params).filter(
      (param) => this.options.params[param] && this.options.params[param].primary,
    );
  }

  protected setBaseRouteMeta(name: BaseRouteName) {
    this.setRouteArgs(name);
    this.setRouteArgsTypes(name);
    this.setInterceptors(name);
    this.setAction(name);
    this.setSwaggerOperation(name);
    this.setSwaggerPathParams(name);
    this.setSwaggerQueryParams(name);
    this.setSwaggerResponseOk(name);
    // set decorators after Swagger so metadata can be overwritten
    this.setDecorators(name);
  }

  protected setRouteArgs(name: BaseRouteName) {
    let rest = {};
    const routes: BaseRouteName[] = ['createManyBase', 'createOneBase', 'updateOneBase', 'replaceOneBase'];

    if (isIn(name, routes)) {
      const action = this.routeNameAction(name);
      const hasDto = !isNil(this.options.dto[action]);
      const { UPDATE, CREATE } = CrudValidationGroups;
      const groupEnum = isIn(name, ['updateOneBase', 'replaceOneBase']) ? UPDATE : CREATE;
      const group = !hasDto ? groupEnum : undefined;

      rest = R.setBodyArg(1, [Validation.getValidationPipe(this.options, group)]);
    }

    R.setRouteArgs({ ...R.setParsedRequestArg(0), ...rest }, this.target, name);
  }

  protected setRouteArgsTypes(name: BaseRouteName) {
    if (isEqual(name, 'createManyBase')) {
      const bulkDto = Validation.createBulkDto(this.options);
      R.setRouteArgsTypes([Object, bulkDto], this.targetProto, name);
    } else if (isIn(name, ['createOneBase', 'updateOneBase', 'replaceOneBase'])) {
      const action = this.routeNameAction(name);
      const dto = this.options.dto[action] || this.modelType;
      R.setRouteArgsTypes([Object, dto], this.targetProto, name);
    } else {
      R.setRouteArgsTypes([Object], this.targetProto, name);
    }
  }

  protected setInterceptors(name: BaseRouteName) {
    const interceptors = this.options.routes[name].interceptors;
    R.setInterceptors(
      [
        CrudRequestInterceptor,
        CrudResponseInterceptor,
        ...(isArrayFull(interceptors) ? /* istanbul ignore next */ interceptors : []),
      ],
      this.targetProto[name],
    );
  }

  protected setDecorators(name: BaseRouteName) {
    const decorators = this.options.routes[name].decorators;
    R.setDecorators(isArrayFull(decorators) ? /* istanbul ignore next */ decorators : [], this.targetProto, name);
  }

  protected setAction(name: BaseRouteName) {
    R.setAction(this.actionsMap[name], this.targetProto[name]);
  }

  protected setSwaggerOperation(name: BaseRouteName) {
    const summary = Swagger.operationsMap(this.modelName)[name];
    const operationId = name + this.targetProto.constructor.name + this.modelName;
    Swagger.setOperation({ summary, operationId }, this.targetProto[name]);
  }

  protected setSwaggerPathParams(name: BaseRouteName) {
    const metadata = Swagger.getParams(this.targetProto[name]);
    const withoutPrimary: BaseRouteName[] = ['createManyBase', 'createOneBase', 'getManyBase'];

    const removePrimary = isIn(name, withoutPrimary);
    const params = objKeys(this.options.params)
      .filter((key) => !this.options.params[key].disabled)
      .filter((key) => !(removePrimary && this.options.params[key].primary))
      .reduce((a, c) => ({ ...a, [c]: this.options.params[c] }), {});

    const pathParamsMeta = Swagger.createPathParamsMeta(params);
    Swagger.setParams([...metadata, ...pathParamsMeta], this.targetProto[name]);
  }

  protected setSwaggerQueryParams(name: BaseRouteName) {
    const metadata = Swagger.getParams(this.targetProto[name]);
    const queryParamsMeta = Swagger.createQueryParamsMeta(name, this.options);
    Swagger.setParams([...metadata, ...queryParamsMeta], this.targetProto[name]);
  }

  protected setSwaggerResponseOk(name: BaseRouteName) {
    const metadata = Swagger.getResponseOk(this.targetProto[name]);
    const metadataToAdd =
      Swagger.createResponseMeta(name, this.options, this.swaggerModels) || /* istanbul ignore next */ {};
    Swagger.setResponseOk({ ...metadata, ...metadataToAdd }, this.targetProto[name]);
  }

  protected routeNameAction(name: BaseRouteName): string {
    return name.split('OneBase')[0] || /* istanbul ignore next */ name.split('ManyBase')[0];
  }
}


================================================
FILE: packages/crud/src/crud/index.ts
================================================
export * from './crud-routes.factory';
export * from './reflection.helper';
export * from './swagger.helper';
export * from './validation.helper';


================================================
FILE: packages/crud/src/crud/reflection.helper.ts
================================================
import { RouteParamtypes } from '@nestjs/common/enums/route-paramtypes.enum';
import {
  CUSTOM_ROUTE_AGRS_METADATA,
  INTERCEPTORS_METADATA,
  METHOD_METADATA,
  PARAMTYPES_METADATA,
  PATH_METADATA,
  ROUTE_ARGS_METADATA,
} from '@nestjs/common/constants';
import { ArgumentsHost } from '@nestjs/common';
import { isFunction } from '@nestjsx/util';

import { BaseRoute, MergedCrudOptions, AuthOptions } from '../interfaces';
import { BaseRouteName } from '../types';
import {
  CRUD_OPTIONS_METADATA,
  ACTION_NAME_METADATA,
  PARSED_CRUD_REQUEST_KEY,
  PARSED_BODY_METADATA,
  OVERRIDE_METHOD_METADATA,
  CRUD_AUTH_OPTIONS_METADATA,
} from '../constants';
import { CrudActions } from '../enums';

export class R {
  static set(metadataKey: any, metadataValue: any, target: unknown, propertyKey: string | symbol = undefined) {
    if (propertyKey) {
      Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey);
    } else {
      Reflect.defineMetadata(metadataKey, metadataValue, target);
    }
  }

  static get<T extends any>(metadataKey: any, target: unknown, propertyKey: string | symbol = undefined): T {
    return propertyKey
      ? Reflect.getMetadata(metadataKey, target, propertyKey)
      : Reflect.getMetadata(metadataKey, target);
  }

  static createCustomRouteArg(
    paramtype: string,
    index: number,
    /* istanbul ignore next */
    pipes: any[] = [],
    data = undefined,
  ): any {
    return {
      [`${paramtype}${CUSTOM_ROUTE_AGRS_METADATA}:${index}`]: {
        index,
        factory: (_, ctx) => R.getContextRequest(ctx)[paramtype],
        data,
        pipes,
      },
    };
  }

  static createRouteArg(
    paramtype: RouteParamtypes,
    index: number,
    /* istanbul ignore next */
    pipes: any[] = [],
    data = undefined,
  ): any {
    return {
      [`${paramtype}:${index}`]: {
        index,
        pipes,
        data,
      },
    };
  }

  static setDecorators(decorators: (PropertyDecorator | MethodDecorator)[], target: any, name: string) {
    // this makes metadata decorator works
    const decoratedDescriptor = Reflect.decorate(
      decorators,
      target,
      name,
      Reflect.getOwnPropertyDescriptor(target, name),
    );

    // this makes proxy decorator works
    Reflect.defineProperty(target, name, decoratedDescriptor);
  }

  static setParsedRequestArg(index: number) {
    return R.createCustomRouteArg(PARSED_CRUD_REQUEST_KEY, index);
  }

  static setBodyArg(index: number, /* istanbul ignore next */ pipes: any[] = []) {
    return R.createRouteArg(RouteParamtypes.BODY, index, pipes);
  }

  static setCrudOptions(options: MergedCrudOptions, target: any) {
    R.set(CRUD_OPTIONS_METADATA, options, target);
  }

  static setRoute(route: BaseRoute, func: unknown) {
    R.set(PATH_METADATA, route.path, func);
    R.set(METHOD_METADATA, route.method, func);
  }

  static setInterceptors(interceptors: any[], func: unknown) {
    R.set(INTERCEPTORS_METADATA, interceptors, func);
  }

  static setRouteArgs(metadata: any, target: any, name: string) {
    R.set(ROUTE_ARGS_METADATA, metadata, target, name);
  }

  static setRouteArgsTypes(metadata: any, target: any, name: string) {
    R.set(PARAMTYPES_METADATA, metadata, target, name);
  }

  static setAction(action: CrudActions, func: unknown) {
    R.set(ACTION_NAME_METADATA, action, func);
  }

  static setCrudAuthOptions(metadata: any, target: any) {
    R.set(CRUD_AUTH_OPTIONS_METADATA, metadata, target);
  }

  static getCrudAuthOptions(target: any): AuthOptions {
    return R.get(CRUD_AUTH_OPTIONS_METADATA, target);
  }

  static getCrudOptions(target: any): MergedCrudOptions {
    return R.get(CRUD_OPTIONS_METADATA, target);
  }

  static getAction(func: unknown): CrudActions {
    return R.get(ACTION_NAME_METADATA, func);
  }

  static getOverrideRoute(func: unknown): BaseRouteName {
    return R.get(OVERRIDE_METHOD_METADATA, func);
  }

  static getInterceptors(func: unknown): any[] {
    return R.get(INTERCEPTORS_METADATA, func) || [];
  }

  static getRouteArgs(target: any, name: string): any {
    return R.get(ROUTE_ARGS_METADATA, target, name);
  }

  static getRouteArgsTypes(target: any, name: string): any[] {
    return R.get(PARAMTYPES_METADATA, target, name) || /* istanbul ignore next */ [];
  }

  static getParsedBody(func: unknown): any {
    return R.get(PARSED_BODY_METADATA, func);
  }

  static getContextRequest(ctx: ArgumentsHost): any {
    return isFunction(ctx.switchToHttp) ? ctx.switchToHttp().getRequest() : /* istanbul ignore next */ ctx;
  }
}


================================================
FILE: packages/crud/src/crud/serialize.helper.ts
================================================
import { Type } from 'class-transformer';
import { GetManyDefaultResponse } from '../interfaces';
import { ApiProperty } from './swagger.helper';

export class SerializeHelper {
  static createGetManyDto(dto: any, resourceName: string): any {
    class GetManyResponseDto implements GetManyDefaultResponse<any> {
      @ApiProperty({ type: dto, isArray: true })
      @Type(() => dto)
      data: any[];

      @ApiProperty({ type: 'number' })
      count: number;

      @ApiProperty({ type: 'number' })
      total: number;

      @ApiProperty({ type: 'number' })
      page: number;

      @ApiProperty({ type: 'number' })
      pageCount: number;
    }

    Object.defineProperty(GetManyResponseDto, 'name', {
      writable: false,
      value: `GetMany${resourceName}ResponseDto`,
    });

    return GetManyResponseDto;
  }

  static createGetOneResponseDto(resourceName: string): any {
    class GetOneResponseDto {}

    Object.defineProperty(GetOneResponseDto, 'name', {
      writable: false,
      value: `${resourceName}ResponseDto`,
    });

    return GetOneResponseDto;
  }
}


================================================
FILE: packages/crud/src/crud/swagger.helper.ts
================================================
import { HttpStatus } from '@nestjs/common';
import { RequestQueryBuilder } from '@nestjsx/crud-request';
import { isString, objKeys } from '@nestjsx/util';
import { MergedCrudOptions, ParamsOptions } from '../interfaces';
import { BaseRouteName } from '../types';
import { safeRequire } from '../util';
import { R } from './reflection.helper';
const pluralize = require('pluralize');

export const swagger = safeRequire('@nestjs/swagger', () => require('@nestjs/swagger'));
export const swaggerConst = safeRequire('@nestjs/swagger/dist/constants', () =>
  require('@nestjs/swagger/dist/constants'),
);
export const swaggerPkgJson = safeRequire('@nestjs/swagger/package.json', () =>
  require('@nestjs/swagger/package.json'),
);

export class Swagger {
  static operationsMap(modelName: string): { [key in BaseRouteName]: string } {
    return {
      getManyBase: `Retrieve multiple ${pluralize(modelName)}`,
      getOneBase: `Retrieve a single ${modelName}`,
      createManyBase: `Create multiple ${pluralize(modelName)}`,
      createOneBase: `Create a single ${modelName}`,
      updateOneBase: `Update a single ${modelName}`,
      replaceOneBase: `Replace a single ${modelName}`,
      deleteOneBase: `Delete a single ${modelName}`,
      recoverOneBase: `Recover one ${modelName}`,
    };
  }

  static setOperation(metadata: unknown, func: any): void {
    /* istanbul ignore else */
    if (swaggerConst) {
      R.set(swaggerConst.DECORATORS.API_OPERATION, metadata, func);
    }
  }

  static setParams(metadata: unknown, func: any): void {
    /* istanbul ignore else */
    if (swaggerConst) {
      R.set(swaggerConst.DECORATORS.API_PARAMETERS, metadata, func);
    }
  }

  static setExtraModels(swaggerModels: any): void {
    /* istanbul ignore else */
    if (swaggerConst) {
      const meta = Swagger.getExtraModels(swaggerModels.get);
      const models: any[] = [
        ...meta,
        ...objKeys(swaggerModels)
          .map((name) => swaggerModels[name])
          .filter((one) => one && one.name !== swaggerModels.get.name),
      ];
      R.set(swaggerConst.DECORATORS.API_EXTRA_MODELS, models, swaggerModels.get);
    }
  }

  static setResponseOk(metadata: unknown, func: any): void {
    /* istanbul ignore else */
    if (swaggerConst) {
      R.set(swaggerConst.DECORATORS.API_RESPONSE, metadata, func);
    }
  }

  static getOperation(func: any): any {
    /* istanbul ignore next */
    return swaggerConst ? R.get(swaggerConst.DECORATORS.API_OPERATION, func) || {} : {};
  }

  static getParams(func: any): any[] {
    /* istanbul ignore next */
    return swaggerConst ? R.get(swaggerConst.DECORATORS.API_PARAMETERS, func) || [] : [];
  }

  static getExtraModels(target: unknown): any[] {
    /* istanbul ignore next */
    return swaggerConst ? R.get(swaggerConst.API_EXTRA_MODELS, target) || [] : [];
  }

  static getResponseOk(func: any): any {
    /* istanbul ignore next */
    return swaggerConst ? R.get(swaggerConst.DECORATORS.API_RESPONSE, func) || {} : {};
  }

  static createResponseMeta(name: BaseRouteName, options: MergedCrudOptions, swaggerModels: any): any {
    /* istanbul ignore else */
    if (swagger) {
      const { routes, query } = options;
      const oldVersion = Swagger.getSwaggerVersion() < 4;

      switch (name) {
        case 'getOneBase':
          return {
            [HttpStatus.OK]: {
              description: 'Get one base response',
              type: swaggerModels.get,
            },
          };
        case 'getManyBase':
          /* istanbul ignore if */
          if (oldVersion) {
            return {
              [HttpStatus.OK]: {
                type: swaggerModels.getMany,
              },
            };
          }

          return {
            [HttpStatus.OK]: query.alwaysPaginate
              ? {
                  description: 'Get paginated response',
                  type: swaggerModels.getMany,
                }
              : {
                  description: 'Get many base response',
                  schema: {
                    oneOf: [
                      { $ref: swagger.getSchemaPath(swaggerModels.getMany.name) },
                      {
                        type: 'array',
                        items: { $ref: swagger.getSchemaPath(swaggerModels.get.name) },
                      },
                    ],
                  },
                },
          };
        case 'createOneBase':
          /* istanbul ignore if */
          if (oldVersion) {
            return {
              [HttpStatus.OK]: {
                type: swaggerModels.create,
              },
            };
          }

          return {
            [HttpStatus.CREATED]: {
              description: 'Get create one base response',
              schema: { $ref: swagger.getSchemaPath(swaggerModels.create.name) },
            },
          };
        case 'createManyBase':
          /* istanbul ignore if */
          if (oldVersion) {
            return {
              [HttpStatus.OK]: {
                type: swaggerModels.create,
                isArray: true,
              },
            };
          }

          return {
            [HttpStatus.CREATED]: swaggerModels.createMany
              ? /* istanbul ignore next */ {
                  description: 'Get create many base response',
                  schema: { $ref: swagger.getSchemaPath(swaggerModels.createMany.name) },
                }
              : {
                  description: 'Get create many base response',
                  schema: {
                    type: 'array',
                    items: { $ref: swagger.getSchemaPath(swaggerModels.create.name) },
                  },
                },
          };
        case 'deleteOneBase':
          /* istanbul ignore if */
          if (oldVersion) {
            return {
              [HttpStatus.OK]: routes.deleteOneBase.returnDeleted
                ? {
                    type: swaggerModels.delete,
                  }
                : {},
            };
          }
          return {
            [HttpStatus.OK]: routes.deleteOneBase.returnDeleted
              ? {
                  description: 'Delete one base response',
                  schema: { $ref: swagger.getSchemaPath(swaggerModels.delete.name) },
                }
              : {
                  description: 'Delete one base response',
                },
          };
        case 'recoverOneBase':
          /* istanbul ignore if */
          if (oldVersion) {
            return {
              [HttpStatus.OK]: routes.recoverOneBase.returnRecovered
                ? {
                    type: swaggerModels.delete,
                  }
                : {},
            };
          }
          return {
            [HttpStatus.OK]: routes.recoverOneBase.returnRecovered
              ? {
                  description: 'Recover one base response',
                  schema: { $ref: swagger.getSchemaPath(swaggerModels.recover.name) },
                }
              : {
                  description: 'Recover one base response',
                },
          };
        default:
          const dto = swaggerModels[name.split('OneBase')[0]];

          /* istanbul ignore if */
          if (oldVersion) {
            return {
              [HttpStatus.OK]: {
                type: dto,
              },
            };
          }

          return {
            [HttpStatus.OK]: {
              description: 'Response',
              schema: { $ref: swagger.getSchemaPath(dto.name) },
            },
          };
      }
    } else {
      return {};
    }
  }

  static createPathParamsMeta(options: ParamsOptions): any[] {
    return swaggerConst
      ? objKeys(options).map((param) => ({
          name: param,
          required: true,
          in: 'path',
          type: options[param].type === 'number' ? Number : String,
          enum: options[param].enum ? Object.values(options[param].enum) : undefined,
        }))
      : /* istanbul ignore next */ [];
  }

  static createQueryParamsMeta(name: BaseRouteName, options: MergedCrudOptions) {
    /* istanbul ignore if */
    if (!swaggerConst) {
      return [];
    }

    const {
      delim: d,
      delimStr: coma,
      fields,
      search,
      filter,
      or,
      join,
      sort,
      limit,
      offset,
      page,
      cache,
      includeDeleted,
    } = Swagger.getQueryParamsNames();
    const oldVersion = Swagger.getSwaggerVersion() < 4;
    const docsLink = (a: string) =>
      `<a href="https://github.com/nestjsx/crud/wiki/Requests#${a}" target="_blank">Docs</a>`;

    const fieldsMetaBase = {
      name: fields,
      description: `Selects resource fields. ${docsLink('select')}`,
      required: false,
      in: 'query',
    };
    const fieldsMeta = oldVersion
      ? /* istanbul ignore next */ {
          ...fieldsMetaBase,
          type: 'array',
          items: {
            type: 'string',
          },
          collectionFormat: 'csv',
        }
      : {
          ...fieldsMetaBase,
          schema: {
            type: 'array',
            items: {
              type: 'string',
            },
          },
          style: 'form',
          explode: false,
        };

    const searchMetaBase = {
      name: search,
      description: `Adds search condition. ${docsLink('search')}`,
      required: false,
      in: 'query',
    };
    const searchMeta = oldVersion
      ? /* istanbul ignore next */ { ...searchMetaBase, type: 'string' }
      : { ...searchMetaBase, schema: { type: 'string' } };

    const filterMetaBase = {
      name: filter,
      description: `Adds filter condition. ${docsLink('filter')}`,
      required: false,
      in: 'query',
    };
    const filterMeta = oldVersion
      ? /* istanbul ignore next */ {
          ...filterMetaBase,
          items: {
            type: 'string',
          },
          type: 'array',
          collectionFormat: 'multi',
        }
      : {
          ...filterMetaBase,
          schema: {
            type: 'array',
            items: {
              type: 'string',
            },
          },
          style: 'form',
          explode: true,
        };

    const orMetaBase = {
      name: or,
      description: `Adds OR condition. ${docsLink('or')}`,
      required: false,
      in: 'query',
    };
    const orMeta = oldVersion
      ? /* istanbul ignore next */ {
          ...orMetaBase,
          items: {
            type: 'string',
          },
          type: 'array',
          collectionFormat: 'multi',
        }
      : {
          ...orMetaBase,
          schema: {
            type: 'array',
            items: {
              type: 'string',
            },
          },
          style: 'form',
          explode: true,
        };

    const sortMetaBase = {
      name: sort,
      description: `Adds sort by field. ${docsLink('sort')}`,
      required: false,
      in: 'query',
    };
    const sortMeta = oldVersion
      ? /* istanbul ignore next */ {
          ...sortMetaBase,
          items: {
            type: 'string',
          },
          type: 'array',
          collectionFormat: 'multi',
        }
      : {
          ...sortMetaBase,
          schema: {
            type: 'array',
            items: {
              type: 'string',
            },
          },
          style: 'form',
          explode: true,
        };

    const joinMetaBase = {
      name: join,
      description: `Adds relational resources. ${docsLink('join')}`,
      required: false,
      in: 'query',
    };
    const joinMeta = oldVersion
      ? /* istanbul ignore next */ {
          ...joinMetaBase,
          items: {
            type: 'string',
          },
          type: 'array',
          collectionFormat: 'multi',
        }
      : {
          ...joinMetaBase,
          schema: {
            type: 'array',
            items: {
              type: 'string',
            },
          },
          style: 'form',
          explode: true,
        };

    const limitMetaBase = {
      name: limit,
      description: `Limit amount of resources. ${docsLink('limit')}`,
      required: false,
      in: 'query',
    };
    const limitMeta = oldVersion
      ? /* istanbul ignore next */ { ...limitMetaBase, type: 'integer' }
      : { ...limitMetaBase, schema: { type: 'integer' } };

    const offsetMetaBase = {
      name: offset,
      description: `Offset amount of resources. ${docsLink('offset')}`,
      required: false,
      in: 'query',
    };
    const offsetMeta = oldVersion
      ? /* istanbul ignore next */ { ...offsetMetaBase, type: 'integer' }
      : { ...offsetMetaBase, schema: { type: 'integer' } };

    const pageMetaBase = {
      name: page,
      description: `Page portion of resources. ${docsLink('page')}`,
      required: false,
      in: 'query',
    };
    const pageMeta = oldVersion
      ? /* istanbul ignore next */ { ...pageMetaBase, type: 'integer' }
      : { ...pageMetaBase, schema: { type: 'integer' } };

    const cacheMetaBase = {
      name: cache,
      description: `Reset cache (if was enabled). ${docsLink('cache')}`,
      required: false,
      in: 'query',
    };
    const cacheMeta = oldVersion
      ? /* istanbul ignore next */ {
          ...cacheMetaBase,
          type: 'integer',
          minimum: 0,
          maximum: 1,
        }
      : { ...cacheMetaBase, schema: { type: 'integer', minimum: 0, maximum: 1 } };

    const includeDeletedMetaBase = {
      name: includeDeleted,
      description: `Include deleted. ${docsLink('includeDeleted')}`,
      required: false,
      in: 'query',
    };
    const includeDeletedMeta = oldVersion
      ? /* istanbul ignore next */ {
          ...includeDeletedMetaBase,
          type: 'integer',
          minimum: 0,
          maximum: 1,
        }
      : {
          ...includeDeletedMetaBase,
          schema: { type: 'integer', minimum: 0, maximum: 1 },
        };

    switch (name) {
      case 'getManyBase':
        return options.query.softDelete
          ? [
              fieldsMeta,
              searchMeta,
              filterMeta,
              orMeta,
              sortMeta,
              joinMeta,
              limitMeta,
              offsetMeta,
              pageMeta,
              cacheMeta,
              includeDeletedMeta,
            ]
          : [
              fieldsMeta,
              searchMeta,
              filterMeta,
              orMeta,
              sortMeta,
              joinMeta,
              limitMeta,
              offsetMeta,
              pageMeta,
              cacheMeta,
            ];
      case 'getOneBase':
        return options.query.softDelete
          ? [fieldsMeta, joinMeta, cacheMeta, includeDeletedMeta]
          : [fieldsMeta, joinMeta, cacheMeta];
      default:
        return [];
    }
  }

  static getQueryParamsNames(): any {
    const qbOptions = RequestQueryBuilder.getOptions();
    const name = (n) => {
      const selected = qbOptions.paramNamesMap[n];
      return isString(selected) ? selected : selected[0];
    };

    return {
      delim: qbOptions.delim,
      delimStr: qbOptions.delimStr,
      fields: name('fields'),
      search: name('search'),
      filter: name('filter'),
      or: name('or'),
      join: name('join'),
      sort: name('sort'),
      limit: name('limit'),
      offset: name('offset'),
      page: name('page'),
      cache: name('cache'),
      includeDeleted: name('includeDeleted'),
    };
  }

  private static getSwaggerVersion(): number {
    return swaggerPkgJson ? parseInt(swaggerPkgJson.version[0], 10) : /* istanbul ignore next */ 3;
  }
}

// tslint:disable-next-line:ban-types
export function ApiProperty(options?: any): PropertyDecorator {
  return (target: unknown, propertyKey: string | symbol) => {
    /* istanbul ignore else */
    if (swagger) {
      // tslint:disable-next-line
      const ApiPropertyDecorator = swagger.ApiProperty || /* istanbul ignore next */ swagger.ApiModelProperty;
      // tslint:disable-next-line
      ApiPropertyDecorator(options)(target, propertyKey);
    }
  };
}


================================================
FILE: packages/crud/src/crud/validation.helper.ts
================================================
import { ValidationPipe } from '@nestjs/common';
import { isFalse, isNil } from '@nestjsx/util';
import { CrudValidationGroups } from '../enums';
import { CreateManyDto, CrudOptions, MergedCrudOptions } from '../interfaces';
import { safeRequire } from '../util';
import { ApiProperty } from './swagger.helper';

const validator = safeRequire('class-validator', () => require('class-validator'));
const transformer = safeRequire('class-transformer', () => require('class-transformer'));

class BulkDto<T> implements CreateManyDto<T> {
  bulk: T[];
}

export class Validation {
  static getValidationPipe(options: CrudOptions, group?: CrudValidationGroups): ValidationPipe {
    return validator && !isFalse(options.validation)
      ? new ValidationPipe({
          ...(options.validation || {}),
          groups: group ? [group] : undefined,
        })
      : /* istanbul ignore next */ undefined;
  }

  static createBulkDto<T = any>(options: MergedCrudOptions): any {
    /* istanbul ignore else */
    if (validator && transformer && !isFalse(options.validation)) {
      const { IsArray, ArrayNotEmpty, ValidateNested } = validator;
      const { Type } = transformer;
      const hasDto = !isNil(options.dto.create);
      const groups = !hasDto ? [CrudValidationGroups.CREATE] : undefined;
      const always = hasDto ? true : undefined;
      const Model = hasDto ? options.dto.create : options.model.type;

      // tslint:disable-next-line:max-classes-per-file
      class BulkDtoImpl implements CreateManyDto<T> {
        @ApiProperty({ type: Model, isArray: true })
        @IsArray({ groups, always })
        @ArrayNotEmpty({ groups, always })
        @ValidateNested({ each: true, groups, always })
        @Type(() => Model)
        bulk: T[];
      }

      Object.defineProperty(BulkDtoImpl, 'name', {
        writable: false,
        value: `CreateMany${options.model.type.name}Dto`,
      });

      return BulkDtoImpl;
    } else {
      return BulkDto;
    }
  }
}


================================================
FILE: packages/crud/src/decorators/crud-auth.decorator.ts
================================================
import { R } from '../crud/reflection.helper';
import { AuthOptions } from '../interfaces';

export const CrudAuth =
  (options: AuthOptions) =>
  (target: unknown): void => {
    R.setCrudAuthOptions(options, target);
  };


================================================
FILE: packages/crud/src/decorators/crud.decorator.ts
================================================
import { CrudRoutesFactory } from '../crud';
import { CrudOptions } from '../interfaces';

export const Crud =
  (options: CrudOptions) =>
  (target: unknown): void => {
    const factoryMethod = options.routesFactory || CrudRoutesFactory;
    const factory = new factoryMethod(target, options);
  };


================================================
FILE: packages/crud/src/decorators/feature-action.decorator.ts
================================================
import { SetMetadata, Type } from '@nestjs/common';

import { ACTION_NAME_METADATA, FEAUTURE_NAME_METADATA } from '../constants';

export const Feature = (name: string) => SetMetadata(FEAUTURE_NAME_METADATA, name);
export const Action = (name: string) => SetMetadata(ACTION_NAME_METADATA, name);

export const getFeature = <T = any>(target: Type<T>) => Reflect.getMetadata(FEAUTURE_NAME_METADATA, target);
export const getAction = (target: unknown) => Reflect.getMetadata(ACTION_NAME_METADATA, target);


================================================
FILE: packages/crud/src/decorators/index.ts
================================================
export * from './crud.decorator';
export * from './crud-auth.decorator';
export * from './override.decorator';
export * from './parsed-request.decorator';
export * from './parsed-body.decorator';
export * from './feature-action.decorator';


================================================
FILE: packages/crud/src/decorators/override.decorator.ts
================================================
import { BaseRouteName } from '../types/base-route-name.type';
import { OVERRIDE_METHOD_METADATA } from '../constants';

export const Override = (name?: BaseRouteName) => (
  target,
  key,
  descriptor: PropertyDescriptor,
) => {
  Reflect.defineMetadata(OVERRIDE_METHOD_METADATA, name || `${key}Base`, target[key]);
  return descriptor;
};


================================================
FILE: packages/crud/src/decorators/parsed-body.decorator.ts
================================================
import { PARSED_BODY_METADATA } from '../constants';

export const ParsedBody = () => (target, key, index) => {
  Reflect.defineMetadata(PARSED_BODY_METADATA, { index }, target[key]);
};


================================================
FILE: packages/crud/src/decorators/parsed-request.decorator.ts
================================================
import { createParamDecorator } from '@nestjs/common';

import { PARSED_CRUD_REQUEST_KEY } from '../constants';
import { R } from '../crud/reflection.helper';

export const ParsedRequest = createParamDecorator(
  (_, ctx): ParameterDecorator => {
    return R.getContextRequest(ctx)[PARSED_CRUD_REQUEST_KEY];
  },
);


================================================
FILE: packages/crud/src/enums/crud-actions.enum.ts
================================================
export enum CrudActions {
  ReadAll = 'Read-All',
  ReadOne = 'Read-One',
  CreateOne = 'Create-One',
  CreateMany = 'Create-Many',
  UpdateOne = 'Update-One',
  ReplaceOne = 'Replace-One',
  DeleteOne = 'Delete-One',
  DeleteAll = 'Delete-All',
  RecoverOne = 'Recover-One',
}


================================================
FILE: packages/crud/src/enums/crud-validation-groups.enum.ts
================================================
export enum CrudValidationGroups {
  CREATE = 'CRUD-CREATE',
  UPDATE = 'CRUD-UPDATE',
}


================================================
FILE: packages/crud/src/enums/index.ts
================================================
export * from './crud-actions.enum';
export * from './crud-validation-groups.enum';


================================================
FILE: packages/crud/src/index.ts
================================================
export * from './crud/crud-routes.factory';
export * from './decorators';
export * from './enums';
export * from './interfaces';
export * from './types';
export * from './module';
export * from './interceptors';
export * from './services';


================================================
FILE: packages/crud/src/interceptors/crud-base.interceptor.ts
================================================
import { ExecutionContext } from '@nestjs/common';
import { R } from '../crud/reflection.helper';
import { CrudActions } from '../enums';
import { MergedCrudOptions } from '../interfaces';

export class CrudBaseInterceptor {
  protected getCrudInfo(
    context: ExecutionContext,
  ): {
    ctrlOptions: MergedCrudOptions;
    crudOptions: Partial<MergedCrudOptions>;
    action: CrudActions;
  } {
    const ctrl = context.getClass();
    const handler = context.getHandler();
    const ctrlOptions = R.getCrudOptions(ctrl);
    const crudOptions = ctrlOptions
      ? ctrlOptions
      : {
          query: {},
          routes: {},
          params: {},
        };
    const action = R.getAction(handler);

    return { ctrlOptions, crudOptions, action };
  }
}


================================================
FILE: packages/crud/src/interceptors/crud-request.interceptor.ts
================================================
import { BadRequestException, CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { RequestQueryException, RequestQueryParser, SCondition, QueryFilter } from '@nestjsx/crud-request';
import { isNil, isFunction, isArrayFull, hasLength } from '@nestjsx/util';
import { ClassTransformOptions } from 'class-transformer';

import { PARSED_CRUD_REQUEST_KEY } from '../constants';
import { CrudActions } from '../enums';
import { MergedCrudOptions, CrudRequest } from '../interfaces';
import { QueryFilterFunction } from '../types';
import { CrudBaseInterceptor } from './crud-base.interceptor';

@Injectable()
export class CrudRequestInterceptor extends CrudBaseInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler) {
    const req = context.switchToHttp().getRequest();

    try {
      /* istanbul ignore else */
      if (!req[PARSED_CRUD_REQUEST_KEY]) {
        const { ctrlOptions, crudOptions, action } = this.getCrudInfo(context);
        const parser = RequestQueryParser.create();

        parser.parseQuery(req.query);

        if (!isNil(ctrlOptions)) {
          const search = this.getSearch(parser, crudOptions, action, req.params);
          const auth = this.getAuth(parser, crudOptions, req);
          parser.search = auth.or ? { $or: [auth.or, { $and: search }] } : { $and: [auth.filter, ...search] };
        } else {
          parser.search = { $and: this.getSearch(parser, crudOptions, action) };
        }

        req[PARSED_CRUD_REQUEST_KEY] = this.getCrudRequest(parser, crudOptions);
      }

      return next.handle();
    } catch (error) {
      /* istanbul ignore next */
      throw error instanceof RequestQueryException ? new BadRequestException(error.message) : error;
    }
  }

  getCrudRequest(parser: RequestQueryParser, crudOptions: Partial<MergedCrudOptions>): CrudRequest {
    const parsed = parser.getParsed();
    const { query, routes, params } = crudOptions;

    return {
      parsed,
      options: {
        query,
        routes,
        params,
      },
    };
  }

  getSearch(
    parser: RequestQueryParser,
    crudOptions: Partial<MergedCrudOptions>,
    action: CrudActions,
    params?: any,
  ): SCondition[] {
    // params condition
    const paramsSearch = this.getParamsSearch(parser, crudOptions, params);

    // if `CrudOptions.query.filter` is a function then return transformed query search conditions
    if (isFunction(crudOptions.query.filter)) {
      const filterCond =
        (crudOptions.query.filter as QueryFilterFunction)(parser.search, action === CrudActions.ReadAll) ||
        /* istanbul ignore next */ {};

      return [...paramsSearch, filterCond];
    }

    // if `CrudOptions.query.filter` is array or search condition type
    const optionsFilter = isArrayFull(crudOptions.query.filter)
      ? (crudOptions.query.filter as QueryFilter[]).map(parser.convertFilterToSearch)
      : [(crudOptions.query.filter as SCondition) || {}];

    let search: SCondition[] = [];

    if (parser.search) {
      search = [parser.search];
    } else if (hasLength(parser.filter) && hasLength(parser.or)) {
      search =
        parser.filter.length === 1 && parser.or.length === 1
          ? [
              {
                $or: [parser.convertFilterToSearch(parser.filter[0]), parser.convertFilterToSearch(parser.or[0])],
              },
            ]
          : [
              {
                $or: [
                  { $and: parser.filter.map(parser.convertFilterToSearch) },
                  { $and: parser.or.map(parser.convertFilterToSearch) },
                ],
              },
            ];
    } else if (hasLength(parser.filter)) {
      search = parser.filter.map(parser.convertFilterToSearch);
    } else {
      if (hasLength(parser.or)) {
        search =
          parser.or.length === 1
            ? [parser.convertFilterToSearch(parser.or[0])]
            : /* istanbul ignore next */ [
                {
                  $or: parser.or.map(parser.convertFilterToSearch),
                },
              ];
      }
    }

    return [...paramsSearch, ...optionsFilter, ...search];
  }

  getParamsSearch(parser: RequestQueryParser, crudOptions: Partial<MergedCrudOptions>, params?: any): SCondition[] {
    if (params) {
      parser.parseParams(params, crudOptions.params);

      return isArrayFull(parser.paramsFilter) ? parser.paramsFilter.map(parser.convertFilterToSearch) : [];
    }

    return [];
  }

  getAuth(parser: RequestQueryParser, crudOptions: Partial<MergedCrudOptions>, req: any): { filter?: any; or?: any } {
    const auth: any = {};

    /* istanbul ignore else */
    if (crudOptions.auth) {
      const userOrRequest = crudOptions.auth.property ? req[crudOptions.auth.property] : req;

      if (isFunction(crudOptions.auth.or)) {
        auth.or = crudOptions.auth.or(userOrRequest);
      }

      if (isFunction(crudOptions.auth.filter) && !auth.or) {
        auth.filter = crudOptions.auth.filter(userOrRequest) || /* istanbul ignore next */ {};
      }

      if (isFunction(crudOptions.auth.persist)) {
        parser.setAuthPersist(crudOptions.auth.persist(userOrRequest));
      }

      const options: ClassTransformOptions = {};
      if (isFunction(crudOptions.auth.classTransformOptions)) {
        Object.assign(options, crudOptions.auth.classTransformOptions(userOrRequest));
      }

      if (isFunction(crudOptions.auth.groups)) {
        options.groups = crudOptions.auth.groups(userOrRequest);
      }
      parser.setClassTransformOptions(options);
    }

    return auth;
  }
}


================================================
FILE: packages/crud/src/interceptors/crud-response.interceptor.ts
================================================
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { isFalse, isObject, isFunction } from '@nestjsx/util';
import { classToPlain, classToPlainFromExist, ClassTransformOptions } from 'class-transformer';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { CrudActions } from '../enums';
import { SerializeOptions } from '../interfaces';
import { CrudBaseInterceptor } from './crud-base.interceptor';

const actionToDtoNameMap: {
  [key in CrudActions]: keyof SerializeOptions;
} = {
  [CrudActions.ReadAll]: 'getMany',
  [CrudActions.ReadOne]: 'get',
  [CrudActions.CreateMany]: 'createMany',
  [CrudActions.CreateOne]: 'create',
  [CrudActions.UpdateOne]: 'update',
  [CrudActions.ReplaceOne]: 'replace',
  [CrudActions.DeleteAll]: 'delete',
  [CrudActions.DeleteOne]: 'delete',
  [CrudActions.RecoverOne]: 'recover',
};

@Injectable()
export class CrudResponseInterceptor extends CrudBaseInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle().pipe(map((data) => this.serialize(context, data)));
  }

  protected transform(dto: any, data: any, options: ClassTransformOptions) {
    if (!isObject(data) || isFalse(dto)) {
      return data;
    }

    if (!isFunction(dto)) {
      return data.constructor !== Object ? classToPlain(data, options) : data;
    }

    return data instanceof dto
      ? classToPlain(data, options)
      : classToPlain(classToPlainFromExist(data, new dto()), options);
  }

  protected serialize(context: ExecutionContext, data: any): any {
    const req = context.switchToHttp().getRequest();
    const { crudOptions, action } = this.getCrudInfo(context);
    const { serialize } = crudOptions;
    const dto = serialize[actionToDtoNameMap[action]];
    const isArray = Array.isArray(data);

    const options: ClassTransformOptions = {};
    /* istanbul ignore else */
    if (isFunction(crudOptions.auth?.classTransformOptions)) {
      const userOrRequest = crudOptions.auth.property ? req[crudOptions.auth.property] : req;
      Object.assign(options, crudOptions.auth.classTransformOptions(userOrRequest));
    }

    /* istanbul ignore else */
    if (isFunction(crudOptions.auth?.groups)) {
      const userOrRequest = crudOptions.auth.property ? req[crudOptions.auth.property] : req;
      options.groups = crudOptions.auth.groups(userOrRequest);
    }

    switch (action) {
      case CrudActions.ReadAll:
        return isArray
          ? (data as any[]).map((item) => this.transform(serialize.get, item, options))
          : this.transform(dto, data, options);
      case CrudActions.CreateMany:
        return isArray
          ? (data as any[]).map((item) => this.transform(dto, item, options))
          : this.transform(dto, data, options);
      default:
        return this.transform(dto, data, options);
    }
  }
}


================================================
FILE: packages/crud/src/interceptors/index.ts
================================================
export * from './crud-request.interceptor';
export * from './crud-response.interceptor';


================================================
FILE: packages/crud/src/interfaces/auth-options.interface.ts
================================================
import { SCondition } from '@nestjsx/crud-request/lib/types/request-query.types';
import { ObjectLiteral } from '@nestjsx/util';
import { ClassTransformOptions } from 'class-transformer';

export interface AuthGlobalOptions {
  property?: string;
  /** Get options for the `classToPlain` function (response) */
  classTransformOptions?: (req: any) => ClassTransformOptions;
  /** Get `groups` value for the `classToPlain` function options (response) */
  groups?: (req: any) => string[];
}

export interface AuthOptions {
  property?: string;
  /** Get options for the `classToPlain` function (response) */
  classTransformOptions?: (req: any) => ClassTransformOptions;
  /** Get `groups` value for the `classToPlain` function options (response) */
  groups?: (req: any) => string[];
  filter?: (req: any) => SCondition | void;
  or?: (req: any) => SCondition | void;
  persist?: (req: any) => ObjectLiteral;
}


================================================
FILE: packages/crud/src/interfaces/base-route.interface.ts
================================================
import { RequestMethod } from '@nestjs/common';

import { BaseRouteName } from '../types';

export interface BaseRoute {
  name: BaseRouteName;
  path: string;
  method: RequestMethod;
  enable: boolean;
  override: boolean;
  withParams: boolean;
}


================================================
FILE: packages/crud/src/interfaces/create-many-dto.interface.ts
================================================
export interface CreateManyDto<T = any> {
  bulk: T[];
}


================================================
FILE: packages/crud/src/interfaces/crud-controller.interface.ts
================================================
import { CrudService } from '../services';
import { CrudRequest, GetManyDefaultResponse, CreateManyDto } from '../interfaces';

export interface CrudController<T> {
  service: CrudService<T>;
  getManyBase?(req: CrudRequest): Promise<GetManyDefaultResponse<T> | T[]>;
  getOneBase?(req: CrudRequest): Promise<T>;
  createOneBase?(req: CrudRequest, dto: T): Promise<T>;
  createManyBase?(req: CrudRequest, dto: CreateManyDto<T>): Promise<T[]>;
  updateOneBase?(req: CrudRequest, dto: T): Promise<T>;
  replaceOneBase?(req: CrudRequest, dto: T): Promise<T>;
  deleteOneBase?(req: CrudRequest): Promise<void | T>;
  recoverOneBase?(req: CrudRequest): Promise<void | T>;
}


================================================
FILE: packages/crud/src/interfaces/crud-global-config.interface.ts
================================================
import { RequestQueryBuilderOptions } from '@nestjsx/crud-request';

import { RoutesOptions } from './routes-options.interface';
import { ParamsOptions } from './params-options.interface';
import { AuthGlobalOptions } from './auth-options.interface';

export interface CrudGlobalConfig {
  queryParser?: RequestQueryBuilderOptions;
  auth?: AuthGlobalOptions;
  routes?: RoutesOptions;
  params?: ParamsOptions;
  query?: {
    limit?: number;
    maxLimit?: number;
    cache?: number | false;
    alwaysPaginate?: boolean;
    softDelete?: boolean;
  };
  serialize?: {
    getMany?: false;
    get?: false;
    create?: false;
    createMany?: false;
    update?: false;
    replace?: false;
    delete?: false;
    recover?: false;
  };
}


================================================
FILE: packages/crud/src/interfaces/crud-options.interface.ts
================================================
import { ValidationPipeOptions } from '@nestjs/common';

import { CrudRoutesFactory } from '../crud';
import { ModelOptions } from './model-options.interface';
import { ParamsOptions } from './params-options.interface';
import { QueryOptions } from './query-options.interface';
import { RoutesOptions } from './routes-options.interface';
import { AuthOptions } from './auth-options.interface';
import { DtoOptions } from './dto-options.interface';
import { SerializeOptions } from './serialize-options.interface';

export interface CrudRequestOptions {
  query?: QueryOptions;
  routes?: RoutesOptions;
  params?: ParamsOptions;
}

export interface CrudOptions {
  model: ModelOptions;
  dto?: DtoOptions;
  serialize?: SerializeOptions;
  query?: QueryOptions;
  routes?: RoutesOptions;
  routesFactory?: typeof CrudRoutesFactory;
  params?: ParamsOptions;
  validation?: ValidationPipeOptions | false;
}

export interface MergedCrudOptions extends CrudOptions {
  auth?: AuthOptions;
}


================================================
FILE: packages/crud/src/interfaces/crud-request.interface.ts
================================================
import { ParsedRequestParams } from '@nestjsx/crud-request';

import { CrudRequestOptions } from '../interfaces';

export interface CrudRequest {
  parsed: ParsedRequestParams;
  options: CrudRequestOptions;
}


================================================
FILE: packages/crud/src/interfaces/dto-options.interface.ts
================================================
export interface DtoOptions {
  create?: any;
  update?: any;
  replace?: any;
}


================================================
FILE: packages/crud/src/interfaces/get-many-default-response.interface.ts
================================================
export interface GetManyDefaultResponse<T> {
  data: T[];
  count: number;
  total: number;
  page: number;
  pageCount: number;
}


================================================
FILE: packages/crud/src/interfaces/index.ts
================================================
export * from './crud-controller.interface';
export * from './crud-options.interface';
export * from './auth-options.interface';
export * from './params-options.interface';
export * from './query-options.interface';
export * from './routes-options.interface';
export * from './base-route.interface';
export * from './crud-request.interface';
export * from './model-options.interface';
export * from './create-many-dto.interface';
export * from './get-many-default-response.interface';
export * from './crud-global-config.interface';
export * from './dto-options.interface';
export * from './serialize-options.interface';


================================================
FILE: packages/crud/src/interfaces/model-options.interface.ts
================================================
export interface ModelOptions {
  type: any;
}


================================================
FILE: packages/crud/src/interfaces/params-options.interface.ts
================================================
import { SwaggerEnumType } from '@nestjs/swagger/dist/types/swagger-enum.type';
import { ParamOptionType } from '@nestjsx/crud-request';

export interface ParamsOptions {
  [key: string]: ParamOption;
}

export interface ParamOption {
  field?: string;
  type?: ParamOptionType;
  enum?: SwaggerEnumType;
  primary?: boolean;
  disabled?: boolean;
}


================================================
FILE: packages/crud/src/interfaces/query-options.interface.ts
================================================
import {
  QueryFields,
  QuerySort,
} from '@nestjsx/crud-request/lib/types/request-query.types';

import { QueryFilterOption } from '../types';

export interface QueryOptions {
  allow?: QueryFields;
  exclude?: QueryFields;
  persist?: QueryFields;
  filter?: QueryFilterOption;
  join?: JoinOptions;
  sort?: QuerySort[];
  limit?: number;
  maxLimit?: number;
  cache?: number | false;
  alwaysPaginate?: boolean;
  softDelete?: boolean;
}

export interface JoinOptions {
  [key: string]: JoinOption;
}

export interface JoinOption {
  alias?: string;
  allow?: QueryFields;
  eager?: boolean;
  exclude?: QueryFields;
  persist?: QueryFields;
  select?: false;
  required?: boolean;
}


================================================
FILE: packages/crud/src/interfaces/routes-options.interface.ts
================================================
import { BaseRouteName } from '../types';

export interface RoutesOptions {
  exclude?: BaseRouteName[];
  only?: BaseRouteName[];
  getManyBase?: GetManyRouteOptions;
  getOneBase?: GetOneRouteOptions;
  createOneBase?: CreateOneRouteOptions;
  createManyBase?: CreateManyRouteOptions;
  updateOneBase?: UpdateOneRouteOptions;
  replaceOneBase?: ReplaceOneRouteOptions;
  deleteOneBase?: DeleteOneRouteOptions;
  recoverOneBase?: RecoverOneRouteOptions;
}

export interface BaseRouteOptions {
  interceptors?: any[];
  decorators?: (PropertyDecorator | MethodDecorator)[];
}

export type GetManyRouteOptions = BaseRouteOptions;

export type GetOneRouteOptions = BaseRouteOptions;

export interface CreateOneRouteOptions extends BaseRouteOptions {
  returnShallow?: boolean;
}

export type CreateManyRouteOptions = BaseRouteOptions;

export interface ReplaceOneRouteOptions extends BaseRouteOptions {
  allowParamsOverride?: boolean;
  returnShallow?: boolean;
}

export interface UpdateOneRouteOptions extends BaseRouteOptions {
  allowParamsOverride?: boolean;
  returnShallow?: boolean;
}

export interface DeleteOneRouteOptions extends BaseRouteOptions {
  returnDeleted?: boolean;
}

export interface RecoverOneRouteOptions extends BaseRouteOptions {
  returnRecovered?: boolean;
}


================================================
FILE: packages/crud/src/interfaces/serialize-options.interface.ts
================================================
import { Type } from '@nestjs/common';

export interface SerializeOptions {
  getMany?: Type<any> | false;
  get?: Type<any> | false;
  create?: Type<any> | false;
  createMany?: Type<any> | false;
  update?: Type<any> | false;
  replace?: Type<any> | false;
  delete?: Type<any> | false;
  recover?: Type<any> | false;
}


================================================
FILE: packages/crud/src/module/crud-config.service.ts
================================================
import { RequestQueryBuilder } from '@nestjsx/crud-request';
import { isObjectFull } from '@nestjsx/util';
import * as deepmerge from 'deepmerge';

import { CrudGlobalConfig } from '../interfaces';

export class CrudConfigService {
  static config: CrudGlobalConfig = {
    auth: {},
    query: {
      alwaysPaginate: false,
    },
    routes: {
      getManyBase: { interceptors: [], decorators: [] },
      getOneBase: { interceptors: [], decorators: [] },
      createOneBase: { interceptors: [], decorators: [], returnShallow: false },
      createManyBase: { interceptors: [], decorators: [] },
      updateOneBase: {
        interceptors: [],
        decorators: [],
        allowParamsOverride: false,
        returnShallow: false,
      },
      replaceOneBase: {
        interceptors: [],
        decorators: [],
        allowParamsOverride: false,
        returnShallow: false,
      },
      deleteOneBase: { interceptors: [], decorators: [], returnDeleted: false },
      recoverOneBase: { interceptors: [], decorators: [], returnRecovered: false },
    },
    params: {},
  };

  static load(config: CrudGlobalConfig = {}) {
    if (isObjectFull(config.queryParser)) {
      RequestQueryBuilder.setOptions(config.queryParser);
    }

    const auth = isObjectFull(config.auth) ? config.auth : {};
    const query = isObjectFull(config.query) ? config.query : {};
    const routes = isObjectFull(config.routes) ? config.routes : {};
    const params = isObjectFull(config.params) ? config.params : {};
    const serialize = isObjectFull(config.serialize) ? config.serialize : {};

    CrudConfigService.config = deepmerge(
      CrudConfigService.config,
      { auth, query, routes, params, serialize },
      { arrayMerge: (a, b, c) => b },
    );
  }
}


================================================
FILE: packages/crud/src/module/index.ts
================================================
export * from './crud-config.service';


================================================
FILE: packages/crud/src/services/crud-service.abstract.ts
================================================
import { BadRequestException, NotFoundException } from '@nestjs/common';
import { ParsedRequestParams } from '@nestjsx/crud-request';
import { objKeys } from '@nestjsx/util';

import { CreateManyDto, CrudRequest, CrudRequestOptions, GetManyDefaultResponse, QueryOptions } from '../interfaces';

export abstract class CrudService<T> {
  throwBadRequestException(msg?: unknown): BadRequestException {
    throw new BadRequestException(msg);
  }

  throwNotFoundException(name: string): NotFoundException {
    throw new NotFoundException(`${name} not found`);
  }

  /**
   * Wrap page into page-info
   * override this method to create custom page-info response
   * or set custom `serialize.getMany` dto in the controller's CrudOption
   * @param data
   * @param total
   * @param limit
   * @param offset
   */
  createPageInfo(data: T[], total: number, limit: number, offset: number): GetManyDefaultResponse<T> {
    return {
      data,
      count: data.length,
      total,
      page: limit ? Math.floor(offset / limit) + 1 : 1,
      pageCount: limit && total ? Math.ceil(total / limit) : 1,
    };
  }

  /**
   * Determine if need paging
   * @param parsed
   * @param options
   */
  decidePagination(parsed: ParsedRequestParams, options: CrudRequestOptions): boolean {
    return (
      options.query.alwaysPaginate ||
      ((Number.isFinite(parsed.page) || Number.isFinite(parsed.offset)) &&
        /* istanbul ignore next */ !!this.getTake(parsed, options.query))
    );
  }

  /**
   * Get number of resources to be fetched
   * @param query
   * @param options
   */
  getTake(query: ParsedRequestParams, options: QueryOptions): number | null {
    if (query.limit) {
      return options.maxLimit ? (query.limit <= options.maxLimit ? query.limit : options.maxLimit) : query.limit;
    }
    /* istanbul ignore if */
    if (options.limit) {
      return options.maxLimit ? (options.limit <= options.maxLimit ? options.limit : options.maxLimit) : options.limit;
    }

    return options.maxLimit ? options.maxLimit : null;
  }

  /**
   * Get number of resources to be skipped
   * @param query
   * @param take
   */
  getSkip(query: ParsedRequestParams, take: number): number | null {
    return query.page && take ? take * (query.page - 1) : query.offset ? query.offset : null;
  }

  /**
   * Get primary param name from CrudOptions
   * @param options
   */
  getPrimaryParams(options: CrudRequestOptions): string[] {
    const params = objKeys(options.params).filter((n) => options.params[n] && options.params[n].primary);

    return params.map((p) => options.params[p].field);
  }

  abstract getMany(req: CrudRequest): Promise<GetManyDefaultResponse<T> | T[]>;

  abstract getOne(req: CrudRequest): Promise<T>;

  abstract createOne(req: CrudRequest, dto: T | Partial<T>): Promise<T>;

  abstract createMany(req: CrudRequest, dto: CreateManyDto): Promise<T[]>;

  abstract updateOne(req: CrudRequest, dto: T | Partial<T>): Promise<T>;

  abstract replaceOne(req: CrudRequest, dto: T | Partial<T>): Promise<T>;

  abstract deleteOne(req: CrudRequest): Promise<void | T>;

  abstract recoverOne(req: CrudRequest): Promise<void | T>;
}


================================================
FILE: packages/crud/src/services/index.ts
================================================
export * from './crud-service.abstract';


================================================
FILE: packages/crud/src/types/base-route-name.type.ts
================================================
export type BaseRouteName =
  | 'getManyBase'
  | 'getOneBase'
  | 'createOneBase'
  | 'createManyBase'
  | 'updateOneBase'
  | 'replaceOneBase'
  | 'deleteOneBase'
  | 'recoverOneBase';


================================================
FILE: packages/crud/src/types/index.ts
================================================
export * from './base-route-name.type';
export * from './query-filter-option.type';


================================================
FILE: packages/crud/src/types/query-filter-option.type.ts
================================================
import {
  QueryFilter,
  SCondition,
} from '@nestjsx/crud-request/lib/types/request-query.types';

export type QueryFilterFunction = (
  search?: SCondition,
  getMany?: boolean,
) => SCondition | void;
export type QueryFilterOption = QueryFilter[] | SCondition | QueryFilterFunction;


================================================
FILE: packages/crud/src/util.ts
================================================
export function safeRequire<T = any>(path: string, loader?: () => T): T | null {
  try {
    /* istanbul ignore next */
    const pack = loader ? loader() : require(path);
    return pack;
  } catch (_) {
    /* istanbul ignore next */
    return null;
  }
}


================================================
FILE: packages/crud/test/__fixture__/dto/index.ts
================================================
export * from './test-create.dto';
export * from './test-update.dto';


================================================
FILE: packages/crud/test/__fixture__/dto/test-create.dto.ts
================================================
import {
  IsString,
  IsEmail,
  IsNumber,
  IsOptional,
  IsNotEmpty,
  IsEmpty,
} from 'class-validator';

export class TestCreateDto {
  @IsString()
  firstName: string;

  @IsString()
  lastName: string;

  @IsEmail({ require_tld: false })
  email: string;

  @IsNumber()
  age: number;
}


================================================
FILE: packages/crud/test/__fixture__/dto/test-update.dto.ts
================================================
import {
  IsString,
  IsEmail,
  IsNumber,
  IsOptional,
  IsNotEmpty,
  IsEmpty,
} from 'class-validator';

export class TestUpdateDto {
  @IsOptional()
  @IsString()
  firstName?: string;

  @IsOptional()
  @IsString()
  lastName?: string;

  @IsOptional()
  @IsEmail({ require_tld: false })
  email?: string;

  @IsOptional()
  @IsNumber()
  age?: number;
}


================================================
FILE: packages/crud/test/__fixture__/exception.filter.ts
================================================
import { ArgumentsHost, Catch, ExceptionFilter, HttpStatus } from '@nestjs/common';
import { RequestQueryException } from '@nestjsx/crud-request';
import { Response } from 'express';

@Catch(RequestQueryException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: RequestQueryException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();

    response.status(HttpStatus.BAD_REQUEST).json({
      statusCode: HttpStatus.BAD_REQUEST,
      message: exception.message,
    });
  }
}


================================================
FILE: packages/crud/test/__fixture__/models/index.ts
================================================
export * from './test.model';
export * from './test-serialize.model';
export * from './test-serialize-2.model';


================================================
FILE: packages/crud/test/__fixture__/models/test-serialize-2.model.ts
================================================
import { Exclude } from 'class-transformer';

import { TestSerializeModel } from './test-serialize.model';

export class TestSerialize2Model extends TestSerializeModel {
  id: number;

  name: string;

  email: string;

  @Exclude()
  isActive: boolean;

  constructor(partial: Partial<TestSerialize2Model>) {
    super(partial);
    Object.assign(this, partial);
  }
}


================================================
FILE: packages/crud/test/__fixture__/models/test-serialize.model.ts
================================================
export class TestSerializeModel {
  id: number;

  name: string;

  email: string;

  isActive: boolean;

  constructor(partial: Partial<TestSerializeModel>) {
    Object.assign(this, partial);
  }
}


================================================
FILE: packages/crud/test/__fixture__/models/test.model.ts
================================================
import {
  IsString,
  IsEmail,
  IsNumber,
  IsOptional,
  IsNotEmpty,
  IsEmpty,
} from 'class-validator';

import { CrudValidationGroups } from '../../../src';

const { CREATE, UPDATE } = CrudValidationGroups;

export class TestModel {
  @IsEmpty({ groups: [CREATE] })
  @IsNumber({}, { groups: [UPDATE] })
  id?: number;

  @IsOptional({ groups: [UPDATE] })
  @IsNotEmpty({ groups: [CREATE] })
  @IsString({ always: true })
  firstName?: string;

  @IsOptional({ groups: [UPDATE] })
  @IsNotEmpty({ groups: [CREATE] })
  @IsString({ always: true })
  lastName?: string;

  @IsOptional({ groups: [UPDATE] })
  @IsNotEmpty({ groups: [CREATE] })
  @IsEmail({ require_tld: false }, { always: true })
  email?: string;

  @IsOptional({ groups: [UPDATE] })
  @IsNotEmpty({ groups: [CREATE] })
  @IsNumber({}, { always: true })
  age?: number;
}


================================================
FILE: packages/crud/test/__fixture__/response/delete-model-response.dto.ts
================================================
import { Exclude, Expose } from 'class-transformer';

@Exclude()
export class DeleteModelResponseDto {
  @Expose()
  id: number;
}


================================================
FILE: packages/crud/test/__fixture__/response/get-many-model-response.dto.ts
================================================
import { Type } from 'class-transformer';

import { GetModelResponseDto } from './get-model-response.dto';

export class GetManyModelResponseDto {
  @Type(() => GetModelResponseDto)
  items: GetModelResponseDto[];
}


================================================
FILE: packages/crud/test/__fixture__/response/get-model-response.dto.ts
================================================
import { Exclude } from 'class-transformer';

export class GetModelResponseDto {
  id: number;

  name: string;

  @Exclude()
  email: string;

  isActive: boolean;
}


================================================
FILE: packages/crud/test/__fixture__/response/index.ts
================================================
export * from './get-many-model-response.dto';
export * from './get-model-response.dto';
export * from './delete-model-response.dto';
export * from './recover-model-response.dto';


================================================
FILE: packages/crud/test/__fixture__/response/recover-model-response.dto.ts
================================================
import { Exclude } from 'class-transformer';

export class RecoverModelResponseDto {
  id: number;

  name: string;

  email: string;

  isActive: boolean;
}


================================================
FILE: packages/crud/test/__fixture__/services/index.ts
================================================
export * from './test.service';
export * from './test-serialize.service';


================================================
FILE: packages/crud/test/__fixture__/services/test-serialize.service.ts
================================================
import { Injectable, Type } from '@nestjs/common';

import { CreateManyDto, CrudRequest, GetManyDefaultResponse } from '../../../src/interfaces';
import { CrudService } from '../../../src/services';
import { TestSerializeModel } from '../models';

@Injectable()
export class TestSerializeService<T = TestSerializeModel> extends CrudService<T> {
  private store: T[] = [];

  constructor(private Model: Type<T>) {
    super();
    this.store = [
      new this.Model({ id: 1, name: 'name', email: 'email1', isActive: true }),
      new this.Model({ id: 2, name: 'name2', email: 'email2', isActive: false }),
      new this.Model({ id: 3, name: 'name3', email: 'email3', isActive: true }),
      new this.Model({ id: 4, name: 'name4', email: 'email4', isActive: false }),
      new this.Model({ id: 5, name: 'name5', email: 'email5', isActive: true }),
    ];
  }

  async getMany(req: CrudRequest): Promise<GetManyDefaultResponse<T> | T[]> {
    const total = this.store.length;
    const limit = this.getTake(req.parsed, req.options.query);
    const offset = this.getSkip(req.parsed, limit);

    return this.decidePagination(req.parsed, req.options)
      ? this.createPageInfo(this.store, total, limit || total, offset || 0)
      : this.store;
  }

  async getOne(req: CrudRequest): Promise<T> {
    return this.store[0];
  }

  async createOne(req: CrudRequest, dto: T): Promise<any> {}

  async createMany(req: CrudRequest, dto: CreateManyDto<T>): Promise<any> {}

  async updateOne(req: CrudRequest, dto: T): Promise<any> {}

  async replaceOne(req: CrudRequest, dto: T): Promise<any> {}

  async deleteOne(req: CrudRequest): Promise<any> {
    return req.options.routes.deleteOneBase.returnDeleted ? this.store[0] : undefined;
  }

  async recoverOne(req: CrudRequest): Promise<any> {
    return req.options.routes.recoverOneBase.returnRecovered ? this.store[0] : undefined;
  }
}


================================================
FILE: packages/crud/test/__fixture__/services/test.service.ts
================================================
import { Injectable } from '@nestjs/common';
import { ParsedRequestParams } from '@nestjsx/crud-request';
import { CrudRequestOptions } from '../../../src/interfaces';

import { CreateManyDto, CrudRequest } from '../../../src/interfaces';
import { CrudService } from '../../../src/services';

@Injectable()
export class TestService<T> extends CrudService<T> {
  async getMany(req: CrudRequest): Promise<any> {
    return { req };
  }

  async getOne(req: CrudRequest): Promise<any> {
    return { req };
  }

  async createOne(req: CrudRequest, dto: T): Promise<any> {
    return { req, dto };
  }

  async createMany(req: CrudRequest, dto: CreateManyDto<T>): Promise<any> {
    return { req, dto };
  }

  async updateOne(req: CrudRequest, dto: T): Promise<any> {
    return { req, dto };
  }

  async replaceOne(req: CrudRequest, dto: T): Promise<any> {
    return { req, dto };
  }

  async deleteOne(req: CrudRequest): Promise<any> {
    return { req };
  }

  async recoverOne(req: CrudRequest): Promise<any> {
    return { req };
  }

  decidePagination(parsed: ParsedRequestParams, options: CrudRequestOptions): boolean {
    return true;
  }
}


================================================
FILE: packages/crud/test/crud-config.service.global.spec.ts
================================================
import * as request from 'supertest';
import { Test } from '@nestjs/testing';
import { Controller, INestApplication } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';

import { CrudGlobalConfig } from '../src/interfaces';
import { CrudConfigService } from '../src/module/crud-config.service';

// IMPORTANT:
// CrudConfigService.load() should be called before importing @Crud() controllers

const conf: CrudGlobalConfig = {
  query: {
    limit: 10,
  },
  params: {
    id: {
      field: 'id',
      type: 'uuid',
      primary: true,
    },
  },
  routes: {
    exclude: ['createManyBase'],
    updateOneBase: {
      allowParamsOverride: true,
    },
    replaceOneBase: {
      allowParamsOverride: true,
    },
  },
  serialize: {
    get: false,
  },
};

// Important: load config before (!!!) you import AppModule
// https://github.com/nestjsx/crud/wiki/Controllers#global-options
CrudConfigService.load(conf);

import { Crud } from '../src/decorators/crud.decorator';
import { HttpExceptionFilter } from './__fixture__/exception.filter';
import { TestModel } from './__fixture__/models';
import { TestService } from './__fixture__/services';

describe('#crud', () => {
  describe('#CrudConfigService', () => {
    let app: INestApplication;
    let server: any;

    @Crud({
      model: { type: TestModel },
    })
    @Controller('test')
    class GlobalTestController {
      constructor(public service: TestService<TestModel>) {}
    }

    @Crud({
      model: { type: TestModel },
      query: {
        limit: 12,
      },
      params: {
        id: {
          field: 'id',
          type: 'number',
          primary: true,
        },
      },
      routes: {
        updateOneBase: {
          allowParamsOverride: false,
        },
        replaceOneBase: {
          allowParamsOverride: false,
        },
        deleteOneBase: {
          returnDeleted: true,
        },
      },
    })
    @Controller('test2')
    class GlobalTestController2 {
      constructor(public service: TestService<TestModel>) {}
    }

    beforeAll(async () => {
      const fixture = await Test.createTestingModule({
        controllers: [GlobalTestController, GlobalTestController2],
        providers: [{ provide: APP_FILTER, useClass: HttpExceptionFilter }, TestService],
      }).compile();

      app = fixture.createNestApplication();

      await app.init();
      server = app.getHttpServer();
    });

    afterAll(async () => {
      app.close();
    });

    it('should use global config', (done) => {
      request(server)
        .get('/test')
        .end((_, res) => {
          expect(res.status).toBe(200);
          expect(res.body.req.options.query).toMatchObject(conf.query);
          expect(res.body.req.options.params).toMatchObject(conf.params);
          expect(res.body.req.options.routes.updateOneBase.allowParamsOverride).toBe(true);
          expect(res.body.req.options.routes.replaceOneBase.allowParamsOverride).toBe(true);
          done();
        });
    });
    it('should use merged config', (done) => {
      request(server)
        .get('/test2')
        .end((_, res) => {
          expect(res.status).toBe(200);
          expect(res.body.req.options.query).toMatchObject({
            limit: 12,
          });
          expect(res.body.req.options.params).toMatchObject({
            id: {
              field: 'id',
              type: 'number',
              primary: true,
            },
          });
          expect(res.body.req.options.routes.updateOneBase.allowParamsOverride).toBe(false);
          expect(res.body.req.options.routes.replaceOneBase.allowParamsOverride).toBe(false);
          expect(res.body.req.options.routes.deleteOneBase.returnDeleted).toBe(true);
          done();
        });
    });
    it('should exclude route, 1', (done) => {
      request(server)
        .post('/test/bulk')
        .send({})
        .end((_, res) => {
          expect(res.status).toBe(404);
          done();
        });
    });
    it('should exclude route, 1', (done) => {
      request(server)
        .post('/test2/bulk')
        .send({})
        .end((_, res) => {
          expect(res.status).toBe(404);
          done();
        });
    });
  });
});


================================================
FILE: packages/crud/test/crud-config.service.spec.ts
================================================
import { RequestQueryBuilder } from '@nestjsx/crud-request';
import { CrudGlobalConfig } from '../src/interfaces';
import { CrudConfigService } from '../src/module/crud-config.service';

describe('#crud', () => {
  describe('#CrudConfigService', () => {
    const defaultConfig = { ...CrudConfigService.config };

    beforeEach(() => {
      CrudConfigService.config = { ...defaultConfig };
    });

    it('should set default config, 1', () => {
      const conf: CrudGlobalConfig = {};
      const expected = { ...CrudConfigService.config };
      CrudConfigService.load(conf);
      expect(CrudConfigService.config).toEqual(expect.objectContaining(expected));
    });
    it('should set default config, 2', () => {
      const expected = { ...CrudConfigService.config };
      CrudConfigService.load();
      expect(CrudConfigService.config).toEqual(expect.objectContaining(expected));
    });
    it('should set queryParser', () => {
      const requestOptions = { ...RequestQueryBuilder.getOptions() };
      const conf: CrudGlobalConfig = {
        queryParser: {
          delim: '__',
        },
      };
      const expected = { ...CrudConfigService.config };
      CrudConfigService.load(conf);
      expect(CrudConfigService.config).toEqual(expect.objectContaining(expected));
      expect(RequestQueryBuilder.getOptions()).toEqual(
        expect.objectContaining({ ...requestOptions, delim: '__' }),
      );
    });
    it('should set query, routes, params', () => {
      const conf: CrudGlobalConfig = {
        auth: {
          property: 'user',
        },
        query: {
          limit: 10,
        },
        params: {
          id: {
            field: 'id',
            type: 'uuid',
            primary: true,
          },
        },
        routes: {
          updateOneBase: {
            allowParamsOverride: true,
            returnShallow: true,
          },
          replaceOneBase: {
            allowParamsOverride: true,
          },
          getManyBase: {
            interceptors: [() => {}],
          },
        },
      };
      const expected = {
        auth: {
          property: 'user',
        },
        query: {
          limit: 10,
        },
        params: {
          id: {
            field: 'id',
            type: 'uuid',
            primary: true,
          },
        },
        routes: {
          getManyBase: {
            interceptors: [() => {}],
            decorators: [],
          },
          getOneBase: { interceptors: [], decorators: [] },
          createOneBase: { interceptors: [], decorators: [], returnShallow: false },
          createManyBase: { interceptors: [], decorators: [] },
          updateOneBase: {
            interceptors: [],
            decorators: [],
            allowParamsOverride: true,
            returnShallow: true,
          },
          replaceOneBase: {
            interceptors: [],
            decorators: [],
            allowParamsOverride: true,
            returnShallow: false,
          },
          deleteOneBase: { interceptors: [], decorators: [], returnDeleted: false },
          recoverOneBase: { interceptors: [], decorators: [], returnRecovered: false },
        },
      };
      CrudConfigService.load(conf);
      expect(CrudConfigService.config.params).toEqual(
        expect.objectContaining(expected.params),
      );
      expect(CrudConfigService.config.query).toEqual(
        expect.objectContaining(expected.query),
      );
      expect(JSON.stringify(CrudConfigService.config.routes)).toEqual(
        JSON.stringify(expected.routes),
      );
    });
  });
});


================================================
FILE: packages/crud/test/crud-request.interceptor.spec.ts
================================================
import { Controller, Get, Param, ParseIntPipe, Query, UseInterceptors } from '@nestjs/common';
import { NestApplication } from '@nestjs/core';
import { Test } from '@nestjs/testing';
import { RequestQueryBuilder } from '@nestjsx/crud-request';
import * as supertest from 'supertest';
import { Crud, ParsedRequest, CrudAuth, Override } from '../src/decorators';
import { CrudRequestInterceptor } from '../src/interceptors';
import { CrudRequest } from '../src/interfaces';
import { TestModel } from './__fixture__/models';
import { TestService } from './__fixture__/services';

// tslint:disable:max-classes-per-file
describe('#crud', () => {
  @UseInterceptors(CrudRequestInterceptor)
  @Controller('test')
  class TestController {
    @Get('/query')
    async query(@ParsedRequest() req: CrudRequest) {
      return req;
    }

    @Get('/other')
    async other(@Query('page', ParseIntPipe) page: number) {
      return { page };
    }

    @Get('/other2/:someParam')
    async routeWithParam(@Param('someParam', ParseIntPipe) p: number) {
      return { p };
    }
  }

  @Crud({
    model: { type: TestModel },
    params: {
      someParam: { field: 'someParam', type: 'number' },
    },
  })
  @Controller('test2')
  class Test2Controller {
    constructor(public service: TestService<TestModel>) {}

    @UseInterceptors(CrudRequestInterceptor)
    @Get('normal/:id')
    async normal(@ParsedRequest() req: CrudRequest) {
      return { filter: req.parsed.paramsFilter };
    }

    @UseInterceptors(CrudRequestInterceptor)
    @Get('/other2/:someParam')
    async routeWithParam(@Param('someParam', ParseIntPipe) p: number) {
      return { p };
    }

    @UseInterceptors(CrudRequestInterceptor)
    @Get('other2/:id/twoParams/:someParam')
    async twoParams(@ParsedRequest() req: CrudRequest, @Param('someParam', ParseIntPipe) p: number) {
      return { filter: req.parsed.paramsFilter };
    }
  }

  @Crud({
    model: { type: TestModel },
    query: {
      filter: () => ({ name: 'persist' }),
    },
  })
  @CrudAuth({
    property: 'user',
    filter: (user) => ({ user: 'test', buz: 1 }),
    persist: () => ({ bar: false }),
  })
  @Controller('test3')
  class Test3Controller {
    constructor(public service: TestService<TestModel>) {}

    @Override('getManyBase')
    get(@ParsedRequest() req: CrudRequest) {
      return req;
    }

    @Override('createOneBase')
    post(@ParsedRequest() req: CrudRequest) {
      return req;
    }
  }

  @Crud({
    model: { type: TestModel },
  })
  @CrudAuth({
    or: () => ({ id: 1 }),
  })
  @Controller('test4')
  class Test4Controller {
    constructor(public service: TestService<TestModel>) {}

    @Override('getManyBase')
    get(@ParsedRequest() req: CrudRequest) {
      return req;
    }
  }

  @Crud({
    model: { type: TestModel },
    params: {
      someParam: { field: 'someParam', type: 'number', primary: true },
      someParam2: { field: 'someParam2', type: 'number', primary: true },
    },
  })
  @Controller('test5')
  class Test5Controller {
    constructor(public service: TestService<TestModel>) {}
  }

  @Crud({
    model: { type: TestModel },
  })
  @CrudAuth({
    groups: () => ['TEST_2'],
    classTransformOptions: () => ({ groups: ['TEST_1'] }),
  })
  @Controller('test6')
  class Test6Controller {
    constructor(public service: TestService<TestModel>) {}

    @Override('getManyBase')
    get(@ParsedRequest() req: CrudRequest) {
      return req;
    }
  }

  let $: supertest.SuperTest<supertest.Test>;
  let app: NestApplication;

  beforeAll(async () => {
    const module = await Test.createTestingModule({
      providers: [TestService],
      controllers: [
        TestController,
        Test2Controller,
        Test3Controller,
        Test4Controller,
        Test5Controller,
        Test6Controller,
      ],
    }).compile();
    app = module.createNestApplication();
    await app.init();

    $ = supertest(app.getHttpServer());
  });

  afterAll(async () => {
    await app.close();
  });

  describe('#interceptor', () => {
    let qb: RequestQueryBuilder;

    beforeEach(() => {
      qb = RequestQueryBuilder.create();
    });

    it('should working on non-crud controller', async () => {
      const page = 2;
      const limit = 10;
      const fields = ['a', 'b', 'c'];
      const sorts: any[][] = [
        ['a', 'ASC'],
        ['b', 'DESC'],
      ];
      const filters: any[][] = [
        ['a', 'eq', 1],
        ['c', 'in', [1, 2, 3]],
        ['d', 'notnull'],
      ];

      qb.setPage(page).setLimit(limit);
      qb.select(fields);
      for (const s of sorts) {
        qb.sortBy({ field: s[0], order: s[1] });
      }
      for (const f of filters) {
        qb.setFilter({ field: f[0], operator: f[1], value: f[2] });
      }

      const res = await $.get('/test/query').query(qb.query()).expect(200);
      expect(res.body.parsed).toHaveProperty('page', page);
      expect(res.body.parsed).toHaveProperty('limit', limit);
      expect(res.body.parsed).toHaveProperty('fields', fields);
      expect(res.body.parsed).toHaveProperty('sort');
      for (let i = 0; i < sorts.length; i++) {
        expect(res.body.parsed.sort[i]).toHaveProperty('field', sorts[i][0]);
        expect(res.body.parsed.sort[i]).toHaveProperty('order', sorts[i][1]);
      }
      expect(res.body.parsed).toHaveProperty('filter');
      for (let i = 0; i < filters.length; i++) {
        expect(res.body.parsed.filter[i]).toHaveProperty('field', filters[i][0]);
        expect(res.body.parsed.filter[i]).toHaveProperty('operator', filters[i][1]);
        expect(res.body.parsed.filter[i]).toHaveProperty('value', filters[i][2] || '');
      }
    });

    it('should others working', async () => {
      const res = await $.get('/test/other').query({ page: 2, per_page: 11 }).expect(200);
      expect(res.body.page).toBe(2);
    });

    it('should parse param', async () => {
      const res = await $.get('/test/other2/123').expect(200);
      expect(res.body.p).toBe(123);
    });

    it('should parse custom param in crud', async () => {
      const res = await $.get('/test2/other2/123').expect(200);
      expect(res.body.p).toBe(123);
    });

    it('should parse crud param and custom param', async () => {
      const res = await $.get('/test2/other2/1/twoParams/123').expect(200);
      expect(res.body.filter).toHaveLength(2);
      expect(res.body.filter[0].field).toBe('id');
      expect(res.body.filter[0].value).toBe(1);
    });

    it('should parse multiple primary key', async () => {
      const res = await $.get('/test5/123/456').expect(200);
    });

    it('should work like before', async () => {
      const res = await $.get('/test2/normal/0').expect(200);
      expect(res.body.filter).toHaveLength(1);
      expect(res.body.filter[0].field).toBe('id');
      expect(res.body.filter[0].value).toBe(0);
    });

    it('should handle authorized request, 1', async () => {
      const res = await $.post('/test3').send({}).expect(201);
      const authPersist = { bar: false };
      const { parsed } = res.body;
      expect(parsed.authPersist).toMatchObject(authPersist);
    });

    it('should handle authorized request, 2', async () => {
      const res = await $.get('/test3').expect(200);
      const search = { $and: [{ user: 'test', buz: 1 }, {}] };
      expect(res.body.parsed.search).toMatchObject(search);
    });

    it('should handle authorized request, 3', async () => {
      const query = qb.search({ name: 'test' }).query();
      const res = await $.get('/test4').query(query).expect(200);
      const search = { $or: [{ id: 1 }, { $and: [{}, { name: 'test' }] }] };
      expect(res.body.parsed.search).toMatchObject(search);
    });
    it('should handle authorized request, 4', async () => {
      const query = qb.search({ name: 'test' }).query();
      const res = await $.get('/test3').query(query).expect(200);
      const search = { $and: [{ user: 'test', buz: 1 }, { name: 'persist' }] };
      expect(res.body.parsed.search).toMatchObject(search);
    });

    it('should handle classTransformOptions, 1', async () => {
      const res = await $.get('/test6').expect(200);
      const groups = ['TEST_2'];
      expect(res.body.parsed.classTransformOptions.groups).toMatchObject(groups);
    });
  });
});


================================================
FILE: packages/crud/test/crud-service.abstract.spec.ts
================================================
import { BadRequestException, NotFoundException } from '@nestjs/common';

import { TestService } from './__fixture__/services';

describe('#crud', () => {
  describe('#CrudService', () => {
    let service: TestService<any>;

    beforeAll(() => {
      service = new TestService();
    });

    describe('#throwBadRequestException', () => {
      it('should throw BadRequestException', () => {
        expect(service.throwBadRequestException.bind(service, '')).toThrowError(
          BadRequestException,
        );
      });
    });

    describe('#throwNotFoundException', () => {
      it('should throw NotFoundException', () => {
        expect(service.throwNotFoundException.bind(service, '')).toThrowError(
          NotFoundException,
        );
      });
    });

    describe('#createPageInfo', () => {
      it('should return an object', () => {
        const expected = {
          count: 0,
          data: [],
          page: 2,
          pageCount: 10,
          total: 100,
        };
        expect(service.createPageInfo([], 100, 10, 10)).toMatchObject(expected);
      });

      it('should return an object when limit and offset undefined', () => {
        const expected = {
          count: 0,
          data: [],
          page: 1,
          pageCount: 1,
          total: 100,
        };
        expect(service.createPageInfo([], 100, undefined, undefined)).toMatchObject(
          expected,
        );
      });
    });
  });
});


================================================
FILE: packages/crud/test/crud.decorator.base.spec.ts
================================================
import * as request from 'supertest';
import { Test } from '@nestjs/testing';
import { Controller, INestApplication } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
import { RequestQueryBuilder } from '@nestjsx/crud-request';

import { Crud } from '../src/decorators/crud.decorator';
import { CreateManyDto } from '../src/interfaces';
import { HttpExceptionFilter } from './__fixture__/exception.filter';
import { TestModel } from './__fixture__/models';
import { TestService } from './__fixture__/services';

describe('#crud', () => {
  describe('#base methods', () => {
    let app: INestApplication;
    let server: any;
    let qb: RequestQueryBuilder;

    @Crud({
      model: { type: TestModel },
    })
    @Controller('test')
    class TestController {
      constructor(public service: TestService<TestModel>) {}
    }

    beforeAll(async () => {
      const fixture = await Test.createTestingModule({
        controllers: [TestController],
        providers: [{ provide: APP_FILTER, useClass: HttpExceptionFilter }, TestService],
      }).compile();

      app = fixture.createNestApplication();

      await app.init();
      server = app.getHttpServer();
    });

    beforeEach(() => {
      qb = RequestQueryBuilder.create();
    });

    afterAll(async () => {
      app.close();
    });

    describe('#getManyBase', () => {
      it('should return status 200', (done) => {
        request(server)
          .get('/test')
          .end((_, res) => {
            expect(res.status).toEqual(200);
            done();
          });
      });
      it('should return status 400', (done) => {
        const query = qb.setFilter({ field: 'foo', operator: 'gt' }).query();
        request(server)
          .get('/test')
          .query(query)
          .end((_, res) => {
            const expected = { statusCode: 400, message: 'Invalid filter value' };
            expect(res.status).toEqual(400);
            expect(res.body).toMatchObject(expected);
            done();
          });
      });
    });

    describe('#getOneBase', () => {
      it('should return status 200', (done) => {
        request(server)
          .get('/test/1')
          .end((_, res) => {
            expect(res.status).toEqual(200);
            done();
          });
      });
      it('should return status 400', (done) => {
        request(server)
          .get('/test/invalid')
          .end((_, res) => {
            const expected = {
              statusCode: 400,
              message: 'Invalid param id. Number expected',
            };
            expect(res.status).toEqual(400);
            expect(res.body).toMatchObject(expected);
            done();
          });
      });
    });

    describe('#createOneBase', () => {
      it('should return status 201', (done) => {
        const send: TestModel = {
          firstName: 'firstName',
          lastName: 'lastName',
          email: 'test@test.com',
          age: 15,
        };
        request(server)
          .post('/test')
          .send(send)
          .end((_, res) => {
            expect(res.status).toEqual(201);
            done();
          });
      });
      it('should return status 400', (done) => {
        const send: TestModel = {
          firstName: 'firstName',
          lastName: 'lastName',
          email: 'test@test.com',
        };
        request(server)
          .post('/test')
          .send(send)
          .end((_, res) => {
            expect(res.status).toEqual(400);
            done();
          });
      });
    });

    describe('#createMadyBase', () => {
      it('should return status 201', (done) => {
        const send: CreateManyDto<TestModel> = {
          bulk: [
            {
              firstName: 'firstName',
              lastName: 'lastName',
              email: 'test@test.com',
              age: 15,
            },
            {
              firstName: 'firstName',
              lastName: 'lastName',
              email: 'test@test.com',
              age: 15,
            },
          ],
        };
        request(server)
          .post('/test/bulk')
          .send(send)
          .end((_, res) => {
            expect(res.status).toEqual(201);
            done();
          });
      });
      it('should return status 400', (done) => {
        const send: CreateManyDto<TestModel> = {
          bulk: [],
        };
        request(server)
          .post('/test/bulk')
          .send(send)
          .end((_, res) => {
            expect(res.status).toEqual(400);
            done();
          });
      });
    });

    describe('#replaceOneBase', () => {
      it('should return status 200', (done) => {
        const send: TestModel = {
          id: 1,
          firstName: 'firstName',
          lastName: 'lastName',
          email: 'test@test.com',
          age: 15,
        };
        request(server)
          .put('/test/1')
          .send(send)
          .end((_, res) => {
            expect(res.status).toEqual(200);
            done();
          });
      });
      it('should return status 400', (done) => {
        const send: TestModel = {
          firstName: 'firstName',
          lastName: 'lastName',
          email: 'test@test.com',
        };
        request(server)
          .put('/test/1')
          .send(send)
          .end((_, res) => {
            expect(res.status).toEqual(400);
            done();
          });
      });
    });

    describe('#updateOneBase', () => {
      it('should return status 200', (done) => {
        const send: TestModel = {
          id: 1,
          firstName: 'firstName',
          lastName: 'lastName',
          email: 'test@test.com',
          age: 15,
        };
        request(server)
          .patch('/test/1')
          .send(send)
          .end((_, res) => {
            expect(res.status).toEqual(200);
            done();
          });
      });
      it('should return status 400', (done) => {
        const send: TestModel = {
          firstName: 'firstName',
          lastName: 'lastName',
          email: 'test@test.com',
        };
        request(server)
          .patch('/test/1')
          .send(send)
          .end((_, res) => {
            expect(res.status).toEqual(400);
            done();
          });
      });
    });

    describe('#deleteOneBase', () => {
      it('should return status 200', (done) => {
        request(server)
          .delete('/test/1')
          .end((_, res) => {
            expect(res.status).toEqual(200);
            done();
          });
      });
    });
  });
});


================================================
FILE: packages/crud/test/crud.decorator.exclude.spec.ts
================================================
import * as request from 's
Download .txt
gitextract_rxpb3oso/

├── .eslintignore
├── .eslintrc.js
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── Bug_report.md
│   │   └── Feature_request.md
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows/
│       ├── release.yml
│       └── tests.yml
├── .gitignore
├── .husky/
│   └── pre-commit
├── .prettierrc.json
├── .yarnrc
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── docker-compose.yml
├── integration/
│   ├── crud-typeorm/
│   │   ├── app.module.ts
│   │   ├── auth.guard.ts
│   │   ├── base-entity.ts
│   │   ├── companies/
│   │   │   ├── companies.controller.ts
│   │   │   ├── companies.module.ts
│   │   │   ├── companies.service.ts
│   │   │   ├── company.entity.ts
│   │   │   ├── index.ts
│   │   │   ├── requests/
│   │   │   │   ├── create-company.dto.ts
│   │   │   │   └── index.ts
│   │   │   └── responses/
│   │   │       ├── get-company-response.dto.ts
│   │   │       └── index.ts
│   │   ├── constants.ts
│   │   ├── devices/
│   │   │   ├── device.entity.ts
│   │   │   ├── devices.controller.ts
│   │   │   ├── devices.module.ts
│   │   │   ├── devices.service.ts
│   │   │   ├── index.ts
│   │   │   └── response/
│   │   │       ├── delete-device-response.dto.ts
│   │   │       └── index.ts
│   │   ├── main.ts
│   │   ├── notes/
│   │   │   ├── index.ts
│   │   │   ├── note.entity.ts
│   │   │   ├── notes.controller.ts
│   │   │   ├── notes.module.ts
│   │   │   ├── notes.service.ts
│   │   │   ├── requests/
│   │   │   │   ├── create-note.dto.ts
│   │   │   │   └── index.ts
│   │   │   └── responses/
│   │   │       ├── get-note-response.dto.ts
│   │   │       └── index.ts
│   │   ├── orm.config.ts
│   │   ├── orm.mysql.ts
│   │   ├── orm.postgres.ts
│   │   ├── orm.yaml
│   │   ├── projects/
│   │   │   ├── index.ts
│   │   │   ├── my-projects.controller.ts
│   │   │   ├── project.entity.ts
│   │   │   ├── projects.controller.ts
│   │   │   ├── projects.module.ts
│   │   │   ├── projects.service.ts
│   │   │   ├── user-project.entity.ts
│   │   │   └── user-projects.service.ts
│   │   ├── seeds.ts
│   │   ├── users/
│   │   │   ├── index.ts
│   │   │   ├── me.controller.ts
│   │   │   ├── user.entity.ts
│   │   │   ├── users.controller.ts
│   │   │   ├── users.module.ts
│   │   │   └── users.service.ts
│   │   ├── users-licenses/
│   │   │   ├── index.ts
│   │   │   ├── license.entity.ts
│   │   │   └── user-license.entity.ts
│   │   └── users-profiles/
│   │       ├── index.ts
│   │       └── user-profile.entity.ts
│   └── shared/
│       └── https-exception.filter.ts
├── jest.config.js
├── lerna.json
├── mrepo.json
├── package.json
├── packages/
│   ├── crud/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── constants.ts
│   │   │   ├── crud/
│   │   │   │   ├── crud-routes.factory.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── reflection.helper.ts
│   │   │   │   ├── serialize.helper.ts
│   │   │   │   ├── swagger.helper.ts
│   │   │   │   └── validation.helper.ts
│   │   │   ├── decorators/
│   │   │   │   ├── crud-auth.decorator.ts
│   │   │   │   ├── crud.decorator.ts
│   │   │   │   ├── feature-action.decorator.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── override.decorator.ts
│   │   │   │   ├── parsed-body.decorator.ts
│   │   │   │   └── parsed-request.decorator.ts
│   │   │   ├── enums/
│   │   │   │   ├── crud-actions.enum.ts
│   │   │   │   ├── crud-validation-groups.enum.ts
│   │   │   │   └── index.ts
│   │   │   ├── index.ts
│   │   │   ├── interceptors/
│   │   │   │   ├── crud-base.interceptor.ts
│   │   │   │   ├── crud-request.interceptor.ts
│   │   │   │   ├── crud-response.interceptor.ts
│   │   │   │   └── index.ts
│   │   │   ├── interfaces/
│   │   │   │   ├── auth-options.interface.ts
│   │   │   │   ├── base-route.interface.ts
│   │   │   │   ├── create-many-dto.interface.ts
│   │   │   │   ├── crud-controller.interface.ts
│   │   │   │   ├── crud-global-config.interface.ts
│   │   │   │   ├── crud-options.interface.ts
│   │   │   │   ├── crud-request.interface.ts
│   │   │   │   ├── dto-options.interface.ts
│   │   │   │   ├── get-many-default-response.interface.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── model-options.interface.ts
│   │   │   │   ├── params-options.interface.ts
│   │   │   │   ├── query-options.interface.ts
│   │   │   │   ├── routes-options.interface.ts
│   │   │   │   └── serialize-options.interface.ts
│   │   │   ├── module/
│   │   │   │   ├── crud-config.service.ts
│   │   │   │   └── index.ts
│   │   │   ├── services/
│   │   │   │   ├── crud-service.abstract.ts
│   │   │   │   └── index.ts
│   │   │   ├── types/
│   │   │   │   ├── base-route-name.type.ts
│   │   │   │   ├── index.ts
│   │   │   │   └── query-filter-option.type.ts
│   │   │   └── util.ts
│   │   ├── test/
│   │   │   ├── __fixture__/
│   │   │   │   ├── dto/
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── test-create.dto.ts
│   │   │   │   │   └── test-update.dto.ts
│   │   │   │   ├── exception.filter.ts
│   │   │   │   ├── models/
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── test-serialize-2.model.ts
│   │   │   │   │   ├── test-serialize.model.ts
│   │   │   │   │   └── test.model.ts
│   │   │   │   ├── response/
│   │   │   │   │   ├── delete-model-response.dto.ts
│   │   │   │   │   ├── get-many-model-response.dto.ts
│   │   │   │   │   ├── get-model-response.dto.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── recover-model-response.dto.ts
│   │   │   │   └── services/
│   │   │   │       ├── index.ts
│   │   │   │       ├── test-serialize.service.ts
│   │   │   │       └── test.service.ts
│   │   │   ├── crud-config.service.global.spec.ts
│   │   │   ├── crud-config.service.spec.ts
│   │   │   ├── crud-request.interceptor.spec.ts
│   │   │   ├── crud-service.abstract.spec.ts
│   │   │   ├── crud.decorator.base.spec.ts
│   │   │   ├── crud.decorator.exclude.spec.ts
│   │   │   ├── crud.decorator.options.spec.ts
│   │   │   ├── crud.decorator.override.spec.ts
│   │   │   ├── crud.decorator.soft.spec.ts
│   │   │   ├── crud.dto.options.spec.ts
│   │   │   ├── crud.serialize.options.spec.ts
│   │   │   └── feature-action.decorator.spec.ts
│   │   └── tsconfig.json
│   ├── crud-request/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── exceptions/
│   │   │   │   ├── index.ts
│   │   │   │   └── request-query.exception.ts
│   │   │   ├── index.ts
│   │   │   ├── interfaces/
│   │   │   │   ├── create-query-params.interface.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── params-options.interface.ts
│   │   │   │   ├── parsed-request.interface.ts
│   │   │   │   └── request-query-builder-options.interface.ts
│   │   │   ├── request-query.builder.ts
│   │   │   ├── request-query.parser.ts
│   │   │   ├── request-query.validator.ts
│   │   │   └── types/
│   │   │       ├── index.ts
│   │   │       ├── request-param.types.ts
│   │   │       └── request-query.types.ts
│   │   ├── test/
│   │   │   ├── request-query.builder.spec.ts
│   │   │   ├── request-query.parser.spec.ts
│   │   │   └── request.query.validator.spec.ts
│   │   └── tsconfig.json
│   ├── crud-typeorm/
│   │   ├── README.md
│   │   ├── package.json
│   │   ├── src/
│   │   │   ├── index.ts
│   │   │   └── typeorm-crud.service.ts
│   │   ├── test/
│   │   │   ├── __fixture__/
│   │   │   │   ├── companies.service.ts
│   │   │   │   ├── devices.service.ts
│   │   │   │   ├── notes.service.ts
│   │   │   │   ├── projects.service.ts
│   │   │   │   └── users.service.ts
│   │   │   ├── a.params-options.spec.ts
│   │   │   ├── b.query-params.spec.ts
│   │   │   ├── c.basic-crud.spec.ts
│   │   │   └── d.crud-auth.spec.ts
│   │   └── tsconfig.json
│   └── util/
│       ├── README.md
│       ├── package.json
│       ├── src/
│       │   ├── checks.util.ts
│       │   ├── index.ts
│       │   ├── obj.util.ts
│       │   └── types/
│       │       ├── class.type.ts
│       │       ├── index.ts
│       │       └── object-literal.type.ts
│       ├── test/
│       │   ├── checks.util.spec.ts
│       │   └── obj.util.spec.ts
│       └── tsconfig.json
├── tsconfig.eslint.json
├── tsconfig.jest.json
├── tsconfig.json
└── tslint.json
Download .txt
SYMBOL INDEX (486 symbols across 114 files)

FILE: integration/crud-typeorm/app.module.ts
  class AppModule (line 29) | class AppModule {}

FILE: integration/crud-typeorm/auth.guard.ts
  class AuthGuard (line 7) | class AuthGuard implements CanActivate {
    method constructor (line 8) | constructor(private usersService: UsersService) {}
    method canActivate (line 10) | async canActivate(ctx: ExecutionContext): Promise<boolean> {

FILE: integration/crud-typeorm/base-entity.ts
  class BaseEntity (line 3) | class BaseEntity {

FILE: integration/crud-typeorm/companies/companies.controller.ts
  class CompaniesController (line 47) | class CompaniesController {
    method constructor (line 48) | constructor(public service: CompaniesService) {}

FILE: integration/crud-typeorm/companies/companies.module.ts
  class CompaniesModule (line 14) | class CompaniesModule {}

FILE: integration/crud-typeorm/companies/companies.service.ts
  class CompaniesService (line 8) | class CompaniesService extends TypeOrmCrudService<Company> {
    method constructor (line 9) | constructor(@InjectRepository(Company) repo) {

FILE: integration/crud-typeorm/companies/company.entity.ts
  class Company (line 20) | class Company extends BaseEntity {

FILE: integration/crud-typeorm/companies/requests/create-company.dto.ts
  class CreateCompanyDto (line 4) | class CreateCompanyDto {

FILE: integration/crud-typeorm/companies/responses/get-company-response.dto.ts
  class GetCompanyResponseDto (line 4) | class GetCompanyResponseDto {

FILE: integration/crud-typeorm/constants.ts
  constant USER_REQUEST_KEY (line 1) | const USER_REQUEST_KEY = 'user';

FILE: integration/crud-typeorm/devices/device.entity.ts
  class Device (line 8) | class Device {

FILE: integration/crud-typeorm/devices/devices.controller.ts
  class DevicesController (line 27) | class DevicesController {
    method constructor (line 28) | constructor(public service: DevicesService) {}

FILE: integration/crud-typeorm/devices/devices.module.ts
  class DevicesModule (line 14) | class DevicesModule {}

FILE: integration/crud-typeorm/devices/devices.service.ts
  class DevicesService (line 8) | class DevicesService extends TypeOrmCrudService<Device> {
    method constructor (line 9) | constructor(@InjectRepository(Device) repo) {

FILE: integration/crud-typeorm/devices/response/delete-device-response.dto.ts
  class DeleteDeviceResponseDto (line 4) | class DeleteDeviceResponseDto {

FILE: integration/crud-typeorm/main.ts
  function bootstrap (line 20) | async function bootstrap() {

FILE: integration/crud-typeorm/notes/note.entity.ts
  class Note (line 4) | class Note {

FILE: integration/crud-typeorm/notes/notes.controller.ts
  class NotesController (line 20) | class NotesController {
    method constructor (line 21) | constructor(public service: NotesService) {}

FILE: integration/crud-typeorm/notes/notes.module.ts
  class NotesModule (line 14) | class NotesModule {}

FILE: integration/crud-typeorm/notes/notes.service.ts
  class NotesService (line 8) | class NotesService extends TypeOrmCrudService<Note> {
    method constructor (line 9) | constructor(@InjectRepository(Note) repo) {

FILE: integration/crud-typeorm/notes/requests/create-note.dto.ts
  class CreateNoteDto (line 4) | class CreateNoteDto {

FILE: integration/crud-typeorm/notes/responses/get-note-response.dto.ts
  class GetNoteResponseDto (line 4) | class GetNoteResponseDto {

FILE: integration/crud-typeorm/projects/my-projects.controller.ts
  class MyProjectsController (line 38) | class MyProjectsController {
    method constructor (line 39) | constructor(public service: UserProjectsService) {}

FILE: integration/crud-typeorm/projects/project.entity.ts
  class Project (line 20) | class Project extends BaseEntity {

FILE: integration/crud-typeorm/projects/projects.controller.ts
  class ProjectsController (line 31) | class ProjectsController {
    method constructor (line 32) | constructor(public service: ProjectsService) {}

FILE: integration/crud-typeorm/projects/projects.module.ts
  class ProjectsModule (line 17) | class ProjectsModule {}

FILE: integration/crud-typeorm/projects/projects.service.ts
  class ProjectsService (line 8) | class ProjectsService extends TypeOrmCrudService<Project> {
    method constructor (line 9) | constructor(@InjectRepository(Project) repo) {

FILE: integration/crud-typeorm/projects/user-project.entity.ts
  class UserProject (line 7) | class UserProject {

FILE: integration/crud-typeorm/projects/user-projects.service.ts
  class UserProjectsService (line 8) | class UserProjectsService extends TypeOrmCrudService<UserProject> {
    method constructor (line 9) | constructor(@InjectRepository(UserProject) repo) {

FILE: integration/crud-typeorm/seeds.ts
  class Seeds1544303473346 (line 11) | class Seeds1544303473346 implements MigrationInterface {
    method save (line 12) | private save<T>(repo: Repository<T>, data: Partial<T>[]): Promise<T[]> {
    method up (line 22) | public async up(queryRunner: QueryRunner): Promise<any> {
    method down (line 159) | public async down(queryRunner: QueryRunner): Promise<any> {}

FILE: integration/crud-typeorm/users-licenses/license.entity.ts
  class License (line 6) | class License extends BaseEntity {

FILE: integration/crud-typeorm/users-licenses/user-license.entity.ts
  class UserLicense (line 7) | class UserLicense {

FILE: integration/crud-typeorm/users-profiles/user-profile.entity.ts
  class UserProfile (line 8) | class UserProfile extends BaseEntity {

FILE: integration/crud-typeorm/users/me.controller.ts
  class MeController (line 39) | class MeController {
    method constructor (line 40) | constructor(public service: UsersService) {}

FILE: integration/crud-typeorm/users/user.entity.ts
  class Name (line 32) | class Name {
  class User (line 44) | class User extends BaseEntity {

FILE: integration/crud-typeorm/users/users.controller.ts
  class UsersController (line 48) | class UsersController implements CrudController<User> {
    method constructor (line 49) | constructor(public service: UsersService) {}
    method base (line 51) | get base(): CrudController<User> {
    method getAll (line 56) | getAll(@ParsedRequest() req: CrudRequest) {

FILE: integration/crud-typeorm/users/users.module.ts
  class UsersModule (line 16) | class UsersModule {}

FILE: integration/crud-typeorm/users/users.service.ts
  class UsersService (line 8) | class UsersService extends TypeOrmCrudService<User> {
    method constructor (line 9) | constructor(@InjectRepository(User) repo) {

FILE: integration/shared/https-exception.filter.ts
  class HttpExceptionFilter (line 5) | class HttpExceptionFilter implements ExceptionFilter {
    method catch (line 6) | catch(exception: HttpException, host: ArgumentsHost) {
    method prepareException (line 14) | prepareException(exc: any): { status: number; json: object } {

FILE: packages/crud-request/src/exceptions/request-query.exception.ts
  class RequestQueryException (line 1) | class RequestQueryException extends Error {
    method constructor (line 2) | constructor(msg: string) {

FILE: packages/crud-request/src/interfaces/create-query-params.interface.ts
  type CreateQueryParams (line 12) | interface CreateQueryParams {

FILE: packages/crud-request/src/interfaces/params-options.interface.ts
  type ParamsOptions (line 3) | interface ParamsOptions {
  type ParamOption (line 7) | interface ParamOption {

FILE: packages/crud-request/src/interfaces/parsed-request.interface.ts
  type ParsedRequestParams (line 5) | interface ParsedRequestParams {

FILE: packages/crud-request/src/interfaces/request-query-builder-options.interface.ts
  type RequestQueryBuilderOptions (line 1) | interface RequestQueryBuilderOptions {

FILE: packages/crud-request/src/request-query.builder.ts
  class RequestQueryBuilder (line 24) | class RequestQueryBuilder {
    method constructor (line 51) | constructor() {
    method setOptions (line 55) | static setOptions(options: RequestQueryBuilderOptions) {
    method getOptions (line 66) | static getOptions(): RequestQueryBuilderOptions {
    method create (line 70) | static create(params?: CreateQueryParams): RequestQueryBuilder {
    method options (line 75) | get options(): RequestQueryBuilderOptions {
    method setParamNames (line 79) | setParamNames() {
    method query (line 86) | query(encode = true): string {
    method select (line 95) | select(fields: QueryFields): this {
    method search (line 103) | search(s: SCondition) {
    method setFilter (line 110) | setFilter(f: QueryFilter | QueryFilterArr | Array<QueryFilter | QueryF...
    method setOr (line 115) | setOr(f: QueryFilter | QueryFilterArr | Array<QueryFilter | QueryFilte...
    method setJoin (line 120) | setJoin(j: QueryJoin | QueryJoinArr | Array<QueryJoin | QueryJoinArr>)...
    method sortBy (line 133) | sortBy(s: QuerySort | QuerySortArr | Array<QuerySort | QuerySortArr>):...
    method setLimit (line 146) | setLimit(n: number): this {
    method setOffset (line 151) | setOffset(n: number): this {
    method setPage (line 156) | setPage(n: number): this {
    method resetCache (line 161) | resetCache(): this {
    method setIncludeDeleted (line 166) | setIncludeDeleted(n: number): this {
    method cond (line 171) | cond(f: QueryFilter | QueryFilterArr, cond: 'filter' | 'or' | 'search'...
    method addJoin (line 179) | private addJoin(j: QueryJoin | QueryJoinArr): string {
    method addSortBy (line 188) | private addSortBy(s: QuerySort | QuerySortArr): string {
    method createFromParams (line 196) | private createFromParams(params: CreateQueryParams): this {
    method checkQueryObjectParam (line 213) | private checkQueryObjectParam(cond: keyof RequestQueryBuilderOptions['...
    method setCondition (line 221) | private setCondition(
    method setNumeric (line 236) | private setNumeric(n: number, cond: 'limit' | 'offset' | 'page' | 'cac...

FILE: packages/crud-request/src/request-query.parser.ts
  class RequestQueryParser (line 39) | class RequestQueryParser implements ParsedRequestParams {
    method _options (line 76) | private get _options(): RequestQueryBuilderOptions {
    method create (line 80) | static create(): RequestQueryParser {
    method getParsed (line 84) | getParsed(): ParsedRequestParams {
    method parseQuery (line 103) | parseQuery(query: any): this {
    method parseParams (line 133) | parseParams(params: any, options: ParamsOptions): this {
    method setAuthPersist (line 147) | setAuthPersist(persist: ObjectLiteral = {}) {
    method setClassTransformOptions (line 151) | setClassTransformOptions(options: ClassTransformOptions = {}) {
    method convertFilterToSearch (line 155) | convertFilterToSearch(filter: QueryFilter): SFields | SConditionAND {
    method getParamNames (line 170) | private getParamNames(type: keyof RequestQueryBuilderOptions['paramNam...
    method getParamValues (line 177) | private getParamValues(value: string | string[], parser: any): string[] {
    method parseQueryParam (line 189) | private parseQueryParam(type: keyof RequestQueryBuilderOptions['paramN...
    method parseValue (line 199) | private parseValue(val: any) {
    method parseValues (line 221) | private parseValues(vals: any) {
    method fieldsParser (line 229) | private fieldsParser(data: string): QueryFields {
    method parseSearchQueryParam (line 233) | private parseSearchQueryParam(d: any): SCondition {
    method conditionParser (line 251) | private conditionParser(cond: 'filter' | 'or' | 'search', data: string...
    method joinParser (line 275) | private joinParser(data: string): QueryJoin {
    method sortParser (line 286) | private sortParser(data: string): QuerySort {
    method numericParser (line 297) | private numericParser(num: 'limit' | 'offset' | 'page' | 'cache' | 'in...
    method paramParser (line 304) | private paramParser(name: string): QueryFilter {

FILE: packages/crud-request/src/request-query.validator.ts
  function validateFields (line 34) | function validateFields(fields: QueryFields): void {
  function validateCondition (line 40) | function validateCondition(val: QueryFilter, cond: 'filter' | 'or' | 'se...
  function validateComparisonOperator (line 47) | function validateComparisonOperator(operator: ComparisonOperator): void {
  function validateJoin (line 53) | function validateJoin(join: QueryJoin): void {
  function validateSort (line 62) | function validateSort(sort: QuerySort): void {
  function validateNumeric (line 71) | function validateNumeric(
  function validateParamOption (line 80) | function validateParamOption(options: ParamsOptions, name: string) {
  function validateUUID (line 93) | function validateUUID(str: string, name: string) {

FILE: packages/crud-request/src/types/request-param.types.ts
  type ParamOptionType (line 1) | type ParamOptionType = 'number' | 'string' | 'uuid';

FILE: packages/crud-request/src/types/request-query.types.ts
  type QueryFields (line 1) | type QueryFields = string[];
  type QueryFilter (line 3) | type QueryFilter = {
  type QueryFilterArr (line 9) | type QueryFilterArr = [string, ComparisonOperator, any?];
  type QueryJoin (line 11) | type QueryJoin = {
  type QueryJoinArr (line 16) | type QueryJoinArr = [string, QueryFields?];
  type QuerySort (line 18) | type QuerySort = {
  type QuerySortArr (line 23) | type QuerySortArr = [string, QuerySortOperator];
  type QuerySortOperator (line 25) | type QuerySortOperator = 'ASC' | 'DESC';
  type DeprecatedCondOperator (line 27) | type DeprecatedCondOperator =
  type CondOperator (line 44) | enum CondOperator {
  type ComparisonOperator (line 70) | type ComparisonOperator = DeprecatedCondOperator | keyof SFieldOperator;
  type SPrimitivesVal (line 73) | type SPrimitivesVal = string | number | boolean;
  type SFiledValues (line 75) | type SFiledValues = SPrimitivesVal | Array<SPrimitivesVal>;
  type SFieldOperator (line 77) | type SFieldOperator = {
  type SField (line 105) | type SField = SPrimitivesVal | SFieldOperator;
  type SFields (line 107) | type SFields = {
  type SConditionAND (line 113) | type SConditionAND = {
  type SConditionKey (line 118) | type SConditionKey = '$and' | '$or';
  type SCondition (line 120) | type SCondition = SFields | SConditionAND;

FILE: packages/crud-typeorm/src/typeorm-crud.service.ts
  type IAllowedRelation (line 33) | interface IAllowedRelation {
  class TypeOrmCrudService (line 43) | class TypeOrmCrudService<T> extends CrudService<T> {
    method constructor (line 63) | constructor(protected repo: Repository<T>) {
    method findOne (line 70) | public get findOne(): Repository<T>['findOne'] {
    method find (line 74) | public get find(): Repository<T>['find'] {
    method count (line 78) | public get count(): Repository<T>['count'] {
    method entityType (line 82) | protected get entityType(): ClassType<T> {
    method alias (line 86) | protected get alias(): string {
    method getMany (line 94) | public async getMany(req: CrudRequest): Promise<GetManyDefaultResponse...
    method getOne (line 104) | public async getOne(req: CrudRequest): Promise<T> {
    method createOne (line 113) | public async createOne(req: CrudRequest, dto: T | Partial<T>): Promise...
    method createMany (line 144) | public async createMany(req: CrudRequest, dto: CreateManyDto<T | Parti...
    method updateOne (line 165) | public async updateOne(req: CrudRequest, dto: T | Partial<T>): Promise...
    method recoverOne (line 192) | public async recoverOne(req: CrudRequest): Promise<T> {
    method replaceOne (line 202) | public async replaceOne(req: CrudRequest, dto: T | Partial<T>): Promis...
    method deleteOne (line 237) | public async deleteOne(req: CrudRequest): Promise<void | T> {
    method getParamFilters (line 250) | public getParamFilters(parsed: CrudRequest['parsed']): ObjectLiteral {
    method createBuilder (line 269) | public async createBuilder(
    method doGetMany (line 360) | protected async doGetMany(
    method onInitMapEntityColumns (line 376) | protected onInitMapEntityColumns() {
    method getOneOrFail (line 392) | protected async getOneOrFail(req: CrudRequest, shallow = false, withDe...
    method prepareEntityBeforeSave (line 411) | protected prepareEntityBeforeSave(dto: T | Partial<T>, parsed: CrudReq...
    method getAllowedColumns (line 433) | protected getAllowedColumns(columns: string[], options: QueryOptions):...
    method getEntityColumns (line 448) | protected getEntityColumns(entityMetadata: EntityMetadata): { columns:...
    method getRelationMetadata (line 456) | protected getRelationMetadata(field: string, options: JoinOption): IAl...
    method setJoin (line 550) | protected setJoin(cond: QueryJoin, joinOptions: JoinOptions, builder: ...
    method setAndWhere (line 583) | protected setAndWhere(cond: QueryFilter, i: any, builder: SelectQueryB...
    method setOrWhere (line 588) | protected setOrWhere(cond: QueryFilter, i: any, builder: SelectQueryBu...
    method setSearchCondition (line 593) | protected setSearchCondition(builder: SelectQueryBuilder<T>, search: S...
    method builderAddBrackets (line 707) | protected builderAddBrackets(builder: SelectQueryBuilder<T>, condition...
    method builderSetWhere (line 715) | protected builderSetWhere(
    method setSearchFieldObjectCondition (line 729) | protected setSearchFieldObjectCondition(
    method getSelect (line 784) | protected getSelect(query: ParsedRequestParams, options: QueryOptions)...
    method getSort (line 803) | protected getSort(query: ParsedRequestParams, options: QueryOptions) {
    method getFieldWithAlias (line 811) | protected getFieldWithAlias(field: string, sort = false) {
    method mapSort (line 832) | protected mapSort(sort: QuerySort[]) {
    method mapOperatorsToQuery (line 844) | protected mapOperatorsToQuery(cond: QueryFilter, param: any): { str: s...
    method checkFilterIsArray (line 980) | private checkFilterIsArray(cond: QueryFilter, withLength?: boolean) {
    method checkSqlInjection (line 987) | private checkSqlInjection(field: string): string {

FILE: packages/crud-typeorm/test/__fixture__/companies.service.ts
  class CompaniesService (line 8) | class CompaniesService extends TypeOrmCrudService<Company> {
    method constructor (line 9) | constructor(@InjectRepository(Company) repo) {

FILE: packages/crud-typeorm/test/__fixture__/devices.service.ts
  class DevicesService (line 8) | class DevicesService extends TypeOrmCrudService<Device> {
    method constructor (line 9) | constructor(@InjectRepository(Device) repo) {

FILE: packages/crud-typeorm/test/__fixture__/notes.service.ts
  class NotesService (line 8) | class NotesService extends TypeOrmCrudService<Note> {
    method constructor (line 9) | constructor(@InjectRepository(Note) repo) {

FILE: packages/crud-typeorm/test/__fixture__/projects.service.ts
  class ProjectsService (line 8) | class ProjectsService extends TypeOrmCrudService<Project> {
    method constructor (line 9) | constructor(@InjectRepository(Project) repo) {

FILE: packages/crud-typeorm/test/__fixture__/users.service.ts
  class UsersService (line 8) | class UsersService extends TypeOrmCrudService<User> {
    method constructor (line 9) | constructor(@InjectRepository(User) repo) {
  class UsersService2 (line 15) | class UsersService2 extends TypeOrmCrudService<User> {
    method constructor (line 16) | constructor(@InjectRepository(User) repo) {

FILE: packages/crud-typeorm/test/a.params-options.spec.ts
  class UsersController1 (line 23) | @Crud({
    method constructor (line 49) | constructor(public service: UsersService) {}
  class UsersController2 (line 52) | @Crud({
    method constructor (line 75) | constructor(public service: UsersService) {}

FILE: packages/crud-typeorm/test/b.query-params.spec.ts
  class CompaniesController (line 29) | @Crud({
    method constructor (line 45) | constructor(public service: CompaniesService) {}
  class ProjectsController (line 48) | @Crud({
    method constructor (line 71) | constructor(public service: ProjectsService) {}
  class ProjectsController2 (line 74) | @Crud({
    method constructor (line 79) | constructor(public service: ProjectsService) {}
  class ProjectsController3 (line 82) | @Crud({
    method constructor (line 90) | constructor(public service: ProjectsService) {}
  class ProjectsController4 (line 93) | @Crud({
    method constructor (line 101) | constructor(public service: ProjectsService) {}
  class UsersController (line 104) | @Crud({
    method constructor (line 122) | constructor(public service: UsersService) {}
  class UsersController2 (line 125) | @Crud({
    method constructor (line 138) | constructor(public service: UsersService) {}
  class UsersController3 (line 141) | @Crud({
    method constructor (line 155) | constructor(public service: UsersService2) {}
  class NotesController (line 158) | @Crud({
    method constructor (line 163) | constructor(public service: NotesService) {}

FILE: packages/crud-typeorm/test/c.basic-crud.spec.ts
  class CompaniesController0 (line 30) | @Crud({
    method constructor (line 39) | constructor(public service: CompaniesService) {}
  class CompaniesController (line 84) | @Crud({
    method constructor (line 90) | constructor(public service: CompaniesService) {}
    method constructor (line 168) | constructor(public service: CompaniesService) {}
  class CompaniesController (line 160) | @Crud({
    method constructor (line 90) | constructor(public service: CompaniesService) {}
    method constructor (line 168) | constructor(public service: CompaniesService) {}
  class UsersController (line 171) | @Crud({
    method constructor (line 199) | constructor(public service: UsersService) {}
  class UsersController2 (line 202) | @Crud({
    method constructor (line 215) | constructor(public service: UsersService) {}
  class UsersController3 (line 218) | @Crud({
    method constructor (line 230) | constructor(public service: UsersService) {}
  class UsersController4 (line 233) | @Crud({
    method constructor (line 242) | constructor(public service: UsersService) {}
  class DevicesController (line 245) | @Crud({
    method constructor (line 262) | constructor(public service: DevicesService) {}

FILE: packages/crud-typeorm/test/d.crud-auth.spec.ts
  class AuthGuard (line 22) | @Injectable()
    method constructor (line 24) | constructor(private usersService: UsersService) {}
    method canActivate (line 26) | async canActivate(ctx: ExecutionContext): Promise<boolean> {
  class MeController (line 34) | @Crud({
    method constructor (line 59) | constructor(public service: UsersService) {}
  class ProjectsController (line 62) | @Crud({
    method constructor (line 81) | constructor(public service: ProjectsService) {}

FILE: packages/crud/src/constants.ts
  constant FEAUTURE_NAME_METADATA (line 1) | const FEAUTURE_NAME_METADATA = 'NESTJSX_FEAUTURE_NAME_METADATA';
  constant ACTION_NAME_METADATA (line 2) | const ACTION_NAME_METADATA = 'NESTJSX_ACTION_NAME_METADATA';
  constant OVERRIDE_METHOD_METADATA (line 3) | const OVERRIDE_METHOD_METADATA = 'NESTJSX_OVERRIDE_METHOD_METADATA';
  constant PARSED_BODY_METADATA (line 4) | const PARSED_BODY_METADATA = 'NESTJSX_PARSED_BODY_METADATA';
  constant PARSED_CRUD_REQUEST_KEY (line 5) | const PARSED_CRUD_REQUEST_KEY = 'NESTJSX_PARSED_CRUD_REQUEST_KEY';
  constant CRUD_OPTIONS_METADATA (line 6) | const CRUD_OPTIONS_METADATA = 'NESTJSX_CRUD_OPTIONS_METADATA';
  constant CRUD_AUTH_OPTIONS_METADATA (line 7) | const CRUD_AUTH_OPTIONS_METADATA = 'NESTJSX_CRUD_AUTH_OPTIONS_METADATA';

FILE: packages/crud/src/crud/crud-routes.factory.ts
  class CrudRoutesFactory (line 27) | class CrudRoutesFactory {
    method constructor (line 32) | constructor(protected target: any, options: CrudOptions) {
    method create (line 38) | static create(target: any, options: CrudOptions): CrudRoutesFactory {
    method targetProto (line 42) | protected get targetProto(): any {
    method modelName (line 46) | protected get modelName(): string {
    method modelType (line 50) | protected get modelType(): any {
    method actionsMap (line 54) | protected get actionsMap(): { [key in BaseRouteName]: CrudActions } {
    method create (line 67) | protected create() {
    method mergeOptions (line 76) | protected mergeOptions() {
    method getRoutesSchema (line 150) | protected getRoutesSchema(): BaseRoute[] {
    method getManyBase (line 219) | protected getManyBase(name: BaseRouteName) {
    method getOneBase (line 225) | protected getOneBase(name: BaseRouteName) {
    method createOneBase (line 231) | protected createOneBase(name: BaseRouteName) {
    method createManyBase (line 237) | protected createManyBase(name: BaseRouteName) {
    method updateOneBase (line 243) | protected updateOneBase(name: BaseRouteName) {
    method replaceOneBase (line 249) | protected replaceOneBase(name: BaseRouteName) {
    method deleteOneBase (line 255) | protected deleteOneBase(name: BaseRouteName) {
    method recoverOneBase (line 261) | protected recoverOneBase(name: BaseRouteName) {
    method canCreateRoute (line 267) | protected canCreateRoute(name: BaseRouteName) {
    method setResponseModels (line 287) | protected setResponseModels() {
    method createRoutes (line 306) | protected createRoutes(routesSchema: BaseRoute[]) {
    method overrideRoutes (line 327) | protected overrideRoutes(routesSchema: BaseRoute[]) {
    method enableRoutes (line 357) | protected enableRoutes(routesSchema: BaseRoute[]) {
    method overrideParsedBodyDecorator (line 365) | protected overrideParsedBodyDecorator(override: BaseRouteName, name: s...
    method getPrimaryParams (line 406) | protected getPrimaryParams(): string[] {
    method setBaseRouteMeta (line 412) | protected setBaseRouteMeta(name: BaseRouteName) {
    method setRouteArgs (line 425) | protected setRouteArgs(name: BaseRouteName) {
    method setRouteArgsTypes (line 442) | protected setRouteArgsTypes(name: BaseRouteName) {
    method setInterceptors (line 455) | protected setInterceptors(name: BaseRouteName) {
    method setDecorators (line 467) | protected setDecorators(name: BaseRouteName) {
    method setAction (line 472) | protected setAction(name: BaseRouteName) {
    method setSwaggerOperation (line 476) | protected setSwaggerOperation(name: BaseRouteName) {
    method setSwaggerPathParams (line 482) | protected setSwaggerPathParams(name: BaseRouteName) {
    method setSwaggerQueryParams (line 496) | protected setSwaggerQueryParams(name: BaseRouteName) {
    method setSwaggerResponseOk (line 502) | protected setSwaggerResponseOk(name: BaseRouteName) {
    method routeNameAction (line 509) | protected routeNameAction(name: BaseRouteName): string {

FILE: packages/crud/src/crud/reflection.helper.ts
  class R (line 25) | class R {
    method set (line 26) | static set(metadataKey: any, metadataValue: any, target: unknown, prop...
    method get (line 34) | static get<T extends any>(metadataKey: any, target: unknown, propertyK...
    method createCustomRouteArg (line 40) | static createCustomRouteArg(
    method createRouteArg (line 57) | static createRouteArg(
    method setDecorators (line 73) | static setDecorators(decorators: (PropertyDecorator | MethodDecorator)...
    method setParsedRequestArg (line 86) | static setParsedRequestArg(index: number) {
    method setBodyArg (line 90) | static setBodyArg(index: number, /* istanbul ignore next */ pipes: any...
    method setCrudOptions (line 94) | static setCrudOptions(options: MergedCrudOptions, target: any) {
    method setRoute (line 98) | static setRoute(route: BaseRoute, func: unknown) {
    method setInterceptors (line 103) | static setInterceptors(interceptors: any[], func: unknown) {
    method setRouteArgs (line 107) | static setRouteArgs(metadata: any, target: any, name: string) {
    method setRouteArgsTypes (line 111) | static setRouteArgsTypes(metadata: any, target: any, name: string) {
    method setAction (line 115) | static setAction(action: CrudActions, func: unknown) {
    method setCrudAuthOptions (line 119) | static setCrudAuthOptions(metadata: any, target: any) {
    method getCrudAuthOptions (line 123) | static getCrudAuthOptions(target: any): AuthOptions {
    method getCrudOptions (line 127) | static getCrudOptions(target: any): MergedCrudOptions {
    method getAction (line 131) | static getAction(func: unknown): CrudActions {
    method getOverrideRoute (line 135) | static getOverrideRoute(func: unknown): BaseRouteName {
    method getInterceptors (line 139) | static getInterceptors(func: unknown): any[] {
    method getRouteArgs (line 143) | static getRouteArgs(target: any, name: string): any {
    method getRouteArgsTypes (line 147) | static getRouteArgsTypes(target: any, name: string): any[] {
    method getParsedBody (line 151) | static getParsedBody(func: unknown): any {
    method getContextRequest (line 155) | static getContextRequest(ctx: ArgumentsHost): any {

FILE: packages/crud/src/crud/serialize.helper.ts
  class SerializeHelper (line 5) | class SerializeHelper {
    method createGetManyDto (line 6) | static createGetManyDto(dto: any, resourceName: string): any {
    method createGetOneResponseDto (line 33) | static createGetOneResponseDto(resourceName: string): any {

FILE: packages/crud/src/crud/swagger.helper.ts
  class Swagger (line 18) | class Swagger {
    method operationsMap (line 19) | static operationsMap(modelName: string): { [key in BaseRouteName]: str...
    method setOperation (line 32) | static setOperation(metadata: unknown, func: any): void {
    method setParams (line 39) | static setParams(metadata: unknown, func: any): void {
    method setExtraModels (line 46) | static setExtraModels(swaggerModels: any): void {
    method setResponseOk (line 60) | static setResponseOk(metadata: unknown, func: any): void {
    method getOperation (line 67) | static getOperation(func: any): any {
    method getParams (line 72) | static getParams(func: any): any[] {
    method getExtraModels (line 77) | static getExtraModels(target: unknown): any[] {
    method getResponseOk (line 82) | static getResponseOk(func: any): any {
    method createResponseMeta (line 87) | static createResponseMeta(name: BaseRouteName, options: MergedCrudOpti...
    method createPathParamsMeta (line 237) | static createPathParamsMeta(options: ParamsOptions): any[] {
    method createQueryParamsMeta (line 249) | static createQueryParamsMeta(name: BaseRouteName, options: MergedCrudO...
    method getQueryParamsNames (line 519) | static getQueryParamsNames(): any {
    method getSwaggerVersion (line 543) | private static getSwaggerVersion(): number {
  function ApiProperty (line 549) | function ApiProperty(options?: any): PropertyDecorator {

FILE: packages/crud/src/crud/validation.helper.ts
  class BulkDto (line 11) | class BulkDto<T> implements CreateManyDto<T> {
  class Validation (line 15) | class Validation {
    method getValidationPipe (line 16) | static getValidationPipe(options: CrudOptions, group?: CrudValidationG...
    method createBulkDto (line 25) | static createBulkDto<T = any>(options: MergedCrudOptions): any {

FILE: packages/crud/src/enums/crud-actions.enum.ts
  type CrudActions (line 1) | enum CrudActions {

FILE: packages/crud/src/enums/crud-validation-groups.enum.ts
  type CrudValidationGroups (line 1) | enum CrudValidationGroups {

FILE: packages/crud/src/interceptors/crud-base.interceptor.ts
  class CrudBaseInterceptor (line 6) | class CrudBaseInterceptor {
    method getCrudInfo (line 7) | protected getCrudInfo(

FILE: packages/crud/src/interceptors/crud-request.interceptor.ts
  class CrudRequestInterceptor (line 13) | class CrudRequestInterceptor extends CrudBaseInterceptor implements Nest...
    method intercept (line 14) | intercept(context: ExecutionContext, next: CallHandler) {
    method getCrudRequest (line 43) | getCrudRequest(parser: RequestQueryParser, crudOptions: Partial<Merged...
    method getSearch (line 57) | getSearch(
    method getParamsSearch (line 118) | getParamsSearch(parser: RequestQueryParser, crudOptions: Partial<Merge...
    method getAuth (line 128) | getAuth(parser: RequestQueryParser, crudOptions: Partial<MergedCrudOpt...

FILE: packages/crud/src/interceptors/crud-response.interceptor.ts
  class CrudResponseInterceptor (line 25) | class CrudResponseInterceptor extends CrudBaseInterceptor implements Nes...
    method intercept (line 26) | intercept(context: ExecutionContext, next: CallHandler): Observable<an...
    method transform (line 30) | protected transform(dto: any, data: any, options: ClassTransformOption...
    method serialize (line 44) | protected serialize(context: ExecutionContext, data: any): any {

FILE: packages/crud/src/interfaces/auth-options.interface.ts
  type AuthGlobalOptions (line 5) | interface AuthGlobalOptions {
  type AuthOptions (line 13) | interface AuthOptions {

FILE: packages/crud/src/interfaces/base-route.interface.ts
  type BaseRoute (line 5) | interface BaseRoute {

FILE: packages/crud/src/interfaces/create-many-dto.interface.ts
  type CreateManyDto (line 1) | interface CreateManyDto<T = any> {

FILE: packages/crud/src/interfaces/crud-controller.interface.ts
  type CrudController (line 4) | interface CrudController<T> {

FILE: packages/crud/src/interfaces/crud-global-config.interface.ts
  type CrudGlobalConfig (line 7) | interface CrudGlobalConfig {

FILE: packages/crud/src/interfaces/crud-options.interface.ts
  type CrudRequestOptions (line 12) | interface CrudRequestOptions {
  type CrudOptions (line 18) | interface CrudOptions {
  type MergedCrudOptions (line 29) | interface MergedCrudOptions extends CrudOptions {

FILE: packages/crud/src/interfaces/crud-request.interface.ts
  type CrudRequest (line 5) | interface CrudRequest {

FILE: packages/crud/src/interfaces/dto-options.interface.ts
  type DtoOptions (line 1) | interface DtoOptions {

FILE: packages/crud/src/interfaces/get-many-default-response.interface.ts
  type GetManyDefaultResponse (line 1) | interface GetManyDefaultResponse<T> {

FILE: packages/crud/src/interfaces/model-options.interface.ts
  type ModelOptions (line 1) | interface ModelOptions {

FILE: packages/crud/src/interfaces/params-options.interface.ts
  type ParamsOptions (line 4) | interface ParamsOptions {
  type ParamOption (line 8) | interface ParamOption {

FILE: packages/crud/src/interfaces/query-options.interface.ts
  type QueryOptions (line 8) | interface QueryOptions {
  type JoinOptions (line 22) | interface JoinOptions {
  type JoinOption (line 26) | interface JoinOption {

FILE: packages/crud/src/interfaces/routes-options.interface.ts
  type RoutesOptions (line 3) | interface RoutesOptions {
  type BaseRouteOptions (line 16) | interface BaseRouteOptions {
  type GetManyRouteOptions (line 21) | type GetManyRouteOptions = BaseRouteOptions;
  type GetOneRouteOptions (line 23) | type GetOneRouteOptions = BaseRouteOptions;
  type CreateOneRouteOptions (line 25) | interface CreateOneRouteOptions extends BaseRouteOptions {
  type CreateManyRouteOptions (line 29) | type CreateManyRouteOptions = BaseRouteOptions;
  type ReplaceOneRouteOptions (line 31) | interface ReplaceOneRouteOptions extends BaseRouteOptions {
  type UpdateOneRouteOptions (line 36) | interface UpdateOneRouteOptions extends BaseRouteOptions {
  type DeleteOneRouteOptions (line 41) | interface DeleteOneRouteOptions extends BaseRouteOptions {
  type RecoverOneRouteOptions (line 45) | interface RecoverOneRouteOptions extends BaseRouteOptions {

FILE: packages/crud/src/interfaces/serialize-options.interface.ts
  type SerializeOptions (line 3) | interface SerializeOptions {

FILE: packages/crud/src/module/crud-config.service.ts
  class CrudConfigService (line 7) | class CrudConfigService {
    method load (line 36) | static load(config: CrudGlobalConfig = {}) {

FILE: packages/crud/src/services/crud-service.abstract.ts
  method throwBadRequestException (line 8) | throwBadRequestException(msg?: unknown): BadRequestException {
  method throwNotFoundException (line 12) | throwNotFoundException(name: string): NotFoundException {
  method createPageInfo (line 25) | createPageInfo(data: T[], total: number, limit: number, offset: number):...
  method decidePagination (line 40) | decidePagination(parsed: ParsedRequestParams, options: CrudRequestOption...
  method getTake (line 53) | getTake(query: ParsedRequestParams, options: QueryOptions): number | null {
  method getSkip (line 70) | getSkip(query: ParsedRequestParams, take: number): number | null {
  method getPrimaryParams (line 78) | getPrimaryParams(options: CrudRequestOptions): string[] {

FILE: packages/crud/src/types/base-route-name.type.ts
  type BaseRouteName (line 1) | type BaseRouteName =

FILE: packages/crud/src/types/query-filter-option.type.ts
  type QueryFilterFunction (line 6) | type QueryFilterFunction = (
  type QueryFilterOption (line 10) | type QueryFilterOption = QueryFilter[] | SCondition | QueryFilterFunction;

FILE: packages/crud/src/util.ts
  function safeRequire (line 1) | function safeRequire<T = any>(path: string, loader?: () => T): T | null {

FILE: packages/crud/test/__fixture__/dto/test-create.dto.ts
  class TestCreateDto (line 10) | class TestCreateDto {

FILE: packages/crud/test/__fixture__/dto/test-update.dto.ts
  class TestUpdateDto (line 10) | class TestUpdateDto {

FILE: packages/crud/test/__fixture__/exception.filter.ts
  class HttpExceptionFilter (line 6) | class HttpExceptionFilter implements ExceptionFilter {
    method catch (line 7) | catch(exception: RequestQueryException, host: ArgumentsHost) {

FILE: packages/crud/test/__fixture__/models/test-serialize-2.model.ts
  class TestSerialize2Model (line 5) | class TestSerialize2Model extends TestSerializeModel {
    method constructor (line 15) | constructor(partial: Partial<TestSerialize2Model>) {

FILE: packages/crud/test/__fixture__/models/test-serialize.model.ts
  class TestSerializeModel (line 1) | class TestSerializeModel {
    method constructor (line 10) | constructor(partial: Partial<TestSerializeModel>) {

FILE: packages/crud/test/__fixture__/models/test.model.ts
  class TestModel (line 14) | class TestModel {

FILE: packages/crud/test/__fixture__/response/delete-model-response.dto.ts
  class DeleteModelResponseDto (line 4) | class DeleteModelResponseDto {

FILE: packages/crud/test/__fixture__/response/get-many-model-response.dto.ts
  class GetManyModelResponseDto (line 5) | class GetManyModelResponseDto {

FILE: packages/crud/test/__fixture__/response/get-model-response.dto.ts
  class GetModelResponseDto (line 3) | class GetModelResponseDto {

FILE: packages/crud/test/__fixture__/response/recover-model-response.dto.ts
  class RecoverModelResponseDto (line 3) | class RecoverModelResponseDto {

FILE: packages/crud/test/__fixture__/services/test-serialize.service.ts
  class TestSerializeService (line 8) | class TestSerializeService<T = TestSerializeModel> extends CrudService<T> {
    method constructor (line 11) | constructor(private Model: Type<T>) {
    method getMany (line 22) | async getMany(req: CrudRequest): Promise<GetManyDefaultResponse<T> | T...
    method getOne (line 32) | async getOne(req: CrudRequest): Promise<T> {
    method createOne (line 36) | async createOne(req: CrudRequest, dto: T): Promise<any> {}
    method createMany (line 38) | async createMany(req: CrudRequest, dto: CreateManyDto<T>): Promise<any...
    method updateOne (line 40) | async updateOne(req: CrudRequest, dto: T): Promise<any> {}
    method replaceOne (line 42) | async replaceOne(req: CrudRequest, dto: T): Promise<any> {}
    method deleteOne (line 44) | async deleteOne(req: CrudRequest): Promise<any> {
    method recoverOne (line 48) | async recoverOne(req: CrudRequest): Promise<any> {

FILE: packages/crud/test/__fixture__/services/test.service.ts
  class TestService (line 9) | class TestService<T> extends CrudService<T> {
    method getMany (line 10) | async getMany(req: CrudRequest): Promise<any> {
    method getOne (line 14) | async getOne(req: CrudRequest): Promise<any> {
    method createOne (line 18) | async createOne(req: CrudRequest, dto: T): Promise<any> {
    method createMany (line 22) | async createMany(req: CrudRequest, dto: CreateManyDto<T>): Promise<any> {
    method updateOne (line 26) | async updateOne(req: CrudRequest, dto: T): Promise<any> {
    method replaceOne (line 30) | async replaceOne(req: CrudRequest, dto: T): Promise<any> {
    method deleteOne (line 34) | async deleteOne(req: CrudRequest): Promise<any> {
    method recoverOne (line 38) | async recoverOne(req: CrudRequest): Promise<any> {
    method decidePagination (line 42) | decidePagination(parsed: ParsedRequestParams, options: CrudRequestOpti...

FILE: packages/crud/test/crud-config.service.global.spec.ts
  class GlobalTestController (line 51) | @Crud({
    method constructor (line 56) | constructor(public service: TestService<TestModel>) {}
  class GlobalTestController2 (line 59) | @Crud({
    method constructor (line 85) | constructor(public service: TestService<TestModel>) {}

FILE: packages/crud/test/crud-request.interceptor.spec.ts
  class TestController (line 14) | @UseInterceptors(CrudRequestInterceptor)
    method query (line 18) | async query(@ParsedRequest() req: CrudRequest) {
    method other (line 23) | async other(@Query('page', ParseIntPipe) page: number) {
    method routeWithParam (line 28) | async routeWithParam(@Param('someParam', ParseIntPipe) p: number) {
  class Test2Controller (line 33) | @Crud({
    method constructor (line 41) | constructor(public service: TestService<TestModel>) {}
    method normal (line 45) | async normal(@ParsedRequest() req: CrudRequest) {
    method routeWithParam (line 51) | async routeWithParam(@Param('someParam', ParseIntPipe) p: number) {
    method twoParams (line 57) | async twoParams(@ParsedRequest() req: CrudRequest, @Param('someParam',...
  class Test3Controller (line 62) | @Crud({
    method constructor (line 75) | constructor(public service: TestService<TestModel>) {}
    method get (line 78) | get(@ParsedRequest() req: CrudRequest) {
    method post (line 83) | post(@ParsedRequest() req: CrudRequest) {
  class Test4Controller (line 88) | @Crud({
    method constructor (line 96) | constructor(public service: TestService<TestModel>) {}
    method get (line 99) | get(@ParsedRequest() req: CrudRequest) {
  class Test5Controller (line 104) | @Crud({
    method constructor (line 113) | constructor(public service: TestService<TestModel>) {}
  class Test6Controller (line 116) | @Crud({
    method constructor (line 125) | constructor(public service: TestService<TestModel>) {}
    method get (line 128) | get(@ParsedRequest() req: CrudRequest) {

FILE: packages/crud/test/crud.decorator.base.spec.ts
  class TestController (line 19) | @Crud({
    method constructor (line 24) | constructor(public service: TestService<TestModel>) {}

FILE: packages/crud/test/crud.decorator.exclude.spec.ts
  class TestController (line 16) | @Crud({
    method constructor (line 24) | constructor(public service: TestService<TestModel>) {}
    method constructor (line 67) | constructor(public service: TestService<TestModel>) {}
  class TestController (line 59) | @Crud({
    method constructor (line 24) | constructor(public service: TestService<TestModel>) {}
    method constructor (line 67) | constructor(public service: TestService<TestModel>) {}

FILE: packages/crud/test/crud.decorator.options.spec.ts
  class CustomSwaggerRoutesFactory (line 19) | class CustomSwaggerRoutesFactory extends CrudRoutesFactory {
    method setSwaggerOperation (line 20) | protected setSwaggerOperation(name: BaseRouteName) {
  class TestController (line 75) | @Crud(options)
    method constructor (line 78) | constructor(public service: TestService<TestModel>) {}

FILE: packages/crud/test/crud.decorator.override.spec.ts
  type Field (line 21) | enum Field {
  class TestController (line 25) | @Crud({
    method constructor (line 42) | constructor(public service: TestService<TestModel>) {}
    method base (line 44) | get base(): CrudController<TestModel> {
    method getMany (line 49) | getMany(@ParsedRequest() req: CrudRequest) {
    method createBulk (line 54) | createBulk(@ParsedBody() dto: CreateManyDto<TestModel>, @ParsedRequest...

FILE: packages/crud/test/crud.decorator.soft.spec.ts
  class TestController (line 16) | @Crud({
    method constructor (line 21) | constructor(public service: TestService<TestModel>) {}
    method constructor (line 64) | constructor(public service: TestService<TestModel>) {}
  class TestController (line 56) | @Crud({
    method constructor (line 21) | constructor(public service: TestService<TestModel>) {}
    method constructor (line 64) | constructor(public service: TestService<TestModel>) {}

FILE: packages/crud/test/crud.dto.options.spec.ts
  class TestController (line 17) | @Crud({
    method constructor (line 28) | constructor(public service: TestService<TestModel>) {}

FILE: packages/crud/test/crud.serialize.options.spec.ts
  class TestController (line 26) | @Crud({
    method constructor (line 42) | constructor(@Inject(SERVICE_TOKEN) public service: TestSerializeServic...
  class Test2Controller (line 45) | @Crud({
    method constructor (line 63) | constructor(@Inject(SERVICE2_TOKEN) public service: TestSerializeServi...
  class Test3Controller (line 66) | @Crud({
    method constructor (line 77) | constructor(@Inject(SERVICE2_TOKEN) public service: TestSerializeServi...
    method base (line 79) | get base(): CrudController<TestSerialize2Model> {
    method getMany (line 84) | async getMany(@ParsedRequest() req: CrudRequest) {
  class Test4Controller (line 92) | @Crud({
    method constructor (line 99) | constructor(@Inject(SERVICE2_TOKEN) public service: TestSerializeServi...
  class Test5Controller (line 102) | @Crud({
    method constructor (line 118) | constructor(@Inject(SERVICE2_TOKEN) public service: TestSerializeServi...
  class Test6Controller (line 121) | @Crud({
    method constructor (line 140) | constructor(@Inject(SERVICE_TOKEN) public service: TestSerializeServic...

FILE: packages/crud/test/feature-action.decorator.spec.ts
  class TestClass (line 7) | @Feature(feature)
    method root (line 10) | root() {}

FILE: packages/util/src/types/class.type.ts
  type ClassType (line 1) | type ClassType<T> = {

FILE: packages/util/src/types/object-literal.type.ts
  type ObjectLiteral (line 1) | type ObjectLiteral = {

FILE: packages/util/test/obj.util.spec.ts
  class Parent (line 14) | class Parent {
  class Child (line 17) | class Child extends Parent {
Condensed preview — 201 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (418K chars).
[
  {
    "path": ".eslintignore",
    "chars": 0,
    "preview": ""
  },
  {
    "path": ".eslintrc.js",
    "chars": 1969,
    "preview": "module.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    project: 'tsconfig.eslint.json',\n    so"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 587,
    "preview": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [u"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/Bug_report.md",
    "chars": 961,
    "preview": "---\nname: \"\\U0001F41B Bug Report\"\nabout: \"If something isn't working as expected \\U0001F914.\"\ntitle: ''\nlabels: 'type: p"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/Feature_request.md",
    "chars": 782,
    "preview": "---\nname: \"\\U0001F680 Feature Request\"\nabout: \"I have a suggestion \\U0001F63B!\"\ntitle: ''\nlabels: 'type: enhancement'\nas"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "chars": 973,
    "preview": "## PR Checklist\n\nPlease check if your PR fulfills the following requirements:\n\n- [ ] The commit message was generated by"
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 3972,
    "preview": "name: Release\n\non:\n  pull_request:\n    types: [closed]\n\njobs:\n  release:\n    if: github.event.pull_request.merged && sta"
  },
  {
    "path": ".github/workflows/tests.yml",
    "chars": 990,
    "preview": "name: Tests\n\non:\n  push:\n    branches: [master]\n  pull_request:\n    branches: [master]\n\n  workflow_dispatch:\n\njobs:\n  te"
  },
  {
    "path": ".gitignore",
    "chars": 238,
    "preview": "# dependencies\n/**/node_modules\nyarn-error.log\nnpm-debug.log\n\n# IDE\n/.idea\n/.awcache\n/.vscode\n\n# misc\n.DS_Store\nlerna-de"
  },
  {
    "path": ".husky/pre-commit",
    "chars": 67,
    "preview": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nyarn lint && yarn format\n"
  },
  {
    "path": ".prettierrc.json",
    "chars": 100,
    "preview": "{\n  \"printWidth\": 120,\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\",\n  \"arrowParens\": \"always\"\n}\n"
  },
  {
    "path": ".yarnrc",
    "chars": 15,
    "preview": "save-prefix \"\"\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 8995,
    "preview": "## [4.6.2] - 2020-05-14\n\n### Bug Fixes\n\n- **typeorm** - fixed selected fields on joins [#510](https://github.com/nestjsx"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 3353,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
  },
  {
    "path": "LICENSE",
    "chars": 1103,
    "preview": "(The MIT License)\n\nCopyright (c) 2018-Present Michael Yali <mihon4ik@gmail.com>\n\nPermission is hereby granted, free of c"
  },
  {
    "path": "README.md",
    "chars": 6931,
    "preview": "[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://"
  },
  {
    "path": "docker-compose.yml",
    "chars": 665,
    "preview": "version: '3'\n\nnetworks:\n  nestjsx_crud:\n\nservices:\n  postgres:\n    # TypeORM fails with Postgres v.12\n    image: postgre"
  },
  {
    "path": "integration/crud-typeorm/app.module.ts",
    "chars": 780,
    "preview": "import { Module } from '@nestjs/common';\nimport { APP_GUARD } from '@nestjs/core';\nimport { TypeOrmModule } from '@nestj"
  },
  {
    "path": "integration/crud-typeorm/auth.guard.ts",
    "chars": 482,
    "preview": "import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';\n\nimport { UsersService } from './users';\nimp"
  },
  {
    "path": "integration/crud-typeorm/base-entity.ts",
    "chars": 280,
    "preview": "import { PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn } from 'typeorm';\n\nexport class BaseEntity {\n  @Prim"
  },
  {
    "path": "integration/crud-typeorm/companies/companies.controller.ts",
    "chars": 1031,
    "preview": "import { Controller } from '@nestjs/common';\nimport { ApiTags } from '@nestjs/swagger';\nimport { Crud } from '@nestjsx/c"
  },
  {
    "path": "integration/crud-typeorm/companies/companies.module.ts",
    "chars": 451,
    "preview": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\n\nimport { Company } from './co"
  },
  {
    "path": "integration/crud-typeorm/companies/companies.service.ts",
    "chars": 357,
    "preview": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { TypeOrmCrudSer"
  },
  {
    "path": "integration/crud-typeorm/companies/company.entity.ts",
    "chars": 1579,
    "preview": "import { CrudValidationGroups } from '@nestjsx/crud';\nimport { Entity, Column, OneToMany, PrimaryGeneratedColumn, Delete"
  },
  {
    "path": "integration/crud-typeorm/companies/index.ts",
    "chars": 71,
    "preview": "export * from './company.entity';\nexport * from './companies.service';\n"
  },
  {
    "path": "integration/crud-typeorm/companies/requests/create-company.dto.ts",
    "chars": 397,
    "preview": "import { ApiProperty } from '@nestjs/swagger';\nimport { IsString, MaxLength } from 'class-validator';\n\nexport class Crea"
  },
  {
    "path": "integration/crud-typeorm/companies/requests/index.ts",
    "chars": 110,
    "preview": "import { CreateCompanyDto } from './create-company.dto';\n\nexport const dto = {\n  create: CreateCompanyDto,\n};\n"
  },
  {
    "path": "integration/crud-typeorm/companies/responses/get-company-response.dto.ts",
    "chars": 410,
    "preview": "import { ApiProperty } from '@nestjs/swagger';\nimport { Exclude } from 'class-transformer';\n\nexport class GetCompanyResp"
  },
  {
    "path": "integration/crud-typeorm/companies/responses/index.ts",
    "chars": 197,
    "preview": "import { SerializeOptions } from '@nestjsx/crud';\nimport { GetCompanyResponseDto } from './get-company-response.dto';\n\ne"
  },
  {
    "path": "integration/crud-typeorm/constants.ts",
    "chars": 40,
    "preview": "export const USER_REQUEST_KEY = 'user';\n"
  },
  {
    "path": "integration/crud-typeorm/devices/device.entity.ts",
    "chars": 529,
    "preview": "import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';\nimport { IsOptional, IsString, IsUUID } from 'class-va"
  },
  {
    "path": "integration/crud-typeorm/devices/devices.controller.ts",
    "chars": 621,
    "preview": "import { Controller } from '@nestjs/common';\nimport { ApiTags } from '@nestjs/swagger';\nimport { Crud } from '@nestjsx/c"
  },
  {
    "path": "integration/crud-typeorm/devices/devices.module.ts",
    "chars": 432,
    "preview": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\n\nimport { Device } from './dev"
  },
  {
    "path": "integration/crud-typeorm/devices/devices.service.ts",
    "chars": 351,
    "preview": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { TypeOrmCrudSer"
  },
  {
    "path": "integration/crud-typeorm/devices/index.ts",
    "chars": 68,
    "preview": "export * from './device.entity';\nexport * from './devices.service';\n"
  },
  {
    "path": "integration/crud-typeorm/devices/response/delete-device-response.dto.ts",
    "chars": 228,
    "preview": "import { ApiProperty } from '@nestjs/swagger';\nimport { Exclude } from 'class-transformer';\n\nexport class DeleteDeviceRe"
  },
  {
    "path": "integration/crud-typeorm/devices/response/index.ts",
    "chars": 206,
    "preview": "import { SerializeOptions } from '@nestjsx/crud';\nimport { DeleteDeviceResponseDto } from './delete-device-response.dto'"
  },
  {
    "path": "integration/crud-typeorm/main.ts",
    "chars": 1048,
    "preview": "import { NestFactory } from '@nestjs/core';\nimport { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';\nimport { C"
  },
  {
    "path": "integration/crud-typeorm/notes/index.ts",
    "chars": 64,
    "preview": "export * from './note.entity';\nexport * from './notes.service';\n"
  },
  {
    "path": "integration/crud-typeorm/notes/note.entity.ts",
    "chars": 223,
    "preview": "import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';\n\n@Entity('notes')\nexport class Note {\n  @PrimaryGenera"
  },
  {
    "path": "integration/crud-typeorm/notes/notes.controller.ts",
    "chars": 507,
    "preview": "import { Controller } from '@nestjs/common';\nimport { ApiTags } from '@nestjs/swagger';\nimport { Crud } from '@nestjsx/c"
  },
  {
    "path": "integration/crud-typeorm/notes/notes.module.ts",
    "chars": 410,
    "preview": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\n\nimport { Note } from './note."
  },
  {
    "path": "integration/crud-typeorm/notes/notes.service.ts",
    "chars": 354,
    "preview": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { TypeOrmCrudSer"
  },
  {
    "path": "integration/crud-typeorm/notes/requests/create-note.dto.ts",
    "chars": 194,
    "preview": "import { ApiProperty } from '@nestjs/swagger';\nimport { IsNumber } from 'class-validator';\n\nexport class CreateNoteDto {"
  },
  {
    "path": "integration/crud-typeorm/notes/requests/index.ts",
    "chars": 101,
    "preview": "import { CreateNoteDto } from './create-note.dto';\n\nexport const dto = {\n  create: CreateNoteDto,\n};\n"
  },
  {
    "path": "integration/crud-typeorm/notes/responses/get-note-response.dto.ts",
    "chars": 263,
    "preview": "import { ApiProperty } from '@nestjs/swagger';\nimport { IsNumber } from 'class-validator';\n\nexport class GetNoteResponse"
  },
  {
    "path": "integration/crud-typeorm/notes/responses/index.ts",
    "chars": 120,
    "preview": "import { GetNoteResponseDto } from './get-note-response.dto';\n\nexport const serialize = {\n  get: GetNoteResponseDto,\n};\n"
  },
  {
    "path": "integration/crud-typeorm/orm.config.ts",
    "chars": 638,
    "preview": "import { join } from 'path';\nimport { TypeOrmModuleOptions } from '@nestjs/typeorm';\nimport { isNil } from '@nestjsx/uti"
  },
  {
    "path": "integration/crud-typeorm/orm.mysql.ts",
    "chars": 319,
    "preview": "import { DataSource } from 'typeorm';\n\nexports.default = new DataSource({\n  type: 'mysql',\n  host: '127.0.0.1',\n  port: "
  },
  {
    "path": "integration/crud-typeorm/orm.postgres.ts",
    "chars": 306,
    "preview": "import { DataSource } from 'typeorm';\n\nexports.default = new DataSource({\n  type: 'postgres',\n  host: '127.0.0.1',\n  por"
  },
  {
    "path": "integration/crud-typeorm/orm.yaml",
    "chars": 451,
    "preview": "default:\n  type: postgres\n  host: 127.0.0.1\n  port: 5455\n  username: root\n  password: root\n  database: nestjsx_crud\n  en"
  },
  {
    "path": "integration/crud-typeorm/projects/index.ts",
    "chars": 109,
    "preview": "export * from './project.entity';\nexport * from './user-project.entity';\nexport * from './projects.service';\n"
  },
  {
    "path": "integration/crud-typeorm/projects/my-projects.controller.ts",
    "chars": 812,
    "preview": "import { Controller } from '@nestjs/common';\nimport { ApiTags } from '@nestjs/swagger';\nimport { Crud, CrudAuth } from '"
  },
  {
    "path": "integration/crud-typeorm/projects/project.entity.ts",
    "chars": 1701,
    "preview": "import { Entity, Column, ManyToOne, ManyToMany, JoinTable, OneToMany } from 'typeorm';\nimport {\n  IsOptional,\n  IsString"
  },
  {
    "path": "integration/crud-typeorm/projects/projects.controller.ts",
    "chars": 645,
    "preview": "import { Controller } from '@nestjs/common';\nimport { ApiTags } from '@nestjs/swagger';\nimport { Crud } from '@nestjsx/c"
  },
  {
    "path": "integration/crud-typeorm/projects/projects.module.ts",
    "chars": 701,
    "preview": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\n\nimport { Project } from './pr"
  },
  {
    "path": "integration/crud-typeorm/projects/projects.service.ts",
    "chars": 356,
    "preview": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { TypeOrmCrudSer"
  },
  {
    "path": "integration/crud-typeorm/projects/user-project.entity.ts",
    "chars": 604,
    "preview": "import { Entity, Column, ManyToOne, PrimaryColumn } from 'typeorm';\n\nimport { User } from '../users/user.entity';\nimport"
  },
  {
    "path": "integration/crud-typeorm/projects/user-projects.service.ts",
    "chars": 377,
    "preview": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { TypeOrmCrudSer"
  },
  {
    "path": "integration/crud-typeorm/seeds.ts",
    "chars": 7312,
    "preview": "import { ClassType } from '@nestjsx/util';\nimport { plainToClass } from 'class-transformer';\nimport { MigrationInterface"
  },
  {
    "path": "integration/crud-typeorm/users/index.ts",
    "chars": 64,
    "preview": "export * from './user.entity';\nexport * from './users.service';\n"
  },
  {
    "path": "integration/crud-typeorm/users/me.controller.ts",
    "chars": 710,
    "preview": "import { Controller } from '@nestjs/common';\nimport { ApiTags } from '@nestjs/swagger';\nimport { Crud, CrudAuth } from '"
  },
  {
    "path": "integration/crud-typeorm/users/user.entity.ts",
    "chars": 2425,
    "preview": "import {\n  Entity,\n  Column,\n  JoinColumn,\n  OneToOne,\n  OneToMany,\n  ManyToOne,\n  ManyToMany,\n  DeleteDateColumn,\n} fro"
  },
  {
    "path": "integration/crud-typeorm/users/users.controller.ts",
    "chars": 1127,
    "preview": "import { Controller } from '@nestjs/common';\nimport { ApiTags } from '@nestjs/swagger';\nimport {\n  Crud,\n  CrudControlle"
  },
  {
    "path": "integration/crud-typeorm/users/users.module.ts",
    "chars": 554,
    "preview": "import { Module } from '@nestjs/common';\nimport { TypeOrmModule } from '@nestjs/typeorm';\n\nimport { User } from './user."
  },
  {
    "path": "integration/crud-typeorm/users/users.service.ts",
    "chars": 341,
    "preview": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\nimport { TypeOrmCrudSer"
  },
  {
    "path": "integration/crud-typeorm/users-licenses/index.ts",
    "chars": 73,
    "preview": "export * from './license.entity';\nexport * from './user-license.entity';\n"
  },
  {
    "path": "integration/crud-typeorm/users-licenses/license.entity.ts",
    "chars": 406,
    "preview": "import { Column, Entity } from 'typeorm';\nimport { BaseEntity } from '../base-entity';\nimport { IsOptional, IsString, Ma"
  },
  {
    "path": "integration/crud-typeorm/users-licenses/user-license.entity.ts",
    "chars": 510,
    "preview": "import { Column, Entity, ManyToOne, PrimaryColumn } from 'typeorm';\nimport { User } from '../users/user.entity';\nimport "
  },
  {
    "path": "integration/crud-typeorm/users-profiles/index.ts",
    "chars": 39,
    "preview": "export * from './user-profile.entity';\n"
  },
  {
    "path": "integration/crud-typeorm/users-profiles/user-profile.entity.ts",
    "chars": 640,
    "preview": "import { Entity, Column, OneToOne, DeleteDateColumn } from 'typeorm';\nimport { IsOptional, IsString, MaxLength } from 'c"
  },
  {
    "path": "integration/shared/https-exception.filter.ts",
    "chars": 908,
    "preview": "import { ExceptionFilter, Catch, ArgumentsHost } from '@nestjs/common';\nimport { HttpException, InternalServerErrorExcep"
  },
  {
    "path": "jest.config.js",
    "chars": 996,
    "preview": "/* eslint-disable @typescript-eslint/no-var-requires */\n\nconst tsconfig = require('tsconfig-extends');\nconst { pathsToMo"
  },
  {
    "path": "lerna.json",
    "chars": 196,
    "preview": "{\n  \"packages\": [\n    \"packages/*\"\n  ],\n  \"npmClient\": \"yarn\",\n  \"useWorkspaces\": true,\n  \"version\": \"5.0.0-alpha.3\",\n  "
  },
  {
    "path": "mrepo.json",
    "chars": 590,
    "preview": "{\n  \"workspace\": {\n    \"name\": \"packages\",\n    \"scope\": \"nestjsx\",\n    \"registry\": \"npm\",\n    \"packages\": [\n      {\n    "
  },
  {
    "path": "package.json",
    "chars": 3704,
    "preview": "{\n  \"name\": \"@nestjsx/crud\",\n  \"version\": \"4.0.0\",\n  \"description\": \"Nest CRUD for RESTful APIs\",\n  \"license\": \"MIT\",\n  "
  },
  {
    "path": "packages/crud/README.md",
    "chars": 7021,
    "preview": "<div align=\"center\">\n  <h1>CRUD (@nestjsx/crud)</h1>\n</div>\n<div align=\"center\">\n  <strong>for RESTful APIs built with N"
  },
  {
    "path": "packages/crud/package.json",
    "chars": 984,
    "preview": "{\n  \"name\": \"@nestjsx/crud\",\n  \"description\": \"NestJs CRUD for RESTful APIs\",\n  \"version\": \"5.0.0-alpha.3\",\n  \"license\":"
  },
  {
    "path": "packages/crud/src/constants.ts",
    "chars": 508,
    "preview": "export const FEAUTURE_NAME_METADATA = 'NESTJSX_FEAUTURE_NAME_METADATA';\nexport const ACTION_NAME_METADATA = 'NESTJSX_ACT"
  },
  {
    "path": "packages/crud/src/crud/crud-routes.factory.ts",
    "chars": 18061,
    "preview": "import { RequestMethod } from '@nestjs/common';\nimport { RouteParamtypes } from '@nestjs/common/enums/route-paramtypes.e"
  },
  {
    "path": "packages/crud/src/crud/index.ts",
    "chars": 147,
    "preview": "export * from './crud-routes.factory';\nexport * from './reflection.helper';\nexport * from './swagger.helper';\nexport * f"
  },
  {
    "path": "packages/crud/src/crud/reflection.helper.ts",
    "chars": 4560,
    "preview": "import { RouteParamtypes } from '@nestjs/common/enums/route-paramtypes.enum';\nimport {\n  CUSTOM_ROUTE_AGRS_METADATA,\n  I"
  },
  {
    "path": "packages/crud/src/crud/serialize.helper.ts",
    "chars": 1092,
    "preview": "import { Type } from 'class-transformer';\nimport { GetManyDefaultResponse } from '../interfaces';\nimport { ApiProperty }"
  },
  {
    "path": "packages/crud/src/crud/swagger.helper.ts",
    "chars": 16094,
    "preview": "import { HttpStatus } from '@nestjs/common';\nimport { RequestQueryBuilder } from '@nestjsx/crud-request';\nimport { isStr"
  },
  {
    "path": "packages/crud/src/crud/validation.helper.ts",
    "chars": 1989,
    "preview": "import { ValidationPipe } from '@nestjs/common';\nimport { isFalse, isNil } from '@nestjsx/util';\nimport { CrudValidation"
  },
  {
    "path": "packages/crud/src/decorators/crud-auth.decorator.ts",
    "chars": 224,
    "preview": "import { R } from '../crud/reflection.helper';\nimport { AuthOptions } from '../interfaces';\n\nexport const CrudAuth =\n  ("
  },
  {
    "path": "packages/crud/src/decorators/crud.decorator.ts",
    "chars": 301,
    "preview": "import { CrudRoutesFactory } from '../crud';\nimport { CrudOptions } from '../interfaces';\n\nexport const Crud =\n  (option"
  },
  {
    "path": "packages/crud/src/decorators/feature-action.decorator.ts",
    "chars": 503,
    "preview": "import { SetMetadata, Type } from '@nestjs/common';\n\nimport { ACTION_NAME_METADATA, FEAUTURE_NAME_METADATA } from '../co"
  },
  {
    "path": "packages/crud/src/decorators/index.ts",
    "chars": 240,
    "preview": "export * from './crud.decorator';\nexport * from './crud-auth.decorator';\nexport * from './override.decorator';\nexport * "
  },
  {
    "path": "packages/crud/src/decorators/override.decorator.ts",
    "chars": 342,
    "preview": "import { BaseRouteName } from '../types/base-route-name.type';\nimport { OVERRIDE_METHOD_METADATA } from '../constants';\n"
  },
  {
    "path": "packages/crud/src/decorators/parsed-body.decorator.ts",
    "chars": 187,
    "preview": "import { PARSED_BODY_METADATA } from '../constants';\n\nexport const ParsedBody = () => (target, key, index) => {\n  Reflec"
  },
  {
    "path": "packages/crud/src/decorators/parsed-request.decorator.ts",
    "chars": 317,
    "preview": "import { createParamDecorator } from '@nestjs/common';\n\nimport { PARSED_CRUD_REQUEST_KEY } from '../constants';\nimport {"
  },
  {
    "path": "packages/crud/src/enums/crud-actions.enum.ts",
    "chars": 278,
    "preview": "export enum CrudActions {\n  ReadAll = 'Read-All',\n  ReadOne = 'Read-One',\n  CreateOne = 'Create-One',\n  CreateMany = 'Cr"
  },
  {
    "path": "packages/crud/src/enums/crud-validation-groups.enum.ts",
    "chars": 89,
    "preview": "export enum CrudValidationGroups {\n  CREATE = 'CRUD-CREATE',\n  UPDATE = 'CRUD-UPDATE',\n}\n"
  },
  {
    "path": "packages/crud/src/enums/index.ts",
    "chars": 84,
    "preview": "export * from './crud-actions.enum';\nexport * from './crud-validation-groups.enum';\n"
  },
  {
    "path": "packages/crud/src/index.ts",
    "chars": 240,
    "preview": "export * from './crud/crud-routes.factory';\nexport * from './decorators';\nexport * from './enums';\nexport * from './inte"
  },
  {
    "path": "packages/crud/src/interceptors/crud-base.interceptor.ts",
    "chars": 766,
    "preview": "import { ExecutionContext } from '@nestjs/common';\nimport { R } from '../crud/reflection.helper';\nimport { CrudActions }"
  },
  {
    "path": "packages/crud/src/interceptors/crud-request.interceptor.ts",
    "chars": 5613,
    "preview": "import { BadRequestException, CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';\nimport"
  },
  {
    "path": "packages/crud/src/interceptors/crud-response.interceptor.ts",
    "chars": 2935,
    "preview": "import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';\nimport { isFalse, isObject,"
  },
  {
    "path": "packages/crud/src/interceptors/index.ts",
    "chars": 89,
    "preview": "export * from './crud-request.interceptor';\nexport * from './crud-response.interceptor';\n"
  },
  {
    "path": "packages/crud/src/interfaces/auth-options.interface.ts",
    "chars": 911,
    "preview": "import { SCondition } from '@nestjsx/crud-request/lib/types/request-query.types';\nimport { ObjectLiteral } from '@nestjs"
  },
  {
    "path": "packages/crud/src/interfaces/base-route.interface.ts",
    "chars": 250,
    "preview": "import { RequestMethod } from '@nestjs/common';\n\nimport { BaseRouteName } from '../types';\n\nexport interface BaseRoute {"
  },
  {
    "path": "packages/crud/src/interfaces/create-many-dto.interface.ts",
    "chars": 57,
    "preview": "export interface CreateManyDto<T = any> {\n  bulk: T[];\n}\n"
  },
  {
    "path": "packages/crud/src/interfaces/crud-controller.interface.ts",
    "chars": 669,
    "preview": "import { CrudService } from '../services';\nimport { CrudRequest, GetManyDefaultResponse, CreateManyDto } from '../interf"
  },
  {
    "path": "packages/crud/src/interfaces/crud-global-config.interface.ts",
    "chars": 743,
    "preview": "import { RequestQueryBuilderOptions } from '@nestjsx/crud-request';\n\nimport { RoutesOptions } from './routes-options.int"
  },
  {
    "path": "packages/crud/src/interfaces/crud-options.interface.ts",
    "chars": 988,
    "preview": "import { ValidationPipeOptions } from '@nestjs/common';\n\nimport { CrudRoutesFactory } from '../crud';\nimport { ModelOpti"
  },
  {
    "path": "packages/crud/src/interfaces/crud-request.interface.ts",
    "chars": 210,
    "preview": "import { ParsedRequestParams } from '@nestjsx/crud-request';\n\nimport { CrudRequestOptions } from '../interfaces';\n\nexpor"
  },
  {
    "path": "packages/crud/src/interfaces/dto-options.interface.ts",
    "chars": 81,
    "preview": "export interface DtoOptions {\n  create?: any;\n  update?: any;\n  replace?: any;\n}\n"
  },
  {
    "path": "packages/crud/src/interfaces/get-many-default-response.interface.ts",
    "chars": 131,
    "preview": "export interface GetManyDefaultResponse<T> {\n  data: T[];\n  count: number;\n  total: number;\n  page: number;\n  pageCount:"
  },
  {
    "path": "packages/crud/src/interfaces/index.ts",
    "chars": 621,
    "preview": "export * from './crud-controller.interface';\nexport * from './crud-options.interface';\nexport * from './auth-options.int"
  },
  {
    "path": "packages/crud/src/interfaces/model-options.interface.ts",
    "chars": 47,
    "preview": "export interface ModelOptions {\n  type: any;\n}\n"
  },
  {
    "path": "packages/crud/src/interfaces/params-options.interface.ts",
    "chars": 350,
    "preview": "import { SwaggerEnumType } from '@nestjs/swagger/dist/types/swagger-enum.type';\nimport { ParamOptionType } from '@nestjs"
  },
  {
    "path": "packages/crud/src/interfaces/query-options.interface.ts",
    "chars": 691,
    "preview": "import {\n  QueryFields,\n  QuerySort,\n} from '@nestjsx/crud-request/lib/types/request-query.types';\n\nimport { QueryFilter"
  },
  {
    "path": "packages/crud/src/interfaces/routes-options.interface.ts",
    "chars": 1287,
    "preview": "import { BaseRouteName } from '../types';\n\nexport interface RoutesOptions {\n  exclude?: BaseRouteName[];\n  only?: BaseRo"
  },
  {
    "path": "packages/crud/src/interfaces/serialize-options.interface.ts",
    "chars": 322,
    "preview": "import { Type } from '@nestjs/common';\n\nexport interface SerializeOptions {\n  getMany?: Type<any> | false;\n  get?: Type<"
  },
  {
    "path": "packages/crud/src/module/crud-config.service.ts",
    "chars": 1769,
    "preview": "import { RequestQueryBuilder } from '@nestjsx/crud-request';\nimport { isObjectFull } from '@nestjsx/util';\nimport * as d"
  },
  {
    "path": "packages/crud/src/module/index.ts",
    "chars": 39,
    "preview": "export * from './crud-config.service';\n"
  },
  {
    "path": "packages/crud/src/services/crud-service.abstract.ts",
    "chars": 3162,
    "preview": "import { BadRequestException, NotFoundException } from '@nestjs/common';\nimport { ParsedRequestParams } from '@nestjsx/c"
  },
  {
    "path": "packages/crud/src/services/index.ts",
    "chars": 41,
    "preview": "export * from './crud-service.abstract';\n"
  },
  {
    "path": "packages/crud/src/types/base-route-name.type.ts",
    "chars": 187,
    "preview": "export type BaseRouteName =\n  | 'getManyBase'\n  | 'getOneBase'\n  | 'createOneBase'\n  | 'createManyBase'\n  | 'updateOneBa"
  },
  {
    "path": "packages/crud/src/types/index.ts",
    "chars": 84,
    "preview": "export * from './base-route-name.type';\nexport * from './query-filter-option.type';\n"
  },
  {
    "path": "packages/crud/src/types/query-filter-option.type.ts",
    "chars": 287,
    "preview": "import {\n  QueryFilter,\n  SCondition,\n} from '@nestjsx/crud-request/lib/types/request-query.types';\n\nexport type QueryFi"
  },
  {
    "path": "packages/crud/src/util.ts",
    "chars": 259,
    "preview": "export function safeRequire<T = any>(path: string, loader?: () => T): T | null {\n  try {\n    /* istanbul ignore next */\n"
  },
  {
    "path": "packages/crud/test/__fixture__/dto/index.ts",
    "chars": 70,
    "preview": "export * from './test-create.dto';\nexport * from './test-update.dto';\n"
  },
  {
    "path": "packages/crud/test/__fixture__/dto/test-create.dto.ts",
    "chars": 294,
    "preview": "import {\n  IsString,\n  IsEmail,\n  IsNumber,\n  IsOptional,\n  IsNotEmpty,\n  IsEmpty,\n} from 'class-validator';\n\nexport cla"
  },
  {
    "path": "packages/crud/test/__fixture__/dto/test-update.dto.ts",
    "chars": 362,
    "preview": "import {\n  IsString,\n  IsEmail,\n  IsNumber,\n  IsOptional,\n  IsNotEmpty,\n  IsEmpty,\n} from 'class-validator';\n\nexport cla"
  },
  {
    "path": "packages/crud/test/__fixture__/exception.filter.ts",
    "chars": 570,
    "preview": "import { ArgumentsHost, Catch, ExceptionFilter, HttpStatus } from '@nestjs/common';\nimport { RequestQueryException } fro"
  },
  {
    "path": "packages/crud/test/__fixture__/models/index.ts",
    "chars": 112,
    "preview": "export * from './test.model';\nexport * from './test-serialize.model';\nexport * from './test-serialize-2.model';\n"
  },
  {
    "path": "packages/crud/test/__fixture__/models/test-serialize-2.model.ts",
    "chars": 370,
    "preview": "import { Exclude } from 'class-transformer';\n\nimport { TestSerializeModel } from './test-serialize.model';\n\nexport class"
  },
  {
    "path": "packages/crud/test/__fixture__/models/test-serialize.model.ts",
    "chars": 200,
    "preview": "export class TestSerializeModel {\n  id: number;\n\n  name: string;\n\n  email: string;\n\n  isActive: boolean;\n\n  constructor("
  },
  {
    "path": "packages/crud/test/__fixture__/models/test.model.ts",
    "chars": 843,
    "preview": "import {\n  IsString,\n  IsEmail,\n  IsNumber,\n  IsOptional,\n  IsNotEmpty,\n  IsEmpty,\n} from 'class-validator';\n\nimport { C"
  },
  {
    "path": "packages/crud/test/__fixture__/response/delete-model-response.dto.ts",
    "chars": 131,
    "preview": "import { Exclude, Expose } from 'class-transformer';\n\n@Exclude()\nexport class DeleteModelResponseDto {\n  @Expose()\n  id:"
  },
  {
    "path": "packages/crud/test/__fixture__/response/get-many-model-response.dto.ts",
    "chars": 216,
    "preview": "import { Type } from 'class-transformer';\n\nimport { GetModelResponseDto } from './get-model-response.dto';\n\nexport class"
  },
  {
    "path": "packages/crud/test/__fixture__/response/get-model-response.dto.ts",
    "chars": 167,
    "preview": "import { Exclude } from 'class-transformer';\n\nexport class GetModelResponseDto {\n  id: number;\n\n  name: string;\n\n  @Excl"
  },
  {
    "path": "packages/crud/test/__fixture__/response/index.ts",
    "chars": 180,
    "preview": "export * from './get-many-model-response.dto';\nexport * from './get-model-response.dto';\nexport * from './delete-model-r"
  },
  {
    "path": "packages/crud/test/__fixture__/response/recover-model-response.dto.ts",
    "chars": 158,
    "preview": "import { Exclude } from 'class-transformer';\n\nexport class RecoverModelResponseDto {\n  id: number;\n\n  name: string;\n\n  e"
  },
  {
    "path": "packages/crud/test/__fixture__/services/index.ts",
    "chars": 74,
    "preview": "export * from './test.service';\nexport * from './test-serialize.service';\n"
  },
  {
    "path": "packages/crud/test/__fixture__/services/test-serialize.service.ts",
    "chars": 1889,
    "preview": "import { Injectable, Type } from '@nestjs/common';\n\nimport { CreateManyDto, CrudRequest, GetManyDefaultResponse } from '"
  },
  {
    "path": "packages/crud/test/__fixture__/services/test.service.ts",
    "chars": 1152,
    "preview": "import { Injectable } from '@nestjs/common';\nimport { ParsedRequestParams } from '@nestjsx/crud-request';\nimport { CrudR"
  },
  {
    "path": "packages/crud/test/crud-config.service.global.spec.ts",
    "chars": 4226,
    "preview": "import * as request from 'supertest';\nimport { Test } from '@nestjs/testing';\nimport { Controller, INestApplication } fr"
  },
  {
    "path": "packages/crud/test/crud-config.service.spec.ts",
    "chars": 3599,
    "preview": "import { RequestQueryBuilder } from '@nestjsx/crud-request';\nimport { CrudGlobalConfig } from '../src/interfaces';\nimpor"
  },
  {
    "path": "packages/crud/test/crud-request.interceptor.spec.ts",
    "chars": 8292,
    "preview": "import { Controller, Get, Param, ParseIntPipe, Query, UseInterceptors } from '@nestjs/common';\nimport { NestApplication "
  },
  {
    "path": "packages/crud/test/crud-service.abstract.spec.ts",
    "chars": 1457,
    "preview": "import { BadRequestException, NotFoundException } from '@nestjs/common';\n\nimport { TestService } from './__fixture__/ser"
  },
  {
    "path": "packages/crud/test/crud.decorator.base.spec.ts",
    "chars": 6569,
    "preview": "import * as request from 'supertest';\nimport { Test } from '@nestjs/testing';\nimport { Controller, INestApplication } fr"
  },
  {
    "path": "packages/crud/test/crud.decorator.exclude.spec.ts",
    "chars": 2694,
    "preview": "import * as request from 'supertest';\nimport { Test } from '@nestjs/testing';\nimport { Controller, INestApplication } fr"
  },
  {
    "path": "packages/crud/test/crud.decorator.options.spec.ts",
    "chars": 3360,
    "preview": "import * as request from 'supertest';\nimport { Test } from '@nestjs/testing';\nimport { Controller, INestApplication } fr"
  },
  {
    "path": "packages/crud/test/crud.decorator.override.spec.ts",
    "chars": 5897,
    "preview": "import * as request from 'supertest';\nimport { Test } from '@nestjs/testing';\nimport { Controller, INestApplication } fr"
  },
  {
    "path": "packages/crud/test/crud.decorator.soft.spec.ts",
    "chars": 2458,
    "preview": "import * as request from 'supertest';\nimport { Test } from '@nestjs/testing';\nimport { Controller, INestApplication } fr"
  },
  {
    "path": "packages/crud/test/crud.dto.options.spec.ts",
    "chars": 2969,
    "preview": "import * as request from 'supertest';\nimport { Test } from '@nestjs/testing';\nimport { Controller, INestApplication } fr"
  },
  {
    "path": "packages/crud/test/crud.serialize.options.spec.ts",
    "chars": 8459,
    "preview": "import * as request from 'supertest';\nimport { Test } from '@nestjs/testing';\nimport { Controller, INestApplication, Inj"
  },
  {
    "path": "packages/crud/test/feature-action.decorator.spec.ts",
    "chars": 611,
    "preview": "import { Feature, Action, getFeature, getAction } from '../src/decorators';\n\ndescribe('#crud', () => {\n  const feature ="
  },
  {
    "path": "packages/crud/tsconfig.json",
    "chars": 225,
    "preview": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"rootDir\": \"src\",\n    \"outDir\": \"lib\"\n  },\n  \"include\":"
  },
  {
    "path": "packages/crud-request/README.md",
    "chars": 7003,
    "preview": "<div align=\"center\">\n  <h1>CRUD (@nestjsx/crud-request)</h1>\n</div>\n<div align=\"center\">\n  <strong>for RESTful APIs buil"
  },
  {
    "path": "packages/crud-request/package.json",
    "chars": 989,
    "preview": "{\n  \"name\": \"@nestjsx/crud-request\",\n  \"description\": \"NestJs CRUD for RESTful APIs - request query builder\",\n  \"version"
  },
  {
    "path": "packages/crud-request/src/exceptions/index.ts",
    "chars": 43,
    "preview": "export * from './request-query.exception';\n"
  },
  {
    "path": "packages/crud-request/src/exceptions/request-query.exception.ts",
    "chars": 102,
    "preview": "export class RequestQueryException extends Error {\n  constructor(msg: string) {\n    super(msg);\n  }\n}\n"
  },
  {
    "path": "packages/crud-request/src/index.ts",
    "chars": 166,
    "preview": "export * from './exceptions';\nexport * from './request-query.builder';\nexport * from './request-query.parser';\nexport * "
  },
  {
    "path": "packages/crud-request/src/interfaces/create-query-params.interface.ts",
    "chars": 632,
    "preview": "import {\n  QueryFields,\n  QueryFilter,\n  QueryFilterArr,\n  QueryJoin,\n  QueryJoinArr,\n  QuerySort,\n  QuerySortArr,\n  SCo"
  },
  {
    "path": "packages/crud-request/src/interfaces/index.ts",
    "chars": 196,
    "preview": "export * from './request-query-builder-options.interface';\nexport * from './params-options.interface';\nexport * from './"
  },
  {
    "path": "packages/crud-request/src/interfaces/params-options.interface.ts",
    "chars": 231,
    "preview": "import { ParamOptionType } from '../types';\n\nexport interface ParamsOptions {\n  [key: string]: ParamOption;\n}\n\nexport in"
  },
  {
    "path": "packages/crud-request/src/interfaces/parsed-request.interface.ts",
    "chars": 571,
    "preview": "import { ObjectLiteral } from '@nestjsx/util';\nimport { ClassTransformOptions } from 'class-transformer';\nimport { Query"
  },
  {
    "path": "packages/crud-request/src/interfaces/request-query-builder-options.interface.ts",
    "chars": 460,
    "preview": "export interface RequestQueryBuilderOptions {\n  delim?: string;\n  delimStr?: string;\n  paramNamesMap?: {\n    fields?: st"
  },
  {
    "path": "packages/crud-request/src/request-query.builder.ts",
    "chars": 6891,
    "preview": "import { hasValue, isObject, isString, isArrayFull, isNil, isUndefined } from '@nestjsx/util';\nimport { stringify } from"
  },
  {
    "path": "packages/crud-request/src/request-query.parser.ts",
    "chars": 8823,
    "preview": "import {\n  hasLength,\n  hasValue,\n  isString,\n  isArrayFull,\n  isDate,\n  isDateString,\n  isObject,\n  isStringFull,\n  obj"
  },
  {
    "path": "packages/crud-request/src/request-query.validator.ts",
    "chars": 3327,
    "preview": "import { isUndefined, isArrayStrings, isStringFull, isObject, isEqual, isNumber, isNil, objKeys } from '@nestjsx/util';\n"
  },
  {
    "path": "packages/crud-request/src/types/index.ts",
    "chars": 78,
    "preview": "export * from './request-query.types';\nexport * from './request-param.types';\n"
  },
  {
    "path": "packages/crud-request/src/types/request-param.types.ts",
    "chars": 60,
    "preview": "export type ParamOptionType = 'number' | 'string' | 'uuid';\n"
  },
  {
    "path": "packages/crud-request/src/types/request-query.types.ts",
    "chars": 2512,
    "preview": "export type QueryFields = string[];\n\nexport type QueryFilter = {\n  field: string;\n  operator: ComparisonOperator;\n  valu"
  },
  {
    "path": "packages/crud-request/test/request-query.builder.spec.ts",
    "chars": 14500,
    "preview": "import 'jest-extended';\nimport { RequestQueryBuilder } from '../src/request-query.builder';\nimport { RequestQueryExcepti"
  },
  {
    "path": "packages/crud-request/test/request-query.parser.spec.ts",
    "chars": 19857,
    "preview": "import 'jest-extended';\nimport { RequestQueryException } from '../src/exceptions/request-query.exception';\nimport { Para"
  },
  {
    "path": "packages/crud-request/test/request.query.validator.spec.ts",
    "chars": 671,
    "preview": "import { validateUUID } from '../src/request-query.validator';\n\ndescribe('#request-query', () => {\n  describe('#validato"
  },
  {
    "path": "packages/crud-request/tsconfig.json",
    "chars": 194,
    "preview": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"rootDir\": \"src\",\n    \"outDir\": \"lib\"\n  },\n  \"include\":"
  },
  {
    "path": "packages/crud-typeorm/README.md",
    "chars": 7027,
    "preview": "<div align=\"center\">\n  <h1>CRUD (@nestjsx/crud-typeorm)</h1>\n</div>\n<div align=\"center\">\n  <strong>for RESTful APIs buil"
  },
  {
    "path": "packages/crud-typeorm/package.json",
    "chars": 808,
    "preview": "{\n  \"name\": \"@nestjsx/crud-typeorm\",\n  \"description\": \"NestJs CRUD for RESTful APIs - TypeORM\",\n  \"version\": \"5.0.0-alph"
  },
  {
    "path": "packages/crud-typeorm/src/index.ts",
    "chars": 40,
    "preview": "export * from './typeorm-crud.service';\n"
  },
  {
    "path": "packages/crud-typeorm/src/typeorm-crud.service.ts",
    "chars": 29801,
    "preview": "import {\n  CreateManyDto,\n  CrudRequest,\n  CrudRequestOptions,\n  CrudService,\n  GetManyDefaultResponse,\n  JoinOption,\n  "
  },
  {
    "path": "packages/crud-typeorm/test/__fixture__/companies.service.ts",
    "chars": 412,
    "preview": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\n\nimport { TypeOrmCrudSe"
  },
  {
    "path": "packages/crud-typeorm/test/__fixture__/devices.service.ts",
    "chars": 405,
    "preview": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\n\nimport { TypeOrmCrudSe"
  },
  {
    "path": "packages/crud-typeorm/test/__fixture__/notes.service.ts",
    "chars": 395,
    "preview": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\n\nimport { TypeOrmCrudSe"
  },
  {
    "path": "packages/crud-typeorm/test/__fixture__/projects.service.ts",
    "chars": 410,
    "preview": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\n\nimport { TypeOrmCrudSe"
  },
  {
    "path": "packages/crud-typeorm/test/__fixture__/users.service.ts",
    "chars": 541,
    "preview": "import { Injectable } from '@nestjs/common';\nimport { InjectRepository } from '@nestjs/typeorm';\n\nimport { TypeOrmCrudSe"
  },
  {
    "path": "packages/crud-typeorm/test/a.params-options.spec.ts",
    "chars": 5133,
    "preview": "import 'jest-extended';\nimport { Controller, INestApplication } from '@nestjs/common';\nimport { APP_FILTER } from '@nest"
  },
  {
    "path": "packages/crud-typeorm/test/b.query-params.spec.ts",
    "chars": 28052,
    "preview": "import { Controller, INestApplication } from '@nestjs/common';\nimport { APP_FILTER } from '@nestjs/core';\nimport { Test "
  },
  {
    "path": "packages/crud-typeorm/test/c.basic-crud.spec.ts",
    "chars": 19672,
    "preview": "import { Controller, INestApplication } from '@nestjs/common';\nimport { APP_FILTER } from '@nestjs/core';\nimport { Test "
  },
  {
    "path": "packages/crud-typeorm/test/d.crud-auth.spec.ts",
    "chars": 4957,
    "preview": "import { Controller, INestApplication, Injectable, CanActivate, ExecutionContext } from '@nestjs/common';\nimport { APP_F"
  },
  {
    "path": "packages/crud-typeorm/tsconfig.json",
    "chars": 264,
    "preview": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"rootDir\": \"src\",\n    \"outDir\": \"lib\"\n  },\n  \"include\":"
  },
  {
    "path": "packages/util/README.md",
    "chars": 6941,
    "preview": "<div align=\"center\">\n  <h1>CRUD (@nestjsx/util)</h1>\n</div>\n<div align=\"center\">\n  <strong>for RESTful APIs built with N"
  },
  {
    "path": "packages/util/package.json",
    "chars": 708,
    "preview": "{\n  \"name\": \"@nestjsx/util\",\n  \"description\": \"NestJs CRUD for RESTful APIs - util\",\n  \"version\": \"5.0.0-alpha.3\",\n  \"li"
  },
  {
    "path": "packages/util/src/checks.util.ts",
    "chars": 2001,
    "preview": "import { objKeys } from './obj.util';\n\nexport const isUndefined = (val: any): boolean => typeof val === 'undefined';\nexp"
  },
  {
    "path": "packages/util/src/index.ts",
    "chars": 84,
    "preview": "export * from './checks.util';\nexport * from './obj.util';\nexport * from './types';\n"
  },
  {
    "path": "packages/util/src/obj.util.ts",
    "chars": 153,
    "preview": "export const objKeys = (val: any): string[] => Object.keys(val);\nexport const getOwnPropNames = (val: any): string[] => "
  },
  {
    "path": "packages/util/src/types/class.type.ts",
    "chars": 59,
    "preview": "export type ClassType<T> = {\n  new (...args: any[]): T;\n};\n"
  },
  {
    "path": "packages/util/src/types/index.ts",
    "chars": 69,
    "preview": "export * from './class.type';\nexport * from './object-literal.type';\n"
  },
  {
    "path": "packages/util/src/types/object-literal.type.ts",
    "chars": 55,
    "preview": "export type ObjectLiteral = {\n  [key: string]: any;\n};\n"
  },
  {
    "path": "packages/util/test/checks.util.spec.ts",
    "chars": 6405,
    "preview": "import {\n  hasLength,\n  hasValue,\n  isArrayFull,\n  isArrayStrings,\n  isBoolean,\n  isDate,\n  isDateString,\n  isEqual,\n  i"
  },
  {
    "path": "packages/util/test/obj.util.spec.ts",
    "chars": 611,
    "preview": "import { objKeys, getOwnPropNames } from '../src';\n\ndescribe('#util', () => {\n  describe('#objKeys', () => {\n    it('sho"
  },
  {
    "path": "packages/util/tsconfig.json",
    "chars": 153,
    "preview": "{\n  \"extends\": \"../../tsconfig.json\",\n  \"compilerOptions\": {\n    \"rootDir\": \"src\",\n    \"outDir\": \"lib\"\n  },\n  \"include\":"
  },
  {
    "path": "tsconfig.eslint.json",
    "chars": 62,
    "preview": "{\n  \"extends\": \"./tsconfig.json\",\n  \"include\": [\"packages\"]\n}\n"
  },
  {
    "path": "tsconfig.jest.json",
    "chars": 91,
    "preview": "{\n  \"extends\": \"./tsconfig.json\",\n  \"compilerOptions\": {\n    \"removeComments\": false\n  }\n}\n"
  },
  {
    "path": "tsconfig.json",
    "chars": 936,
    "preview": "{\n  \"compilerOptions\": {\n    \"module\": \"commonjs\",\n    \"declaration\": true,\n    \"noImplicitAny\": false,\n    \"noUnusedLoc"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the nestjsx/crud GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 201 files (379.5 KB), approximately 103.0k tokens, and a symbol index with 486 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!