Skip to content

Commit

Permalink
Merge pull request #1 from Karibash/feature/inject-package
Browse files Browse the repository at this point in the history
Add inject package
  • Loading branch information
Karibash authored Jun 19, 2022
2 parents 399f181 + 93f1e93 commit f8623b2
Show file tree
Hide file tree
Showing 42 changed files with 2,552 additions and 53 deletions.
34 changes: 33 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,33 @@
# nestjs-modular
# nestjs-modular

[![codecov][coverage-badge]][coverage-link]
[![license][license-badge]][license-link]
[![Github][github-follower-badge]][github-follower-link]
[![Twitter][twitter-follower-badge]][twitter-follower-link]

| package | Version | Description | Changelog |
|---------------------------------------------|---------------------------------------------------------------------|----------------------------------------------------------------------------------------|-------------------------------------------|
| [`@nestjs-modular/inject`](packages/inject) | [![npm version][inject-npm-version-badge]][inject-npm-version-link] | This module provides the ability to inject features in bulk by specifying a directory. | [CHANGELOG](packages/inject/CHANGELOG.md) |

## 🤝 Contributing

Contributions, issues and feature requests are welcome.

Feel free to check [issues page](https://github.com/Karibash/nestjs-modular/issues) if you want to contribute.

## 📝 License

Copyright © 2020 [@Karibash](https://twitter.com/karibash).

This project is [```MIT```](https://github.com/Karibash/nestjs-modular/blob/main/LICENSE) licensed.

[coverage-badge]: https://codecov.io/gh/Karibash/nestjs-modular/branch/main/graph/badge.svg
[coverage-link]: https://codecov.io/gh/Karibash/nestjs-modular
[license-badge]: https://img.shields.io/badge/License-MIT-green.svg
[license-link]: https://github.com/Karibash/nestjs-modular/blob/main/LICENSE
[github-follower-badge]: https://img.shields.io/github/followers/Karibash?label=Follow&logo=github&style=social
[github-follower-link]: https://github.com/Karibash?tab=followers
[twitter-follower-badge]: https://img.shields.io/twitter/follow/Karibash?label=Follow&style=social
[twitter-follower-link]: https://twitter.com/intent/follow?screen_name=Karibash
[inject-npm-version-badge]: https://badge.fury.io/js/@nestjs-modular%2Finject.svg
[inject-npm-version-link]: https://www.npmjs.com/package/@nestjs-modular/inject
1 change: 1 addition & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ module.exports = {
],
plugins: [
['@babel/plugin-transform-runtime', { version: require('@babel/runtime/package.json').version }],
['@babel/plugin-proposal-decorators', { legacy: true }],
],
};
Empty file removed examples/.gitkeep
Empty file.
35 changes: 35 additions & 0 deletions examples/inject/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# compiled output
/dist
/node_modules

# Logs
logs
*.log
npm-debug.log*
pnpm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# OS
.DS_Store

# Tests
/coverage
/.nyc_output

# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace

# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
12 changes: 12 additions & 0 deletions examples/inject/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# nest-js-modular-inject

This is a example program describing the basic usage of @nestjs-modular/inject package.

## Usage

The example program can be run by executing the following command.

```sh
npm install
npm run start
```
5 changes: 5 additions & 0 deletions examples/inject/nest-cli.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"sourceRoot": "src"
}
37 changes: 37 additions & 0 deletions examples/inject/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "nest-js-modular-inject-example",
"version": "0.0.0",
"description": "",
"author": "",
"private": true,
"license": "MIT",
"scripts": {
"prebuild": "rimraf dist",
"build": "nest build",
"start": "nest start",
"start:mock": "APP_ENV=mock nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main"
},
"dependencies": {
"@nestjs/common": "^8.0.0",
"@nestjs/core": "^8.0.0",
"@nestjs/platform-express": "^8.0.0",
"@nestjs-modular/inject": "^1.0.0",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^7.2.0"
},
"devDependencies": {
"@nestjs/cli": "^8.0.0",
"@nestjs/schematics": "^8.0.0",
"@types/express": "^4.17.13",
"@types/node": "^16.0.0",
"source-map-support": "^0.5.20",
"ts-loader": "^9.2.3",
"ts-node": "^10.0.0",
"tsconfig-paths": "4.0.0",
"typescript": "^4.3.5"
}
}
16 changes: 16 additions & 0 deletions examples/inject/src/app.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Module } from '@nestjs/common';
import { InjectModule } from '@nestjs-modular/inject';
import path from 'path';

@Module({
imports: [
InjectModule.forRootAsync({
imports: {
path: path.resolve(__dirname, './modules'),
includeFileNames: [/\.module$/],
includeExportNames: [/Module$/],
},
}),
],
})
export class AppModule {}
11 changes: 11 additions & 0 deletions examples/inject/src/core/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export type AnyFunction = (...args: any[]) => any;

export type KeysOfType<T, S> = {
[key in keyof T]: S extends T[key] ? key : never;
}[keyof T];

export type UndefinedToOptional<T> =
Omit<T, KeysOfType<T, undefined>> &
Partial<Pick<T, KeysOfType<T, undefined>>>;

export type Fields<T> = UndefinedToOptional<Omit<T, KeysOfType<T, AnyFunction>>>;
10 changes: 10 additions & 0 deletions examples/inject/src/domains/entities/task.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Fields } from '../../core/types';

export class Task {
public readonly id: string;
public readonly title: string;

constructor(props: Fields<Task>) {
Object.assign(this, props);
}
}
10 changes: 10 additions & 0 deletions examples/inject/src/domains/entities/user.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Fields } from '../../core/types';

export class User {
public readonly id: string;
public readonly name: string;

constructor(props: Fields<User>) {
Object.assign(this, props);
}
}
8 changes: 8 additions & 0 deletions examples/inject/src/domains/repositories/task.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Task } from '../entities/task.entity';

export abstract class TaskRepository {
public abstract save(task: Task): Promise<Task>;
public abstract delete(task: Task): Promise<void>;
public abstract findAll(): Promise<Task[]>;
public abstract findById(id: Task['id']): Promise<Task>;
}
8 changes: 8 additions & 0 deletions examples/inject/src/domains/repositories/user.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { User } from '../entities/user.entity';

export abstract class UserRepository {
public abstract save(user: User): Promise<User>;
public abstract delete(user: User): Promise<void>;
public abstract findAll(): Promise<User[]>;
public abstract findById(id: User['id']): Promise<User>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Task } from '../../../domains/entities/task.entity';
import { TaskRepository } from '../../../domains/repositories/task.repository';

export class InMemoryTaskRepository extends TaskRepository {
private readonly store: Record<string, Task> = {};

public async save(task: Task): Promise<Task> {
this.store[task.id] = task;
return task;
}

public async delete(task: Task): Promise<void> {
delete this.store[task.id];
}

public async findAll(): Promise<Task[]> {
return Object.values(this.store);
}

public async findById(id: Task['id']): Promise<Task> {
return this.store[id];
}
}

export const taskRepositoryProvider = {
provide: TaskRepository,
useClass: InMemoryTaskRepository,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { User } from '../../../domains/entities/user.entity';
import { UserRepository } from '../../../domains/repositories/user.repository';

export class InMemoryUserRepository extends UserRepository {
private readonly store: Record<string, User> = {};

public async save(user: User): Promise<User> {
this.store[user.id] = user;
return user;
}

public async delete(user: User): Promise<void> {
delete this.store[user.id];
}

public async findAll(): Promise<User[]> {
return Object.values(this.store);
}

public async findById(id: User['id']): Promise<User> {
return this.store[id];
}
}

export const userRepositoryProvider = {
provide: UserRepository,
useClass: InMemoryUserRepository,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Task } from '../../../domains/entities/task.entity';
import { TaskRepository } from '../../../domains/repositories/task.repository';

export class MockTaskRepository extends TaskRepository {
public async save(task: Task): Promise<Task> {
return task;
}

public async delete(task: Task): Promise<void> {
}

public async findAll(): Promise<Task[]> {
return [
new Task({ id: 'task-1', title: 'task-1' }),
new Task({ id: 'task-2', title: 'task-2' }),
];
}

public async findById(id: Task['id']): Promise<Task> {
return new Task({ id: id, title: id });
}
}

export const taskRepositoryProvider = {
provide: TaskRepository,
useClass: MockTaskRepository,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { User } from '../../../domains/entities/user.entity';
import { UserRepository } from '../../../domains/repositories/user.repository';

export class MockUserRepository extends UserRepository {
public async save(user: User): Promise<User> {
return user;
}

public async delete(user: User): Promise<void> {
}

public async findAll(): Promise<User[]> {
return [
new User({ id: 'user-1', name: 'user-1' }),
new User({ id: 'user-2', name: 'user-2' }),
];
}

public async findById(id: User['id']): Promise<User> {
return new User({ id: id, name: id });
}
}

export const userRepositoryProvider = {
provide: UserRepository,
useClass: MockUserRepository,
};
10 changes: 10 additions & 0 deletions examples/inject/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { NestFactory } from '@nestjs/core';

import { AppModule } from './app.module';

const bootstrap = async () => {
const app = await NestFactory.create(AppModule);
await app.listen(3005);
};

bootstrap().then();
26 changes: 26 additions & 0 deletions examples/inject/src/modules/core/core.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Global, Module } from '@nestjs/common';
import { InjectModule } from '@nestjs-modular/inject';
import path from 'path';

const isMock = process.env.APP_ENV === 'mock';
const repositoryType = isMock ? 'mock' : 'inmemory';

@Global()
@Module({
imports: [
InjectModule.forRootAsync({
global: true,
providers: {
path: path.resolve(__dirname, `../../infrastructures/repositories/${repositoryType}`),
includeFileNames: [/\.repository$/],
includeExportNames: [/RepositoryProvider$/],
},
exports: {
path: path.resolve(__dirname, `../../infrastructures/repositories/${repositoryType}`),
includeFileNames: [/\.repository$/],
includeExportNames: [/RepositoryProvider$/],
},
}),
],
})
export class CoreModule {}
37 changes: 37 additions & 0 deletions examples/inject/src/modules/tasks/tasks.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Body, Controller, Delete, Get, Param, Post } from '@nestjs/common';

import { CreateTaskUseCase } from './usecases/create-task.usecase';
import { DeleteTaskUseCase } from './usecases/delete-task.usecase';
import { GetTaskUseCase } from './usecases/get-task.usecase';
import { GetTasksUseCase } from './usecases/get-tasks.usecase';
import { Task } from '../../domains/entities/task.entity';

@Controller('tasks')
export class TasksController {
constructor(
private readonly createTaskUseCase: CreateTaskUseCase,
private readonly deleteTaskUseCase: DeleteTaskUseCase,
private readonly getTaskUseCase: GetTaskUseCase,
private readonly getTasksUseCase: GetTasksUseCase,
) {}

@Get()
public async getTasks(): Promise<Task[]> {
return await this.getTasksUseCase.invoke();
}

@Post()
public async createTask(@Body('title') title: string): Promise<Task> {
return await this.createTaskUseCase.invoke(title);
}

@Get(':id')
public async getTask(@Param('id') id: string): Promise<Task> {
return await this.getTaskUseCase.invoke(id);
}

@Delete(':id')
public async deleteTask(@Param('id') id: string): Promise<void> {
return await this.deleteTaskUseCase.invoke(id);
}
}
Loading

0 comments on commit f8623b2

Please sign in to comment.