This repository has been archived by the owner on Feb 2, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature(main): Basic mixin implementation
- Loading branch information
Kevin Delisle
committed
Nov 23, 2017
1 parent
6ff849a
commit 9696903
Showing
9 changed files
with
656 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,96 @@ | ||
# loopback-typeorm | ||
A component to provide TypeORM in Loopback 4 | ||
|
||
## Usage | ||
Note: These instructions aren't entirely applicable yet, this module has not | ||
been published. | ||
|
||
1. Install this plugin | ||
```ts | ||
npm install --save loopback-typeorm | ||
``` | ||
2. In your application, make your own Application class, but instead of | ||
extending `Application`, you'll want to call the provided mixin as your base | ||
class. | ||
```ts | ||
import {Application} from '@loopback/core'; | ||
import {TypeORMRepositoryMixin} from 'loopback-typeorm'; | ||
|
||
export class MyApplication extends TypeORMRepositoryMixin(Application) { | ||
constructor() { | ||
super(...); | ||
} | ||
} | ||
``` | ||
3. Create a connection (or multiple!) in your new subclass, and define | ||
whatever repositories you'd like to create. | ||
|
||
A helpful way to ensure that your configuration has all of the _required_ values | ||
is to import the `ConnectionOptions` type from TypeORM directly. | ||
|
||
**Note**: There are connection options that become required within different | ||
use cases and contexts. For info on how to configure your database connection, | ||
see the [TypeORM docs](https://github.com/typeorm/typeorm). | ||
|
||
```ts | ||
import {Application} from '@loopback/core'; | ||
import {TypeORMRepositoryMixin} from 'loopback-typeorm'; | ||
import {ConnectionOptions} from 'typeorm'; | ||
import {Order, Customer} from './models'; | ||
|
||
export class MyApplication extends TypeORMRepositoryMixin(Application) { | ||
mySqlConnection: Connection; | ||
constructor() { | ||
super(); | ||
const connectionOptions: ConnectionOptions = { | ||
name: 'connectionName', | ||
host: 'somehost.com', | ||
database: 'mydb', | ||
port: 3306, | ||
type: 'mysql', | ||
username: 'admin', | ||
password: 'secretpassword', | ||
// etc... | ||
}; | ||
this.mySqlConnection = this.createTypeOrmConnection(connectionOptions); | ||
|
||
// Automatically uses the connection to bind repositories to | ||
// your application context. | ||
this.typeOrmRepository(this.mySqlConnection, Order); | ||
this.typeOrmRepository(this.mySqlConnection, Customer); | ||
} | ||
} | ||
``` | ||
4. Finally, consume your repositories in your controllers! | ||
```ts | ||
import {Customer, CustomerSchema} from '../models'; | ||
import {Repository} from 'typeorm'; | ||
|
||
export class CustomerController { | ||
constructor(@inject('repositories.Customer') customerRepo: Repository) { | ||
// ... | ||
} | ||
|
||
@get('/customer/{id}') | ||
@param.path.number('id'); | ||
async getCustomerById(id: number) { | ||
// Using TypeORM's repository! | ||
return await this.customerRepo.findOneById(id); | ||
} | ||
|
||
@post('/customer') | ||
@param.body('customer', CustomerSchema); | ||
async createCustomer(customer: Customer) { | ||
return await this.customerRepo.save(customer); | ||
} | ||
} | ||
``` | ||
|
||
## Testing | ||
To run tests, you'll need an installation of Docker. | ||
``` | ||
npm it | ||
``` | ||
|
||
[![LoopBack](http://loopback.io/images/overview/powered-by-LB-xs.png)](http://loopback.io/) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1 @@ | ||
// Copyright IBM Corp. 2017. All Rights Reserved. | ||
// Node module: loopback-typeorm | ||
// This file is licensed under the MIT License. | ||
// License text available at https://opensource.org/licenses/MIT | ||
|
||
// NOTE(bajtos) This file is used by TypeScript compiler to resolve imports | ||
// from "test" files against original TypeScript sources in "src" directory. | ||
// As a side effect, `tsc` also produces "dist/index.{js,d.ts,map} files | ||
// that allow test files to import paths pointing to {src,test} root directory, | ||
// which is project root for TS sources but "dist" for transpiled sources. | ||
export * from './src'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import {ConnectionManager, Connection} from 'typeorm'; | ||
|
||
export class TypeORMConnectionManager extends ConnectionManager { | ||
// This is to allow more direct access to the connection objects | ||
// during start/stop of the application. | ||
public connections: Connection[]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './typeorm-mixin'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import {Application, Component, Server} from '@loopback/core'; | ||
import {Context, Binding, Constructor} from '@loopback/context'; | ||
import {Connection, Entity, BaseEntity, ConnectionOptions} from 'typeorm'; | ||
import {TypeORMConnectionManager} from './connection-manager'; | ||
|
||
// tslint:disable:no-any | ||
export function TypeORMMixin( | ||
superClass: typeof Application, | ||
): TypeORMApplicationClass { | ||
return class extends superClass { | ||
typeOrmConnectionManager: TypeORMConnectionManager; | ||
constructor(...args: any[]) { | ||
super(...args); | ||
this.typeOrmConnectionManager = new TypeORMConnectionManager(); | ||
this.bind('typeorm.connections.manager').to( | ||
this.typeOrmConnectionManager, | ||
); | ||
} | ||
|
||
async start() { | ||
for (const connection of this.typeOrmConnectionManager.connections) { | ||
await connection.connect(); | ||
} | ||
await super.start(); | ||
} | ||
|
||
async stop() { | ||
for (const connection of this.typeOrmConnectionManager.connections) { | ||
await connection.close(); | ||
} | ||
await super.stop(); | ||
} | ||
|
||
/** | ||
* Register a TypeORM-based repository instance of the given class. | ||
* Generated repositories will be bound using the `repositories.{name}` | ||
* convention. | ||
* | ||
* ```ts | ||
* this.typeOrmRepository(Foo); | ||
* const fooRepo = this.getSync(`repositories.Foo`); | ||
* ``` | ||
* | ||
* @param ctor The constructor (class) that represents the entity to | ||
* generate a repository for. | ||
*/ | ||
typeOrmRepository<S>( | ||
connection: Connection, | ||
ctor: Constructor<S>, | ||
): Binding { | ||
// XXX(kjdelisle): I wanted to make this a provider, but it requires | ||
// the constructor instance to be available in the provider scope, which | ||
// would require injection of each constructor, so I had to settle for | ||
// this instead. | ||
return this.bind(`repositories.${ctor.name}`).toDynamicValue(async () => { | ||
if (!connection.isConnected) { | ||
await connection.connect(); | ||
} | ||
return connection.getRepository(ctor); | ||
}); | ||
} | ||
|
||
/** | ||
* Get an existing connection instance from the connection manager, | ||
* or create one if it does not exist. If you do not provide a name, a | ||
* default connection instance will be provided. | ||
* @param name The name of the connection (if it already exists) | ||
*/ | ||
getTypeOrmConnection(name?: string): Connection { | ||
return this.typeOrmConnectionManager.get(name); | ||
} | ||
|
||
/** | ||
* Create a new TypeORM connection with the provided set of options. | ||
* @param options | ||
*/ | ||
createTypeOrmConnection(options: ConnectionOptions): Connection { | ||
if (!options) { | ||
throw new Error('Connection options are required!'); | ||
} | ||
return this.typeOrmConnectionManager.create(options); | ||
} | ||
}; | ||
} | ||
|
||
/** | ||
* Define any implementation of Application. | ||
*/ | ||
|
||
export interface TypeORMApplication extends Application { | ||
typeOrmRepository<S>(connection: Connection, ctor: Constructor<S>): Binding; | ||
createTypeOrmConnection(options: ConnectionOptions): Connection; | ||
getTypeOrmConnection(name?: string): Connection; | ||
} | ||
|
||
export interface TypeORMApplicationClass | ||
extends Constructor<TypeORMApplication> { | ||
[property: string]: any; | ||
} | ||
|
||
export interface Options { | ||
[property: string]: any; | ||
} |
Oops, something went wrong.