Skip to content

Commit

Permalink
feat: remove mysql + prepare release 0.15.0 (#10)
Browse files Browse the repository at this point in the history
* feat: remove mysql driver

* chore: prepare release 0.15.0

* feat: better config parsing + fix core persisters
  • Loading branch information
Mararok authored Jun 25, 2024
1 parent 389f483 commit c73aa4a
Show file tree
Hide file tree
Showing 22 changed files with 211 additions and 144 deletions.
15 changes: 14 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.15.0] - 2024-06-24

### Changed

- Updated @hexancore/common to 0.14.*
- Updated @hexancore/core to ^0.15.*

### Removed

- removed support for mysql driver


## [0.14.0] - 2024-02-11

### Changed
Expand Down Expand Up @@ -59,7 +71,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- First release(start from 0.12 for consistency)
- Implemented generic from domain infrastructre from Hexancore

[unreleased] https://github.com/hexancore/typeorm/compare/0.14.0...HEAD
[unreleased] https://github.com/hexancore/typeorm/compare/0.15.0...HEAD
[0.15.0] https://github.com/hexancore/typeorm/compare/0.14.0...0.15.0
[0.14.0] https://github.com/hexancore/typeorm/compare/0.13.3...0.14.0
[0.13.3] https://github.com/hexancore/typeorm/compare/0.13.2...0.13.3
[0.13.2] https://github.com/hexancore/typeorm/compare/0.13.1...0.13.2
Expand Down
4 changes: 2 additions & 2 deletions config/test/config.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
core:
typeorm-mysql:
typeorm-mariadb:
type: mariadb
host: 127.0.0.1
port: 10020
synchronizeSchema: true
dropSchema: true
retryAttempts: 4
retryDelay: 3000
authSecretKey: core.typeorm.mysql
authSecretKey: core.typeorm.mariadb
typeorm-postgres:
type: postgres
host: 127.0.0.1
Expand Down
File renamed without changes.
19 changes: 10 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hexancore/typeorm",
"version": "0.14.0",
"version": "0.15.0",
"type": "commonjs",
"engines": {
"node": ">=22"
Expand Down Expand Up @@ -53,11 +53,12 @@
"dependencies": {
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.0",
"tslib": "^2.6.3"
"tslib": "^2.6.3",
"zod": "^3.23.8"
},
"devDependencies": {
"@hexancore/common": "^0.14.0",
"@hexancore/core": "^0.15.2",
"@hexancore/core": "^0.15.4",
"@hexancore/mocker": "^1.1.2",
"@nestjs/cli": "^10.3.2",
"@nestjs/common": "^10.3.9",
Expand Down Expand Up @@ -112,12 +113,12 @@
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"lint": "eslint \"{src,test}/**/*.ts\"",
"lint:fix": "eslint \"{src,test}/**/*.ts\" --fix",
"test": "jest --runInBand",
"test:clearCache": "jest --clearCache",
"test:unit": "jest --runInBand --group=unit",
"test:watch": "jest --runInBand --watchAll",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"jest": "node --disable-warning=ExperimentalWarning --experimental-vm-modules node_modules/jest/bin/jest.js --config jest.config.ts",
"test": "yarn run jest --runInBand",
"test:clearCache": "yarn run jest --clearCache",
"test:unit": "yarn run jest --runInBand --group=unit",
"test:watch": "yarn run jest --runInBand --watchAll",
"test:cov": "yarn run jest --coverage",
"prepublish": "yarn run build",
"deps:upgrade": "yarn add -D @hexancore/common @hexancore/core"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { DataSourceManager, WeakDataSourceRef } from './DataSourceManager';
import { DataSourceContextConfig } from './DataSourceContextConfig';
import { AR } from '@hexancore/common';

export abstract class DataSourceContext {
public constructor(private manager: DataSourceManager) {}
export abstract class AbstractDataSourceContext {
public constructor(private manager: DataSourceManager) { }

public get(): AR<WeakDataSourceRef> {
return this.getConfig().onOk((config) => {
Expand Down
4 changes: 2 additions & 2 deletions src/DataSource/AccountDataSourceContext.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { DataSourceManager } from './DataSourceManager';
import { AR, OKA } from '@hexancore/common';

import { DataSourceContext } from './DataSourceContext';
import { AbstractDataSourceContext } from './AbstractDataSourceContext';
import { DataSourceContextConfig } from './DataSourceContextConfig';
import { Injectable } from '@nestjs/common';
import { AccountContext } from '@hexancore/core';
import { TYPEORM_ACCOUNT_PERSISTER_TYPE } from '@/Repository';

@Injectable()
export class AccountDataSourceContext extends DataSourceContext {
export class AccountDataSourceContext extends AbstractDataSourceContext {
public constructor(
manager: DataSourceManager,
protected ac: AccountContext,
Expand Down
32 changes: 17 additions & 15 deletions src/DataSource/DataSourceFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ export interface DataSourceFactoryOptions {
maxRetryAttempts?: number;
}

/**
* Factory to create TypeORM DataSource(db connection) from given context config.
*/
export class DataSourceFactory {
public constructor(private options: DataSourceFactoryOptions) {
options.dbPrefix = options.dbPrefix ?? '';
Expand All @@ -29,22 +32,21 @@ export class DataSourceFactory {
entities,
};

return RetryHelper.retryAsync(
() => {
let ds: DataSource| null = null;
try {
ds = new DataSource(options);
return ARW(ds.initialize());
} catch (e) {
if (ds && ds.isInitialized) {
return ARW(ds.destroy())
.onOk(() => INTERNAL_ERR<DataSource, any>(e))
.onErr(() => INTERNAL_ERR<DataSource, any>(e));
}

return INTERNAL_ERRA(e as any);
return RetryHelper.retryAsync(() => {
let ds: DataSource | null = null;
try {
ds = new DataSource(options);
return ARW(ds.initialize());
} catch (e) {
if (ds && ds.isInitialized) {
return ARW(ds.destroy())
.onOk(() => INTERNAL_ERR<DataSource, any>(e))
.onErr(() => INTERNAL_ERR<DataSource, any>(e));
}
},

return INTERNAL_ERRA(e as any);
}
},
{
id: 'create_typeorm_data_source_' + config.id,
retryDelay: this.options.retryDelay,
Expand Down
6 changes: 5 additions & 1 deletion src/DataSource/DataSourceManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ export interface WeakDataSourceRef {
initPromise?: AR<WeakDataSourceRef>;
}

/**
* Manages active database connections.
* Connection can be closed after defined idle timeout.
*/
export class DataSourceManager {
private map: Map<string, WeakDataSourceRef>;
private logger: Logger;
Expand All @@ -21,7 +25,7 @@ export class DataSourceManager {
private ct: CurrentTime,
) {
this.map = new Map();
this.logger = getLogger('core.typeorm.infra.data_source');
this.logger = getLogger('core.typeorm.infra.data_source', ['core', 'typeorm']);
}

public async get(context: DataSourceContextConfig): ARP<WeakDataSourceRef> {
Expand Down
4 changes: 2 additions & 2 deletions src/DataSource/SystemDataSourceContext.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { AR, OKA } from '@hexancore/common';
import { DataSource, EntityManager } from 'typeorm';
import { DataSourceContext } from './DataSourceContext';
import { AbstractDataSourceContext } from './AbstractDataSourceContext';
import { DataSourceContextConfig } from './DataSourceContextConfig';
import { WeakDataSourceRef } from './DataSourceManager';
import { Injectable } from '@nestjs/common';
import { TYPEORM_SYSTEM_PERSISTER_TYPE } from '@/Repository';

@Injectable()
export class SystemDataSourceContext extends DataSourceContext {
export class SystemDataSourceContext extends AbstractDataSourceContext {
protected getConfig(): AR<DataSourceContextConfig> {
return OKA({
id: 'system',
Expand Down
1 change: 1 addition & 0 deletions src/DataSource/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './DataSourceFactory';
export * from './DataSourceManager';
export * from './AbstractDataSourceContext';
export * from './AccountDataSourceContext';
export * from './SystemDataSourceContext';
export * from './DataSourceContextConfig';
100 changes: 26 additions & 74 deletions src/HcTypeOrmModule.ts
Original file line number Diff line number Diff line change
@@ -1,98 +1,60 @@
import { AppMeta, CurrentTime, INTERNAL_ERROR, LogicError, OK, getLogger } from '@hexancore/common';
import { CurrentTime, INTERNAL_ERROR, OK, getLogger } from '@hexancore/common';
import { AppConfig, EntityPersisterFactoryManager } from '@hexancore/core';
import { ConfigurableModuleBuilder, Module, OnApplicationShutdown } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';
import { MysqlConnectionOptions } from 'typeorm/driver/mysql/MysqlConnectionOptions';
import { PostgresConnectionOptions } from 'typeorm/driver/postgres/PostgresConnectionOptions';
import { AccountDataSourceContext } from './DataSource';
import { DataSourceFactory } from './DataSource/DataSourceFactory';
import { DataSourceManager } from './DataSource/DataSourceManager';
import { SnakeNamingStrategy } from './DataSource/SnakeNamingStrategy';
import { SystemDataSourceContext } from './DataSource/SystemDataSourceContext';
import { CONFIG_TOKEN, HcTypeOrmModuleConfigProvider } from './HcTypeOrmModuleConfigProvider';
import type { HcTypeOrmModuleOptions } from './HcTypeOrmModuleOptions';
import { TYPEORM_ACCOUNT_PERSISTER_TYPE, TYPEORM_SYSTEM_PERSISTER_TYPE } from './Repository';
import { TypeOrmEntityPersisterFactory } from './Repository/Persister/TypeOrmEntityPersisterFactory';

export interface HcTypeOrmModuleOptions {
configPath?: string;
accountContext: boolean;
}

const CONFIG_TOKEN = 'HC_TYPEORM_CONFIG';
const SYSTEM_ENTITY_PERSISTER_FACTORY_TOKEN = 'HC_SystemEntityPersisterFactory';
const ACCOUNT_ENTITY_PERSISTER_FACTORY_TOKEN = 'HC_AccountEntityPersisterFactory';

const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } = new ConfigurableModuleBuilder<HcTypeOrmModuleOptions>()
.setClassMethodName('forRoot')
.setExtras({ accountContext: false }, (def, extras) => {
def.providers = def.providers ?? [];

if (extras.accountContext) {
def.providers.push(AccountDataSourceContext);
def.providers.push({
provide: 'AccountEntityPersisterFactory',
provide: ACCOUNT_ENTITY_PERSISTER_FACTORY_TOKEN,
inject: [AccountDataSourceContext, EntityPersisterFactoryManager],
useFactory: (account: AccountDataSourceContext, factoryManager: EntityPersisterFactoryManager) => {
const accountFactory = new TypeOrmEntityPersisterFactory(account);
factoryManager.registerFactory(TYPEORM_ACCOUNT_PERSISTER_TYPE, accountFactory);
return accountFactory;
},
useFactory: (context: AccountDataSourceContext, manager: EntityPersisterFactoryManager) => {
const factory = new TypeOrmEntityPersisterFactory(context);
manager.registerFactory(TYPEORM_ACCOUNT_PERSISTER_TYPE, factory);
return factory;
}
});
}

def.providers.push(SystemDataSourceContext);
def.providers.push({
provide: SYSTEM_ENTITY_PERSISTER_FACTORY_TOKEN,
inject: [SystemDataSourceContext, EntityPersisterFactoryManager],
useFactory: (context: SystemDataSourceContext, manager: EntityPersisterFactoryManager) => {
const factory = new TypeOrmEntityPersisterFactory(context);
manager.registerFactory(TYPEORM_SYSTEM_PERSISTER_TYPE, factory);
return factory;
},
});
return def;
})
.build();

@Module({
providers: [
{
provide: CONFIG_TOKEN,
inject: [AppConfig, MODULE_OPTIONS_TOKEN],
useFactory: (config: AppConfig, options: HcTypeOrmModuleOptions) => {
const configPath = options.configPath ?? 'core.typeorm';
const c = config.config.get(configPath);
if (!c) {
throw new LogicError('Empty config key for typeorm: ' + configPath);
}

const supportedDrivers = ['mysql', 'postgres', 'mariadb'];
if (['mysql', 'postgres', 'mariadb'].indexOf(c.type) === -1) {
throw new LogicError(`HcTypeOrmModule supports only [${supportedDrivers.join(", ")}] drivers`);
}

const isProd = AppMeta.get().isProd();
const dropSchema = c.dropSchema == true && !isProd;
const synchronizeSchema = c.synchronizeSchema == true && !isProd;

const common: MysqlConnectionOptions | PostgresConnectionOptions = {
type: c.type,
host: c.host,
port: Number.parseInt(c.port),
charset: c.charset ?? (c.type === 'postgres' ? 'utf8' : 'utf8mb4'),
applicationName: AppMeta.get().id,
useUTC: true,
timezone: 'Z',
synchronize: synchronizeSchema,
namingStrategy: new SnakeNamingStrategy(),
cache: c.cache == true ? true : false,
dropSchema: dropSchema,
};

return {
maxDataSourceIdleSecs: c.maxDataSourceIdleSecs ?? 60 * 60,
commonDataSourceConfig: common,
dbPrefix: c.dbPrefix ?? '',
authSecretKey: c.authSecretKey ?? 'core.typeorm',
retryDelay: c.retryDelay,
maxRetryAttempts: c.maxRetryAttempts,
};
},
},
HcTypeOrmModuleConfigProvider(MODULE_OPTIONS_TOKEN),
{
provide: DataSourceFactory,
inject: [CONFIG_TOKEN, AppConfig],
useFactory: (typeOrmConfig: any, config: AppConfig) => {
const secret = config.secrets.getAsBasicAuth(typeOrmConfig.authSecretKey);
if (secret.isError()) {
secret.e.panic();
}

secret.panicIfError();
typeOrmConfig.commonDataSourceConfig.username = secret.v.username;
typeOrmConfig.commonDataSourceConfig.password = secret.v.password;

Expand All @@ -111,18 +73,8 @@ const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } = new ConfigurableModule
return new DataSourceManager(factory, typeOrmConfig.maxDataSourceIdleSecs, ct);
},
},
SystemDataSourceContext,
{
provide: 'SystemEntityPersisterFactory',
inject: [SystemDataSourceContext, EntityPersisterFactoryManager],
useFactory: (system: SystemDataSourceContext, factoryManager: EntityPersisterFactoryManager) => {
const systemFactory = new TypeOrmEntityPersisterFactory(system);
factoryManager.registerFactory(TYPEORM_SYSTEM_PERSISTER_TYPE, systemFactory);
return systemFactory;
},
},
],
exports: [DataSourceManager],
exports: [DataSourceManager, SYSTEM_ENTITY_PERSISTER_FACTORY_TOKEN, ACCOUNT_ENTITY_PERSISTER_FACTORY_TOKEN],
})
export class HcTypeOrmModule extends ConfigurableModuleClass implements OnApplicationShutdown {
public constructor(private moduleRef: ModuleRef) {
Expand Down
Loading

0 comments on commit c73aa4a

Please sign in to comment.