├── .all-contributorsrc ├── .dockerignore ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ └── docker-e2e.yml ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .hygen.js ├── .hygen ├── generate │ ├── all-db-resource │ │ ├── app-module-import.ejs.t │ │ ├── app-module.ejs.t │ │ ├── controller.ejs.t │ │ ├── domain │ │ │ └── domain.ejs.t │ │ ├── dto │ │ │ ├── create.dto.ejs.t │ │ │ ├── domain.dto.ejs.t │ │ │ ├── find-all.dto.ejs.t │ │ │ └── update.dto.ejs.t │ │ ├── infrastructure │ │ │ └── persistence │ │ │ │ ├── document │ │ │ │ ├── document-persistence.module.ejs.t │ │ │ │ ├── entities │ │ │ │ │ └── schema.ejs.t │ │ │ │ ├── mappers │ │ │ │ │ └── mapper.ejs.t │ │ │ │ └── repositories │ │ │ │ │ └── repository.ejs.t │ │ │ │ ├── relational │ │ │ │ ├── entities │ │ │ │ │ └── entity.ejs.t │ │ │ │ ├── mappers │ │ │ │ │ └── mapper.ejs.t │ │ │ │ ├── relational-persistence.module.ejs.t │ │ │ │ └── repositories │ │ │ │ │ └── repository.ejs.t │ │ │ │ └── repository.ejs.t │ │ ├── module.ejs.t │ │ └── service.ejs.t │ ├── document-resource │ │ ├── app-module-import.ejs.t │ │ ├── app-module.ejs.t │ │ ├── controller.ejs.t │ │ ├── domain │ │ │ └── domain.ejs.t │ │ ├── dto │ │ │ ├── create.dto.ejs.t │ │ │ ├── domain.dto.ejs.t │ │ │ ├── find-all.dto.ejs.t │ │ │ └── update.dto.ejs.t │ │ ├── infrastructure │ │ │ └── persistence │ │ │ │ ├── document │ │ │ │ ├── document-persistence.module.ejs.t │ │ │ │ ├── entities │ │ │ │ │ └── schema.ejs.t │ │ │ │ ├── mappers │ │ │ │ │ └── mapper.ejs.t │ │ │ │ └── repositories │ │ │ │ │ └── repository.ejs.t │ │ │ │ └── repository.ejs.t │ │ ├── module.ejs.t │ │ └── service.ejs.t │ └── relational-resource │ │ ├── app-module-import.ejs.t │ │ ├── app-module.ejs.t │ │ ├── controller.ejs.t │ │ ├── domain │ │ └── domain.ejs.t │ │ ├── dto │ │ ├── create.dto.ejs.t │ │ ├── domain.dto.ejs.t │ │ ├── find-all.dto.ejs.t │ │ └── update.dto.ejs.t │ │ ├── infrastructure │ │ └── persistence │ │ │ ├── relational │ │ │ ├── entities │ │ │ │ └── entity.ejs.t │ │ │ ├── mappers │ │ │ │ └── mapper.ejs.t │ │ │ ├── relational-persistence.module.ejs.t │ │ │ └── repositories │ │ │ │ └── repository.ejs.t │ │ │ └── repository.ejs.t │ │ ├── module.ejs.t │ │ └── service.ejs.t ├── property │ ├── add-to-all-db │ │ ├── 01-service-inject.ejs.t │ │ ├── 02-service-inject-decorator.ejs.t │ │ ├── domain │ │ │ ├── domain-import.ejs.t │ │ │ └── domain.ejs.t │ │ ├── dto │ │ │ ├── 01-create.dto.ejs.t │ │ │ ├── 02-create-import-class-transformer.dto.ejs.t │ │ │ ├── 03-create-import-class-validator.dto.ejs.t │ │ │ ├── 04-create-import-swagger.dto.ejs.t │ │ │ ├── 05-create-boolean.dto.ejs.t │ │ │ ├── 06-create-number.dto.ejs.t │ │ │ ├── 07-create-string.dto.ejs.t │ │ │ ├── 08-create-api-property.dto.ejs.t │ │ │ ├── 09-create-class-transformer-type.dto.ejs.t │ │ │ ├── 10-create-validate-is-array.dto.ejs.t │ │ │ ├── 11-create-validate-nested.dto.ejs.t │ │ │ ├── 12-create-validate-not-empty-object.dto.ejs.t │ │ │ ├── 13-create-type-dto-import.ejs.t │ │ │ ├── 14-create-optional.dto.ejs.t │ │ │ ├── 15-create-date.dto.ejs.t │ │ │ └── 16-create-class-transformer-transform.dto.ejs.t │ │ ├── index.js │ │ ├── infrastructure │ │ │ └── persistence │ │ │ │ ├── document │ │ │ │ ├── entities │ │ │ │ │ ├── schema-mongoose-import.ejs.t │ │ │ │ │ ├── schema.ejs.t │ │ │ │ │ └── type-import.ejs.t │ │ │ │ └── mappers │ │ │ │ │ ├── mapper-domain.ejs.t │ │ │ │ │ ├── mapper-import.ejs.t │ │ │ │ │ └── mapper-persistence.ejs.t │ │ │ │ └── relational │ │ │ │ ├── entities │ │ │ │ ├── entity-column.ejs.t │ │ │ │ ├── entity-join-column.ejs.t │ │ │ │ ├── entity-join-table.ejs.t │ │ │ │ ├── entity-many-to-many.ejs.t │ │ │ │ ├── entity-many-to-one.ejs.t │ │ │ │ ├── entity-one-to-many.ejs.t │ │ │ │ ├── entity-one-to-one.ejs.t │ │ │ │ ├── entity.ejs.t │ │ │ │ └── type-import.ejs.t │ │ │ │ └── mappers │ │ │ │ ├── mapper-domain.ejs.t │ │ │ │ ├── mapper-import.ejs.t │ │ │ │ └── mapper-persistence.ejs.t │ │ ├── module-forward-ref.ejs.t │ │ ├── module-import-forward-ref.ejs.t │ │ ├── module-import.ejs.t │ │ ├── module.ejs.t │ │ ├── service-create-payload.ejs.t │ │ ├── service-create.ejs.t │ │ ├── service-import-forward-ref.ejs.t │ │ ├── service-import-http-code.ejs.t │ │ ├── service-import-inject-decorator.ejs.t │ │ ├── service-import-type-domain.ejs.t │ │ ├── service-import.ejs.t │ │ ├── service-update-payload.ejs.t │ │ └── service-update.ejs.t │ ├── add-to-document │ │ ├── 01-service-inject.ejs.t │ │ ├── 02-service-inject-decorator.ejs.t │ │ ├── domain │ │ │ ├── domain-import.ejs.t │ │ │ └── domain.ejs.t │ │ ├── dto │ │ │ ├── 01-create.dto.ejs.t │ │ │ ├── 02-create-import-class-transformer.dto.ejs.t │ │ │ ├── 03-create-import-class-validator.dto.ejs.t │ │ │ ├── 04-create-import-swagger.dto.ejs.t │ │ │ ├── 05-create-boolean.dto.ejs.t │ │ │ ├── 06-create-number.dto.ejs.t │ │ │ ├── 07-create-string.dto.ejs.t │ │ │ ├── 08-create-api-property.dto.ejs.t │ │ │ ├── 09-create-class-transformer-type.dto.ejs.t │ │ │ ├── 10-create-validate-is-array.dto.ejs.t │ │ │ ├── 11-create-validate-nested.dto.ejs.t │ │ │ ├── 12-create-validate-not-empty-object.dto.ejs.t │ │ │ ├── 13-create-type-dto-import.ejs.t │ │ │ ├── 14-create-optional.dto.ejs.t │ │ │ ├── 15-create-date.dto.ejs.t │ │ │ └── 16-create-class-transformer-transform.dto.ejs.t │ │ ├── index.js │ │ ├── infrastructure │ │ │ └── persistence │ │ │ │ └── document │ │ │ │ ├── entities │ │ │ │ ├── schema-mongoose-import.ejs.t │ │ │ │ ├── schema.ejs.t │ │ │ │ └── type-import.ejs.t │ │ │ │ └── mappers │ │ │ │ ├── mapper-domain.ejs.t │ │ │ │ ├── mapper-import.ejs.t │ │ │ │ └── mapper-persistence.ejs.t │ │ ├── module-forward-ref.ejs.t │ │ ├── module-import-forward-ref.ejs.t │ │ ├── module-import.ejs.t │ │ ├── module.ejs.t │ │ ├── service-create-payload.ejs.t │ │ ├── service-create.ejs.t │ │ ├── service-import-http-code.ejs.t │ │ ├── service-import-inject-decorator.ejs.t │ │ ├── service-import-type-domain.ejs.t │ │ ├── service-import.ejs.t │ │ ├── service-update-payload.ejs.t │ │ └── service-update.ejs.t │ └── add-to-relational │ │ ├── 01-service-inject.ejs.t │ │ ├── 02-service-inject-decorator.ejs.t │ │ ├── domain │ │ ├── domain-import.ejs.t │ │ └── domain.ejs.t │ │ ├── dto │ │ ├── 01-create.dto.ejs.t │ │ ├── 02-create-import-class-transformer.dto.ejs.t │ │ ├── 03-create-import-class-validator.dto.ejs.t │ │ ├── 04-create-import-swagger.dto.ejs.t │ │ ├── 05-create-boolean.dto.ejs.t │ │ ├── 06-create-number.dto.ejs.t │ │ ├── 07-create-string.dto.ejs.t │ │ ├── 08-create-api-property.dto.ejs.t │ │ ├── 09-create-class-transformer-type.dto.ejs.t │ │ ├── 10-create-validate-is-array.dto.ejs.t │ │ ├── 11-create-validate-nested.dto.ejs.t │ │ ├── 12-create-validate-not-empty-object.dto.ejs.t │ │ ├── 13-create-type-dto-import.ejs.t │ │ ├── 14-create-optional.dto.ejs.t │ │ ├── 15-create-date.dto.ejs.t │ │ └── 16-create-class-transformer-transform.dto.ejs.t │ │ ├── index.js │ │ ├── infrastructure │ │ └── persistence │ │ │ └── relational │ │ │ ├── entities │ │ │ ├── entity-column.ejs.t │ │ │ ├── entity-join-column.ejs.t │ │ │ ├── entity-join-table.ejs.t │ │ │ ├── entity-many-to-many.ejs.t │ │ │ ├── entity-many-to-one.ejs.t │ │ │ ├── entity-one-to-many.ejs.t │ │ │ ├── entity-one-to-one.ejs.t │ │ │ ├── entity.ejs.t │ │ │ └── type-import.ejs.t │ │ │ └── mappers │ │ │ ├── mapper-domain.ejs.t │ │ │ ├── mapper-import.ejs.t │ │ │ └── mapper-persistence.ejs.t │ │ ├── module-forward-ref.ejs.t │ │ ├── module-import-forward-ref.ejs.t │ │ ├── module-import.ejs.t │ │ ├── module.ejs.t │ │ ├── service-create-payload.ejs.t │ │ ├── service-create.ejs.t │ │ ├── service-import-http-code.ejs.t │ │ ├── service-import-inject-decorator.ejs.t │ │ ├── service-import-type-domain.ejs.t │ │ ├── service-import.ejs.t │ │ ├── service-update-payload.ejs.t │ │ └── service-update.ejs.t └── seeds │ ├── create-document │ ├── module.ejs.t │ ├── run-seed-import.ejs.t │ ├── run-seed-service.ejs.t │ ├── seed-module-import.ejs.t │ ├── seed-module.ejs.t │ └── service.ejs.t │ └── create-relational │ ├── module.ejs.t │ ├── run-seed-import.ejs.t │ ├── run-seed-service.ejs.t │ ├── seed-module-import.ejs.t │ ├── seed-module.ejs.t │ └── service.ejs.t ├── .install-scripts ├── helpers │ └── replace.ts ├── index.ts └── scripts │ ├── property-generation-scripts │ ├── remove-all-db.ts │ ├── remove-document.ts │ └── remove-relational.ts │ ├── remove-auth-apple.ts │ ├── remove-auth-facebook.ts │ ├── remove-auth-google.ts │ ├── remove-install-scripts.ts │ ├── remove-mongodb.ts │ ├── remove-postgresql.ts │ └── resource-generation-scripts │ ├── remove-all-db.ts │ ├── remove-document.ts │ └── remove-relational.ts ├── .nvmrc ├── .prettierrc ├── .vscode ├── extensions.json └── settings.json ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── Dockerfile ├── LICENSE ├── Procfile ├── README.md ├── commitlint.config.js ├── docker-compose.document.ci.yaml ├── docker-compose.document.test.yaml ├── docker-compose.document.yaml ├── docker-compose.relational.ci.yaml ├── docker-compose.relational.test.yaml ├── docker-compose.yaml ├── docs ├── architecture.md ├── auth.md ├── automatic-update-dependencies.md ├── benchmarking.md ├── cli.md ├── database.md ├── file-uploading.md ├── installing-and-running.md ├── introduction.md ├── readme.md ├── serialization.md ├── tests.md └── translations.md ├── document.Dockerfile ├── document.e2e.Dockerfile ├── document.test.Dockerfile ├── env-example-document ├── env-example-relational ├── eslint.config.mjs ├── maildev.Dockerfile ├── nest-cli.json ├── package-lock.json ├── package.json ├── relational.e2e.Dockerfile ├── relational.test.Dockerfile ├── renovate.json ├── src ├── app.module.ts ├── auth-apple │ ├── auth-apple.controller.ts │ ├── auth-apple.module.ts │ ├── auth-apple.service.ts │ ├── config │ │ ├── apple-config.type.ts │ │ └── apple.config.ts │ └── dto │ │ └── auth-apple-login.dto.ts ├── auth-facebook │ ├── auth-facebook.controller.ts │ ├── auth-facebook.module.ts │ ├── auth-facebook.service.ts │ ├── config │ │ ├── facebook-config.type.ts │ │ └── facebook.config.ts │ ├── dto │ │ └── auth-facebook-login.dto.ts │ └── interfaces │ │ └── facebook.interface.ts ├── auth-google │ ├── auth-google.controller.ts │ ├── auth-google.module.ts │ ├── auth-google.service.ts │ ├── config │ │ ├── google-config.type.ts │ │ └── google.config.ts │ └── dto │ │ └── auth-google-login.dto.ts ├── auth │ ├── auth-providers.enum.ts │ ├── auth.controller.ts │ ├── auth.module.ts │ ├── auth.service.ts │ ├── config │ │ ├── auth-config.type.ts │ │ └── auth.config.ts │ ├── dto │ │ ├── auth-confirm-email.dto.ts │ │ ├── auth-email-login.dto.ts │ │ ├── auth-forgot-password.dto.ts │ │ ├── auth-register-login.dto.ts │ │ ├── auth-reset-password.dto.ts │ │ ├── auth-update.dto.ts │ │ ├── login-response.dto.ts │ │ └── refresh-response.dto.ts │ └── strategies │ │ ├── anonymous.strategy.ts │ │ ├── jwt-refresh.strategy.ts │ │ ├── jwt.strategy.ts │ │ └── types │ │ ├── jwt-payload.type.ts │ │ └── jwt-refresh-payload.type.ts ├── config │ ├── app-config.type.ts │ ├── app.config.ts │ └── config.type.ts ├── database │ ├── config │ │ ├── database-config.type.ts │ │ └── database.config.ts │ ├── data-source.ts │ ├── migrations │ │ └── 1715028537217-CreateUser.ts │ ├── mongoose-config.service.ts │ ├── seeds │ │ ├── document │ │ │ ├── run-seed.ts │ │ │ ├── seed.module.ts │ │ │ └── user │ │ │ │ ├── user-seed.module.ts │ │ │ │ └── user-seed.service.ts │ │ └── relational │ │ │ ├── role │ │ │ ├── role-seed.module.ts │ │ │ └── role-seed.service.ts │ │ │ ├── run-seed.ts │ │ │ ├── seed.module.ts │ │ │ ├── status │ │ │ ├── status-seed.module.ts │ │ │ └── status-seed.service.ts │ │ │ └── user │ │ │ ├── user-seed.module.ts │ │ │ └── user-seed.service.ts │ └── typeorm-config.service.ts ├── files │ ├── config │ │ ├── file-config.type.ts │ │ └── file.config.ts │ ├── domain │ │ └── file.ts │ ├── dto │ │ └── file.dto.ts │ ├── files.module.ts │ ├── files.service.ts │ └── infrastructure │ │ ├── persistence │ │ ├── document │ │ │ ├── document-persistence.module.ts │ │ │ ├── entities │ │ │ │ └── file.schema.ts │ │ │ ├── mappers │ │ │ │ └── file.mapper.ts │ │ │ └── repositories │ │ │ │ └── file.repository.ts │ │ ├── file.repository.ts │ │ └── relational │ │ │ ├── entities │ │ │ └── file.entity.ts │ │ │ ├── mappers │ │ │ └── file.mapper.ts │ │ │ ├── relational-persistence.module.ts │ │ │ └── repositories │ │ │ └── file.repository.ts │ │ └── uploader │ │ ├── local │ │ ├── dto │ │ │ └── file-response.dto.ts │ │ ├── files.controller.ts │ │ ├── files.module.ts │ │ └── files.service.ts │ │ ├── s3-presigned │ │ ├── dto │ │ │ ├── file-response.dto.ts │ │ │ └── file.dto.ts │ │ ├── files.controller.ts │ │ ├── files.module.ts │ │ └── files.service.ts │ │ └── s3 │ │ ├── dto │ │ └── file-response.dto.ts │ │ ├── files.controller.ts │ │ ├── files.module.ts │ │ └── files.service.ts ├── home │ ├── home.controller.ts │ ├── home.module.ts │ └── home.service.ts ├── i18n │ ├── ar │ │ ├── common.json │ │ ├── confirm-email.json │ │ ├── confirm-new-email.json │ │ └── reset-password.json │ ├── en │ │ ├── common.json │ │ ├── confirm-email.json │ │ ├── confirm-new-email.json │ │ └── reset-password.json │ ├── es │ │ ├── common.json │ │ ├── confirm-email.json │ │ ├── confirm-new-email.json │ │ └── reset-password.json │ ├── fr │ │ ├── common.json │ │ ├── confirm-email.json │ │ ├── confirm-new-email.json │ │ └── reset-password.json │ ├── hi │ │ ├── common.json │ │ ├── confirm-email.json │ │ ├── confirm-new-email.json │ │ └── reset-password.json │ ├── uk │ │ ├── common.json │ │ ├── confirm-email.json │ │ ├── confirm-new-email.json │ │ └── reset-password.json │ └── zh │ │ ├── common.json │ │ ├── confirm-email.json │ │ ├── confirm-new-email.json │ │ └── reset-password.json ├── mail │ ├── config │ │ ├── mail-config.type.ts │ │ └── mail.config.ts │ ├── interfaces │ │ └── mail-data.interface.ts │ ├── mail-templates │ │ ├── activation.hbs │ │ ├── confirm-new-email.hbs │ │ └── reset-password.hbs │ ├── mail.module.ts │ └── mail.service.ts ├── mailer │ ├── mailer.module.ts │ └── mailer.service.ts ├── main.ts ├── roles │ ├── domain │ │ └── role.ts │ ├── dto │ │ └── role.dto.ts │ ├── infrastructure │ │ └── persistence │ │ │ ├── document │ │ │ └── entities │ │ │ │ └── role.schema.ts │ │ │ └── relational │ │ │ └── entities │ │ │ └── role.entity.ts │ ├── roles.decorator.ts │ ├── roles.enum.ts │ └── roles.guard.ts ├── session │ ├── domain │ │ └── session.ts │ ├── infrastructure │ │ └── persistence │ │ │ ├── document │ │ │ ├── document-persistence.module.ts │ │ │ ├── entities │ │ │ │ └── session.schema.ts │ │ │ ├── mappers │ │ │ │ └── session.mapper.ts │ │ │ └── repositories │ │ │ │ └── session.repository.ts │ │ │ ├── relational │ │ │ ├── entities │ │ │ │ └── session.entity.ts │ │ │ ├── mappers │ │ │ │ └── session.mapper.ts │ │ │ ├── relational-persistence.module.ts │ │ │ └── repositories │ │ │ │ └── session.repository.ts │ │ │ └── session.repository.ts │ ├── session.module.ts │ └── session.service.ts ├── social │ ├── interfaces │ │ └── social.interface.ts │ └── tokens.ts ├── statuses │ ├── domain │ │ └── status.ts │ ├── dto │ │ └── status.dto.ts │ ├── infrastructure │ │ └── persistence │ │ │ ├── document │ │ │ └── entities │ │ │ │ └── status.schema.ts │ │ │ └── relational │ │ │ └── entities │ │ │ └── status.entity.ts │ └── statuses.enum.ts ├── users │ ├── domain │ │ └── user.ts │ ├── dto │ │ ├── create-user.dto.ts │ │ ├── query-user.dto.ts │ │ ├── update-user.dto.ts │ │ └── user.dto.ts │ ├── infrastructure │ │ └── persistence │ │ │ ├── document │ │ │ ├── document-persistence.module.ts │ │ │ ├── entities │ │ │ │ └── user.schema.ts │ │ │ ├── mappers │ │ │ │ └── user.mapper.ts │ │ │ └── repositories │ │ │ │ └── user.repository.ts │ │ │ ├── relational │ │ │ ├── entities │ │ │ │ └── user.entity.ts │ │ │ ├── mappers │ │ │ │ └── user.mapper.ts │ │ │ ├── relational-persistence.module.ts │ │ │ └── repositories │ │ │ │ └── user.repository.ts │ │ │ └── user.repository.ts │ ├── users.controller.ts │ ├── users.module.ts │ └── users.service.ts └── utils │ ├── deep-resolver.ts │ ├── document-entity-helper.ts │ ├── dto │ └── infinity-pagination-response.dto.ts │ ├── infinity-pagination.ts │ ├── relational-entity-helper.ts │ ├── serializer.interceptor.ts │ ├── transformers │ └── lower-case.transformer.ts │ ├── types │ ├── deep-partial.type.ts │ ├── maybe.type.ts │ ├── nullable.type.ts │ ├── or-never.type.ts │ └── pagination-options.ts │ ├── validate-config.ts │ └── validation-options.ts ├── startup.document.ci.sh ├── startup.document.dev.sh ├── startup.document.test.sh ├── startup.relational.ci.sh ├── startup.relational.dev.sh ├── startup.relational.test.sh ├── test ├── admin │ ├── auth.e2e-spec.ts │ └── users.e2e-spec.ts ├── jest-e2e.json ├── user │ └── auth.e2e-spec.ts └── utils │ └── constants.ts ├── tsconfig.build.json ├── tsconfig.json └── wait-for-it.sh /.dockerignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /.data 3 | /dist 4 | /files 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: Shchepotin 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Send '....' 17 | 4. See error 18 | 19 | **Expected behavior** 20 | A clear and concise description of what you expected to happen. 21 | 22 | **Screenshots** 23 | If applicable, add screenshots to help explain your problem. 24 | 25 | **Desktop (please complete the following information):** 26 | - OS: [e.g. Windows] 27 | - NodeJS Version [e.g. 18.16.0] 28 | - Database [e.g. PostgreSQL] 29 | 30 | **Additional context** 31 | Add any other context about the problem here. 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | pnpm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | 14 | # OS 15 | .DS_Store 16 | 17 | # Tests 18 | /coverage 19 | /.nyc_output 20 | 21 | # IDEs and editors 22 | /.idea 23 | .project 24 | .classpath 25 | .c9/ 26 | *.launch 27 | .settings/ 28 | *.sublime-workspace 29 | 30 | # IDE - VSCode 31 | .vscode/* 32 | !.vscode/settings.json 33 | !.vscode/tasks.json 34 | !.vscode/launch.json 35 | !.vscode/extensions.json 36 | 37 | .data 38 | /files 39 | .env 40 | /ormconfig.json 41 | .codegpt -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | npx commitlint --edit 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npm run lint 2 | npm run test -- --passWithNoTests 3 | -------------------------------------------------------------------------------- /.hygen.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | templates: `${__dirname}/.hygen`, 3 | }; 4 | -------------------------------------------------------------------------------- /.hygen/generate/all-db-resource/app-module-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/app.module.ts 4 | before: \@Module 5 | --- 6 | import { <%= h.inflection.transform(name, ['pluralize']) %>Module } from './<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.module'; 7 | -------------------------------------------------------------------------------- /.hygen/generate/all-db-resource/app-module.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/app.module.ts 4 | after: imports 5 | --- 6 | <%= h.inflection.transform(name, ['pluralize']) %>Module, -------------------------------------------------------------------------------- /.hygen/generate/all-db-resource/domain/domain.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/domain/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.ts 3 | --- 4 | import { ApiProperty } from '@nestjs/swagger'; 5 | 6 | export class <%= name %> { 7 | @ApiProperty({ 8 | type: String, 9 | }) 10 | id: string; 11 | 12 | @ApiProperty() 13 | createdAt: Date; 14 | 15 | @ApiProperty() 16 | updatedAt: Date; 17 | } 18 | -------------------------------------------------------------------------------- /.hygen/generate/all-db-resource/dto/create.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 3 | --- 4 | export class Create<%= name %>Dto { 5 | // Don't forget to use the class-validator decorators in the DTO properties. 6 | } 7 | -------------------------------------------------------------------------------- /.hygen/generate/all-db-resource/dto/domain.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 3 | --- 4 | import { ApiProperty } from '@nestjs/swagger'; 5 | import { IsNotEmpty, IsString } from 'class-validator'; 6 | 7 | export class <%= name %>Dto { 8 | @ApiProperty() 9 | @IsString() 10 | @IsNotEmpty() 11 | id: string; 12 | } 13 | -------------------------------------------------------------------------------- /.hygen/generate/all-db-resource/dto/find-all.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/find-all-<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.dto.ts 3 | --- 4 | import { ApiPropertyOptional } from '@nestjs/swagger'; 5 | import { IsNumber, IsOptional } from 'class-validator'; 6 | import { Transform } from 'class-transformer'; 7 | 8 | export class FindAll<%= h.inflection.transform(name, ['pluralize']) %>Dto { 9 | @ApiPropertyOptional() 10 | @Transform(({ value }) => (value ? Number(value) : 1)) 11 | @IsNumber() 12 | @IsOptional() 13 | page?: number; 14 | 15 | @ApiPropertyOptional() 16 | @Transform(({ value }) => (value ? Number(value) : 10)) 17 | @IsNumber() 18 | @IsOptional() 19 | limit?: number; 20 | } 21 | -------------------------------------------------------------------------------- /.hygen/generate/all-db-resource/dto/update.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/update-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 3 | --- 4 | // Don't forget to use the class-validator decorators in the DTO properties. 5 | // import { Allow } from 'class-validator'; 6 | 7 | import { PartialType } from '@nestjs/swagger'; 8 | import { Create<%= name %>Dto } from './create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto'; 9 | 10 | export class Update<%= name %>Dto extends PartialType(Create<%= name %>Dto) {} 11 | -------------------------------------------------------------------------------- /.hygen/generate/all-db-resource/infrastructure/persistence/document/document-persistence.module.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/document/document-persistence.module.ts 3 | --- 4 | import { Module } from '@nestjs/common'; 5 | import { MongooseModule } from '@nestjs/mongoose'; 6 | import { 7 | <%= name %>Schema, 8 | <%= name %>SchemaClass, 9 | } from './entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.schema'; 10 | import { <%= name %>Repository } from '../<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.repository'; 11 | import { <%= name %>DocumentRepository } from './repositories/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.repository'; 12 | 13 | @Module({ 14 | imports: [ 15 | MongooseModule.forFeature([ 16 | { name: <%= name %>SchemaClass.name, schema: <%= name %>Schema }, 17 | ]), 18 | ], 19 | providers: [ 20 | { 21 | provide: <%= name %>Repository, 22 | useClass: <%= name %>DocumentRepository, 23 | }, 24 | ], 25 | exports: [<%= name %>Repository], 26 | }) 27 | export class Document<%= name %>PersistenceModule {} 28 | -------------------------------------------------------------------------------- /.hygen/generate/all-db-resource/infrastructure/persistence/document/entities/schema.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/document/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.schema.ts 3 | --- 4 | import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; 5 | import { now, HydratedDocument } from 'mongoose'; 6 | import { EntityDocumentHelper } from '../../../../../utils/document-entity-helper'; 7 | 8 | export type <%= name %>SchemaDocument = HydratedDocument<<%= name %>SchemaClass>; 9 | 10 | @Schema({ 11 | timestamps: true, 12 | toJSON: { 13 | virtuals: true, 14 | getters: true, 15 | }, 16 | }) 17 | export class <%= name %>SchemaClass extends EntityDocumentHelper { 18 | @Prop({ default: now }) 19 | createdAt: Date; 20 | 21 | @Prop({ default: now }) 22 | updatedAt: Date; 23 | } 24 | 25 | export const <%= name %>Schema = SchemaFactory.createForClass(<%= name %>SchemaClass); 26 | -------------------------------------------------------------------------------- /.hygen/generate/all-db-resource/infrastructure/persistence/relational/entities/entity.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity.ts 3 | --- 4 | import { 5 | CreateDateColumn, 6 | Entity, 7 | PrimaryGeneratedColumn, 8 | UpdateDateColumn, 9 | } from 'typeorm'; 10 | import { EntityRelationalHelper } from '../../../../../utils/relational-entity-helper'; 11 | 12 | @Entity({ 13 | name: '<%= h.inflection.transform(name, ['underscore']) %>', 14 | }) 15 | export class <%= name %>Entity extends EntityRelationalHelper { 16 | @PrimaryGeneratedColumn('uuid') 17 | id: string; 18 | 19 | @CreateDateColumn() 20 | createdAt: Date; 21 | 22 | @UpdateDateColumn() 23 | updatedAt: Date; 24 | } 25 | -------------------------------------------------------------------------------- /.hygen/generate/all-db-resource/infrastructure/persistence/relational/mappers/mapper.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/mappers/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.mapper.ts 3 | --- 4 | import { <%= name %> } from '../../../../domain/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>'; 5 | import { <%= name %>Entity } from '../entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity'; 6 | 7 | export class <%= name %>Mapper { 8 | static toDomain(raw: <%= name %>Entity): <%= name %> { 9 | const domainEntity = new <%= name %>(); 10 | domainEntity.id = raw.id; 11 | domainEntity.createdAt = raw.createdAt; 12 | domainEntity.updatedAt = raw.updatedAt; 13 | 14 | return domainEntity; 15 | } 16 | 17 | static toPersistence(domainEntity: <%= name %>): <%= name %>Entity { 18 | const persistenceEntity = new <%= name %>Entity(); 19 | if (domainEntity.id) { 20 | persistenceEntity.id = domainEntity.id; 21 | } 22 | persistenceEntity.createdAt = domainEntity.createdAt; 23 | persistenceEntity.updatedAt = domainEntity.updatedAt; 24 | 25 | return persistenceEntity; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.hygen/generate/all-db-resource/infrastructure/persistence/relational/relational-persistence.module.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/relational-persistence.module.ts 3 | --- 4 | import { Module } from '@nestjs/common'; 5 | import { <%= name %>Repository } from '../<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.repository'; 6 | import { <%= name %>RelationalRepository } from './repositories/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.repository'; 7 | import { TypeOrmModule } from '@nestjs/typeorm'; 8 | import { <%= name %>Entity } from './entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity'; 9 | 10 | @Module({ 11 | imports: [TypeOrmModule.forFeature([<%= name %>Entity])], 12 | providers: [ 13 | { 14 | provide: <%= name %>Repository, 15 | useClass: <%= name %>RelationalRepository, 16 | }, 17 | ], 18 | exports: [<%= name %>Repository], 19 | }) 20 | export class Relational<%= name %>PersistenceModule {} 21 | -------------------------------------------------------------------------------- /.hygen/generate/document-resource/app-module-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/app.module.ts 4 | before: \@Module 5 | --- 6 | import { <%= h.inflection.transform(name, ['pluralize']) %>Module } from './<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.module'; 7 | -------------------------------------------------------------------------------- /.hygen/generate/document-resource/app-module.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/app.module.ts 4 | after: imports 5 | --- 6 | <%= h.inflection.transform(name, ['pluralize']) %>Module, -------------------------------------------------------------------------------- /.hygen/generate/document-resource/domain/domain.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/domain/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.ts 3 | --- 4 | import { ApiProperty } from '@nestjs/swagger'; 5 | 6 | export class <%= name %> { 7 | @ApiProperty({ 8 | type: String, 9 | }) 10 | id: string; 11 | 12 | @ApiProperty() 13 | createdAt: Date; 14 | 15 | @ApiProperty() 16 | updatedAt: Date; 17 | } 18 | -------------------------------------------------------------------------------- /.hygen/generate/document-resource/dto/create.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 3 | --- 4 | export class Create<%= name %>Dto { 5 | // Don't forget to use the class-validator decorators in the DTO properties. 6 | } 7 | -------------------------------------------------------------------------------- /.hygen/generate/document-resource/dto/domain.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 3 | --- 4 | import { ApiProperty } from '@nestjs/swagger'; 5 | import { IsNotEmpty, IsString } from 'class-validator'; 6 | 7 | export class <%= name %>Dto { 8 | @ApiProperty() 9 | @IsString() 10 | @IsNotEmpty() 11 | id: string; 12 | } 13 | -------------------------------------------------------------------------------- /.hygen/generate/document-resource/dto/find-all.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/find-all-<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.dto.ts 3 | --- 4 | import { ApiPropertyOptional } from '@nestjs/swagger'; 5 | import { IsNumber, IsOptional } from 'class-validator'; 6 | import { Transform } from 'class-transformer'; 7 | 8 | export class FindAll<%= h.inflection.transform(name, ['pluralize']) %>Dto { 9 | @ApiPropertyOptional() 10 | @Transform(({ value }) => (value ? Number(value) : 1)) 11 | @IsNumber() 12 | @IsOptional() 13 | page?: number; 14 | 15 | @ApiPropertyOptional() 16 | @Transform(({ value }) => (value ? Number(value) : 10)) 17 | @IsNumber() 18 | @IsOptional() 19 | limit?: number; 20 | } 21 | -------------------------------------------------------------------------------- /.hygen/generate/document-resource/dto/update.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/update-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 3 | --- 4 | // Don't forget to use the class-validator decorators in the DTO properties. 5 | // import { Allow } from 'class-validator'; 6 | 7 | import { PartialType } from '@nestjs/swagger'; 8 | import { Create<%= name %>Dto } from './create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto'; 9 | 10 | export class Update<%= name %>Dto extends PartialType(Create<%= name %>Dto) {} 11 | -------------------------------------------------------------------------------- /.hygen/generate/document-resource/infrastructure/persistence/document/document-persistence.module.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/document/document-persistence.module.ts 3 | --- 4 | import { Module } from '@nestjs/common'; 5 | import { MongooseModule } from '@nestjs/mongoose'; 6 | import { 7 | <%= name %>Schema, 8 | <%= name %>SchemaClass, 9 | } from './entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.schema'; 10 | import { <%= name %>Repository } from '../<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.repository'; 11 | import { <%= name %>DocumentRepository } from './repositories/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.repository'; 12 | 13 | @Module({ 14 | imports: [ 15 | MongooseModule.forFeature([ 16 | { name: <%= name %>SchemaClass.name, schema: <%= name %>Schema }, 17 | ]), 18 | ], 19 | providers: [ 20 | { 21 | provide: <%= name %>Repository, 22 | useClass: <%= name %>DocumentRepository, 23 | }, 24 | ], 25 | exports: [<%= name %>Repository], 26 | }) 27 | export class Document<%= name %>PersistenceModule {} 28 | -------------------------------------------------------------------------------- /.hygen/generate/document-resource/infrastructure/persistence/document/entities/schema.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/document/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.schema.ts 3 | --- 4 | import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; 5 | import { now, HydratedDocument } from 'mongoose'; 6 | import { EntityDocumentHelper } from '../../../../../utils/document-entity-helper'; 7 | 8 | export type <%= name %>SchemaDocument = HydratedDocument<<%= name %>SchemaClass>; 9 | 10 | @Schema({ 11 | timestamps: true, 12 | toJSON: { 13 | virtuals: true, 14 | getters: true, 15 | }, 16 | }) 17 | export class <%= name %>SchemaClass extends EntityDocumentHelper { 18 | @Prop({ default: now }) 19 | createdAt: Date; 20 | 21 | @Prop({ default: now }) 22 | updatedAt: Date; 23 | } 24 | 25 | export const <%= name %>Schema = SchemaFactory.createForClass(<%= name %>SchemaClass); 26 | -------------------------------------------------------------------------------- /.hygen/generate/document-resource/module.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.module.ts 3 | --- 4 | import { 5 | // do not remove this comment 6 | Module, 7 | } from '@nestjs/common'; 8 | import { <%= h.inflection.transform(name, ['pluralize']) %>Service } from './<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service'; 9 | import { <%= h.inflection.transform(name, ['pluralize']) %>Controller } from './<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.controller'; 10 | import { Document<%= name %>PersistenceModule } from './infrastructure/persistence/document/document-persistence.module'; 11 | 12 | @Module({ 13 | imports: [ 14 | // do not remove this comment 15 | Document<%= name %>PersistenceModule, 16 | ], 17 | controllers: [<%= h.inflection.transform(name, ['pluralize']) %>Controller], 18 | providers: [<%= h.inflection.transform(name, ['pluralize']) %>Service], 19 | exports: [<%= h.inflection.transform(name, ['pluralize']) %>Service, Document<%= name %>PersistenceModule], 20 | }) 21 | export class <%= h.inflection.transform(name, ['pluralize']) %>Module {} 22 | -------------------------------------------------------------------------------- /.hygen/generate/relational-resource/app-module-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/app.module.ts 4 | before: \@Module 5 | --- 6 | import { <%= h.inflection.transform(name, ['pluralize']) %>Module } from './<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.module'; 7 | -------------------------------------------------------------------------------- /.hygen/generate/relational-resource/app-module.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/app.module.ts 4 | after: imports 5 | --- 6 | <%= h.inflection.transform(name, ['pluralize']) %>Module, -------------------------------------------------------------------------------- /.hygen/generate/relational-resource/domain/domain.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/domain/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.ts 3 | --- 4 | import { ApiProperty } from '@nestjs/swagger'; 5 | 6 | export class <%= name %> { 7 | @ApiProperty({ 8 | type: String, 9 | }) 10 | id: string; 11 | 12 | @ApiProperty() 13 | createdAt: Date; 14 | 15 | @ApiProperty() 16 | updatedAt: Date; 17 | } 18 | -------------------------------------------------------------------------------- /.hygen/generate/relational-resource/dto/create.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 3 | --- 4 | export class Create<%= name %>Dto { 5 | // Don't forget to use the class-validator decorators in the DTO properties. 6 | } 7 | -------------------------------------------------------------------------------- /.hygen/generate/relational-resource/dto/domain.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 3 | --- 4 | import { ApiProperty } from '@nestjs/swagger'; 5 | import { IsNotEmpty, IsString } from 'class-validator'; 6 | 7 | export class <%= name %>Dto { 8 | @ApiProperty() 9 | @IsString() 10 | @IsNotEmpty() 11 | id: string; 12 | } 13 | -------------------------------------------------------------------------------- /.hygen/generate/relational-resource/dto/find-all.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/find-all-<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.dto.ts 3 | --- 4 | import { ApiPropertyOptional } from '@nestjs/swagger'; 5 | import { IsNumber, IsOptional } from 'class-validator'; 6 | import { Transform } from 'class-transformer'; 7 | 8 | export class FindAll<%= h.inflection.transform(name, ['pluralize']) %>Dto { 9 | @ApiPropertyOptional() 10 | @Transform(({ value }) => (value ? Number(value) : 1)) 11 | @IsNumber() 12 | @IsOptional() 13 | page?: number; 14 | 15 | @ApiPropertyOptional() 16 | @Transform(({ value }) => (value ? Number(value) : 10)) 17 | @IsNumber() 18 | @IsOptional() 19 | limit?: number; 20 | } 21 | -------------------------------------------------------------------------------- /.hygen/generate/relational-resource/dto/update.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/update-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 3 | --- 4 | // Don't forget to use the class-validator decorators in the DTO properties. 5 | // import { Allow } from 'class-validator'; 6 | 7 | import { PartialType } from '@nestjs/swagger'; 8 | import { Create<%= name %>Dto } from './create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto'; 9 | 10 | export class Update<%= name %>Dto extends PartialType(Create<%= name %>Dto) {} 11 | -------------------------------------------------------------------------------- /.hygen/generate/relational-resource/infrastructure/persistence/relational/entities/entity.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity.ts 3 | --- 4 | import { 5 | CreateDateColumn, 6 | Entity, 7 | PrimaryGeneratedColumn, 8 | UpdateDateColumn, 9 | } from 'typeorm'; 10 | import { EntityRelationalHelper } from '../../../../../utils/relational-entity-helper'; 11 | 12 | @Entity({ 13 | name: '<%= h.inflection.transform(name, ['underscore']) %>', 14 | }) 15 | export class <%= name %>Entity extends EntityRelationalHelper { 16 | @PrimaryGeneratedColumn('uuid') 17 | id: string; 18 | 19 | @CreateDateColumn() 20 | createdAt: Date; 21 | 22 | @UpdateDateColumn() 23 | updatedAt: Date; 24 | } 25 | -------------------------------------------------------------------------------- /.hygen/generate/relational-resource/infrastructure/persistence/relational/mappers/mapper.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/mappers/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.mapper.ts 3 | --- 4 | import { <%= name %> } from '../../../../domain/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>'; 5 | import { <%= name %>Entity } from '../entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity'; 6 | 7 | export class <%= name %>Mapper { 8 | static toDomain(raw: <%= name %>Entity): <%= name %> { 9 | const domainEntity = new <%= name %>(); 10 | domainEntity.id = raw.id; 11 | domainEntity.createdAt = raw.createdAt; 12 | domainEntity.updatedAt = raw.updatedAt; 13 | 14 | return domainEntity; 15 | } 16 | 17 | static toPersistence(domainEntity: <%= name %>): <%= name %>Entity { 18 | const persistenceEntity = new <%= name %>Entity(); 19 | if (domainEntity.id) { 20 | persistenceEntity.id = domainEntity.id; 21 | } 22 | persistenceEntity.createdAt = domainEntity.createdAt; 23 | persistenceEntity.updatedAt = domainEntity.updatedAt; 24 | 25 | return persistenceEntity; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.hygen/generate/relational-resource/infrastructure/persistence/relational/relational-persistence.module.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/relational-persistence.module.ts 3 | --- 4 | import { Module } from '@nestjs/common'; 5 | import { <%= name %>Repository } from '../<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.repository'; 6 | import { <%= name %>RelationalRepository } from './repositories/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.repository'; 7 | import { TypeOrmModule } from '@nestjs/typeorm'; 8 | import { <%= name %>Entity } from './entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity'; 9 | 10 | @Module({ 11 | imports: [TypeOrmModule.forFeature([<%= name %>Entity])], 12 | providers: [ 13 | { 14 | provide: <%= name %>Repository, 15 | useClass: <%= name %>RelationalRepository, 16 | }, 17 | ], 18 | exports: [<%= name %>Repository], 19 | }) 20 | export class Relational<%= name %>PersistenceModule {} 21 | -------------------------------------------------------------------------------- /.hygen/generate/relational-resource/module.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.module.ts 3 | --- 4 | import { 5 | // do not remove this comment 6 | Module, 7 | } from '@nestjs/common'; 8 | import { <%= h.inflection.transform(name, ['pluralize']) %>Service } from './<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service'; 9 | import { <%= h.inflection.transform(name, ['pluralize']) %>Controller } from './<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.controller'; 10 | import { Relational<%= name %>PersistenceModule } from './infrastructure/persistence/relational/relational-persistence.module'; 11 | 12 | @Module({ 13 | imports: [ 14 | // do not remove this comment 15 | Relational<%= name %>PersistenceModule, 16 | ], 17 | controllers: [<%= h.inflection.transform(name, ['pluralize']) %>Controller], 18 | providers: [<%= h.inflection.transform(name, ['pluralize']) %>Service], 19 | exports: [<%= h.inflection.transform(name, ['pluralize']) %>Service, Relational<%= name %>PersistenceModule], 20 | }) 21 | export class <%= h.inflection.transform(name, ['pluralize']) %>Module {} 22 | -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/01-service-inject.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | after: constructor 5 | skip_if: private readonly <%= h.inflection.camelize(type, true) %>Service 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | private readonly <%= h.inflection.camelize(type, true) %>Service: <%= h.inflection.transform(type, ['pluralize']) %>Service, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/02-service-inject-decorator.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | before: private readonly <%= h.inflection.camelize(type, true) %>Service 5 | skip_if: \=\> <%= h.inflection.transform(type, ['pluralize']) %>Service\)\) 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | <% if (referenceType === 'oneToMany' || (referenceType === 'manyToOne' && !!propertyInReference)) { -%> 9 | @Inject(forwardRef(() => <%= h.inflection.transform(type, ['pluralize']) %>Service)) 10 | <% } -%> 11 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/domain/domain-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/domain/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.ts 4 | at_line: 0 5 | skip_if: import { <%= type %><% if (type === 'File') { -%>Type<% } -%> 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%>import { <%= type %><% if (type === 'File') { -%>Type<% } -%> } from '../../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/domain/<%= h.inflection.transform(type, ['underscore', 'dasherize']) %>';<% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/dto/02-create-import-class-transformer.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: export class Create<%= name %>Dto 5 | skip_if: "} from 'class-transformer'" 6 | --- 7 | <% if (isAddToDto && (kind === 'reference' || kind === 'duplication' || (kind === 'primitive' && type === 'Date'))) { -%> 8 | import { 9 | // decorators here 10 | } from 'class-transformer'; 11 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/dto/03-create-import-class-validator.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: export class Create<%= name %>Dto 5 | skip_if: "} from 'class-validator'" 6 | --- 7 | <% if (isAddToDto) { -%> 8 | import { 9 | // decorators here 10 | } from 'class-validator'; 11 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/dto/04-create-import-swagger.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: export class Create<%= name %>Dto 5 | skip_if: "} from '@nestjs/swagger'" 6 | --- 7 | <% if (isAddToDto) { -%> 8 | import { 9 | // decorators here 10 | } from '@nestjs/swagger'; 11 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/dto/05-create-boolean.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsBoolean, 6 | --- 7 | <% if (isAddToDto && type === 'boolean') { -%> 8 | IsBoolean, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/dto/06-create-number.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsNumber, 6 | --- 7 | <% if (isAddToDto && type === 'number') { -%> 8 | IsNumber, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/dto/07-create-string.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsString, 6 | --- 7 | <% if (isAddToDto && type === 'string') { -%> 8 | IsString, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/dto/08-create-api-property.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from '@nestjs/swagger'" 5 | skip_if: \ApiProperty, 6 | --- 7 | <% if (isAddToDto) { -%> 8 | ApiProperty, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/dto/09-create-class-transformer-type.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-transformer'" 5 | skip_if: \Type, 6 | --- 7 | <% if (isAddToDto && (kind === 'reference' || kind === 'duplication')) { -%> 8 | Type, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/dto/10-create-validate-is-array.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsArray, 6 | --- 7 | <% if (isAddToDto && (kind === 'reference' || kind === 'duplication') && (referenceType === 'oneToMany' || referenceType === 'manyToMany')) { -%> 8 | IsArray, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/dto/11-create-validate-nested.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \ValidateNested, 6 | --- 7 | <% if (isAddToDto && (kind === 'reference' || kind === 'duplication')) { -%> 8 | ValidateNested, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/dto/12-create-validate-not-empty-object.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsNotEmptyObject, 6 | --- 7 | <% if (isAddToDto && ((kind === 'reference' || kind === 'duplication') && (referenceType === 'oneToOne' || referenceType === 'manyToOne'))) { -%> 8 | IsNotEmptyObject, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/dto/13-create-type-dto-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | at_line: 0 5 | skip_if: import { <%= type %>Dto 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | import { <%= type %>Dto } from '../../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/dto/<%= h.inflection.transform(type, ['underscore', 'dasherize']) %>.dto'; 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/dto/14-create-optional.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsOptional, 6 | --- 7 | <% if (isAddToDto && (isOptional || isNullable)) { -%> 8 | IsOptional, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/dto/15-create-date.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsDate, 6 | --- 7 | <% if (isAddToDto && type === 'Date') { -%> 8 | IsDate, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/dto/16-create-class-transformer-transform.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-transformer'" 5 | skip_if: \Transform, 6 | --- 7 | <% if (isAddToDto && (kind === 'primitive' && type === 'Date')) { -%> 8 | Transform, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/infrastructure/persistence/document/entities/schema-mongoose-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/document/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.schema.ts 4 | at_line: 0 5 | skip_if: import mongoose 6 | --- 7 | <% if (kind === 'reference') { -%> 8 | import mongoose from 'mongoose'; 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/infrastructure/persistence/document/entities/type-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/document/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.schema.ts 4 | at_line: 0 5 | skip_if: <% if (kind === 'reference' || kind === 'duplication') { -%>import { <%= type %>SchemaClass<% } else { -%><%= true %><% } -%> 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | import { <%= type %>SchemaClass } from '../../../../../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/document/entities/<%= h.inflection.transform(type, ['underscore', 'dasherize']) %>.schema'; 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/infrastructure/persistence/document/mappers/mapper-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/document/mappers/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.mapper.ts 4 | at_line: 1 5 | skip_if: import { <%= type %>Mapper 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | import { <%= type %>Mapper } from '../../../../../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/document/mappers/<%= h.inflection.transform(type, ['underscore', 'dasherize']) %>.mapper'; 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/infrastructure/persistence/relational/entities/entity-column.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity.ts 4 | before: from \'typeorm\' 5 | skip_if: \sColumn, 6 | --- 7 | <% if (kind === 'primitive' || kind === 'duplication') { -%> 8 | Column, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/infrastructure/persistence/relational/entities/entity-join-column.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity.ts 4 | before: from \'typeorm\' 5 | skip_if: \sJoinColumn, 6 | --- 7 | <% if (kind === 'reference' && referenceType === 'oneToOne') { -%> 8 | JoinColumn, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/infrastructure/persistence/relational/entities/entity-join-table.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity.ts 4 | before: from \'typeorm\' 5 | skip_if: \JoinTable, 6 | --- 7 | <% if (kind === 'reference' && referenceType === 'manyToMany') { -%> 8 | JoinTable, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/infrastructure/persistence/relational/entities/entity-many-to-many.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity.ts 4 | before: from \'typeorm\' 5 | skip_if: \ManyToMany, 6 | --- 7 | <% if (kind === 'reference' && referenceType === 'manyToMany') { -%> 8 | ManyToMany, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/infrastructure/persistence/relational/entities/entity-many-to-one.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity.ts 4 | before: from \'typeorm\' 5 | skip_if: \sManyToOne, 6 | --- 7 | <% if (kind === 'reference' && referenceType === 'manyToOne') { -%> 8 | ManyToOne, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/infrastructure/persistence/relational/entities/entity-one-to-many.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity.ts 4 | before: from \'typeorm\' 5 | skip_if: \sOneToMany, 6 | --- 7 | <% if (kind === 'reference' && referenceType === 'oneToMany') { -%> 8 | OneToMany, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/infrastructure/persistence/relational/entities/entity-one-to-one.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity.ts 4 | before: from \'typeorm\' 5 | skip_if: \sOneToOne, 6 | --- 7 | <% if (kind === 'reference' && referenceType === 'oneToOne') { -%> 8 | OneToOne, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/infrastructure/persistence/relational/entities/type-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity.ts 4 | at_line: 0 5 | skip_if: <% if (kind === 'reference' || kind === 'duplication') { -%>import { <%= type %>Entity<% } else { -%><%= true %><% } -%> 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | import { <%= type %>Entity } from '../../../../../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(type, ['underscore', 'dasherize']) %>.entity'; 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/infrastructure/persistence/relational/mappers/mapper-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/mappers/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.mapper.ts 4 | at_line: 1 5 | skip_if: import { <%= type %>Mapper 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | import { <%= type %>Mapper } from '../../../../../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/mappers/<%= h.inflection.transform(type, ['underscore', 'dasherize']) %>.mapper'; 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/module-forward-ref.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.module.ts 4 | after: imports.*\[ 5 | skip_if: \=\> <%= h.inflection.transform(type, ['pluralize']) %>Module\)?, 6 | --- 7 | 8 | <% if (kind === 'reference' || kind === 'duplication') { -%> 9 | <% if (referenceType === 'oneToMany' || (referenceType === 'manyToOne' && propertyInReference)) { -%> 10 | forwardRef(() => <%= h.inflection.transform(type, ['pluralize']) %>Module), 11 | <% } -%> 12 | <% } -%> 13 | -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/module-import-forward-ref.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.module.ts 4 | before: from '@nestjs/common' 5 | skip_if: forwardRef, 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | <% if (referenceType === 'oneToMany' || (referenceType === 'manyToOne' && propertyInReference)) { -%> 9 | forwardRef, 10 | <% } -%> 11 | <% } -%> 12 | -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/module-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.module.ts 4 | at_line: 0 5 | skip_if: import { <%= h.inflection.transform(type, ['pluralize']) %>Module 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%>import { <%= h.inflection.transform(type, ['pluralize']) %>Module } from '../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>.module';<% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/module.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.module.ts 4 | after: imports.*\[ 5 | skip_if: <%= h.inflection.transform(type, ['pluralize']) %>Module\)?, 6 | --- 7 | 8 | <% if (kind === 'reference' || kind === 'duplication') { -%> 9 | <% if (!(referenceType === 'oneToMany' || (referenceType === 'manyToOne' && propertyInReference))) { -%> 10 | <%= h.inflection.transform(type, ['pluralize']) %>Module, 11 | <% } -%> 12 | <% } -%> 13 | -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/service-create-payload.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | after: \ 5 | --- 6 | 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | <%= property %>, 9 | <% } else { -%> 10 | <%= property %>: create<%= name %>Dto.<%= property %>, 11 | <% } -%> 12 | -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/service-import-forward-ref.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | before: from '@nestjs/common' 5 | skip_if: forwardRef, 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | <% if (referenceType === 'oneToMany' || (referenceType === 'manyToOne' && propertyInReference)) { -%> 9 | forwardRef, 10 | <% } -%> 11 | <% } -%> 12 | -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/service-import-http-code.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | before: from '@nestjs/common' 5 | skip_if: HttpStatus, 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | HttpStatus, 9 | UnprocessableEntityException, 10 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/service-import-inject-decorator.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | before: from '@nestjs/common' 5 | skip_if: Inject, 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | <% if (referenceType === 'oneToMany' || (referenceType === 'manyToOne' && propertyInReference)) { -%> 9 | Inject, 10 | <% } -%> 11 | <% } -%> 12 | -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/service-import-type-domain.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | at_line: 0 5 | skip_if: import { <%= type %><% if (type === 'File') { -%>Type<% } -%> 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | import { <%= type %><% if (type === 'File') { -%>Type<% } -%> } from '../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/domain/<%= h.inflection.transform(type, ['underscore', 'dasherize']) %>'; 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/service-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | at_line: 0 5 | skip_if: import { <%= h.inflection.transform(type, ['pluralize']) %>Service 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%>import { <%= h.inflection.transform(type, ['pluralize']) %>Service } from '../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>.service';<% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-all-db/service-update-payload.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | after: \ 5 | --- 6 | <% if (kind === 'reference' || kind === 'duplication') { -%> 7 | <%= property %>, 8 | <% } else { -%> 9 | <%= property %>: update<%= name %>Dto.<%= property %>, 10 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/01-service-inject.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | after: constructor 5 | skip_if: private readonly <%= h.inflection.camelize(type, true) %>Service 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | private readonly <%= h.inflection.camelize(type, true) %>Service: <%= h.inflection.transform(type, ['pluralize']) %>Service, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/02-service-inject-decorator.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | before: private readonly <%= h.inflection.camelize(type, true) %>Service 5 | skip_if: \=\> <%= h.inflection.transform(type, ['pluralize']) %>Service\)\) 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | <% if (referenceType === 'oneToMany' || (referenceType === 'manyToOne' && !!propertyInReference)) { -%> 9 | @Inject(forwardRef(() => <%= h.inflection.transform(type, ['pluralize']) %>Service)) 10 | <% } -%> 11 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/domain/domain-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/domain/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.ts 4 | at_line: 0 5 | skip_if: import { <%= type %><% if (type === 'File') { -%>Type<% } -%> 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%>import { <%= type %><% if (type === 'File') { -%>Type<% } -%> } from '../../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/domain/<%= h.inflection.transform(type, ['underscore', 'dasherize']) %>';<% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/dto/02-create-import-class-transformer.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: export class Create<%= name %>Dto 5 | skip_if: "} from 'class-transformer'" 6 | --- 7 | <% if (isAddToDto && (kind === 'reference' || kind === 'duplication' || (kind === 'primitive' && type === 'Date'))) { -%> 8 | import { 9 | // decorators here 10 | } from 'class-transformer'; 11 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/dto/03-create-import-class-validator.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: export class Create<%= name %>Dto 5 | skip_if: "} from 'class-validator'" 6 | --- 7 | <% if (isAddToDto) { -%> 8 | import { 9 | // decorators here 10 | } from 'class-validator'; 11 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/dto/04-create-import-swagger.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: export class Create<%= name %>Dto 5 | skip_if: "} from '@nestjs/swagger'" 6 | --- 7 | <% if (isAddToDto) { -%> 8 | import { 9 | // decorators here 10 | } from '@nestjs/swagger'; 11 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/dto/05-create-boolean.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsBoolean, 6 | --- 7 | <% if (isAddToDto && type === 'boolean') { -%> 8 | IsBoolean, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/dto/06-create-number.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsNumber, 6 | --- 7 | <% if (isAddToDto && type === 'number') { -%> 8 | IsNumber, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/dto/07-create-string.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsString, 6 | --- 7 | <% if (isAddToDto && type === 'string') { -%> 8 | IsString, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/dto/08-create-api-property.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from '@nestjs/swagger'" 5 | skip_if: \ApiProperty, 6 | --- 7 | <% if (isAddToDto) { -%> 8 | ApiProperty, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/dto/09-create-class-transformer-type.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-transformer'" 5 | skip_if: \Type, 6 | --- 7 | <% if (isAddToDto && (kind === 'reference' || kind === 'duplication')) { -%> 8 | Type, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/dto/10-create-validate-is-array.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsArray, 6 | --- 7 | <% if (isAddToDto && (kind === 'reference' || kind === 'duplication') && (referenceType === 'oneToMany' || referenceType === 'manyToMany')) { -%> 8 | IsArray, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/dto/11-create-validate-nested.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \ValidateNested, 6 | --- 7 | <% if (isAddToDto && (kind === 'reference' || kind === 'duplication')) { -%> 8 | ValidateNested, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/dto/12-create-validate-not-empty-object.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsNotEmptyObject, 6 | --- 7 | <% if (isAddToDto && ((kind === 'reference' || kind === 'duplication') && (referenceType === 'oneToOne' || referenceType === 'manyToOne'))) { -%> 8 | IsNotEmptyObject, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/dto/13-create-type-dto-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | at_line: 0 5 | skip_if: import { <%= type %>Dto 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | import { <%= type %>Dto } from '../../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/dto/<%= h.inflection.transform(type, ['underscore', 'dasherize']) %>.dto'; 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/dto/14-create-optional.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsOptional, 6 | --- 7 | <% if (isAddToDto && (isOptional || isNullable)) { -%> 8 | IsOptional, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/dto/15-create-date.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsDate, 6 | --- 7 | <% if (isAddToDto && type === 'Date') { -%> 8 | IsDate, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/dto/16-create-class-transformer-transform.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-transformer'" 5 | skip_if: \Transform, 6 | --- 7 | <% if (isAddToDto && (kind === 'primitive' && type === 'Date')) { -%> 8 | Transform, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/infrastructure/persistence/document/entities/schema-mongoose-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/document/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.schema.ts 4 | at_line: 0 5 | skip_if: import mongoose 6 | --- 7 | <% if (kind === 'reference') { -%> 8 | import mongoose from 'mongoose'; 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/infrastructure/persistence/document/entities/type-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/document/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.schema.ts 4 | at_line: 0 5 | skip_if: <% if (kind === 'reference' || kind === 'duplication') { -%>import { <%= type %>SchemaClass<% } else { -%><%= true %><% } -%> 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | import { <%= type %>SchemaClass } from '../../../../../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/document/entities/<%= h.inflection.transform(type, ['underscore', 'dasherize']) %>.schema'; 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/infrastructure/persistence/document/mappers/mapper-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/document/mappers/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.mapper.ts 4 | at_line: 1 5 | skip_if: import { <%= type %>Mapper 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | import { <%= type %>Mapper } from '../../../../../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/document/mappers/<%= h.inflection.transform(type, ['underscore', 'dasherize']) %>.mapper'; 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/module-forward-ref.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.module.ts 4 | after: imports.*\[ 5 | skip_if: \=\> <%= h.inflection.transform(type, ['pluralize']) %>Module\)?, 6 | --- 7 | 8 | <% if (kind === 'reference' || kind === 'duplication') { -%> 9 | <% if (referenceType === 'oneToMany' || (referenceType === 'manyToOne' && propertyInReference)) { -%> 10 | forwardRef(() => <%= h.inflection.transform(type, ['pluralize']) %>Module), 11 | <% } -%> 12 | <% } -%> 13 | -------------------------------------------------------------------------------- /.hygen/property/add-to-document/module-import-forward-ref.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.module.ts 4 | before: from '@nestjs/common' 5 | skip_if: forwardRef, 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | <% if (referenceType === 'oneToMany' || (referenceType === 'manyToOne' && propertyInReference)) { -%> 9 | forwardRef, 10 | <% } -%> 11 | <% } -%> 12 | -------------------------------------------------------------------------------- /.hygen/property/add-to-document/module-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.module.ts 4 | at_line: 0 5 | skip_if: import { <%= h.inflection.transform(type, ['pluralize']) %>Module 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%>import { <%= h.inflection.transform(type, ['pluralize']) %>Module } from '../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>.module';<% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/module.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.module.ts 4 | after: imports.*\[ 5 | skip_if: <%= h.inflection.transform(type, ['pluralize']) %>Module\)?, 6 | --- 7 | 8 | <% if (kind === 'reference' || kind === 'duplication') { -%> 9 | <% if (!(referenceType === 'oneToMany' || (referenceType === 'manyToOne' && propertyInReference))) { -%> 10 | <%= h.inflection.transform(type, ['pluralize']) %>Module, 11 | <% } -%> 12 | <% } -%> 13 | -------------------------------------------------------------------------------- /.hygen/property/add-to-document/service-create-payload.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | after: \ 5 | --- 6 | 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | <%= property %>, 9 | <% } else { -%> 10 | <%= property %>: create<%= name %>Dto.<%= property %>, 11 | <% } -%> 12 | -------------------------------------------------------------------------------- /.hygen/property/add-to-document/service-import-http-code.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | before: from '@nestjs/common' 5 | skip_if: HttpStatus, 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | HttpStatus, 9 | UnprocessableEntityException, 10 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/service-import-inject-decorator.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | before: from '@nestjs/common' 5 | skip_if: Inject, 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | <% if (referenceType === 'oneToMany' || (referenceType === 'manyToOne' && propertyInReference)) { -%> 9 | Inject, 10 | <% } -%> 11 | <% } -%> 12 | -------------------------------------------------------------------------------- /.hygen/property/add-to-document/service-import-type-domain.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | at_line: 0 5 | skip_if: import { <%= type %><% if (type === 'File') { -%>Type<% } -%> 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | import { <%= type %><% if (type === 'File') { -%>Type<% } -%> } from '../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/domain/<%= h.inflection.transform(type, ['underscore', 'dasherize']) %>'; 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/service-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | at_line: 0 5 | skip_if: import { <%= h.inflection.transform(type, ['pluralize']) %>Service 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%>import { <%= h.inflection.transform(type, ['pluralize']) %>Service } from '../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>.service';<% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-document/service-update-payload.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | after: \ 5 | --- 6 | <% if (kind === 'reference' || kind === 'duplication') { -%> 7 | <%= property %>, 8 | <% } else { -%> 9 | <%= property %>: update<%= name %>Dto.<%= property %>, 10 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/01-service-inject.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | after: constructor 5 | skip_if: private readonly <%= h.inflection.camelize(type, true) %>Service 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | private readonly <%= h.inflection.camelize(type, true) %>Service: <%= h.inflection.transform(type, ['pluralize']) %>Service, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/02-service-inject-decorator.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | before: private readonly <%= h.inflection.camelize(type, true) %>Service 5 | skip_if: \=\> <%= h.inflection.transform(type, ['pluralize']) %>Service\)\) 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | <% if (referenceType === 'oneToMany' || (referenceType === 'manyToOne' && !!propertyInReference)) { -%> 9 | @Inject(forwardRef(() => <%= h.inflection.transform(type, ['pluralize']) %>Service)) 10 | <% } -%> 11 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/domain/domain-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/domain/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.ts 4 | at_line: 0 5 | skip_if: import { <%= type %><% if (type === 'File') { -%>Type<% } -%> 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%>import { <%= type %><% if (type === 'File') { -%>Type<% } -%> } from '../../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/domain/<%= h.inflection.transform(type, ['underscore', 'dasherize']) %>';<% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/dto/02-create-import-class-transformer.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: export class Create<%= name %>Dto 5 | skip_if: "} from 'class-transformer'" 6 | --- 7 | <% if (isAddToDto && (kind === 'reference' || kind === 'duplication' || (kind === 'primitive' && type === 'Date'))) { -%> 8 | import { 9 | // decorators here 10 | } from 'class-transformer'; 11 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/dto/03-create-import-class-validator.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: export class Create<%= name %>Dto 5 | skip_if: "} from 'class-validator'" 6 | --- 7 | <% if (isAddToDto) { -%> 8 | import { 9 | // decorators here 10 | } from 'class-validator'; 11 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/dto/04-create-import-swagger.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: export class Create<%= name %>Dto 5 | skip_if: "} from '@nestjs/swagger'" 6 | --- 7 | <% if (isAddToDto) { -%> 8 | import { 9 | // decorators here 10 | } from '@nestjs/swagger'; 11 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/dto/05-create-boolean.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsBoolean, 6 | --- 7 | <% if (isAddToDto && type === 'boolean') { -%> 8 | IsBoolean, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/dto/06-create-number.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsNumber, 6 | --- 7 | <% if (isAddToDto && type === 'number') { -%> 8 | IsNumber, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/dto/07-create-string.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsString, 6 | --- 7 | <% if (isAddToDto && type === 'string') { -%> 8 | IsString, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/dto/08-create-api-property.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from '@nestjs/swagger'" 5 | skip_if: \ApiProperty, 6 | --- 7 | <% if (isAddToDto) { -%> 8 | ApiProperty, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/dto/09-create-class-transformer-type.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-transformer'" 5 | skip_if: \Type, 6 | --- 7 | <% if (isAddToDto && (kind === 'reference' || kind === 'duplication')) { -%> 8 | Type, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/dto/10-create-validate-is-array.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsArray, 6 | --- 7 | <% if (isAddToDto && (kind === 'reference' || kind === 'duplication') && (referenceType === 'oneToMany' || referenceType === 'manyToMany')) { -%> 8 | IsArray, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/dto/11-create-validate-nested.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \ValidateNested, 6 | --- 7 | <% if (isAddToDto && (kind === 'reference' || kind === 'duplication')) { -%> 8 | ValidateNested, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/dto/12-create-validate-not-empty-object.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsNotEmptyObject, 6 | --- 7 | <% if (isAddToDto && ((kind === 'reference' || kind === 'duplication') && (referenceType === 'oneToOne' || referenceType === 'manyToOne'))) { -%> 8 | IsNotEmptyObject, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/dto/13-create-type-dto-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | at_line: 0 5 | skip_if: import { <%= type %>Dto 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | import { <%= type %>Dto } from '../../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/dto/<%= h.inflection.transform(type, ['underscore', 'dasherize']) %>.dto'; 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/dto/14-create-optional.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsOptional, 6 | --- 7 | <% if (isAddToDto && (isOptional || isNullable)) { -%> 8 | IsOptional, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/dto/15-create-date.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-validator'" 5 | skip_if: \IsDate, 6 | --- 7 | <% if (isAddToDto && type === 'Date') { -%> 8 | IsDate, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/dto/16-create-class-transformer-transform.dto.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/dto/create-<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.dto.ts 4 | before: "} from 'class-transformer'" 5 | skip_if: \Transform, 6 | --- 7 | <% if (isAddToDto && (kind === 'primitive' && type === 'Date')) { -%> 8 | Transform, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/infrastructure/persistence/relational/entities/entity-column.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity.ts 4 | before: from \'typeorm\' 5 | skip_if: \sColumn, 6 | --- 7 | <% if (kind === 'primitive' || kind === 'duplication') { -%> 8 | Column, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/infrastructure/persistence/relational/entities/entity-join-column.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity.ts 4 | before: from \'typeorm\' 5 | skip_if: \sJoinColumn, 6 | --- 7 | <% if (kind === 'reference' && referenceType === 'oneToOne') { -%> 8 | JoinColumn, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/infrastructure/persistence/relational/entities/entity-join-table.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity.ts 4 | before: from \'typeorm\' 5 | skip_if: \JoinTable, 6 | --- 7 | <% if (kind === 'reference' && referenceType === 'manyToMany') { -%> 8 | JoinTable, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/infrastructure/persistence/relational/entities/entity-many-to-many.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity.ts 4 | before: from \'typeorm\' 5 | skip_if: \ManyToMany, 6 | --- 7 | <% if (kind === 'reference' && referenceType === 'manyToMany') { -%> 8 | ManyToMany, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/infrastructure/persistence/relational/entities/entity-many-to-one.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity.ts 4 | before: from \'typeorm\' 5 | skip_if: \sManyToOne, 6 | --- 7 | <% if (kind === 'reference' && referenceType === 'manyToOne') { -%> 8 | ManyToOne, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/infrastructure/persistence/relational/entities/entity-one-to-many.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity.ts 4 | before: from \'typeorm\' 5 | skip_if: \sOneToMany, 6 | --- 7 | <% if (kind === 'reference' && referenceType === 'oneToMany') { -%> 8 | OneToMany, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/infrastructure/persistence/relational/entities/entity-one-to-one.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity.ts 4 | before: from \'typeorm\' 5 | skip_if: \sOneToOne, 6 | --- 7 | <% if (kind === 'reference' && referenceType === 'oneToOne') { -%> 8 | OneToOne, 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/infrastructure/persistence/relational/entities/type-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity.ts 4 | at_line: 0 5 | skip_if: <% if (kind === 'reference' || kind === 'duplication') { -%>import { <%= type %>Entity<% } else { -%><%= true %><% } -%> 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | import { <%= type %>Entity } from '../../../../../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(type, ['underscore', 'dasherize']) %>.entity'; 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/infrastructure/persistence/relational/mappers/mapper-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/mappers/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.mapper.ts 4 | at_line: 1 5 | skip_if: import { <%= type %>Mapper 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | import { <%= type %>Mapper } from '../../../../../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/mappers/<%= h.inflection.transform(type, ['underscore', 'dasherize']) %>.mapper'; 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/module-forward-ref.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.module.ts 4 | after: imports.*\[ 5 | skip_if: \=\> <%= h.inflection.transform(type, ['pluralize']) %>Module\)?, 6 | --- 7 | 8 | <% if (kind === 'reference' || kind === 'duplication') { -%> 9 | <% if (referenceType === 'oneToMany' || (referenceType === 'manyToOne' && propertyInReference)) { -%> 10 | forwardRef(() => <%= h.inflection.transform(type, ['pluralize']) %>Module), 11 | <% } -%> 12 | <% } -%> 13 | -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/module-import-forward-ref.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.module.ts 4 | before: from '@nestjs/common' 5 | skip_if: forwardRef, 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | <% if (referenceType === 'oneToMany' || (referenceType === 'manyToOne' && propertyInReference)) { -%> 9 | forwardRef, 10 | <% } -%> 11 | <% } -%> 12 | -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/module-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.module.ts 4 | at_line: 0 5 | skip_if: import { <%= h.inflection.transform(type, ['pluralize']) %>Module 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%>import { <%= h.inflection.transform(type, ['pluralize']) %>Module } from '../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>.module';<% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/module.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.module.ts 4 | after: imports.*\[ 5 | skip_if: <%= h.inflection.transform(type, ['pluralize']) %>Module\)?, 6 | --- 7 | 8 | <% if (kind === 'reference' || kind === 'duplication') { -%> 9 | <% if (!(referenceType === 'oneToMany' || (referenceType === 'manyToOne' && propertyInReference))) { -%> 10 | <%= h.inflection.transform(type, ['pluralize']) %>Module, 11 | <% } -%> 12 | <% } -%> 13 | -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/service-create-payload.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | after: \ 5 | --- 6 | 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | <%= property %>, 9 | <% } else { -%> 10 | <%= property %>: create<%= name %>Dto.<%= property %>, 11 | <% } -%> 12 | -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/service-import-http-code.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | before: from '@nestjs/common' 5 | skip_if: HttpStatus, 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | HttpStatus, 9 | UnprocessableEntityException, 10 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/service-import-inject-decorator.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | before: from '@nestjs/common' 5 | skip_if: Inject, 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | <% if (referenceType === 'oneToMany' || (referenceType === 'manyToOne' && propertyInReference)) { -%> 9 | Inject, 10 | <% } -%> 11 | <% } -%> 12 | -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/service-import-type-domain.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | at_line: 0 5 | skip_if: import { <%= type %><% if (type === 'File') { -%>Type<% } -%> 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%> 8 | import { <%= type %><% if (type === 'File') { -%>Type<% } -%> } from '../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/domain/<%= h.inflection.transform(type, ['underscore', 'dasherize']) %>'; 9 | <% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/service-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | at_line: 0 5 | skip_if: import { <%= h.inflection.transform(type, ['pluralize']) %>Service 6 | --- 7 | <% if (kind === 'reference' || kind === 'duplication') { -%>import { <%= h.inflection.transform(type, ['pluralize']) %>Service } from '../<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(type, ['pluralize', 'underscore', 'dasherize']) %>.service';<% } -%> -------------------------------------------------------------------------------- /.hygen/property/add-to-relational/service-update-payload.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>.service.ts 4 | after: \ 5 | --- 6 | <% if (kind === 'reference' || kind === 'duplication') { -%> 7 | <%= property %>, 8 | <% } else { -%> 9 | <%= property %>: update<%= name %>Dto.<%= property %>, 10 | <% } -%> -------------------------------------------------------------------------------- /.hygen/seeds/create-document/module.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/database/seeds/document/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>-seed.module.ts 3 | --- 4 | import { Module } from '@nestjs/common'; 5 | import { MongooseModule } from '@nestjs/mongoose'; 6 | import { <%= name %>Schema, <%= name %>SchemaClass } from '../../../../<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/document/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.schema'; 7 | import { <%= name %>SeedService } from './<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>-seed.service'; 8 | 9 | @Module({ 10 | imports: [ 11 | MongooseModule.forFeature([ 12 | { 13 | name: <%= name %>SchemaClass.name, 14 | schema: <%= name %>Schema, 15 | }, 16 | ]), 17 | ], 18 | providers: [<%= name %>SeedService], 19 | exports: [<%= name %>SeedService], 20 | }) 21 | export class <%= name %>SeedModule {} 22 | -------------------------------------------------------------------------------- /.hygen/seeds/create-document/run-seed-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/database/seeds/document/run-seed.ts 4 | after: \@nestjs\/core 5 | --- 6 | import { <%= name %>SeedService } from './<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>-seed.service'; -------------------------------------------------------------------------------- /.hygen/seeds/create-document/run-seed-service.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/database/seeds/document/run-seed.ts 4 | before: close 5 | --- 6 | await app.get(<%= name %>SeedService).run(); 7 | -------------------------------------------------------------------------------- /.hygen/seeds/create-document/seed-module-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/database/seeds/document/seed.module.ts 4 | before: \@Module 5 | --- 6 | import { <%= name %>SeedModule } from './<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>-seed.module'; 7 | -------------------------------------------------------------------------------- /.hygen/seeds/create-document/seed-module.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/database/seeds/document/seed.module.ts 4 | after: imports 5 | --- 6 | <%= name %>SeedModule, -------------------------------------------------------------------------------- /.hygen/seeds/create-document/service.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/database/seeds/document/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>-seed.service.ts 3 | --- 4 | import { Injectable } from '@nestjs/common'; 5 | import { InjectModel } from '@nestjs/mongoose'; 6 | import { Model } from 'mongoose'; 7 | import { <%= name %>SchemaClass } from '../../../../<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/document/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.schema'; 8 | 9 | @Injectable() 10 | export class <%= name %>SeedService { 11 | constructor( 12 | @InjectModel(<%= name %>SchemaClass.name) 13 | private readonly model: Model<<%= name %>SchemaClass>, 14 | ) {} 15 | 16 | async run() { 17 | const count = await this.model.countDocuments(); 18 | 19 | if (count === 0) { 20 | const data = new this.model({}); 21 | await data.save(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.hygen/seeds/create-relational/module.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/database/seeds/relational/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>-seed.module.ts 3 | --- 4 | import { Module } from '@nestjs/common'; 5 | import { TypeOrmModule } from '@nestjs/typeorm'; 6 | import { <%= name %>Entity } from '../../../../<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity'; 7 | import { <%= name %>SeedService } from './<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>-seed.service'; 8 | 9 | @Module({ 10 | imports: [TypeOrmModule.forFeature([<%= name %>Entity])], 11 | providers: [<%= name %>SeedService], 12 | exports: [<%= name %>SeedService], 13 | }) 14 | export class <%= name %>SeedModule {} 15 | -------------------------------------------------------------------------------- /.hygen/seeds/create-relational/run-seed-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/database/seeds/relational/run-seed.ts 4 | after: \@nestjs\/core 5 | --- 6 | import { <%= name %>SeedService } from './<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>-seed.service'; -------------------------------------------------------------------------------- /.hygen/seeds/create-relational/run-seed-service.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/database/seeds/relational/run-seed.ts 4 | before: close 5 | --- 6 | await app.get(<%= name %>SeedService).run(); 7 | -------------------------------------------------------------------------------- /.hygen/seeds/create-relational/seed-module-import.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/database/seeds/relational/seed.module.ts 4 | before: \@Module 5 | --- 6 | import { <%= name %>SeedModule } from './<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>-seed.module'; 7 | -------------------------------------------------------------------------------- /.hygen/seeds/create-relational/seed-module.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | inject: true 3 | to: src/database/seeds/relational/seed.module.ts 4 | after: imports 5 | --- 6 | <%= name %>SeedModule, -------------------------------------------------------------------------------- /.hygen/seeds/create-relational/service.ejs.t: -------------------------------------------------------------------------------- 1 | --- 2 | to: src/database/seeds/relational/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>-seed.service.ts 3 | --- 4 | import { Injectable } from '@nestjs/common'; 5 | import { InjectRepository } from '@nestjs/typeorm'; 6 | import { <%= name %>Entity } from '../../../../<%= h.inflection.transform(name, ['pluralize', 'underscore', 'dasherize']) %>/infrastructure/persistence/relational/entities/<%= h.inflection.transform(name, ['underscore', 'dasherize']) %>.entity'; 7 | import { Repository } from 'typeorm'; 8 | 9 | @Injectable() 10 | export class <%= name %>SeedService { 11 | constructor( 12 | @InjectRepository(<%= name %>Entity) 13 | private repository: Repository<<%= name %>Entity>, 14 | ) {} 15 | 16 | async run() { 17 | const count = await this.repository.count(); 18 | 19 | if (count === 0) { 20 | await this.repository.save(this.repository.create({})); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.install-scripts/helpers/replace.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | 3 | const replace = (params: { 4 | path: string; 5 | actions: Array<{ 6 | find: string | RegExp; 7 | replace: string; 8 | }>; 9 | }) => { 10 | const { path, actions } = params; 11 | 12 | try { 13 | let content = fs.readFileSync(path, 'utf-8'); 14 | 15 | actions.forEach((action) => { 16 | content = content.replace(action.find, action.replace); 17 | }); 18 | 19 | fs.writeFileSync(path, content, 'utf-8'); 20 | } catch (error) { 21 | console.error(`Error replacing text in ${path}:`, error.message); 22 | } 23 | }; 24 | 25 | export default replace; 26 | -------------------------------------------------------------------------------- /.install-scripts/scripts/property-generation-scripts/remove-all-db.ts: -------------------------------------------------------------------------------- 1 | import replace from '../../helpers/replace'; 2 | import path from 'path'; 3 | import fs from 'fs'; 4 | 5 | const removeAllDbPropertyGeneration = async () => { 6 | const filesToRemove = [ 7 | path.join(process.cwd(), '.hygen', 'property', 'add-to-all-db'), 8 | ]; 9 | 10 | replace({ 11 | path: path.join(process.cwd(), 'package.json'), 12 | actions: [ 13 | { 14 | find: /\s*\"add:property:to-all-db\":.*/g, 15 | replace: '', 16 | }, 17 | { 18 | find: /\s*\"postadd:property:to-all-db\":.*/g, 19 | replace: '', 20 | }, 21 | ], 22 | }); 23 | 24 | filesToRemove.map((file) => { 25 | fs.rmSync(file, { 26 | recursive: true, 27 | force: true, 28 | }); 29 | }); 30 | }; 31 | 32 | export default removeAllDbPropertyGeneration; 33 | -------------------------------------------------------------------------------- /.install-scripts/scripts/property-generation-scripts/remove-document.ts: -------------------------------------------------------------------------------- 1 | import replace from '../../helpers/replace'; 2 | import path from 'path'; 3 | import fs from 'fs'; 4 | 5 | const removeDocumentPropertyGeneration = async () => { 6 | const filesToRemove = [ 7 | path.join(process.cwd(), '.hygen', 'property', 'add-to-document'), 8 | ]; 9 | 10 | replace({ 11 | path: path.join(process.cwd(), 'package.json'), 12 | actions: [ 13 | { 14 | find: /\s*\"add:property:to-document\":.*/g, 15 | replace: '', 16 | }, 17 | { 18 | find: /\s*\"postadd:property:to-document\":.*/g, 19 | replace: '', 20 | }, 21 | ], 22 | }); 23 | 24 | filesToRemove.map((file) => { 25 | fs.rmSync(file, { 26 | recursive: true, 27 | force: true, 28 | }); 29 | }); 30 | }; 31 | 32 | export default removeDocumentPropertyGeneration; 33 | -------------------------------------------------------------------------------- /.install-scripts/scripts/property-generation-scripts/remove-relational.ts: -------------------------------------------------------------------------------- 1 | import replace from '../../helpers/replace'; 2 | import path from 'path'; 3 | import fs from 'fs'; 4 | 5 | const removeRelationalPropertyGeneration = async () => { 6 | const filesToRemove = [ 7 | path.join(process.cwd(), '.hygen', 'property', 'add-to-relational'), 8 | ]; 9 | 10 | replace({ 11 | path: path.join(process.cwd(), 'package.json'), 12 | actions: [ 13 | { 14 | find: /\s*\"add:property:to-relational\":.*/g, 15 | replace: '', 16 | }, 17 | { 18 | find: /\s*\"postadd:property:to-relational\":.*/g, 19 | replace: '', 20 | }, 21 | ], 22 | }); 23 | 24 | filesToRemove.map((file) => { 25 | fs.rmSync(file, { 26 | recursive: true, 27 | force: true, 28 | }); 29 | }); 30 | }; 31 | 32 | export default removeRelationalPropertyGeneration; 33 | -------------------------------------------------------------------------------- /.install-scripts/scripts/remove-install-scripts.ts: -------------------------------------------------------------------------------- 1 | import replace from '../helpers/replace'; 2 | import path from 'path'; 3 | import fs from 'fs'; 4 | 5 | const removeInstallScripts = async () => { 6 | replace({ 7 | path: path.join(process.cwd(), 'package.json'), 8 | actions: [ 9 | { 10 | find: /\s*\"app:config\".*/g, 11 | replace: '', 12 | }, 13 | { 14 | find: /\s*\"@types\/prompts\"\:.*/g, 15 | replace: '', 16 | }, 17 | ], 18 | }); 19 | fs.rmSync(path.join(process.cwd(), '.install-scripts'), { 20 | recursive: true, 21 | force: true, 22 | }); 23 | }; 24 | 25 | export default removeInstallScripts; 26 | -------------------------------------------------------------------------------- /.install-scripts/scripts/resource-generation-scripts/remove-all-db.ts: -------------------------------------------------------------------------------- 1 | import replace from '../../helpers/replace'; 2 | import path from 'path'; 3 | import fs from 'fs'; 4 | 5 | const removeAllDbResourceGeneration = async () => { 6 | const filesToRemove = [ 7 | path.join(process.cwd(), '.hygen', 'generate', 'all-db-resource'), 8 | ]; 9 | 10 | replace({ 11 | path: path.join(process.cwd(), 'package.json'), 12 | actions: [ 13 | { 14 | find: /\s*\"generate:resource:all-db\":.*/g, 15 | replace: '', 16 | }, 17 | { 18 | find: /\s*\"postgenerate:resource:all-db\":.*/g, 19 | replace: '', 20 | }, 21 | ], 22 | }); 23 | 24 | filesToRemove.map((file) => { 25 | fs.rmSync(file, { 26 | recursive: true, 27 | force: true, 28 | }); 29 | }); 30 | }; 31 | 32 | export default removeAllDbResourceGeneration; 33 | -------------------------------------------------------------------------------- /.install-scripts/scripts/resource-generation-scripts/remove-document.ts: -------------------------------------------------------------------------------- 1 | import replace from '../../helpers/replace'; 2 | import path from 'path'; 3 | import fs from 'fs'; 4 | 5 | const removeDocumentResourceGeneration = async () => { 6 | const filesToRemove = [ 7 | path.join(process.cwd(), '.hygen', 'generate', 'document-resource'), 8 | ]; 9 | 10 | replace({ 11 | path: path.join(process.cwd(), 'package.json'), 12 | actions: [ 13 | { 14 | find: /\s*\"generate:resource:document\":.*/g, 15 | replace: '', 16 | }, 17 | { 18 | find: /\s*\"postgenerate:resource:document\":.*/g, 19 | replace: '', 20 | }, 21 | ], 22 | }); 23 | 24 | filesToRemove.map((file) => { 25 | fs.rmSync(file, { 26 | recursive: true, 27 | force: true, 28 | }); 29 | }); 30 | }; 31 | 32 | export default removeDocumentResourceGeneration; 33 | -------------------------------------------------------------------------------- /.install-scripts/scripts/resource-generation-scripts/remove-relational.ts: -------------------------------------------------------------------------------- 1 | import replace from '../../helpers/replace'; 2 | import path from 'path'; 3 | import fs from 'fs'; 4 | 5 | const removeRelationalResourceGeneration = async () => { 6 | const filesToRemove = [ 7 | path.join(process.cwd(), '.hygen', 'generate', 'relational-resource'), 8 | ]; 9 | 10 | replace({ 11 | path: path.join(process.cwd(), 'package.json'), 12 | actions: [ 13 | { 14 | find: /\s*\"generate:resource:relational\":.*/g, 15 | replace: '', 16 | }, 17 | { 18 | find: /\s*\"postgenerate:resource:relational\":.*/g, 19 | replace: '', 20 | }, 21 | ], 22 | }); 23 | 24 | filesToRemove.map((file) => { 25 | fs.rmSync(file, { 26 | recursive: true, 27 | force: true, 28 | }); 29 | }); 30 | }; 31 | 32 | export default removeRelationalResourceGeneration; 33 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 22.16.0 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "all" 4 | } 5 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "yzhang.markdown-all-in-one", 4 | "DavidAnson.vscode-markdownlint" 5 | ] 6 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "markdown.extension.toc.levels": "2..6", 3 | "markdown.extension.orderedList.autoRenumber": false, 4 | "typescript.preferences.importModuleSpecifier": "relative" 5 | } 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:22.16.0-alpine 2 | 3 | RUN apk add --no-cache bash 4 | RUN npm i -g @nestjs/cli typescript ts-node 5 | 6 | COPY package*.json /tmp/app/ 7 | RUN cd /tmp/app && npm install 8 | 9 | COPY . /usr/src/app 10 | RUN cp -a /tmp/app/node_modules /usr/src/app 11 | COPY ./wait-for-it.sh /opt/wait-for-it.sh 12 | RUN chmod +x /opt/wait-for-it.sh 13 | COPY ./startup.relational.dev.sh /opt/startup.relational.dev.sh 14 | RUN chmod +x /opt/startup.relational.dev.sh 15 | RUN sed -i 's/\r//g' /opt/wait-for-it.sh 16 | RUN sed -i 's/\r//g' /opt/startup.relational.dev.sh 17 | 18 | WORKDIR /usr/src/app 19 | RUN if [ ! -f .env ]; then cp env-example-relational .env; fi 20 | RUN npm run build 21 | 22 | CMD ["/opt/startup.relational.dev.sh"] 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Brocoders 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: npm run start:prod 2 | release: echo '' > .env && npm run migration:run && npm run seed:run:relational -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'], 3 | }; 4 | -------------------------------------------------------------------------------- /docker-compose.document.ci.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | mongo: 3 | image: mongo:8.0.9 4 | restart: always 5 | environment: 6 | MONGO_INITDB_ROOT_USERNAME: ${DATABASE_USERNAME} 7 | MONGO_INITDB_ROOT_PASSWORD: ${DATABASE_PASSWORD} 8 | expose: 9 | - 27017 10 | 11 | maildev: 12 | build: 13 | context: . 14 | dockerfile: maildev.Dockerfile 15 | expose: 16 | - 1080 17 | - 1025 18 | 19 | # Uncomment to use redis 20 | # redis: 21 | # image: redis:7-alpine 22 | # expose: 23 | # - 6379 24 | 25 | api: 26 | build: 27 | context: . 28 | dockerfile: document.e2e.Dockerfile 29 | env_file: 30 | - env-example-document 31 | -------------------------------------------------------------------------------- /docker-compose.document.test.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | mongo: 3 | image: mongo:8.0.9 4 | restart: always 5 | environment: 6 | MONGO_INITDB_ROOT_USERNAME: ${DATABASE_USERNAME} 7 | MONGO_INITDB_ROOT_PASSWORD: ${DATABASE_PASSWORD} 8 | expose: 9 | - 27017 10 | 11 | maildev: 12 | build: 13 | context: . 14 | dockerfile: maildev.Dockerfile 15 | expose: 16 | - 1080 17 | - 1025 18 | 19 | # Uncomment to use redis 20 | # redis: 21 | # image: redis:7-alpine 22 | # expose: 23 | # - 6379 24 | 25 | api: 26 | build: 27 | context: . 28 | dockerfile: document.test.Dockerfile 29 | env_file: 30 | - env-example-document 31 | volumes: 32 | - ./src:/usr/src/app/src 33 | - ./test:/usr/src/app/test 34 | -------------------------------------------------------------------------------- /docker-compose.document.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | maildev: 3 | build: 4 | context: . 5 | dockerfile: maildev.Dockerfile 6 | ports: 7 | - ${MAIL_CLIENT_PORT}:1080 8 | - ${MAIL_PORT}:1025 9 | 10 | mongo: 11 | image: mongo:8.0.9 12 | restart: always 13 | environment: 14 | MONGO_INITDB_ROOT_USERNAME: ${DATABASE_USERNAME} 15 | MONGO_INITDB_ROOT_PASSWORD: ${DATABASE_PASSWORD} 16 | volumes: 17 | - boilerplate-mongo-db:/data/db 18 | ports: 19 | - ${DATABASE_PORT}:27017 20 | 21 | mongo-express: 22 | image: mongo-express 23 | restart: always 24 | ports: 25 | - 8081:8081 26 | environment: 27 | ME_CONFIG_BASICAUTH_USERNAME: ${DATABASE_USERNAME} 28 | ME_CONFIG_BASICAUTH_PASSWORD: ${DATABASE_PASSWORD} 29 | ME_CONFIG_MONGODB_URL: mongodb://${DATABASE_USERNAME}:${DATABASE_PASSWORD}@mongo:${DATABASE_PORT}/ 30 | 31 | # Uncomment to use redis 32 | # redis: 33 | # image: redis:7-alpine 34 | # ports: 35 | # - 6379:6379 36 | 37 | api: 38 | build: 39 | context: . 40 | dockerfile: document.Dockerfile 41 | ports: 42 | - ${APP_PORT}:${APP_PORT} 43 | 44 | volumes: 45 | boilerplate-mongo-db: 46 | -------------------------------------------------------------------------------- /docker-compose.relational.ci.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | postgres: 3 | image: postgres:17.5-alpine 4 | expose: 5 | - 5432 6 | environment: 7 | POSTGRES_USER: ${DATABASE_USERNAME} 8 | POSTGRES_PASSWORD: ${DATABASE_PASSWORD} 9 | POSTGRES_DB: ${DATABASE_NAME} 10 | 11 | maildev: 12 | build: 13 | context: . 14 | dockerfile: maildev.Dockerfile 15 | expose: 16 | - 1080 17 | - 1025 18 | 19 | # Uncomment to use redis 20 | # redis: 21 | # image: redis:7-alpine 22 | # expose: 23 | # - 6379 24 | 25 | api: 26 | build: 27 | context: . 28 | dockerfile: relational.e2e.Dockerfile 29 | env_file: 30 | - env-example-relational 31 | -------------------------------------------------------------------------------- /docker-compose.relational.test.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | postgres: 3 | image: postgres:17.5-alpine 4 | expose: 5 | - 5432 6 | environment: 7 | POSTGRES_USER: ${DATABASE_USERNAME} 8 | POSTGRES_PASSWORD: ${DATABASE_PASSWORD} 9 | POSTGRES_DB: ${DATABASE_NAME} 10 | 11 | maildev: 12 | build: 13 | context: . 14 | dockerfile: maildev.Dockerfile 15 | expose: 16 | - 1080 17 | - 1025 18 | 19 | # Uncomment to use redis 20 | # redis: 21 | # image: redis:7-alpine 22 | # expose: 23 | # - 6379 24 | 25 | api: 26 | build: 27 | context: . 28 | dockerfile: relational.test.Dockerfile 29 | env_file: 30 | - env-example-relational 31 | volumes: 32 | - ./src:/usr/src/app/src 33 | - ./test:/usr/src/app/test 34 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | postgres: 3 | image: postgres:17.5-alpine 4 | ports: 5 | - ${DATABASE_PORT}:5432 6 | volumes: 7 | - boilerplate-db:/var/lib/postgresql/data 8 | environment: 9 | POSTGRES_USER: ${DATABASE_USERNAME} 10 | POSTGRES_PASSWORD: ${DATABASE_PASSWORD} 11 | POSTGRES_DB: ${DATABASE_NAME} 12 | 13 | maildev: 14 | build: 15 | context: . 16 | dockerfile: maildev.Dockerfile 17 | ports: 18 | - ${MAIL_CLIENT_PORT}:1080 19 | - ${MAIL_PORT}:1025 20 | 21 | adminer: 22 | image: adminer 23 | restart: always 24 | ports: 25 | - 8080:8080 26 | 27 | # Uncomment to use redis 28 | # redis: 29 | # image: redis:7-alpine 30 | # ports: 31 | # - 6379:6379 32 | 33 | api: 34 | build: 35 | context: . 36 | dockerfile: Dockerfile 37 | ports: 38 | - ${APP_PORT}:${APP_PORT} 39 | 40 | volumes: 41 | boilerplate-db: 42 | -------------------------------------------------------------------------------- /docs/automatic-update-dependencies.md: -------------------------------------------------------------------------------- 1 | # Automatic update of dependencies 2 | 3 | If you want to automatically update dependencies, you can connect [Renovate](https://github.com/marketplace/renovate) for your project. 4 | 5 | --- 6 | 7 | Previous: [Benchmarking](benchmarking.md) 8 | 9 | Next: [Translations](translations.md) -------------------------------------------------------------------------------- /docs/benchmarking.md: -------------------------------------------------------------------------------- 1 | # Test benchmarking 2 | 3 | ## Table of Contents 4 | 5 | - [Apache Benchmark](#apache-benchmark) 6 | 7 | ## Apache Benchmark 8 | 9 | ```bash 10 | docker run --rm jordi/ab -n 100 -c 100 -T application/json -H "Authorization: Bearer USER_TOKEN" -v 2 http://:3000/api/v1/users 11 | ``` 12 | 13 | --- 14 | 15 | Previous: [Tests](tests.md) 16 | 17 | Next: [Automatic update of dependencies](automatic-update-dependencies.md) 18 | -------------------------------------------------------------------------------- /docs/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | ## Online demo 4 | 5 | Demo: 6 | 7 | Frontend (React, Next.js): 8 | 9 | 10 | 11 | ## Features 12 | 13 | - [x] Database. Support [TypeORM](https://www.npmjs.com/package/typeorm) and [Mongoose](https://www.npmjs.com/package/mongoose). 14 | - [x] Seeding. 15 | - [x] Config Service ([@nestjs/config](https://www.npmjs.com/package/@nestjs/config)). 16 | - [x] Mailing ([nodemailer](https://www.npmjs.com/package/nodemailer)). 17 | - [x] Sign in and sign up via email. 18 | - [x] Social sign in (Apple, Facebook, Google). 19 | - [x] Admin and User roles. 20 | - [x] Internationalization/Translations (I18N) ([nestjs-i18n](https://www.npmjs.com/package/nestjs-i18n)). 21 | - [x] File uploads. Support local and Amazon S3 drivers. 22 | - [x] Swagger. 23 | - [x] Support E2E and units tests. 24 | - [x] Docker. 25 | - [x] CI (Github Actions). 26 | 27 | --- 28 | 29 | Previous: [Main](readme.md) 30 | 31 | Next: [Installing and Running](installing-and-running.md) 32 | -------------------------------------------------------------------------------- /docs/readme.md: -------------------------------------------------------------------------------- 1 | # NestJS Boilerplate Documentation 2 | 3 | --- 4 | 5 | ## Table of Contents 6 | 7 | - [Introduction](introduction.md) 8 | - [Installing and Running](installing-and-running.md) 9 | - [Architecture](architecture.md) 10 | - [Command Line Interface](cli.md) 11 | - [Database](database.md) 12 | - [Auth](auth.md) 13 | - [Serialization](serialization.md) 14 | - [File uploading](file-uploading.md) 15 | - [Tests](tests.md) 16 | - [Benchmarking](benchmarking.md) 17 | - [Automatic update of dependencies](automatic-update-dependencies.md) 18 | - [Translations](translations.md) 19 | -------------------------------------------------------------------------------- /docs/tests.md: -------------------------------------------------------------------------------- 1 | # Tests 2 | 3 | ## Table of Contents 4 | 5 | - [Unit Tests](#unit-tests) 6 | - [E2E Tests](#e2e-tests) 7 | - [Tests in Docker](#tests-in-docker) 8 | - [For relational database](#for-relational-database) 9 | - [For document database](#for-document-database) 10 | 11 | ## Unit Tests 12 | 13 | ```bash 14 | npm run test 15 | ``` 16 | 17 | ## E2E Tests 18 | 19 | ```bash 20 | npm run test:e2e 21 | ``` 22 | 23 | ## Tests in Docker 24 | 25 | ### For relational database 26 | 27 | ```bash 28 | npm run test:e2e:relational:docker 29 | ``` 30 | 31 | ### For document database 32 | 33 | ```bash 34 | npm run test:e2e:document:docker 35 | ``` 36 | 37 | --- 38 | 39 | Previous: [File uploading](file-uploading.md) 40 | 41 | Next: [Benchmarking](benchmarking.md) 42 | -------------------------------------------------------------------------------- /docs/translations.md: -------------------------------------------------------------------------------- 1 | # Translations 2 | 3 | ## Table of Contents 4 | 5 | - [How to add a new translation](#how-to-add-a-new-translation) 6 | - [How to use translations on frontend](#how-to-use-translations-on-frontend) 7 | - [How to use translations in code](#how-to-use-translations-in-code) 8 | 9 | ## How to add a new translation 10 | 11 | 1. Copy the `en` folder and rename it to the language you are adding. 12 | 2. Translate files in the new folder. 13 | 14 | ## How to use translations on frontend 15 | 16 | 1. Add header `x-custom-lang` to the request with the language you want to use. 17 | 18 | ## How to use translations in code 19 | 20 | ```typescript 21 | import { I18nContext } from 'nestjs-i18n'; 22 | 23 | // code ... 24 | 25 | @Injectable() 26 | export class SomeService { 27 | // code ... 28 | 29 | async someMethod(): Promise { 30 | const i18n = I18nContext.current(); 31 | 32 | if (!i18n) { 33 | throw new Error('I18nContext is not available'); 34 | } 35 | 36 | const emailConfirmTitle = await i18n.t('common.confirmEmail'); 37 | 38 | // code ... 39 | } 40 | } 41 | ``` 42 | 43 | --- 44 | 45 | Previous: [Automatic update of dependencies](automatic-update-dependencies.md) 46 | -------------------------------------------------------------------------------- /document.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:22.16.0-alpine 2 | 3 | RUN apk add --no-cache bash 4 | RUN npm i -g @nestjs/cli typescript ts-node 5 | 6 | COPY package*.json /tmp/app/ 7 | RUN cd /tmp/app && npm install 8 | 9 | COPY . /usr/src/app 10 | RUN cp -a /tmp/app/node_modules /usr/src/app 11 | COPY ./wait-for-it.sh /opt/wait-for-it.sh 12 | RUN chmod +x /opt/wait-for-it.sh 13 | COPY ./startup.document.dev.sh /opt/startup.document.dev.sh 14 | RUN chmod +x /opt/startup.document.dev.sh 15 | RUN sed -i 's/\r//g' /opt/wait-for-it.sh 16 | RUN sed -i 's/\r//g' /opt/startup.document.dev.sh 17 | 18 | WORKDIR /usr/src/app 19 | RUN if [ ! -f .env ]; then cp env-example-document .env; fi 20 | RUN npm run build 21 | 22 | CMD ["/opt/startup.document.dev.sh"] 23 | -------------------------------------------------------------------------------- /document.e2e.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:22.16.0-alpine 2 | 3 | RUN apk add --no-cache bash 4 | RUN npm i -g @nestjs/cli typescript ts-node 5 | 6 | COPY package*.json /tmp/app/ 7 | RUN cd /tmp/app && npm install 8 | 9 | COPY . /usr/src/app 10 | RUN cp -a /tmp/app/node_modules /usr/src/app 11 | COPY ./wait-for-it.sh /opt/wait-for-it.sh 12 | RUN chmod +x /opt/wait-for-it.sh 13 | COPY ./startup.document.ci.sh /opt/startup.document.ci.sh 14 | RUN chmod +x /opt/startup.document.ci.sh 15 | RUN sed -i 's/\r//g' /opt/wait-for-it.sh 16 | RUN sed -i 's/\r//g' /opt/startup.document.ci.sh 17 | 18 | WORKDIR /usr/src/app 19 | RUN echo "" > .env 20 | RUN npm run build 21 | 22 | CMD ["/opt/startup.document.ci.sh"] 23 | -------------------------------------------------------------------------------- /document.test.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:22.16.0-alpine 2 | 3 | RUN apk add --no-cache bash 4 | RUN npm i -g @nestjs/cli typescript ts-node 5 | 6 | COPY package*.json /tmp/app/ 7 | RUN cd /tmp/app && npm install 8 | 9 | COPY . /usr/src/app 10 | 11 | COPY ./wait-for-it.sh /opt/wait-for-it.sh 12 | RUN chmod +x /opt/wait-for-it.sh 13 | COPY ./startup.document.test.sh /opt/startup.document.test.sh 14 | RUN chmod +x /opt/startup.document.test.sh 15 | RUN sed -i 's/\r//g' /opt/wait-for-it.sh 16 | RUN sed -i 's/\r//g' /opt/startup.document.test.sh 17 | 18 | WORKDIR /usr/src/app 19 | 20 | RUN echo "" > .env 21 | 22 | CMD ["/opt/startup.document.test.sh"] 23 | -------------------------------------------------------------------------------- /maildev.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:22.16.0-alpine 2 | 3 | RUN npm i -g maildev@2.0.5 4 | 5 | CMD maildev 6 | -------------------------------------------------------------------------------- /nest-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/nest-cli", 3 | "collection": "@nestjs/schematics", 4 | "sourceRoot": "src", 5 | "compilerOptions": { 6 | "assets": [{ "include": "i18n/**/*", "watchAssets": true }] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /relational.e2e.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:22.16.0-alpine 2 | 3 | RUN apk add --no-cache bash 4 | RUN npm i -g @nestjs/cli typescript ts-node 5 | 6 | COPY package*.json /tmp/app/ 7 | RUN cd /tmp/app && npm install 8 | 9 | COPY . /usr/src/app 10 | RUN cp -a /tmp/app/node_modules /usr/src/app 11 | COPY ./wait-for-it.sh /opt/wait-for-it.sh 12 | RUN chmod +x /opt/wait-for-it.sh 13 | COPY ./startup.relational.ci.sh /opt/startup.relational.ci.sh 14 | RUN chmod +x /opt/startup.relational.ci.sh 15 | RUN sed -i 's/\r//g' /opt/wait-for-it.sh 16 | RUN sed -i 's/\r//g' /opt/startup.relational.ci.sh 17 | 18 | WORKDIR /usr/src/app 19 | RUN echo "" > .env 20 | RUN npm run build 21 | 22 | CMD ["/opt/startup.relational.ci.sh"] 23 | -------------------------------------------------------------------------------- /relational.test.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:22.16.0-alpine 2 | 3 | RUN apk add --no-cache bash 4 | RUN npm i -g @nestjs/cli typescript ts-node 5 | 6 | COPY package*.json /tmp/app/ 7 | RUN cd /tmp/app && npm install 8 | 9 | COPY . /usr/src/app 10 | 11 | COPY ./wait-for-it.sh /opt/wait-for-it.sh 12 | RUN chmod +x /opt/wait-for-it.sh 13 | COPY ./startup.relational.test.sh /opt/startup.relational.test.sh 14 | RUN chmod +x /opt/startup.relational.test.sh 15 | RUN sed -i 's/\r//g' /opt/wait-for-it.sh 16 | RUN sed -i 's/\r//g' /opt/startup.relational.test.sh 17 | 18 | WORKDIR /usr/src/app 19 | 20 | RUN echo "" > .env 21 | 22 | CMD ["/opt/startup.relational.test.sh"] 23 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/auth-apple/auth-apple.controller.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Body, 3 | Controller, 4 | HttpCode, 5 | HttpStatus, 6 | Post, 7 | SerializeOptions, 8 | } from '@nestjs/common'; 9 | import { ApiOkResponse, ApiTags } from '@nestjs/swagger'; 10 | import { AuthService } from '../auth/auth.service'; 11 | import { AuthAppleService } from './auth-apple.service'; 12 | import { AuthAppleLoginDto } from './dto/auth-apple-login.dto'; 13 | import { LoginResponseDto } from '../auth/dto/login-response.dto'; 14 | 15 | @ApiTags('Auth') 16 | @Controller({ 17 | path: 'auth/apple', 18 | version: '1', 19 | }) 20 | export class AuthAppleController { 21 | constructor( 22 | private readonly authService: AuthService, 23 | private readonly authAppleService: AuthAppleService, 24 | ) {} 25 | 26 | @ApiOkResponse({ 27 | type: LoginResponseDto, 28 | }) 29 | @SerializeOptions({ 30 | groups: ['me'], 31 | }) 32 | @Post('login') 33 | @HttpCode(HttpStatus.OK) 34 | async login(@Body() loginDto: AuthAppleLoginDto): Promise { 35 | const socialData = await this.authAppleService.getProfileByToken(loginDto); 36 | 37 | return this.authService.validateSocialLogin('apple', socialData); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/auth-apple/auth-apple.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { AuthAppleService } from './auth-apple.service'; 3 | import { ConfigModule } from '@nestjs/config'; 4 | import { AuthAppleController } from './auth-apple.controller'; 5 | import { AuthModule } from '../auth/auth.module'; 6 | 7 | @Module({ 8 | imports: [ConfigModule, AuthModule], 9 | providers: [AuthAppleService], 10 | exports: [AuthAppleService], 11 | controllers: [AuthAppleController], 12 | }) 13 | export class AuthAppleModule {} 14 | -------------------------------------------------------------------------------- /src/auth-apple/auth-apple.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import appleSigninAuth from 'apple-signin-auth'; 3 | import { ConfigService } from '@nestjs/config'; 4 | import { SocialInterface } from '../social/interfaces/social.interface'; 5 | import { AuthAppleLoginDto } from './dto/auth-apple-login.dto'; 6 | import { AllConfigType } from '../config/config.type'; 7 | 8 | @Injectable() 9 | export class AuthAppleService { 10 | constructor(private configService: ConfigService) {} 11 | 12 | async getProfileByToken( 13 | loginDto: AuthAppleLoginDto, 14 | ): Promise { 15 | const data = await appleSigninAuth.verifyIdToken(loginDto.idToken, { 16 | audience: this.configService.get('apple.appAudience', { infer: true }), 17 | }); 18 | 19 | return { 20 | id: data.sub, 21 | email: data.email, 22 | firstName: loginDto.firstName, 23 | lastName: loginDto.lastName, 24 | }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/auth-apple/config/apple-config.type.ts: -------------------------------------------------------------------------------- 1 | export type AppleConfig = { 2 | appAudience: string[]; 3 | }; 4 | -------------------------------------------------------------------------------- /src/auth-apple/config/apple.config.ts: -------------------------------------------------------------------------------- 1 | import { registerAs } from '@nestjs/config'; 2 | 3 | import { IsJSON, IsOptional } from 'class-validator'; 4 | import validateConfig from '../../utils/validate-config'; 5 | import { AppleConfig } from './apple-config.type'; 6 | 7 | class EnvironmentVariablesValidator { 8 | @IsJSON() 9 | @IsOptional() 10 | APPLE_APP_AUDIENCE: string; 11 | } 12 | 13 | export default registerAs('apple', () => { 14 | validateConfig(process.env, EnvironmentVariablesValidator); 15 | 16 | return { 17 | appAudience: JSON.parse(process.env.APPLE_APP_AUDIENCE ?? '[]'), 18 | }; 19 | }); 20 | -------------------------------------------------------------------------------- /src/auth-apple/dto/auth-apple-login.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; 2 | import { Allow, IsNotEmpty } from 'class-validator'; 3 | 4 | export class AuthAppleLoginDto { 5 | @ApiProperty({ example: 'abc' }) 6 | @IsNotEmpty() 7 | idToken: string; 8 | 9 | @Allow() 10 | @ApiPropertyOptional() 11 | firstName?: string; 12 | 13 | @Allow() 14 | @ApiPropertyOptional() 15 | lastName?: string; 16 | } 17 | -------------------------------------------------------------------------------- /src/auth-facebook/auth-facebook.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { AuthFacebookService } from './auth-facebook.service'; 3 | import { ConfigModule } from '@nestjs/config'; 4 | import { AuthFacebookController } from './auth-facebook.controller'; 5 | import { AuthModule } from '../auth/auth.module'; 6 | 7 | @Module({ 8 | imports: [ConfigModule, AuthModule], 9 | providers: [AuthFacebookService], 10 | exports: [AuthFacebookService], 11 | controllers: [AuthFacebookController], 12 | }) 13 | export class AuthFacebookModule {} 14 | -------------------------------------------------------------------------------- /src/auth-facebook/config/facebook-config.type.ts: -------------------------------------------------------------------------------- 1 | export type FacebookConfig = { 2 | appId?: string; 3 | appSecret?: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/auth-facebook/config/facebook.config.ts: -------------------------------------------------------------------------------- 1 | import { registerAs } from '@nestjs/config'; 2 | 3 | import { IsOptional, IsString } from 'class-validator'; 4 | import validateConfig from '../../utils/validate-config'; 5 | import { FacebookConfig } from './facebook-config.type'; 6 | 7 | class EnvironmentVariablesValidator { 8 | @IsString() 9 | @IsOptional() 10 | FACEBOOK_APP_ID: string; 11 | 12 | @IsString() 13 | @IsOptional() 14 | FACEBOOK_APP_SECRET: string; 15 | } 16 | 17 | export default registerAs('facebook', () => { 18 | validateConfig(process.env, EnvironmentVariablesValidator); 19 | 20 | return { 21 | appId: process.env.FACEBOOK_APP_ID, 22 | appSecret: process.env.FACEBOOK_APP_SECRET, 23 | }; 24 | }); 25 | -------------------------------------------------------------------------------- /src/auth-facebook/dto/auth-facebook-login.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | import { IsNotEmpty } from 'class-validator'; 3 | 4 | export class AuthFacebookLoginDto { 5 | @ApiProperty({ example: 'abc' }) 6 | @IsNotEmpty() 7 | accessToken: string; 8 | } 9 | -------------------------------------------------------------------------------- /src/auth-facebook/interfaces/facebook.interface.ts: -------------------------------------------------------------------------------- 1 | export interface FacebookInterface { 2 | id: string; 3 | first_name?: string; 4 | last_name?: string; 5 | email?: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/auth-google/auth-google.controller.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Body, 3 | Controller, 4 | HttpCode, 5 | HttpStatus, 6 | Post, 7 | SerializeOptions, 8 | } from '@nestjs/common'; 9 | import { ApiOkResponse, ApiTags } from '@nestjs/swagger'; 10 | import { AuthService } from '../auth/auth.service'; 11 | import { AuthGoogleService } from './auth-google.service'; 12 | import { AuthGoogleLoginDto } from './dto/auth-google-login.dto'; 13 | import { LoginResponseDto } from '../auth/dto/login-response.dto'; 14 | 15 | @ApiTags('Auth') 16 | @Controller({ 17 | path: 'auth/google', 18 | version: '1', 19 | }) 20 | export class AuthGoogleController { 21 | constructor( 22 | private readonly authService: AuthService, 23 | private readonly authGoogleService: AuthGoogleService, 24 | ) {} 25 | 26 | @ApiOkResponse({ 27 | type: LoginResponseDto, 28 | }) 29 | @SerializeOptions({ 30 | groups: ['me'], 31 | }) 32 | @Post('login') 33 | @HttpCode(HttpStatus.OK) 34 | async login(@Body() loginDto: AuthGoogleLoginDto): Promise { 35 | const socialData = await this.authGoogleService.getProfileByToken(loginDto); 36 | 37 | return this.authService.validateSocialLogin('google', socialData); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/auth-google/auth-google.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { AuthGoogleService } from './auth-google.service'; 3 | import { ConfigModule } from '@nestjs/config'; 4 | import { AuthGoogleController } from './auth-google.controller'; 5 | import { AuthModule } from '../auth/auth.module'; 6 | 7 | @Module({ 8 | imports: [ConfigModule, AuthModule], 9 | providers: [AuthGoogleService], 10 | exports: [AuthGoogleService], 11 | controllers: [AuthGoogleController], 12 | }) 13 | export class AuthGoogleModule {} 14 | -------------------------------------------------------------------------------- /src/auth-google/config/google-config.type.ts: -------------------------------------------------------------------------------- 1 | export type GoogleConfig = { 2 | clientId?: string; 3 | clientSecret?: string; 4 | }; 5 | -------------------------------------------------------------------------------- /src/auth-google/config/google.config.ts: -------------------------------------------------------------------------------- 1 | import { registerAs } from '@nestjs/config'; 2 | 3 | import { IsOptional, IsString } from 'class-validator'; 4 | import validateConfig from '../../utils/validate-config'; 5 | import { GoogleConfig } from './google-config.type'; 6 | 7 | class EnvironmentVariablesValidator { 8 | @IsString() 9 | @IsOptional() 10 | GOOGLE_CLIENT_ID: string; 11 | 12 | @IsString() 13 | @IsOptional() 14 | GOOGLE_CLIENT_SECRET: string; 15 | } 16 | 17 | export default registerAs('google', () => { 18 | validateConfig(process.env, EnvironmentVariablesValidator); 19 | 20 | return { 21 | clientId: process.env.GOOGLE_CLIENT_ID, 22 | clientSecret: process.env.GOOGLE_CLIENT_SECRET, 23 | }; 24 | }); 25 | -------------------------------------------------------------------------------- /src/auth-google/dto/auth-google-login.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | import { IsNotEmpty } from 'class-validator'; 3 | 4 | export class AuthGoogleLoginDto { 5 | @ApiProperty({ example: 'abc' }) 6 | @IsNotEmpty() 7 | idToken: string; 8 | } 9 | -------------------------------------------------------------------------------- /src/auth/auth-providers.enum.ts: -------------------------------------------------------------------------------- 1 | export enum AuthProvidersEnum { 2 | email = 'email', 3 | facebook = 'facebook', 4 | google = 'google', 5 | apple = 'apple', 6 | } 7 | -------------------------------------------------------------------------------- /src/auth/auth.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { AuthController } from './auth.controller'; 3 | import { AuthService } from './auth.service'; 4 | import { PassportModule } from '@nestjs/passport'; 5 | import { JwtModule } from '@nestjs/jwt'; 6 | import { JwtStrategy } from './strategies/jwt.strategy'; 7 | import { AnonymousStrategy } from './strategies/anonymous.strategy'; 8 | import { JwtRefreshStrategy } from './strategies/jwt-refresh.strategy'; 9 | import { MailModule } from '../mail/mail.module'; 10 | import { SessionModule } from '../session/session.module'; 11 | import { UsersModule } from '../users/users.module'; 12 | 13 | @Module({ 14 | imports: [ 15 | UsersModule, 16 | SessionModule, 17 | PassportModule, 18 | MailModule, 19 | JwtModule.register({}), 20 | ], 21 | controllers: [AuthController], 22 | providers: [AuthService, JwtStrategy, JwtRefreshStrategy, AnonymousStrategy], 23 | exports: [AuthService], 24 | }) 25 | export class AuthModule {} 26 | -------------------------------------------------------------------------------- /src/auth/config/auth-config.type.ts: -------------------------------------------------------------------------------- 1 | import ms from 'ms'; 2 | 3 | export type AuthConfig = { 4 | secret?: string; 5 | expires?: ms.StringValue; 6 | refreshSecret?: string; 7 | refreshExpires?: ms.StringValue; 8 | forgotSecret?: string; 9 | forgotExpires?: ms.StringValue; 10 | confirmEmailSecret?: string; 11 | confirmEmailExpires?: ms.StringValue; 12 | }; 13 | -------------------------------------------------------------------------------- /src/auth/dto/auth-confirm-email.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | import { IsNotEmpty } from 'class-validator'; 3 | 4 | export class AuthConfirmEmailDto { 5 | @ApiProperty() 6 | @IsNotEmpty() 7 | hash: string; 8 | } 9 | -------------------------------------------------------------------------------- /src/auth/dto/auth-email-login.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | import { IsEmail, IsNotEmpty } from 'class-validator'; 3 | import { Transform } from 'class-transformer'; 4 | import { lowerCaseTransformer } from '../../utils/transformers/lower-case.transformer'; 5 | 6 | export class AuthEmailLoginDto { 7 | @ApiProperty({ example: 'test1@example.com', type: String }) 8 | @Transform(lowerCaseTransformer) 9 | @IsEmail() 10 | @IsNotEmpty() 11 | email: string; 12 | 13 | @ApiProperty() 14 | @IsNotEmpty() 15 | password: string; 16 | } 17 | -------------------------------------------------------------------------------- /src/auth/dto/auth-forgot-password.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | import { IsEmail } from 'class-validator'; 3 | import { Transform } from 'class-transformer'; 4 | import { lowerCaseTransformer } from '../../utils/transformers/lower-case.transformer'; 5 | 6 | export class AuthForgotPasswordDto { 7 | @ApiProperty({ example: 'test1@example.com', type: String }) 8 | @Transform(lowerCaseTransformer) 9 | @IsEmail() 10 | email: string; 11 | } 12 | -------------------------------------------------------------------------------- /src/auth/dto/auth-register-login.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | import { IsEmail, IsNotEmpty, MinLength } from 'class-validator'; 3 | import { Transform } from 'class-transformer'; 4 | import { lowerCaseTransformer } from '../../utils/transformers/lower-case.transformer'; 5 | 6 | export class AuthRegisterLoginDto { 7 | @ApiProperty({ example: 'test1@example.com', type: String }) 8 | @Transform(lowerCaseTransformer) 9 | @IsEmail() 10 | email: string; 11 | 12 | @ApiProperty() 13 | @MinLength(6) 14 | password: string; 15 | 16 | @ApiProperty({ example: 'John' }) 17 | @IsNotEmpty() 18 | firstName: string; 19 | 20 | @ApiProperty({ example: 'Doe' }) 21 | @IsNotEmpty() 22 | lastName: string; 23 | } 24 | -------------------------------------------------------------------------------- /src/auth/dto/auth-reset-password.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | import { IsNotEmpty } from 'class-validator'; 3 | 4 | export class AuthResetPasswordDto { 5 | @ApiProperty() 6 | @IsNotEmpty() 7 | password: string; 8 | 9 | @ApiProperty() 10 | @IsNotEmpty() 11 | hash: string; 12 | } 13 | -------------------------------------------------------------------------------- /src/auth/dto/auth-update.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiPropertyOptional } from '@nestjs/swagger'; 2 | import { IsEmail, IsNotEmpty, IsOptional, MinLength } from 'class-validator'; 3 | import { FileDto } from '../../files/dto/file.dto'; 4 | import { Transform } from 'class-transformer'; 5 | import { lowerCaseTransformer } from '../../utils/transformers/lower-case.transformer'; 6 | 7 | export class AuthUpdateDto { 8 | @ApiPropertyOptional({ type: () => FileDto }) 9 | @IsOptional() 10 | photo?: FileDto | null; 11 | 12 | @ApiPropertyOptional({ example: 'John' }) 13 | @IsOptional() 14 | @IsNotEmpty({ message: 'mustBeNotEmpty' }) 15 | firstName?: string; 16 | 17 | @ApiPropertyOptional({ example: 'Doe' }) 18 | @IsOptional() 19 | @IsNotEmpty({ message: 'mustBeNotEmpty' }) 20 | lastName?: string; 21 | 22 | @ApiPropertyOptional({ example: 'new.email@example.com' }) 23 | @IsOptional() 24 | @IsNotEmpty() 25 | @IsEmail() 26 | @Transform(lowerCaseTransformer) 27 | email?: string; 28 | 29 | @ApiPropertyOptional() 30 | @IsOptional() 31 | @IsNotEmpty() 32 | @MinLength(6) 33 | password?: string; 34 | 35 | @ApiPropertyOptional() 36 | @IsOptional() 37 | @IsNotEmpty({ message: 'mustBeNotEmpty' }) 38 | oldPassword?: string; 39 | } 40 | -------------------------------------------------------------------------------- /src/auth/dto/login-response.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | import { User } from '../../users/domain/user'; 3 | 4 | export class LoginResponseDto { 5 | @ApiProperty() 6 | token: string; 7 | 8 | @ApiProperty() 9 | refreshToken: string; 10 | 11 | @ApiProperty() 12 | tokenExpires: number; 13 | 14 | @ApiProperty({ 15 | type: () => User, 16 | }) 17 | user: User; 18 | } 19 | -------------------------------------------------------------------------------- /src/auth/dto/refresh-response.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | 3 | export class RefreshResponseDto { 4 | @ApiProperty() 5 | token: string; 6 | 7 | @ApiProperty() 8 | refreshToken: string; 9 | 10 | @ApiProperty() 11 | tokenExpires: number; 12 | } 13 | -------------------------------------------------------------------------------- /src/auth/strategies/anonymous.strategy.ts: -------------------------------------------------------------------------------- 1 | import { Strategy } from 'passport-anonymous'; 2 | import { Injectable } from '@nestjs/common'; 3 | import { PassportStrategy } from '@nestjs/passport'; 4 | 5 | @Injectable() 6 | export class AnonymousStrategy extends PassportStrategy(Strategy) { 7 | constructor() { 8 | super(); 9 | } 10 | 11 | public validate(payload: unknown, request: unknown): unknown { 12 | return request; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/auth/strategies/jwt-refresh.strategy.ts: -------------------------------------------------------------------------------- 1 | import { ExtractJwt, Strategy } from 'passport-jwt'; 2 | import { Injectable, UnauthorizedException } from '@nestjs/common'; 3 | import { PassportStrategy } from '@nestjs/passport'; 4 | import { ConfigService } from '@nestjs/config'; 5 | import { JwtRefreshPayloadType } from './types/jwt-refresh-payload.type'; 6 | import { OrNeverType } from '../../utils/types/or-never.type'; 7 | import { AllConfigType } from '../../config/config.type'; 8 | 9 | @Injectable() 10 | export class JwtRefreshStrategy extends PassportStrategy( 11 | Strategy, 12 | 'jwt-refresh', 13 | ) { 14 | constructor(configService: ConfigService) { 15 | super({ 16 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), 17 | secretOrKey: configService.getOrThrow('auth.refreshSecret', { 18 | infer: true, 19 | }), 20 | }); 21 | } 22 | 23 | public validate( 24 | payload: JwtRefreshPayloadType, 25 | ): OrNeverType { 26 | if (!payload.sessionId) { 27 | throw new UnauthorizedException(); 28 | } 29 | 30 | return payload; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/auth/strategies/jwt.strategy.ts: -------------------------------------------------------------------------------- 1 | import { ExtractJwt, Strategy } from 'passport-jwt'; 2 | import { Injectable, UnauthorizedException } from '@nestjs/common'; 3 | import { PassportStrategy } from '@nestjs/passport'; 4 | import { ConfigService } from '@nestjs/config'; 5 | import { OrNeverType } from '../../utils/types/or-never.type'; 6 | import { JwtPayloadType } from './types/jwt-payload.type'; 7 | import { AllConfigType } from '../../config/config.type'; 8 | 9 | @Injectable() 10 | export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') { 11 | constructor(configService: ConfigService) { 12 | super({ 13 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), 14 | secretOrKey: configService.getOrThrow('auth.secret', { infer: true }), 15 | }); 16 | } 17 | 18 | // Why we don't check if the user exists in the database: 19 | // https://github.com/brocoders/nestjs-boilerplate/blob/main/docs/auth.md#about-jwt-strategy 20 | public validate(payload: JwtPayloadType): OrNeverType { 21 | if (!payload.id) { 22 | throw new UnauthorizedException(); 23 | } 24 | 25 | return payload; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/auth/strategies/types/jwt-payload.type.ts: -------------------------------------------------------------------------------- 1 | import { Session } from '../../../session/domain/session'; 2 | import { User } from '../../../users/domain/user'; 3 | 4 | export type JwtPayloadType = Pick & { 5 | sessionId: Session['id']; 6 | iat: number; 7 | exp: number; 8 | }; 9 | -------------------------------------------------------------------------------- /src/auth/strategies/types/jwt-refresh-payload.type.ts: -------------------------------------------------------------------------------- 1 | import { Session } from '../../../session/domain/session'; 2 | 3 | export type JwtRefreshPayloadType = { 4 | sessionId: Session['id']; 5 | hash: Session['hash']; 6 | iat: number; 7 | exp: number; 8 | }; 9 | -------------------------------------------------------------------------------- /src/config/app-config.type.ts: -------------------------------------------------------------------------------- 1 | export type AppConfig = { 2 | nodeEnv: string; 3 | name: string; 4 | workingDirectory: string; 5 | frontendDomain?: string; 6 | backendDomain: string; 7 | port: number; 8 | apiPrefix: string; 9 | fallbackLanguage: string; 10 | headerLanguage: string; 11 | }; 12 | -------------------------------------------------------------------------------- /src/config/config.type.ts: -------------------------------------------------------------------------------- 1 | import { AppConfig } from './app-config.type'; 2 | import { AppleConfig } from '../auth-apple/config/apple-config.type'; 3 | import { AuthConfig } from '../auth/config/auth-config.type'; 4 | import { DatabaseConfig } from '../database/config/database-config.type'; 5 | import { FacebookConfig } from '../auth-facebook/config/facebook-config.type'; 6 | import { FileConfig } from '../files/config/file-config.type'; 7 | import { GoogleConfig } from '../auth-google/config/google-config.type'; 8 | import { MailConfig } from '../mail/config/mail-config.type'; 9 | 10 | export type AllConfigType = { 11 | app: AppConfig; 12 | apple: AppleConfig; 13 | auth: AuthConfig; 14 | database: DatabaseConfig; 15 | facebook: FacebookConfig; 16 | file: FileConfig; 17 | google: GoogleConfig; 18 | mail: MailConfig; 19 | }; 20 | -------------------------------------------------------------------------------- /src/database/config/database-config.type.ts: -------------------------------------------------------------------------------- 1 | export type DatabaseConfig = { 2 | isDocumentDatabase: boolean; 3 | url?: string; 4 | type?: string; 5 | host?: string; 6 | port?: number; 7 | password?: string; 8 | name?: string; 9 | username?: string; 10 | synchronize?: boolean; 11 | maxConnections: number; 12 | sslEnabled?: boolean; 13 | rejectUnauthorized?: boolean; 14 | ca?: string; 15 | key?: string; 16 | cert?: string; 17 | }; 18 | -------------------------------------------------------------------------------- /src/database/mongoose-config.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { ConfigService } from '@nestjs/config'; 3 | import { 4 | MongooseModuleOptions, 5 | MongooseOptionsFactory, 6 | } from '@nestjs/mongoose'; 7 | import { AllConfigType } from '../config/config.type'; 8 | import mongooseAutoPopulate from 'mongoose-autopopulate'; 9 | 10 | @Injectable() 11 | export class MongooseConfigService implements MongooseOptionsFactory { 12 | constructor(private configService: ConfigService) {} 13 | 14 | createMongooseOptions(): MongooseModuleOptions { 15 | return { 16 | uri: this.configService.get('database.url', { infer: true }), 17 | dbName: this.configService.get('database.name', { infer: true }), 18 | user: this.configService.get('database.username', { infer: true }), 19 | pass: this.configService.get('database.password', { infer: true }), 20 | connectionFactory(connection) { 21 | connection.plugin(mongooseAutoPopulate); 22 | return connection; 23 | }, 24 | }; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/database/seeds/document/run-seed.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import { UserSeedService } from './user/user-seed.service'; 3 | 4 | import { SeedModule } from './seed.module'; 5 | 6 | const runSeed = async () => { 7 | const app = await NestFactory.create(SeedModule); 8 | 9 | // run 10 | await app.get(UserSeedService).run(); 11 | 12 | await app.close(); 13 | }; 14 | 15 | void runSeed(); 16 | -------------------------------------------------------------------------------- /src/database/seeds/document/seed.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ConfigModule } from '@nestjs/config'; 3 | 4 | import { MongooseModule } from '@nestjs/mongoose'; 5 | 6 | import { UserSeedModule } from './user/user-seed.module'; 7 | import appConfig from '../../../config/app.config'; 8 | import databaseConfig from '../../config/database.config'; 9 | import { MongooseConfigService } from '../../mongoose-config.service'; 10 | 11 | @Module({ 12 | imports: [ 13 | UserSeedModule, 14 | ConfigModule.forRoot({ 15 | isGlobal: true, 16 | load: [databaseConfig, appConfig], 17 | envFilePath: ['.env'], 18 | }), 19 | MongooseModule.forRootAsync({ 20 | useClass: MongooseConfigService, 21 | }), 22 | ], 23 | }) 24 | export class SeedModule {} 25 | -------------------------------------------------------------------------------- /src/database/seeds/document/user/user-seed.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { MongooseModule } from '@nestjs/mongoose'; 3 | import { UserSeedService } from './user-seed.service'; 4 | import { 5 | UserSchemaClass, 6 | UserSchema, 7 | } from '../../../../users/infrastructure/persistence/document/entities/user.schema'; 8 | 9 | @Module({ 10 | imports: [ 11 | MongooseModule.forFeature([ 12 | { 13 | name: UserSchemaClass.name, 14 | schema: UserSchema, 15 | }, 16 | ]), 17 | ], 18 | providers: [UserSeedService], 19 | exports: [UserSeedService], 20 | }) 21 | export class UserSeedModule {} 22 | -------------------------------------------------------------------------------- /src/database/seeds/relational/role/role-seed.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { TypeOrmModule } from '@nestjs/typeorm'; 3 | 4 | import { RoleSeedService } from './role-seed.service'; 5 | import { RoleEntity } from '../../../../roles/infrastructure/persistence/relational/entities/role.entity'; 6 | 7 | @Module({ 8 | imports: [TypeOrmModule.forFeature([RoleEntity])], 9 | providers: [RoleSeedService], 10 | exports: [RoleSeedService], 11 | }) 12 | export class RoleSeedModule {} 13 | -------------------------------------------------------------------------------- /src/database/seeds/relational/role/role-seed.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { InjectRepository } from '@nestjs/typeorm'; 3 | import { Repository } from 'typeorm'; 4 | import { RoleEntity } from '../../../../roles/infrastructure/persistence/relational/entities/role.entity'; 5 | import { RoleEnum } from '../../../../roles/roles.enum'; 6 | 7 | @Injectable() 8 | export class RoleSeedService { 9 | constructor( 10 | @InjectRepository(RoleEntity) 11 | private repository: Repository, 12 | ) {} 13 | 14 | async run() { 15 | const countUser = await this.repository.count({ 16 | where: { 17 | id: RoleEnum.user, 18 | }, 19 | }); 20 | 21 | if (!countUser) { 22 | await this.repository.save( 23 | this.repository.create({ 24 | id: RoleEnum.user, 25 | name: 'User', 26 | }), 27 | ); 28 | } 29 | 30 | const countAdmin = await this.repository.count({ 31 | where: { 32 | id: RoleEnum.admin, 33 | }, 34 | }); 35 | 36 | if (!countAdmin) { 37 | await this.repository.save( 38 | this.repository.create({ 39 | id: RoleEnum.admin, 40 | name: 'Admin', 41 | }), 42 | ); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/database/seeds/relational/run-seed.ts: -------------------------------------------------------------------------------- 1 | import { NestFactory } from '@nestjs/core'; 2 | import { RoleSeedService } from './role/role-seed.service'; 3 | import { SeedModule } from './seed.module'; 4 | import { StatusSeedService } from './status/status-seed.service'; 5 | import { UserSeedService } from './user/user-seed.service'; 6 | 7 | const runSeed = async () => { 8 | const app = await NestFactory.create(SeedModule); 9 | 10 | // run 11 | await app.get(RoleSeedService).run(); 12 | await app.get(StatusSeedService).run(); 13 | await app.get(UserSeedService).run(); 14 | 15 | await app.close(); 16 | }; 17 | 18 | void runSeed(); 19 | -------------------------------------------------------------------------------- /src/database/seeds/relational/seed.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ConfigModule } from '@nestjs/config'; 3 | import { TypeOrmModule } from '@nestjs/typeorm'; 4 | 5 | import { DataSource, DataSourceOptions } from 'typeorm'; 6 | import { TypeOrmConfigService } from '../../typeorm-config.service'; 7 | import { RoleSeedModule } from './role/role-seed.module'; 8 | import { StatusSeedModule } from './status/status-seed.module'; 9 | import { UserSeedModule } from './user/user-seed.module'; 10 | import databaseConfig from '../../config/database.config'; 11 | import appConfig from '../../../config/app.config'; 12 | 13 | @Module({ 14 | imports: [ 15 | RoleSeedModule, 16 | StatusSeedModule, 17 | UserSeedModule, 18 | ConfigModule.forRoot({ 19 | isGlobal: true, 20 | load: [databaseConfig, appConfig], 21 | envFilePath: ['.env'], 22 | }), 23 | TypeOrmModule.forRootAsync({ 24 | useClass: TypeOrmConfigService, 25 | dataSourceFactory: async (options: DataSourceOptions) => { 26 | return new DataSource(options).initialize(); 27 | }, 28 | }), 29 | ], 30 | }) 31 | export class SeedModule {} 32 | -------------------------------------------------------------------------------- /src/database/seeds/relational/status/status-seed.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { TypeOrmModule } from '@nestjs/typeorm'; 3 | import { StatusSeedService } from './status-seed.service'; 4 | import { StatusEntity } from '../../../../statuses/infrastructure/persistence/relational/entities/status.entity'; 5 | 6 | @Module({ 7 | imports: [TypeOrmModule.forFeature([StatusEntity])], 8 | providers: [StatusSeedService], 9 | exports: [StatusSeedService], 10 | }) 11 | export class StatusSeedModule {} 12 | -------------------------------------------------------------------------------- /src/database/seeds/relational/status/status-seed.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { InjectRepository } from '@nestjs/typeorm'; 3 | import { Repository } from 'typeorm'; 4 | import { StatusEntity } from '../../../../statuses/infrastructure/persistence/relational/entities/status.entity'; 5 | import { StatusEnum } from '../../../../statuses/statuses.enum'; 6 | 7 | @Injectable() 8 | export class StatusSeedService { 9 | constructor( 10 | @InjectRepository(StatusEntity) 11 | private repository: Repository, 12 | ) {} 13 | 14 | async run() { 15 | const count = await this.repository.count(); 16 | 17 | if (!count) { 18 | await this.repository.save([ 19 | this.repository.create({ 20 | id: StatusEnum.active, 21 | name: 'Active', 22 | }), 23 | this.repository.create({ 24 | id: StatusEnum.inactive, 25 | name: 'Inactive', 26 | }), 27 | ]); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/database/seeds/relational/user/user-seed.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { TypeOrmModule } from '@nestjs/typeorm'; 3 | 4 | import { UserSeedService } from './user-seed.service'; 5 | import { UserEntity } from '../../../../users/infrastructure/persistence/relational/entities/user.entity'; 6 | 7 | @Module({ 8 | imports: [TypeOrmModule.forFeature([UserEntity])], 9 | providers: [UserSeedService], 10 | exports: [UserSeedService], 11 | }) 12 | export class UserSeedModule {} 13 | -------------------------------------------------------------------------------- /src/files/config/file-config.type.ts: -------------------------------------------------------------------------------- 1 | export enum FileDriver { 2 | LOCAL = 'local', 3 | S3 = 's3', 4 | S3_PRESIGNED = 's3-presigned', 5 | } 6 | 7 | export type FileConfig = { 8 | driver: FileDriver; 9 | accessKeyId?: string; 10 | secretAccessKey?: string; 11 | awsDefaultS3Bucket?: string; 12 | awsS3Region?: string; 13 | maxFileSize: number; 14 | }; 15 | -------------------------------------------------------------------------------- /src/files/dto/file.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | import { IsNotEmpty, IsString } from 'class-validator'; 3 | 4 | export class FileDto { 5 | @ApiProperty() 6 | @IsString() 7 | @IsNotEmpty() 8 | id: string; 9 | 10 | path: string; 11 | } 12 | -------------------------------------------------------------------------------- /src/files/files.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | 3 | import { FileRepository } from './infrastructure/persistence/file.repository'; 4 | import { FileType } from './domain/file'; 5 | import { NullableType } from '../utils/types/nullable.type'; 6 | 7 | @Injectable() 8 | export class FilesService { 9 | constructor(private readonly fileRepository: FileRepository) {} 10 | 11 | findById(id: FileType['id']): Promise> { 12 | return this.fileRepository.findById(id); 13 | } 14 | 15 | findByIds(ids: FileType['id'][]): Promise { 16 | return this.fileRepository.findByIds(ids); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/files/infrastructure/persistence/document/document-persistence.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { MongooseModule } from '@nestjs/mongoose'; 3 | import { FileSchema, FileSchemaClass } from './entities/file.schema'; 4 | import { FileRepository } from '../file.repository'; 5 | import { FileDocumentRepository } from './repositories/file.repository'; 6 | 7 | @Module({ 8 | imports: [ 9 | MongooseModule.forFeature([ 10 | { name: FileSchemaClass.name, schema: FileSchema }, 11 | ]), 12 | ], 13 | providers: [ 14 | { 15 | provide: FileRepository, 16 | useClass: FileDocumentRepository, 17 | }, 18 | ], 19 | exports: [FileRepository], 20 | }) 21 | export class DocumentFilePersistenceModule {} 22 | -------------------------------------------------------------------------------- /src/files/infrastructure/persistence/document/entities/file.schema.ts: -------------------------------------------------------------------------------- 1 | import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; 2 | import { HydratedDocument } from 'mongoose'; 3 | import { EntityDocumentHelper } from '../../../../../utils/document-entity-helper'; 4 | 5 | export type FileSchemaDocument = HydratedDocument; 6 | 7 | @Schema({ 8 | toJSON: { 9 | virtuals: true, 10 | getters: true, 11 | }, 12 | }) 13 | export class FileSchemaClass extends EntityDocumentHelper { 14 | @Prop() 15 | path: string; 16 | } 17 | 18 | export const FileSchema = SchemaFactory.createForClass(FileSchemaClass); 19 | -------------------------------------------------------------------------------- /src/files/infrastructure/persistence/document/mappers/file.mapper.ts: -------------------------------------------------------------------------------- 1 | import { FileType } from '../../../../domain/file'; 2 | import { FileSchemaClass } from '../entities/file.schema'; 3 | 4 | export class FileMapper { 5 | static toDomain(raw: FileSchemaClass): FileType { 6 | const domainEntity = new FileType(); 7 | domainEntity.id = raw._id.toString(); 8 | domainEntity.path = raw.path; 9 | return domainEntity; 10 | } 11 | static toPersistence(domainEntity: FileType): FileSchemaClass { 12 | const persistenceSchema = new FileSchemaClass(); 13 | if (domainEntity.id) { 14 | persistenceSchema._id = domainEntity.id; 15 | } 16 | persistenceSchema.path = domainEntity.path; 17 | return persistenceSchema; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/files/infrastructure/persistence/file.repository.ts: -------------------------------------------------------------------------------- 1 | import { NullableType } from '../../../utils/types/nullable.type'; 2 | import { FileType } from '../../domain/file'; 3 | 4 | export abstract class FileRepository { 5 | abstract create(data: Omit): Promise; 6 | 7 | abstract findById(id: FileType['id']): Promise>; 8 | 9 | abstract findByIds(ids: FileType['id'][]): Promise; 10 | } 11 | -------------------------------------------------------------------------------- /src/files/infrastructure/persistence/relational/entities/file.entity.ts: -------------------------------------------------------------------------------- 1 | import { 2 | // typeorm decorators here 3 | Column, 4 | Entity, 5 | PrimaryGeneratedColumn, 6 | } from 'typeorm'; 7 | import { EntityRelationalHelper } from '../../../../../utils/relational-entity-helper'; 8 | 9 | @Entity({ name: 'file' }) 10 | export class FileEntity extends EntityRelationalHelper { 11 | @PrimaryGeneratedColumn('uuid') 12 | id: string; 13 | 14 | @Column() 15 | path: string; 16 | } 17 | -------------------------------------------------------------------------------- /src/files/infrastructure/persistence/relational/mappers/file.mapper.ts: -------------------------------------------------------------------------------- 1 | import { FileType } from '../../../../domain/file'; 2 | import { FileEntity } from '../entities/file.entity'; 3 | 4 | export class FileMapper { 5 | static toDomain(raw: FileEntity): FileType { 6 | const domainEntity = new FileType(); 7 | domainEntity.id = raw.id; 8 | domainEntity.path = raw.path; 9 | return domainEntity; 10 | } 11 | 12 | static toPersistence(domainEntity: FileType): FileEntity { 13 | const persistenceEntity = new FileEntity(); 14 | persistenceEntity.id = domainEntity.id; 15 | persistenceEntity.path = domainEntity.path; 16 | return persistenceEntity; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/files/infrastructure/persistence/relational/relational-persistence.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { TypeOrmModule } from '@nestjs/typeorm'; 3 | import { FileEntity } from './entities/file.entity'; 4 | import { FileRepository } from '../file.repository'; 5 | import { FileRelationalRepository } from './repositories/file.repository'; 6 | 7 | @Module({ 8 | imports: [TypeOrmModule.forFeature([FileEntity])], 9 | providers: [ 10 | { 11 | provide: FileRepository, 12 | useClass: FileRelationalRepository, 13 | }, 14 | ], 15 | exports: [FileRepository], 16 | }) 17 | export class RelationalFilePersistenceModule {} 18 | -------------------------------------------------------------------------------- /src/files/infrastructure/uploader/local/dto/file-response.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | import { FileType } from '../../../../domain/file'; 3 | 4 | export class FileResponseDto { 5 | @ApiProperty({ 6 | type: () => FileType, 7 | }) 8 | file: FileType; 9 | } 10 | -------------------------------------------------------------------------------- /src/files/infrastructure/uploader/local/files.service.ts: -------------------------------------------------------------------------------- 1 | import { 2 | HttpStatus, 3 | Injectable, 4 | UnprocessableEntityException, 5 | } from '@nestjs/common'; 6 | import { ConfigService } from '@nestjs/config'; 7 | 8 | import { FileRepository } from '../../persistence/file.repository'; 9 | import { AllConfigType } from '../../../../config/config.type'; 10 | import { FileType } from '../../../domain/file'; 11 | 12 | @Injectable() 13 | export class FilesLocalService { 14 | constructor( 15 | private readonly configService: ConfigService, 16 | private readonly fileRepository: FileRepository, 17 | ) {} 18 | 19 | async create(file: Express.Multer.File): Promise<{ file: FileType }> { 20 | if (!file) { 21 | throw new UnprocessableEntityException({ 22 | status: HttpStatus.UNPROCESSABLE_ENTITY, 23 | errors: { 24 | file: 'selectFile', 25 | }, 26 | }); 27 | } 28 | 29 | return { 30 | file: await this.fileRepository.create({ 31 | path: `/${this.configService.get('app.apiPrefix', { 32 | infer: true, 33 | })}/v1/${file.path}`, 34 | }), 35 | }; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/files/infrastructure/uploader/s3-presigned/dto/file-response.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | import { FileType } from '../../../../domain/file'; 3 | 4 | export class FileResponseDto { 5 | @ApiProperty({ 6 | type: () => FileType, 7 | }) 8 | file: FileType; 9 | 10 | @ApiProperty({ 11 | type: String, 12 | }) 13 | uploadSignedUrl: string; 14 | } 15 | -------------------------------------------------------------------------------- /src/files/infrastructure/uploader/s3-presigned/dto/file.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | import { IsNumber, IsString } from 'class-validator'; 3 | 4 | export class FileUploadDto { 5 | @ApiProperty({ example: 'image.jpg' }) 6 | @IsString() 7 | fileName: string; 8 | 9 | @ApiProperty({ example: 138723 }) 10 | @IsNumber() 11 | fileSize: number; 12 | } 13 | -------------------------------------------------------------------------------- /src/files/infrastructure/uploader/s3-presigned/files.controller.ts: -------------------------------------------------------------------------------- 1 | import { Body, Controller, Post, UseGuards } from '@nestjs/common'; 2 | import { ApiBearerAuth, ApiCreatedResponse, ApiTags } from '@nestjs/swagger'; 3 | import { AuthGuard } from '@nestjs/passport'; 4 | import { FilesS3PresignedService } from './files.service'; 5 | import { FileUploadDto } from './dto/file.dto'; 6 | import { FileResponseDto } from './dto/file-response.dto'; 7 | 8 | @ApiTags('Files') 9 | @Controller({ 10 | path: 'files', 11 | version: '1', 12 | }) 13 | export class FilesS3PresignedController { 14 | constructor(private readonly filesService: FilesS3PresignedService) {} 15 | 16 | @ApiCreatedResponse({ 17 | type: FileResponseDto, 18 | }) 19 | @ApiBearerAuth() 20 | @UseGuards(AuthGuard('jwt')) 21 | @Post('upload') 22 | async uploadFile(@Body() file: FileUploadDto) { 23 | return this.filesService.create(file); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/files/infrastructure/uploader/s3/dto/file-response.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | import { FileType } from '../../../../domain/file'; 3 | 4 | export class FileResponseDto { 5 | @ApiProperty({ 6 | type: () => FileType, 7 | }) 8 | file: FileType; 9 | } 10 | -------------------------------------------------------------------------------- /src/files/infrastructure/uploader/s3/files.service.ts: -------------------------------------------------------------------------------- 1 | import { 2 | HttpStatus, 3 | Injectable, 4 | UnprocessableEntityException, 5 | } from '@nestjs/common'; 6 | import { FileRepository } from '../../persistence/file.repository'; 7 | import { FileType } from '../../../domain/file'; 8 | 9 | @Injectable() 10 | export class FilesS3Service { 11 | constructor(private readonly fileRepository: FileRepository) {} 12 | 13 | async create(file: Express.MulterS3.File): Promise<{ file: FileType }> { 14 | if (!file) { 15 | throw new UnprocessableEntityException({ 16 | status: HttpStatus.UNPROCESSABLE_ENTITY, 17 | errors: { 18 | file: 'selectFile', 19 | }, 20 | }); 21 | } 22 | 23 | return { 24 | file: await this.fileRepository.create({ 25 | path: file.key, 26 | }), 27 | }; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/home/home.controller.ts: -------------------------------------------------------------------------------- 1 | import { Controller, Get } from '@nestjs/common'; 2 | import { ApiTags } from '@nestjs/swagger'; 3 | 4 | import { HomeService } from './home.service'; 5 | 6 | @ApiTags('Home') 7 | @Controller() 8 | export class HomeController { 9 | constructor(private service: HomeService) {} 10 | 11 | @Get() 12 | appInfo() { 13 | return this.service.appInfo(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/home/home.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { HomeService } from './home.service'; 3 | import { HomeController } from './home.controller'; 4 | import { ConfigModule } from '@nestjs/config'; 5 | 6 | @Module({ 7 | imports: [ConfigModule], 8 | controllers: [HomeController], 9 | providers: [HomeService], 10 | }) 11 | export class HomeModule {} 12 | -------------------------------------------------------------------------------- /src/home/home.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@nestjs/common'; 2 | import { ConfigService } from '@nestjs/config'; 3 | import { AllConfigType } from '../config/config.type'; 4 | 5 | @Injectable() 6 | export class HomeService { 7 | constructor(private configService: ConfigService) {} 8 | 9 | appInfo() { 10 | return { name: this.configService.get('app.name', { infer: true }) }; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/i18n/ar/common.json: -------------------------------------------------------------------------------- 1 | { 2 | "confirmEmail": "تأكيد البريد الإلكتروني", 3 | "resetPassword": "إعادة تعيين كلمة المرور" 4 | } -------------------------------------------------------------------------------- /src/i18n/ar/confirm-email.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "مرحباً!", 3 | "text2": "أنت على وشك البدء في الاستمتاع", 4 | "text3": "ببساطة اضغط على الزر الأخضر الكبير أدناه للتحقق من بريدك الإلكتروني." 5 | } 6 | -------------------------------------------------------------------------------- /src/i18n/ar/confirm-new-email.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "مرحباً!", 3 | "text2": "يرجى تأكيد عنوان بريدك الإلكتروني الجديد.", 4 | "text3": "ببساطة اضغط على الزر الأخضر الكبير أدناه للتحقق من بريدك الإلكتروني." 5 | } 6 | -------------------------------------------------------------------------------- /src/i18n/ar/reset-password.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "هل تواجه مشكلة في تسجيل الدخول؟", 3 | "text2": "إعادة تعيين كلمة المرور سهلة.", 4 | "text3": "فقط اضغط على الزر أدناه واتبع التعليمات. سنجعلك تعمل مرة أخرى في وقت قصير.", 5 | "text4": "إذا لم تقم بهذا الطلب، يرجى تجاهل هذا البريد الإلكتروني." 6 | } 7 | -------------------------------------------------------------------------------- /src/i18n/en/common.json: -------------------------------------------------------------------------------- 1 | { 2 | "confirmEmail": "Confirm email", 3 | "resetPassword": "Reset password" 4 | } 5 | -------------------------------------------------------------------------------- /src/i18n/en/confirm-email.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "Hey!", 3 | "text2": "You’re almost ready to start enjoying", 4 | "text3": "Simply click the big green button below to verify your email address." 5 | } 6 | -------------------------------------------------------------------------------- /src/i18n/en/confirm-new-email.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "Hey!", 3 | "text2": "Confirm your new email address.", 4 | "text3": "Simply click the big green button below to verify your email address." 5 | } 6 | -------------------------------------------------------------------------------- /src/i18n/en/reset-password.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "Trouble signing in?", 3 | "text2": "Resetting your password is easy.", 4 | "text3": "Just press the button below and follow the instructions. We’ll have you up and running in no time.", 5 | "text4": "If you did not make this request then please ignore this email." 6 | } 7 | -------------------------------------------------------------------------------- /src/i18n/es/common.json: -------------------------------------------------------------------------------- 1 | { 2 | "confirmEmail": "Confirmar correo electrónico", 3 | "resetPassword": "Restablecer contraseña" 4 | } 5 | -------------------------------------------------------------------------------- /src/i18n/es/confirm-email.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "¡Hola!", 3 | "text2": "Ya casi estás listo para empezar a disfrutar", 4 | "text3": "Simplemente haz clic en el botón verde de abajo para verificar tu dirección de correo electrónico." 5 | } 6 | -------------------------------------------------------------------------------- /src/i18n/es/confirm-new-email.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "¡Hola!", 3 | "text2": "Confirma tu nueva dirección de correo electrónico.", 4 | "text3": "Simplemente haz clic en el botón verde de abajo para verificar tu dirección de correo electrónico." 5 | } 6 | -------------------------------------------------------------------------------- /src/i18n/es/reset-password.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "¿Problemas para iniciar sesión?", 3 | "text2": "Restablecer tu contraseña es fácil.", 4 | "text3": "Simplemente presiona el botón de abajo y sigue las instrucciones. Estarás listo en poco tiempo.", 5 | "text4": "Si no realizaste esta solicitud, por favor ignora este correo electrónico." 6 | } 7 | -------------------------------------------------------------------------------- /src/i18n/fr/common.json: -------------------------------------------------------------------------------- 1 | { 2 | "confirmEmail": "Confirmer l'e-mail", 3 | "resetPassword": "Réinitialiser le mot de passe" 4 | } 5 | -------------------------------------------------------------------------------- /src/i18n/fr/confirm-email.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "Salut !", 3 | "text2": "Vous êtes presque prêt à commencer", 4 | "text3": "Cliquez simplement sur le gros bouton vert ci-dessous pour vérifier votre adresse e-mail." 5 | } 6 | -------------------------------------------------------------------------------- /src/i18n/fr/confirm-new-email.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "Salut !", 3 | "text2": "Confirmez votre nouvelle adresse e-mail.", 4 | "text3": "Cliquez simplement sur le gros bouton vert ci-dessous pour vérifier votre adresse e-mail." 5 | } 6 | -------------------------------------------------------------------------------- /src/i18n/fr/reset-password.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "Des difficultés pour vous connecter ?", 3 | "text2": "Réinitialiser votre mot de passe est facile.", 4 | "text3": "Cliquez simplement sur le bouton ci-dessous et suivez les instructions. Vous serez de retour en un rien de temps.", 5 | "text4": "Si vous n'êtes pas à l'origine de cette demande, veuillez ignorer cet e-mail." 6 | } 7 | -------------------------------------------------------------------------------- /src/i18n/hi/common.json: -------------------------------------------------------------------------------- 1 | { 2 | "confirmEmail": "ईमेल सुनिश्चित करें", 3 | "resetPassword": "पासवर्ड रीसेट करें" 4 | } 5 | -------------------------------------------------------------------------------- /src/i18n/hi/confirm-email.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "नमस्ते!", 3 | "text2": "आप आनंद लेना शुरू करने के लिए लगभग तैयार हैं", 4 | "text3": "अपना ईमेल पता सत्यापित करने के लिए नीचे दिए गए बड़े हरे बटन पर क्लिक करें।" 5 | } 6 | -------------------------------------------------------------------------------- /src/i18n/hi/confirm-new-email.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "नमस्ते!", 3 | "text2": "अपना नया ईमेल पता सुनिश्चित करें।", 4 | "text3": "अपना ईमेल पता सत्यापित करने के लिए नीचे दिए गए बड़े हरे बटन पर क्लिक करें।" 5 | } 6 | -------------------------------------------------------------------------------- /src/i18n/hi/reset-password.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "साइन इन करने में परेशानी हो रही है?", 3 | "text2": "अपना पासवर्ड रीसेट करना आसान है।", 4 | "text3": "बस नीचे दिए गए बटन को दबाएं और निर्देशों का पालन करें। हम आपको जल्द ही चालू कर देंगे।", 5 | "text4": "यदि आपने यह अनुरोध नहीं किया है तो कृपया इस ईमेल को अनदेखा करें।" 6 | } 7 | -------------------------------------------------------------------------------- /src/i18n/uk/common.json: -------------------------------------------------------------------------------- 1 | { 2 | "confirmEmail": "Підтвердити email", 3 | "resetPassword": "Скинути пароль" 4 | } 5 | -------------------------------------------------------------------------------- /src/i18n/uk/confirm-email.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "Привіт!", 3 | "text2": "Ви майже готові почати користуватися", 4 | "text3": "Просто натисніть велику зелену кнопку нижче, щоб підтвердити свою електронну адресу." 5 | } 6 | -------------------------------------------------------------------------------- /src/i18n/uk/confirm-new-email.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "Привіт!", 3 | "text2": "Підтвердіть свою нову електронну адресу.", 4 | "text3": "Просто натисніть велику зелену кнопку нижче, щоб підтвердити свою електронну адресу." 5 | } 6 | -------------------------------------------------------------------------------- /src/i18n/uk/reset-password.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "Проблеми із входом?", 3 | "text2": "Скинути пароль дуже просто.", 4 | "text3": "Просто натисніть кнопку нижче та дотримуйтесь інструкцій. Ми швидко допоможемо вам повернутися до роботи.", 5 | "text4": "Якщо ви не робили цей запит, проігноруйте цей електронний лист." 6 | } 7 | -------------------------------------------------------------------------------- /src/i18n/zh/common.json: -------------------------------------------------------------------------------- 1 | { 2 | "confirmEmail": "确认电子邮件", 3 | "resetPassword": "重置密码" 4 | } 5 | -------------------------------------------------------------------------------- /src/i18n/zh/confirm-email.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "嗨!", 3 | "text2": "您即将开始使用", 4 | "text3": "只需点击下方的绿色按钮来验证您的电子邮件地址。" 5 | } 6 | -------------------------------------------------------------------------------- /src/i18n/zh/confirm-new-email.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "嗨!", 3 | "text2": "确认您的新电子邮件地址。", 4 | "text3": "只需点击下方的绿色按钮来验证您的电子邮件地址。" 5 | } 6 | -------------------------------------------------------------------------------- /src/i18n/zh/reset-password.json: -------------------------------------------------------------------------------- 1 | { 2 | "text1": "登录遇到问题?", 3 | "text2": "重置密码很简单。", 4 | "text3": "只需点击下方按钮并按照说明操作。我们很快就能帮您搞定。", 5 | "text4": "如果您没有发出此请求,请忽略此电子邮件。" 6 | } 7 | -------------------------------------------------------------------------------- /src/mail/config/mail-config.type.ts: -------------------------------------------------------------------------------- 1 | export type MailConfig = { 2 | port: number; 3 | host?: string; 4 | user?: string; 5 | password?: string; 6 | defaultEmail?: string; 7 | defaultName?: string; 8 | ignoreTLS: boolean; 9 | secure: boolean; 10 | requireTLS: boolean; 11 | }; 12 | -------------------------------------------------------------------------------- /src/mail/interfaces/mail-data.interface.ts: -------------------------------------------------------------------------------- 1 | export interface MailData { 2 | to: string; 3 | data: T; 4 | } 5 | -------------------------------------------------------------------------------- /src/mail/mail-templates/activation.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {{title}} 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 23 | 24 | 25 | 29 | 30 |
14 | {{app_name}} 15 |
19 | {{text1}}
20 | {{text2}} {{app_name}}.
21 | {{text3}} 22 |
26 | {{actionTitle}} 28 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /src/mail/mail-templates/confirm-new-email.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {{title}} 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 23 | 24 | 25 | 29 | 30 |
14 | {{app_name}} 15 |
19 | {{text1}}
20 | {{text2}}
21 | {{text3}} 22 |
26 | {{actionTitle}} 28 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /src/mail/mail.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { ConfigModule } from '@nestjs/config'; 3 | import { MailService } from './mail.service'; 4 | import { MailerModule } from '../mailer/mailer.module'; 5 | 6 | @Module({ 7 | imports: [ConfigModule, MailerModule], 8 | providers: [MailService], 9 | exports: [MailService], 10 | }) 11 | export class MailModule {} 12 | -------------------------------------------------------------------------------- /src/mailer/mailer.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { MailerService } from './mailer.service'; 3 | 4 | @Module({ 5 | providers: [MailerService], 6 | exports: [MailerService], 7 | }) 8 | export class MailerModule {} 9 | -------------------------------------------------------------------------------- /src/roles/domain/role.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | import { Allow } from 'class-validator'; 3 | import databaseConfig from '../../database/config/database.config'; 4 | import { DatabaseConfig } from '../../database/config/database-config.type'; 5 | 6 | // 7 | const idType = (databaseConfig() as DatabaseConfig).isDocumentDatabase 8 | ? String 9 | : Number; 10 | // 11 | 12 | export class Role { 13 | @Allow() 14 | @ApiProperty({ 15 | type: idType, 16 | }) 17 | id: number | string; 18 | 19 | @Allow() 20 | @ApiProperty({ 21 | type: String, 22 | example: 'admin', 23 | }) 24 | name?: string; 25 | } 26 | -------------------------------------------------------------------------------- /src/roles/dto/role.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | import { IsNumber } from 'class-validator'; 3 | 4 | export class RoleDto { 5 | @ApiProperty() 6 | @IsNumber() 7 | id: number | string; 8 | } 9 | -------------------------------------------------------------------------------- /src/roles/infrastructure/persistence/document/entities/role.schema.ts: -------------------------------------------------------------------------------- 1 | export class RoleSchema { 2 | _id: string; 3 | 4 | name?: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/roles/infrastructure/persistence/relational/entities/role.entity.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, PrimaryColumn } from 'typeorm'; 2 | import { EntityRelationalHelper } from '../../../../../utils/relational-entity-helper'; 3 | 4 | @Entity({ 5 | name: 'role', 6 | }) 7 | export class RoleEntity extends EntityRelationalHelper { 8 | @PrimaryColumn() 9 | id: number; 10 | 11 | @Column() 12 | name?: string; 13 | } 14 | -------------------------------------------------------------------------------- /src/roles/roles.decorator.ts: -------------------------------------------------------------------------------- 1 | import { SetMetadata } from '@nestjs/common'; 2 | 3 | export const Roles = (...roles: number[]) => SetMetadata('roles', roles); 4 | -------------------------------------------------------------------------------- /src/roles/roles.enum.ts: -------------------------------------------------------------------------------- 1 | export enum RoleEnum { 2 | 'admin' = 1, 3 | 'user' = 2, 4 | } 5 | -------------------------------------------------------------------------------- /src/roles/roles.guard.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; 2 | import { Reflector } from '@nestjs/core'; 3 | 4 | @Injectable() 5 | export class RolesGuard implements CanActivate { 6 | constructor(private reflector: Reflector) {} 7 | 8 | canActivate(context: ExecutionContext): boolean { 9 | const roles = this.reflector.getAllAndOverride<(number | string)[]>( 10 | 'roles', 11 | [context.getClass(), context.getHandler()], 12 | ); 13 | if (!roles.length) { 14 | return true; 15 | } 16 | const request = context.switchToHttp().getRequest(); 17 | 18 | return roles.map(String).includes(String(request.user?.role?.id)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/session/domain/session.ts: -------------------------------------------------------------------------------- 1 | import { User } from '../../users/domain/user'; 2 | 3 | export class Session { 4 | id: number | string; 5 | user: User; 6 | hash: string; 7 | createdAt: Date; 8 | updatedAt: Date; 9 | deletedAt: Date; 10 | } 11 | -------------------------------------------------------------------------------- /src/session/infrastructure/persistence/document/document-persistence.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { MongooseModule } from '@nestjs/mongoose'; 3 | import { SessionSchema, SessionSchemaClass } from './entities/session.schema'; 4 | import { SessionRepository } from '../session.repository'; 5 | import { SessionDocumentRepository } from './repositories/session.repository'; 6 | 7 | @Module({ 8 | imports: [ 9 | MongooseModule.forFeature([ 10 | { name: SessionSchemaClass.name, schema: SessionSchema }, 11 | ]), 12 | ], 13 | providers: [ 14 | { 15 | provide: SessionRepository, 16 | useClass: SessionDocumentRepository, 17 | }, 18 | ], 19 | exports: [SessionRepository], 20 | }) 21 | export class DocumentSessionPersistenceModule {} 22 | -------------------------------------------------------------------------------- /src/session/infrastructure/persistence/document/entities/session.schema.ts: -------------------------------------------------------------------------------- 1 | import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; 2 | import mongoose, { now, HydratedDocument } from 'mongoose'; 3 | import { UserSchemaClass } from '../../../../../users/infrastructure/persistence/document/entities/user.schema'; 4 | import { EntityDocumentHelper } from '../../../../../utils/document-entity-helper'; 5 | 6 | export type SessionSchemaDocument = HydratedDocument; 7 | 8 | @Schema({ 9 | timestamps: true, 10 | toJSON: { 11 | virtuals: true, 12 | getters: true, 13 | }, 14 | }) 15 | export class SessionSchemaClass extends EntityDocumentHelper { 16 | @Prop({ type: mongoose.Schema.Types.ObjectId, ref: 'UserSchemaClass' }) 17 | user: UserSchemaClass; 18 | 19 | @Prop() 20 | hash: string; 21 | 22 | @Prop({ default: now }) 23 | createdAt: Date; 24 | 25 | @Prop({ default: now }) 26 | updatedAt: Date; 27 | 28 | @Prop() 29 | deletedAt: Date; 30 | } 31 | 32 | export const SessionSchema = SchemaFactory.createForClass(SessionSchemaClass); 33 | 34 | SessionSchema.index({ user: 1 }); 35 | -------------------------------------------------------------------------------- /src/session/infrastructure/persistence/relational/entities/session.entity.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CreateDateColumn, 3 | Entity, 4 | Index, 5 | ManyToOne, 6 | PrimaryGeneratedColumn, 7 | DeleteDateColumn, 8 | Column, 9 | UpdateDateColumn, 10 | } from 'typeorm'; 11 | import { UserEntity } from '../../../../../users/infrastructure/persistence/relational/entities/user.entity'; 12 | 13 | import { EntityRelationalHelper } from '../../../../../utils/relational-entity-helper'; 14 | 15 | @Entity({ 16 | name: 'session', 17 | }) 18 | export class SessionEntity extends EntityRelationalHelper { 19 | @PrimaryGeneratedColumn() 20 | id: number; 21 | 22 | @ManyToOne(() => UserEntity, { 23 | eager: true, 24 | }) 25 | @Index() 26 | user: UserEntity; 27 | 28 | @Column() 29 | hash: string; 30 | 31 | @CreateDateColumn() 32 | createdAt: Date; 33 | 34 | @UpdateDateColumn() 35 | updatedAt: Date; 36 | 37 | @DeleteDateColumn() 38 | deletedAt: Date; 39 | } 40 | -------------------------------------------------------------------------------- /src/session/infrastructure/persistence/relational/relational-persistence.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { SessionRepository } from '../session.repository'; 3 | import { SessionRelationalRepository } from './repositories/session.repository'; 4 | import { TypeOrmModule } from '@nestjs/typeorm'; 5 | import { SessionEntity } from './entities/session.entity'; 6 | 7 | @Module({ 8 | imports: [TypeOrmModule.forFeature([SessionEntity])], 9 | providers: [ 10 | { 11 | provide: SessionRepository, 12 | useClass: SessionRelationalRepository, 13 | }, 14 | ], 15 | exports: [SessionRepository], 16 | }) 17 | export class RelationalSessionPersistenceModule {} 18 | -------------------------------------------------------------------------------- /src/session/infrastructure/persistence/session.repository.ts: -------------------------------------------------------------------------------- 1 | import { User } from '../../../users/domain/user'; 2 | import { NullableType } from '../../../utils/types/nullable.type'; 3 | import { Session } from '../../domain/session'; 4 | 5 | export abstract class SessionRepository { 6 | abstract findById(id: Session['id']): Promise>; 7 | 8 | abstract create( 9 | data: Omit, 10 | ): Promise; 11 | 12 | abstract update( 13 | id: Session['id'], 14 | payload: Partial< 15 | Omit 16 | >, 17 | ): Promise; 18 | 19 | abstract deleteById(id: Session['id']): Promise; 20 | 21 | abstract deleteByUserId(conditions: { userId: User['id'] }): Promise; 22 | 23 | abstract deleteByUserIdWithExclude(conditions: { 24 | userId: User['id']; 25 | excludeSessionId: Session['id']; 26 | }): Promise; 27 | } 28 | -------------------------------------------------------------------------------- /src/session/session.module.ts: -------------------------------------------------------------------------------- 1 | import { 2 | // common 3 | Module, 4 | } from '@nestjs/common'; 5 | 6 | import { DocumentSessionPersistenceModule } from './infrastructure/persistence/document/document-persistence.module'; 7 | import { RelationalSessionPersistenceModule } from './infrastructure/persistence/relational/relational-persistence.module'; 8 | import { SessionService } from './session.service'; 9 | import { DatabaseConfig } from '../database/config/database-config.type'; 10 | import databaseConfig from '../database/config/database.config'; 11 | 12 | // 13 | const infrastructurePersistenceModule = (databaseConfig() as DatabaseConfig) 14 | .isDocumentDatabase 15 | ? DocumentSessionPersistenceModule 16 | : RelationalSessionPersistenceModule; 17 | // 18 | 19 | @Module({ 20 | imports: [infrastructurePersistenceModule], 21 | providers: [SessionService], 22 | exports: [SessionService, infrastructurePersistenceModule], 23 | }) 24 | export class SessionModule {} 25 | -------------------------------------------------------------------------------- /src/social/interfaces/social.interface.ts: -------------------------------------------------------------------------------- 1 | export interface SocialInterface { 2 | id: string; 3 | firstName?: string; 4 | lastName?: string; 5 | email?: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/social/tokens.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | import { Allow, IsNotEmpty } from 'class-validator'; 3 | 4 | export class Tokens { 5 | @ApiProperty() 6 | @IsNotEmpty() 7 | token1: string; 8 | 9 | @Allow() 10 | @ApiProperty() 11 | token2?: string; 12 | } 13 | -------------------------------------------------------------------------------- /src/statuses/domain/status.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | import { Allow } from 'class-validator'; 3 | import databaseConfig from '../../database/config/database.config'; 4 | import { DatabaseConfig } from '../../database/config/database-config.type'; 5 | 6 | // 7 | const idType = (databaseConfig() as DatabaseConfig).isDocumentDatabase 8 | ? String 9 | : Number; 10 | // 11 | 12 | export class Status { 13 | @Allow() 14 | @ApiProperty({ 15 | type: idType, 16 | }) 17 | id: number | string; 18 | 19 | @Allow() 20 | @ApiProperty({ 21 | type: String, 22 | example: 'active', 23 | }) 24 | name?: string; 25 | } 26 | -------------------------------------------------------------------------------- /src/statuses/dto/status.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | import { IsNumber } from 'class-validator'; 3 | 4 | export class StatusDto { 5 | @ApiProperty() 6 | @IsNumber() 7 | id: number | string; 8 | } 9 | -------------------------------------------------------------------------------- /src/statuses/infrastructure/persistence/document/entities/status.schema.ts: -------------------------------------------------------------------------------- 1 | export class StatusSchema { 2 | _id: string; 3 | 4 | name?: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/statuses/infrastructure/persistence/relational/entities/status.entity.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, PrimaryColumn } from 'typeorm'; 2 | 3 | import { EntityRelationalHelper } from '../../../../../utils/relational-entity-helper'; 4 | 5 | @Entity({ 6 | name: 'status', 7 | }) 8 | export class StatusEntity extends EntityRelationalHelper { 9 | @PrimaryColumn() 10 | id: number; 11 | 12 | @Column() 13 | name?: string; 14 | } 15 | -------------------------------------------------------------------------------- /src/statuses/statuses.enum.ts: -------------------------------------------------------------------------------- 1 | export enum StatusEnum { 2 | 'active' = 1, 3 | 'inactive' = 2, 4 | } 5 | -------------------------------------------------------------------------------- /src/users/dto/user.dto.ts: -------------------------------------------------------------------------------- 1 | import { ApiProperty } from '@nestjs/swagger'; 2 | import { IsNotEmpty } from 'class-validator'; 3 | 4 | export class UserDto { 5 | @ApiProperty({ 6 | type: String, 7 | example: 'userId', 8 | }) 9 | @IsNotEmpty() 10 | id: string | number; 11 | } 12 | -------------------------------------------------------------------------------- /src/users/infrastructure/persistence/document/document-persistence.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { MongooseModule } from '@nestjs/mongoose'; 3 | import { UserSchema, UserSchemaClass } from './entities/user.schema'; 4 | import { UserRepository } from '../user.repository'; 5 | import { UsersDocumentRepository } from './repositories/user.repository'; 6 | 7 | @Module({ 8 | imports: [ 9 | MongooseModule.forFeature([ 10 | { name: UserSchemaClass.name, schema: UserSchema }, 11 | ]), 12 | ], 13 | providers: [ 14 | { 15 | provide: UserRepository, 16 | useClass: UsersDocumentRepository, 17 | }, 18 | ], 19 | exports: [UserRepository], 20 | }) 21 | export class DocumentUserPersistenceModule {} 22 | -------------------------------------------------------------------------------- /src/users/infrastructure/persistence/relational/relational-persistence.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | import { UserRepository } from '../user.repository'; 3 | import { UsersRelationalRepository } from './repositories/user.repository'; 4 | import { TypeOrmModule } from '@nestjs/typeorm'; 5 | import { UserEntity } from './entities/user.entity'; 6 | 7 | @Module({ 8 | imports: [TypeOrmModule.forFeature([UserEntity])], 9 | providers: [ 10 | { 11 | provide: UserRepository, 12 | useClass: UsersRelationalRepository, 13 | }, 14 | ], 15 | exports: [UserRepository], 16 | }) 17 | export class RelationalUserPersistenceModule {} 18 | -------------------------------------------------------------------------------- /src/users/users.module.ts: -------------------------------------------------------------------------------- 1 | import { 2 | // common 3 | Module, 4 | } from '@nestjs/common'; 5 | 6 | import { UsersController } from './users.controller'; 7 | 8 | import { UsersService } from './users.service'; 9 | import { DocumentUserPersistenceModule } from './infrastructure/persistence/document/document-persistence.module'; 10 | import { RelationalUserPersistenceModule } from './infrastructure/persistence/relational/relational-persistence.module'; 11 | import { DatabaseConfig } from '../database/config/database-config.type'; 12 | import databaseConfig from '../database/config/database.config'; 13 | import { FilesModule } from '../files/files.module'; 14 | 15 | // 16 | const infrastructurePersistenceModule = (databaseConfig() as DatabaseConfig) 17 | .isDocumentDatabase 18 | ? DocumentUserPersistenceModule 19 | : RelationalUserPersistenceModule; 20 | // 21 | 22 | @Module({ 23 | imports: [ 24 | // import modules, etc. 25 | infrastructurePersistenceModule, 26 | FilesModule, 27 | ], 28 | controllers: [UsersController], 29 | providers: [UsersService], 30 | exports: [UsersService, infrastructurePersistenceModule], 31 | }) 32 | export class UsersModule {} 33 | -------------------------------------------------------------------------------- /src/utils/deep-resolver.ts: -------------------------------------------------------------------------------- 1 | async function deepResolvePromises(input) { 2 | if (input instanceof Promise) { 3 | return await input; 4 | } 5 | 6 | if (Array.isArray(input)) { 7 | const resolvedArray = await Promise.all(input.map(deepResolvePromises)); 8 | return resolvedArray; 9 | } 10 | 11 | if (input instanceof Date) { 12 | return input; 13 | } 14 | 15 | if (typeof input === 'object' && input !== null) { 16 | const keys = Object.keys(input); 17 | const resolvedObject = {}; 18 | 19 | for (const key of keys) { 20 | const resolvedValue = await deepResolvePromises(input[key]); 21 | resolvedObject[key] = resolvedValue; 22 | } 23 | 24 | return resolvedObject; 25 | } 26 | 27 | return input; 28 | } 29 | 30 | export default deepResolvePromises; 31 | -------------------------------------------------------------------------------- /src/utils/document-entity-helper.ts: -------------------------------------------------------------------------------- 1 | import { Transform } from 'class-transformer'; 2 | 3 | export class EntityDocumentHelper { 4 | @Transform( 5 | (value) => { 6 | if ('value' in value) { 7 | // https://github.com/typestack/class-transformer/issues/879 8 | return value.obj[value.key].toString(); 9 | } 10 | 11 | return 'unknown value'; 12 | }, 13 | { 14 | toPlainOnly: true, 15 | }, 16 | ) 17 | public _id: string; 18 | } 19 | -------------------------------------------------------------------------------- /src/utils/dto/infinity-pagination-response.dto.ts: -------------------------------------------------------------------------------- 1 | import { Type } from '@nestjs/common'; 2 | import { ApiProperty } from '@nestjs/swagger'; 3 | 4 | export class InfinityPaginationResponseDto { 5 | data: T[]; 6 | hasNextPage: boolean; 7 | } 8 | 9 | export function InfinityPaginationResponse(classReference: Type) { 10 | abstract class Pagination { 11 | @ApiProperty({ type: [classReference] }) 12 | data!: T[]; 13 | 14 | @ApiProperty({ 15 | type: Boolean, 16 | example: true, 17 | }) 18 | hasNextPage: boolean; 19 | } 20 | 21 | Object.defineProperty(Pagination, 'name', { 22 | writable: false, 23 | value: `InfinityPagination${classReference.name}ResponseDto`, 24 | }); 25 | 26 | return Pagination; 27 | } 28 | -------------------------------------------------------------------------------- /src/utils/infinity-pagination.ts: -------------------------------------------------------------------------------- 1 | import { IPaginationOptions } from './types/pagination-options'; 2 | import { InfinityPaginationResponseDto } from './dto/infinity-pagination-response.dto'; 3 | 4 | export const infinityPagination = ( 5 | data: T[], 6 | options: IPaginationOptions, 7 | ): InfinityPaginationResponseDto => { 8 | return { 9 | data, 10 | hasNextPage: data.length === options.limit, 11 | }; 12 | }; 13 | -------------------------------------------------------------------------------- /src/utils/relational-entity-helper.ts: -------------------------------------------------------------------------------- 1 | import { instanceToPlain } from 'class-transformer'; 2 | import { AfterLoad, BaseEntity } from 'typeorm'; 3 | 4 | export class EntityRelationalHelper extends BaseEntity { 5 | __entity?: string; 6 | 7 | @AfterLoad() 8 | setEntityName() { 9 | this.__entity = this.constructor.name; 10 | } 11 | 12 | toJSON() { 13 | return instanceToPlain(this); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/utils/serializer.interceptor.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Injectable, 3 | NestInterceptor, 4 | ExecutionContext, 5 | CallHandler, 6 | } from '@nestjs/common'; 7 | import { Observable } from 'rxjs'; 8 | import { map } from 'rxjs/operators'; 9 | import deepResolvePromises from './deep-resolver'; 10 | 11 | @Injectable() 12 | export class ResolvePromisesInterceptor implements NestInterceptor { 13 | intercept(context: ExecutionContext, next: CallHandler): Observable { 14 | return next.handle().pipe(map((data) => deepResolvePromises(data))); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/utils/transformers/lower-case.transformer.ts: -------------------------------------------------------------------------------- 1 | import { TransformFnParams } from 'class-transformer/types/interfaces'; 2 | import { MaybeType } from '../types/maybe.type'; 3 | 4 | export const lowerCaseTransformer = ( 5 | params: TransformFnParams, 6 | ): MaybeType => params.value?.toLowerCase().trim(); 7 | -------------------------------------------------------------------------------- /src/utils/types/deep-partial.type.ts: -------------------------------------------------------------------------------- 1 | export type DeepPartial = { 2 | [P in keyof T]?: DeepPartial; 3 | }; 4 | -------------------------------------------------------------------------------- /src/utils/types/maybe.type.ts: -------------------------------------------------------------------------------- 1 | export type MaybeType = T | undefined; 2 | -------------------------------------------------------------------------------- /src/utils/types/nullable.type.ts: -------------------------------------------------------------------------------- 1 | export type NullableType = T | null; 2 | -------------------------------------------------------------------------------- /src/utils/types/or-never.type.ts: -------------------------------------------------------------------------------- 1 | export type OrNeverType = T | never; 2 | -------------------------------------------------------------------------------- /src/utils/types/pagination-options.ts: -------------------------------------------------------------------------------- 1 | export interface IPaginationOptions { 2 | page: number; 3 | limit: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/utils/validate-config.ts: -------------------------------------------------------------------------------- 1 | import { plainToClass } from 'class-transformer'; 2 | import { validateSync } from 'class-validator'; 3 | import { ClassConstructor } from 'class-transformer/types/interfaces'; 4 | 5 | function validateConfig( 6 | config: Record, 7 | envVariablesClass: ClassConstructor, 8 | ) { 9 | const validatedConfig = plainToClass(envVariablesClass, config, { 10 | enableImplicitConversion: true, 11 | }); 12 | const errors = validateSync(validatedConfig, { 13 | skipMissingProperties: false, 14 | }); 15 | 16 | if (errors.length > 0) { 17 | throw new Error(errors.toString()); 18 | } 19 | return validatedConfig; 20 | } 21 | 22 | export default validateConfig; 23 | -------------------------------------------------------------------------------- /src/utils/validation-options.ts: -------------------------------------------------------------------------------- 1 | import { 2 | HttpStatus, 3 | UnprocessableEntityException, 4 | ValidationError, 5 | ValidationPipeOptions, 6 | } from '@nestjs/common'; 7 | 8 | function generateErrors(errors: ValidationError[]) { 9 | return errors.reduce( 10 | (accumulator, currentValue) => ({ 11 | ...accumulator, 12 | [currentValue.property]: 13 | (currentValue.children?.length ?? 0) > 0 14 | ? generateErrors(currentValue.children ?? []) 15 | : Object.values(currentValue.constraints ?? {}).join(', '), 16 | }), 17 | {}, 18 | ); 19 | } 20 | 21 | const validationOptions: ValidationPipeOptions = { 22 | transform: true, 23 | whitelist: true, 24 | errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY, 25 | exceptionFactory: (errors: ValidationError[]) => { 26 | return new UnprocessableEntityException({ 27 | status: HttpStatus.UNPROCESSABLE_ENTITY, 28 | errors: generateErrors(errors), 29 | }); 30 | }, 31 | }; 32 | 33 | export default validationOptions; 34 | -------------------------------------------------------------------------------- /startup.document.ci.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | /opt/wait-for-it.sh mongo:27017 5 | npm run seed:run:document 6 | npm run start:prod > prod.log 2>&1 & 7 | /opt/wait-for-it.sh maildev:1080 8 | /opt/wait-for-it.sh localhost:3000 9 | npm run lint 10 | npm run test:e2e -- --runInBand 11 | -------------------------------------------------------------------------------- /startup.document.dev.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | /opt/wait-for-it.sh mongo:27017 5 | cat .env 6 | npm run seed:run:document 7 | npm run start:prod 8 | -------------------------------------------------------------------------------- /startup.document.test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | /opt/wait-for-it.sh mongo:27017 5 | /opt/wait-for-it.sh maildev:1080 6 | npm install 7 | npm run seed:run:document 8 | npm run start:dev 9 | -------------------------------------------------------------------------------- /startup.relational.ci.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | /opt/wait-for-it.sh postgres:5432 5 | npm run migration:run 6 | npm run seed:run:relational 7 | npm run start:prod > prod.log 2>&1 & 8 | /opt/wait-for-it.sh maildev:1080 9 | /opt/wait-for-it.sh localhost:3000 10 | npm run lint 11 | npm run test:e2e -- --runInBand 12 | -------------------------------------------------------------------------------- /startup.relational.dev.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | /opt/wait-for-it.sh postgres:5432 5 | npm run migration:run 6 | npm run seed:run:relational 7 | npm run start:prod 8 | -------------------------------------------------------------------------------- /startup.relational.test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | /opt/wait-for-it.sh postgres:5432 5 | /opt/wait-for-it.sh maildev:1080 6 | npm install 7 | npm run migration:run 8 | npm run seed:run:relational 9 | npm run start:dev 10 | -------------------------------------------------------------------------------- /test/admin/auth.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import request from 'supertest'; 2 | import { ADMIN_EMAIL, ADMIN_PASSWORD, APP_URL } from '../utils/constants'; 3 | 4 | describe('Auth', () => { 5 | const app = APP_URL; 6 | 7 | describe('Admin', () => { 8 | it('should successfully login via /api/v1/auth/email/login (POST)', () => { 9 | return request(app) 10 | .post('/api/v1/auth/email/login') 11 | .send({ email: ADMIN_EMAIL, password: ADMIN_PASSWORD }) 12 | .expect(200) 13 | .expect(({ body }) => { 14 | expect(body.token).toBeDefined(); 15 | expect(body.user.email).toBeDefined(); 16 | expect(body.user.role).toBeDefined(); 17 | }); 18 | }); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /test/jest-e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "moduleFileExtensions": ["js", "json", "ts"], 3 | "rootDir": ".", 4 | "testEnvironment": "node", 5 | "testRegex": ".e2e-spec.ts$", 6 | "transform": { 7 | "^.+\\.(t|j)s$": "ts-jest" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/utils/constants.ts: -------------------------------------------------------------------------------- 1 | export const APP_URL = `http://localhost:${process.env.APP_PORT}`; 2 | export const TESTER_EMAIL = 'john.doe@example.com'; 3 | export const TESTER_PASSWORD = 'secret'; 4 | export const ADMIN_EMAIL = 'admin@example.com'; 5 | export const ADMIN_PASSWORD = 'secret'; 6 | export const MAIL_HOST = process.env.MAIL_HOST; 7 | export const MAIL_PORT = process.env.MAIL_CLIENT_PORT; 8 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "ES2021", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": true, 16 | "noImplicitAny": false, 17 | "strictBindCallApply": false, 18 | "forceConsistentCasingInFileNames": false, 19 | "noFallthroughCasesInSwitch": false, 20 | "esModuleInterop": true 21 | } 22 | } 23 | --------------------------------------------------------------------------------