Skip to content

Commit

Permalink
feat(di): Add InjectorService.destroy() method
Browse files Browse the repository at this point in the history
TypeORM now can close all active connections
  • Loading branch information
Romakita committed Apr 29, 2019
1 parent 1ff45bc commit 17c14e8
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 43 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@
"typescript": "^3.0.1",
"vue-analytics": "^5.14.0",
"vuepress": "^0.14.2",
"vuepress-theme-tsed": "^1.7.0"
"vuepress-theme-tsed": "^1.7.1"
},
"directories": {
"packages": "packages",
Expand Down
8 changes: 6 additions & 2 deletions packages/common/test/mvc/class/HandlerBuilder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,11 @@ describe("HandlerBuilder", () => {

// THEN
expect(nextStub.isCalled).to.eq(true);
infoStub.should.have.been.calledWithExactly({tagId: "1"}, {error: undefined, event: "invoke.end", execTime: 0});
infoStub.should.have.been.calledWithExactly({tagId: "1"}, {
error: undefined,
event: "invoke.end",
execTime: Sinon.match.number
});
});
});

Expand Down Expand Up @@ -317,7 +321,7 @@ describe("HandlerBuilder", () => {

const request = new FakeRequest();
request.ctx.data = "data";

const handlerBuilder = new HandlerBuilder(metadata);
// @ts-ignore
handlerBuilder.debug = true;
Expand Down
5 changes: 5 additions & 0 deletions packages/di/src/services/InjectorService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ export class InjectorService extends Map<RegistryKey, Provider<any>> {
.map(([key, provider]) => provider);
}

async destroy() {
await this.emit("$onDestroy");
this.clear();
}

/**
* Invoke the class and inject all services that required by the class constructor.
*
Expand Down
4 changes: 2 additions & 2 deletions packages/testing/src/TestContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ export class TestContext {
/**
* Resets the test injector of the test context, so it won't pollute your next test. Call this in your `tearDown` logic.
*/
static reset() {
static async reset() {
if (TestContext._injector) {
TestContext._injector.clear();
await TestContext._injector.destroy();
TestContext._injector = null;
}
}
Expand Down
5 changes: 3 additions & 2 deletions packages/testing/test/TestContext.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ describe("TestContext", () => {
describe("reset()", () => {
before(TestContext.create);

it("should reset the injector", () => {
it("should reset the injector", async () => {
const injectionKey = "key";
TestContext.injector.set(injectionKey, new Provider("something"));
TestContext.reset();
await TestContext.reset();

expect((TestContext as any)._injector).eq(null);
});
});
Expand Down
8 changes: 6 additions & 2 deletions packages/typeorm/src/TypeORMModule.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {Constant, OnInit, Service} from "@tsed/common";
import {Constant, OnDestroy, OnInit, Service} from "@tsed/common";
import {ConnectionOptions} from "typeorm";
import {TypeORMService} from "./services/TypeORMService";

@Service()
export class TypeORMModule implements OnInit {
export class TypeORMModule implements OnInit, OnDestroy {
@Constant("typeorm", {})
private settings: {[key: string]: ConnectionOptions};

Expand All @@ -14,4 +14,8 @@ export class TypeORMModule implements OnInit {

return Promise.all(promises);
}

$onDestroy(): Promise<any> | void {
return this.typeORMService.closeConnections();
}
}
14 changes: 10 additions & 4 deletions packages/typeorm/src/services/TypeORMService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export class TypeORMService {
* @type {Map<any, any>}
* @private
*/
private _instances: Map<string, Connection> = new Map();
readonly instances: Map<string, Connection> = new Map();

/**
*
Expand All @@ -28,7 +28,7 @@ export class TypeORMService {
try {
const connection = await createConnection(settings!);
$log.info(`Connected with typeorm to database: ${key}`);
this._instances.set(key || "default", connection);
this.instances.set(key || "default", connection);

return connection;
} catch (err) {
Expand All @@ -44,7 +44,7 @@ export class TypeORMService {
* @returns {"mongoose".Connection}
*/
get(id: string = "default"): Connection | undefined {
return this._instances.get(id);
return this.instances.get(id);
}

/**
Expand All @@ -53,6 +53,12 @@ export class TypeORMService {
* @returns {boolean}
*/
has(id: string = "default"): boolean {
return this._instances.has(id);
return this.instances.has(id);
}

closeConnections(): Promise<any> {
const promises = Array.from(this.instances.values()).map(instance => instance.close());

return Promise.all(promises);
}
}
8 changes: 6 additions & 2 deletions packages/typeorm/test/TypeORMModule.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import {TypeORMModule} from "../src";

describe("TypeORMModule", () => {
describe("$onInit()", () => {
const connection: any = {
close() {
}
};
before(
inject([TypeORMModule, ServerSettingsService], (service: TypeORMModule, settings: ServerSettingsService) => {
this.service = service;
Expand All @@ -14,7 +18,7 @@ describe("TypeORMModule", () => {
}
});

this.createConnectionStub = Sinon.stub(this.service.typeORMService, "createConnection").resolves("connection" as any);
this.createConnectionStub = Sinon.stub(this.service.typeORMService, "createConnection").resolves(connection);

return (this.result = this.service.$onInit());
})
Expand All @@ -33,7 +37,7 @@ describe("TypeORMModule", () => {
});

it("should return a promise", () => {
this.result.should.eventually.deep.eq(["connection"]);
return this.result.should.eventually.deep.eq([connection]);
});
});
});
47 changes: 30 additions & 17 deletions packages/typeorm/test/services/TypeORMService.spec.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,45 @@
import {inject, TestContext} from "@tsed/testing";
import {TestContext} from "@tsed/testing";
import * as Sinon from "sinon";
import * as TypeORM from "typeorm";
import {TypeORMService} from "../../src";

describe("TypeORMService", () => {
describe("createConnection()", () => {
before(
inject([TypeORMService], (service: TypeORMService) => {
this.connectStub = Sinon.stub(TypeORM, "createConnection").resolves("connection" as any);

return (this.result = service.createConnection("key", {config: "config"} as any).then(() => {
return service.createConnection("key", {config: "config"} as any);
}));
})
);
before(() => {
Sinon.stub(TypeORM, "createConnection");
});

after(() => {
TestContext.reset();
this.connectStub.restore();
// @ts-ignore
TypeORM.createConnection.restore();
});

it("should call mongoose.connect", () => {
this.connectStub.should.have.been.calledOnce;
this.connectStub.should.have.been.calledWithExactly({config: "config"});
});
it("should create connection and close connection", async () => {
// GIVEN
const connection: any = {
close: Sinon.stub()
};

// @ts-ignore
TypeORM.createConnection.resolves(connection);

const service = new TypeORMService();

// WHEN
const result1 = await service.createConnection("key", {config: "config"} as any);
const result2 = await service.createConnection("key", {config: "config"} as any);

// THEN
result1.should.deep.eq(connection);
result2.should.deep.eq(connection);
TypeORM.createConnection.should.have.been.calledOnce.and.calledWithExactly({config: "config"});

// WHEN close
await service.closeConnections();

it("should return the instance of mongoose", () => {
return this.result.should.eventually.eq("connection");
// THEN
connection.close.should.have.been.calledWithExactly();
});
});
});
32 changes: 21 additions & 11 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2792,6 +2792,14 @@ aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==

axios@^0.18.0:
version "0.18.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102"
integrity sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=
dependencies:
follow-redirects "^1.3.0"
is-buffer "^1.1.5"

babel-code-frame@^6.22.0, babel-code-frame@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
Expand Down Expand Up @@ -4566,7 +4574,7 @@ debug@3.1.0, debug@~3.1.0:
dependencies:
ms "2.0.0"

debug@3.X, debug@^3.1.0:
debug@3.X, debug@^3.1.0, debug@^3.2.6:
version "3.2.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
Expand Down Expand Up @@ -5763,6 +5771,13 @@ fn-name@~2.0.1:
resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-2.0.1.tgz#5214d7537a4d06a4a301c0cc262feb84188002e7"
integrity sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc=

follow-redirects@^1.3.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76"
integrity sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==
dependencies:
debug "^3.2.6"

for-in@^0.1.3:
version "0.1.8"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1"
Expand Down Expand Up @@ -13869,19 +13884,19 @@ vuepress-html-webpack-plugin@^3.2.0:
toposort "^1.0.0"
util.promisify "1.0.0"

vuepress-theme-tsed@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/vuepress-theme-tsed/-/vuepress-theme-tsed-1.7.0.tgz#fbccf4fe73c8ed55a5f54b83d984f85065624096"
integrity sha512-pUu3gW7OrIu5CRiqIyApJz5rktZGOndhzorTdStzH6iq7UReWQgDHcoMiXQyeXL/zyC/Ci2lvaKL/1E1R9IvZg==
vuepress-theme-tsed@^1.7.1:
version "1.7.1"
resolved "https://registry.yarnpkg.com/vuepress-theme-tsed/-/vuepress-theme-tsed-1.7.1.tgz#a421a779e80518293db93f23dc2a558981de38de"
integrity sha512-M3R8XKlYR4i8PYRE4soguhY+dhUY7Pz511FDtAppQBFkZzvzoy+2OMvTXApwkupS0Km7SKdTtiSptbFhCRBrcQ==
dependencies:
axios "^0.18.0"
include-media "^1.4.9"
node-sass "^4.9.3"
sass-loader "^7.1.0"
sass-rem "^2.0.1"
vue "^2.6.9"
vue-template-compiler "^2.6.10"
vuepress "^0.14.1"
whatwg-fetch "^3.0.0"

vuepress@^0.14.1:
version "0.14.8"
Expand Down Expand Up @@ -14161,11 +14176,6 @@ webpackbar@^2.6.1:
std-env "^1.3.1"
table "^4.0.3"

whatwg-fetch@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb"
integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==

when@~3.6.x:
version "3.6.4"
resolved "https://registry.yarnpkg.com/when/-/when-3.6.4.tgz#473b517ec159e2b85005497a13983f095412e34e"
Expand Down

0 comments on commit 17c14e8

Please sign in to comment.