diff --git a/libs/typeorm/src/config.module-definition.ts b/libs/typeorm/src/config.module-definition.ts new file mode 100644 index 0000000..d146d7d --- /dev/null +++ b/libs/typeorm/src/config.module-definition.ts @@ -0,0 +1,7 @@ +import { ConfigurableModuleBuilder } from '@nestjs/common'; +import { TypeORMModuleOptions } from './interfaces'; + +export const { ConfigurableModuleClass } = + new ConfigurableModuleBuilder() + .setClassMethodName('forRoot') + .build(); diff --git a/libs/typeorm/src/constants.ts b/libs/typeorm/src/constants.ts new file mode 100644 index 0000000..f8b73de --- /dev/null +++ b/libs/typeorm/src/constants.ts @@ -0,0 +1,2 @@ +export const TYPEORM_DATASOURCE = 'TYPEORM_DATASOURCE'; +export const TYPEORM_REPOSITORY = 'TYPEORM_REPOSITORY'; diff --git a/libs/typeorm/src/index.ts b/libs/typeorm/src/index.ts new file mode 100644 index 0000000..5e59fe0 --- /dev/null +++ b/libs/typeorm/src/index.ts @@ -0,0 +1,4 @@ +export * from './typeorm.module'; +export * from './typeorm.service'; +export * from './interfaces'; +export * from './constants'; diff --git a/libs/typeorm/src/interfaces/config-module-options.interface.ts b/libs/typeorm/src/interfaces/config-module-options.interface.ts new file mode 100644 index 0000000..3e6cc26 --- /dev/null +++ b/libs/typeorm/src/interfaces/config-module-options.interface.ts @@ -0,0 +1,5 @@ +export interface TypeORMModuleOptions { + entity; + synchronize?: boolean; + entities: string[]; +} diff --git a/libs/typeorm/src/interfaces/index.ts b/libs/typeorm/src/interfaces/index.ts new file mode 100644 index 0000000..094edd2 --- /dev/null +++ b/libs/typeorm/src/interfaces/index.ts @@ -0,0 +1 @@ +export * from './config-module-options.interface'; diff --git a/libs/typeorm/src/typeorm.module.ts b/libs/typeorm/src/typeorm.module.ts new file mode 100644 index 0000000..29f7092 --- /dev/null +++ b/libs/typeorm/src/typeorm.module.ts @@ -0,0 +1,76 @@ +import { DynamicModule, Module } from '@nestjs/common'; +import { TypeormService } from './typeorm.service'; +import { TypeORMModuleOptions } from './interfaces'; +import { ConfigurableModuleClass } from './config.module-definition'; +import { DataSource } from 'typeorm'; +import { TYPEORM_DATASOURCE, TYPEORM_REPOSITORY } from './constants'; + +const getDatabaseCredential = ( + synchronize?: boolean, + entities?: string[], +): any => { + const url = new URL(process.env.DATABASE_URL); + + let entityList = [__dirname + '/../**/*.entity{.ts,.js}']; + if (entities) { + entityList = entities; + } + + let protocol; + switch (url.protocol) { + case 'postgresql': + protocol = 'postgres'; + break; + case 'mysql': + protocol = 'mysql'; + break; + } + + // Extract the necessary components + const username = url.username; + const password = url.password; + const host = url.hostname; + const port = url.port; + const databaseName = url.pathname.substring(1); // Remove the leading slash + return { + type: protocol, + host: host, + port: port, + username: username, + password: password, + database: databaseName, + entities: entityList, + synchronize: synchronize ?? false, + }; +}; + +@Module({ + providers: [TypeormService], + exports: [TypeormService], +}) +export class TypeORMModule extends ConfigurableModuleClass { + static forRoot(options: TypeORMModuleOptions): DynamicModule { + let providers = [ + { + provide: TYPEORM_DATASOURCE, + useFactory: async () => { + const dataSource = new DataSource( + getDatabaseCredential(options.synchronize, options.entities), + ); + return dataSource.initialize(); + }, + }, + { + provide: TYPEORM_REPOSITORY, + useFactory: (dataSource: DataSource) => + dataSource.getRepository(options.entity), + inject: [TYPEORM_DATASOURCE], + }, + ]; + + return { + ...super.forRoot(options), + providers, + }; + } +} diff --git a/libs/typeorm/src/typeorm.service.ts b/libs/typeorm/src/typeorm.service.ts new file mode 100644 index 0000000..405bcd6 --- /dev/null +++ b/libs/typeorm/src/typeorm.service.ts @@ -0,0 +1,11 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { Repository } from 'typeorm'; +import { TYPEORM_REPOSITORY } from './constants'; + +@Injectable() +export class TypeormService { + constructor( + @Inject(TYPEORM_REPOSITORY) + private repository: Repository, + ) {} +} diff --git a/libs/typeorm/tsconfig.lib.json b/libs/typeorm/tsconfig.lib.json new file mode 100644 index 0000000..b522cee --- /dev/null +++ b/libs/typeorm/tsconfig.lib.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "declaration": true, + "outDir": "../../dist/libs/typeorm" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] +} diff --git a/nest-cli.json b/nest-cli.json index c85f899..630b8ee 100644 --- a/nest-cli.json +++ b/nest-cli.json @@ -24,6 +24,15 @@ "compilerOptions": { "tsConfigPath": "libs/prisma/tsconfig.lib.json" } + }, + "typeorm": { + "type": "library", + "root": "libs/typeorm", + "entryFile": "index", + "sourceRoot": "libs/typeorm/src", + "compilerOptions": { + "tsConfigPath": "libs/typeorm/tsconfig.lib.json" + } } } } \ No newline at end of file diff --git a/package.json b/package.json index dae1738..dc45db1 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,8 @@ ], "moduleNameMapper": { "^@aditama-labs/nest-autocrud/skeleton(|/.*)$": "/libs/skeleton/$1", - "^@aditama-labs/nest-autocrud/prisma(|/.*)$": "/libs/prisma/$1" + "^@aditama-labs/nest-autocrud/prisma(|/.*)$": "/libs/prisma/$1", + "^@aditama-labs/nest-autocrud/typeorm(|/.*)$": "/libs/typeorm/src/$1" } } -} +} \ No newline at end of file diff --git a/src/app.module.ts b/src/app.module.ts index c4f0269..4fd1ccb 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -7,13 +7,22 @@ const getDatabaseCredential = (): any => { const url = new URL(process.env.DATABASE_URL); // Extract the necessary components + let protocol; + switch(url.protocol){ + case 'postgresql': + protocol = 'postgres'; + break; + case 'mysql': + protocol = 'mysql'; + break; + } const username = url.username; const password = url.password; const host = url.hostname; const port = url.port; const databaseName = url.pathname.substring(1); // Remove the leading slash return { - type: 'postgres', + type: protocol, host: host, port: port, username: username, diff --git a/test/jest-e2e.json b/test/jest-e2e.json index 7a372e7..5d9a0c0 100644 --- a/test/jest-e2e.json +++ b/test/jest-e2e.json @@ -14,6 +14,8 @@ "@aditama-labs/nest-autocrud/skeleton/(.*)": "/../libs/skeleton/$1", "@aditama-labs/nest-autocrud/skeleton": "/../libs/skeleton", "@aditama-labs/nest-autocrud/prisma/(.*)": "/../libs/prisma/$1", - "@aditama-labs/nest-autocrud/prisma": "/../libs/prisma" + "@aditama-labs/nest-autocrud/prisma": "/../libs/prisma", + "@aditama-labs/nest-autocrud/typeorm/(.*)": "/../libs/typeorm/src/$1", + "@aditama-labs/nest-autocrud/typeorm": "/../libs/typeorm/src" } } \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index cbc5a3a..955a14b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -29,6 +29,12 @@ ], "@aditama-labs/nest-autocrud/prisma/*": [ "libs/prisma/*" + ], + "@aditama-labs/nest-autocrud/typeorm": [ + "libs/typeorm/src" + ], + "@aditama-labs/nest-autocrud/typeorm/*": [ + "libs/typeorm/src/*" ] } }