Skip to content

Commit

Permalink
refactor(*): make knex.config required
Browse files Browse the repository at this point in the history
Also add more tests.

BREAKING CHANGE: config is now required

Signed-off-by: Will Soto <[email protected]>
  • Loading branch information
willsoto committed Feb 7, 2019
1 parent 84c52ca commit 0a40d73
Show file tree
Hide file tree
Showing 7 changed files with 212 additions and 17 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export class DatabaseModule {}

## Configuration

| Name | Type | Required | Default |
| -------- | -------- | -------- | ------------------- |
| `Model` | `Object` | `false` | `objection.Model` |
| `config` | `Object` | `false` | Knex default config |
| Name | Type | Required | Default |
| -------- | -------- | -------- | ----------------- |
| `Model` | `Object` | `false` | `objection.Model` |
| `config` | `Object` | `true` | |
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module.exports = {
clearMocks: true,
collectCoverage: true,
collectCoverageFrom: ["<rootDir>/lib/**/*.ts", "!**/node_modules/**"],
coverageDirectory: "coverage",
coverageReporters: ["json", "text", "lcov"],
testEnvironment: "node",
Expand Down
13 changes: 4 additions & 9 deletions lib/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ import {
} from "./interfaces";

export class ObjectionCoreModule {
public static forRoot(options: ObjectionModuleOptions = {}): DynamicModule {
const knexConfig = options.config || {};
public static forRoot(options: ObjectionModuleOptions): DynamicModule {
const Base = options.Model || Model;
const connection = knex(knexConfig);
const connection = knex(options.config);

Base.knex(connection);

Expand Down Expand Up @@ -54,9 +53,7 @@ export class ObjectionCoreModule {
provide: KNEX_CONNECTION,
inject: [OBJECTION_MODULE_OPTIONS],
useFactory(objectionModuleOptions: ObjectionModuleOptions) {
const config = objectionModuleOptions.config || {};

return knex(config);
return knex(objectionModuleOptions.config);
}
};

Expand Down Expand Up @@ -93,9 +90,7 @@ export class ObjectionCoreModule {
): Provider[] {
if (options.useExisting || options.useFactory) {
return [this.createAsyncOptionsProvider(options)];
}

if (!options.useClass) {
} else if (!options.useClass) {
throw new Error("Invalid configuration");
}

Expand Down
2 changes: 1 addition & 1 deletion lib/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Model } from "objection";

export interface ObjectionModuleOptions {
Model?: typeof Model;
config?: Knex.Config;
config: Knex.Config;
}

export interface ObjectionModuleOptionsFactory {
Expand Down
2 changes: 1 addition & 1 deletion lib/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
// eslint-disable-next-line new-cap
@Module({})
export class ObjectionModule {
public static forRoot(options?: ObjectionModuleOptions): DynamicModule {
public static forRoot(options: ObjectionModuleOptions): DynamicModule {
return {
module: ObjectionModule,
imports: [ObjectionCoreModule.forRoot(options)]
Expand Down
198 changes: 198 additions & 0 deletions tests/core.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
import {
KNEX_CONNECTION,
OBJECTION_BASE_MODEL,
OBJECTION_MODULE_OPTIONS
} from "@/constants";
import { ObjectionCoreModule } from "@/core";
import {
ObjectionModuleOptions,
ObjectionModuleOptionsFactory
} from "@/interfaces";
import { Injectable } from "@nestjs/common";
import { Test, TestingModule } from "@nestjs/testing";
import knex from "knex";
import { Model } from "objection";

describe("ObjectionCoreModule", () => {
let testingModule: TestingModule;
const config: knex.Config = {
client: "sqlite3",
useNullAsDefault: true,
connection: {
filename: "./testing.sqlite"
}
};

describe("#forRoot", () => {
beforeEach(async () => {
testingModule = await Test.createTestingModule({
imports: [
ObjectionCoreModule.forRoot({
config
})
]
}).compile();
});

test("provides a connection", () => {
const connection = testingModule.get<knex>("KnexConnection");

expect(connection).toBeDefined();
});

test("provides a base model", () => {
const model = testingModule.get<Model>("ObjectionBaseModel");

expect(model).toBeDefined();
});
});

describe("#forRootAsync", () => {
beforeEach(async () => {
testingModule = await Test.createTestingModule({
imports: [
ObjectionCoreModule.forRootAsync({
useFactory() {
return {
config
};
}
})
]
}).compile();
});

test("provides a connection", () => {
const connection = testingModule.get<knex>(KNEX_CONNECTION);

expect(connection).toBeDefined();
});

test("provides a base model", () => {
const model = testingModule.get<Model>(OBJECTION_BASE_MODEL);

expect(model).toBeDefined();
});
});

describe("#createAsyncProviders", () => {
class ModuleOptionsFactory implements ObjectionModuleOptionsFactory {
public createObjectionModuleOptions(): ObjectionModuleOptions {
return {
config
};
}
}

test("throws an error if options.useClass, useExisting, useFactory are not provided", () => {
expect(() => {
ObjectionCoreModule.createAsyncProviders({});
}).toThrowError("Invalid configuration");
});

test("leverages useClass if provided", () => {
const providers = ObjectionCoreModule.createAsyncProviders({
useClass: ModuleOptionsFactory
});

expect(providers).toEqual([
{
inject: [ModuleOptionsFactory],
useFactory: expect.any(Function),
provide: OBJECTION_MODULE_OPTIONS
},
{
useClass: ModuleOptionsFactory,
provide: ModuleOptionsFactory
}
]);
});

test("returns an array of providers when useExisting is passed", () => {
const providers = ObjectionCoreModule.createAsyncProviders({
useExisting: ModuleOptionsFactory
});

expect(providers).toEqual([
{
inject: [ModuleOptionsFactory],
useFactory: expect.any(Function),
provide: OBJECTION_MODULE_OPTIONS
}
]);
});

test("returns an array of providers when useFactory is passed", () => {
const providers = ObjectionCoreModule.createAsyncProviders({
useFactory: () => ({
config
})
});

expect(providers).toEqual([
{
inject: [],
useFactory: expect.any(Function),
provide: OBJECTION_MODULE_OPTIONS
}
]);
});
});

describe("#createAsyncOptionsProvider", () => {
// eslint-disable-next-line new-cap
@Injectable()
class ModuleOptionsFactory implements ObjectionModuleOptionsFactory {
public createObjectionModuleOptions(): ObjectionModuleOptions {
return {
config
};
}
}

test("returns the appropriate provider when useFactory is passed", () => {
const provider = ObjectionCoreModule.createAsyncOptionsProvider({
useFactory: () => ({
config
})
});

expect(provider).toEqual({
inject: [],
provide: OBJECTION_MODULE_OPTIONS,
useFactory: expect.any(Function)
});
});

test("returns the appropriate provider when useExisting is passed", () => {
const provider = ObjectionCoreModule.createAsyncOptionsProvider({
useExisting: ModuleOptionsFactory
});

expect(provider).toEqual({
inject: [ModuleOptionsFactory],
provide: OBJECTION_MODULE_OPTIONS,
useFactory: expect.any(Function)
});
});

test("returns an async factory function that calls createObjectionModuleOptions", async () => {
jest.spyOn(
ModuleOptionsFactory.prototype,
"createObjectionModuleOptions"
);

await Test.createTestingModule({
imports: [
ObjectionCoreModule.forRootAsync({
useClass: ModuleOptionsFactory
})
]
}).compile();

expect(
ModuleOptionsFactory.prototype.createObjectionModuleOptions
).toHaveBeenCalled();
});
});
});
5 changes: 3 additions & 2 deletions tests/module.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { KNEX_CONNECTION, OBJECTION_BASE_MODEL } from "@/constants";
import { ObjectionModule } from "@/module";
import { Test, TestingModule } from "@nestjs/testing";
import knex from "knex";
Expand Down Expand Up @@ -25,13 +26,13 @@ describe("ObjectionModule", () => {
});

test("provides a connection", () => {
const connection = testingModule.get<knex>("KnexConnection");
const connection = testingModule.get<knex>(KNEX_CONNECTION);

expect(connection).toBeDefined();
});

test("provides a base model", () => {
const model = testingModule.get<Model>("ObjectionBaseModel");
const model = testingModule.get<Model>(OBJECTION_BASE_MODEL);

expect(model).toBeDefined();
});
Expand Down

0 comments on commit 0a40d73

Please sign in to comment.