<a href="https://travis-ci.org/hapinessjs/mongo-module.svg?branch=master">
<img src="https://travis-ci.org/hapinessjs/mongo-module.svg?branch=master" alt="build" />
</a>
<a href="https://coveralls.io/github/hapinessjs/mongo-module?branch=master">
<img src="https://coveralls.io/repos/github/hapinessjs/mongo-module/badge.svg?branch=master" alt="coveralls" />
</a>
<a href="https://david-dm.org/hapinessjs/mongo-module">
<img src="https://david-dm.org/hapinessjs/mongo-module.svg" alt="dependencies" />
</a>
<a href="https://david-dm.org/hapinessjs/mongo-module?type=dev">
<img src="https://david-dm.org/hapinessjs/mongo-module/dev-status.svg" alt="devDependencies" />
</a>
<a href="https://www.typescriptlang.org/docs/tutorial.html">
<img src="https://cdn-images-1.medium.com/max/800/1*8lKzkDJVWuVbqumysxMRYw.png"
align="right" alt="Typescript logo" width="50" height="50" style="border:none;" />
</a>
<a href="http://reactivex.io/rxjs">
<img src="http://reactivex.io/assets/Rx_Logo_S.png"
align="right" alt="ReactiveX logo" width="50" height="50" style="border:none;" />
</a>
<a href="http://hapijs.com">
<img src="http://bit.ly/2lYPYPw"
align="right" alt="Hapijs logo" width="75" style="border:none;" />
</a>
Mongo Module
Mongo
module for the Hapiness framework including mongoose
, mongoose-gridfs
(deprecated) and mongoose-gridfs-bucket
adapter one.Table of contents
* [`yarn` or `npm` it in your `package.json`](#yarn-or-npm-it-in-your-package)
* [Importing `MongoModule` from the library](#importing-mongomodule-from-the-library)
* [Step 1](step-1)
* [Step 2](step-2)
* [Step 3](step-3)
- Registering adapters
- Using a registered adapter
- Configuration
- Get your adapter anywhere
- Model management
- Helpers functions
- Contributing
- Change History
- Maintainers
- License
Using your module inside Hapiness application
yarn
or npm
it in your package.json
$ npm install --save @hapiness/core @hapiness/mongo rxjs
or
$ yarn add @hapiness/core @hapiness/mongo rxjs
"dependencies": {
"@hapiness/core": "^1.3.0",
"@hapiness/mongo": "^1.1.3",
"rxjs": "^5.5.6",
//...
}
//...
Importing MongoModule
from the library
This module provide an Hapiness extension for Mongo. To use it, simply register it during the bootstrap
step of your project like that:import { MongoModule, MongoClientExt } from '@hapiness/mongo';
@HapinessModule({
version: '1.0.0',
providers: [ ],
declarations: [ ],
imports: [ MongoModule ]
})
class MyModule implements OnStart {
constructor() { /* ... */ }
}
Hapiness.bootstrap(MyModule, [ MongoClientExt.setConfig(/* ... */) ]);
Back to top
Creating Adapters
The Mongo
module is based on adapters. Included to the module, there is an adapter using mongoose and one using mongoose to manage gridfs.But you can create your own adapters if you want by following some required steps described belows.
Step 1
Your adapter should be a class which inherits fromAbstractHapinessMongoAdapter
.Step 2
You absolutely need to implement a static functiongetInterfaceName
, which will return a uniq string identifier for your adapter (NOTE mongoose
, mongoose-gridfs
and mongoose-gridfs-bucket
are already used by adapters provided by this module).Step 3
You need to override 4 functions_tryConnect(): Observable<void> { /* ... */ }
_afterConnect(): Observable<void> { /* ... */ }
getLibrary(): any { /* ... */ }
registerValue(): any { /* ... */ }
tryConnect: you will create your database connection inside
Example for mongoose
protected _tryConnect(): Observable<void> {
return Observable
.create(observer => {
this._isReady = false;
if (this._db) {
this._db.close();
}
const connectOptions = {
server: {
reconnectTries: Number.MAX_VALUE,
reconnectInterval: 5000,
},
};
this._connection = mongoose.createConnection(this._uri, connectOptions);
this._connection.once('connected', () => {
observer.next();
observer.complete();
});
this._connection.once('error', err => {
observer.error(err);
});
});
}
afterConnect: this function will be called just after
_tryConnect
if you want to manage some stuff once your connection is fine.Example for mongoose:
protected _afterConnect(): Observable<void> {
return Observable
.create(observer => {
this._db = this._connection.db;
this.onConnected().subscribe(_ => {
/* ... */
}, (e) => {
/* ... */
});
this._connection.once('error', err =>
this.onError(err).subscribe(_ => {
/* ... */
}, (e) => {
/* ... */
})
);
this._connection.once('disconnected', () =>
this.onDisconnected().subscribe(_ => {
/* ... */
}, (e) => {
/* ... */
})
);
observer.next();
observer.complete();
});
}
getLibrary: this will just return the library your adapter use to use it as you want.
Example for mongoose:
public getLibrary(): any {
return mongoose;
}
registerValue: this will register your document and return a model value to get through the DI.
Example for mongoose:
public registerValue(document, collection): any {
return this._connection.model(collection, document);
}
NOTE DONT FORGET TO SET
_isReady = true
once you are done, else your adapter will never be ready.You should also override:
close(): Observalbe<void> { /* */ }
Back to top
Registering adapters
When you want to create your own adapters, first you need to tell the Mongo extension to register it. The Mongo extension will add your classes and map it with the uniq identifier you put inside the staticddd
.class MyCustomAdapter extends AbstractHapinessMongoAdapter {
public static getInterfaceName(): string {
return 'custom-identifier-for-my-adapter';
}
constructor(options) { super(options); }
/* ... */
}
Hapiness.bootstrap(
MyModule,
[
MongoClientExt
.setConfig(
{
register: [ MyCustomAdapter ]
}
)
]
);
Now, the mongo extension knows that an Adapter with the identifier
custom-identifier-for-my-adapter
exists.The two provided adapters don't need to be registered as it is already done.
Using a registered adapter
It will work the same for both custom adapters you made and provided adapters.Just load them with the config you want to use:
class MyCustomAdapter extends AbstractHapinessMongoAdapter {
public static getInterfaceName(): string {
return 'custom-identifier-for-my-adapter';
}
constructor(options) { super(options); }
}
Hapiness.bootstrap(
MyModule,
[
MongoClientExt
.setConfig(
{
register: [ MyCustomAdapter ]
load: [
{
name: 'custom-identifier-for-my-adapter',
config: {
host: 'my.hostname1.com',
port: 27017,
db: 'db_1'
}
},
{
name: 'mongoose',
config: {
host: 'my.hostname2.com',
port: 27017,
db: 'db_1'
}
}
]
}
)
]
);
So you can load as many connections as you want and provide custom configs for each adapter you load.
Back to top
Configuration
When you load adapters (see previous section), you can provide a config, but you have the possibility to not provide one every time.Lets say you want two adapters pointing to the same database, you can for that use the
common
option.class MyCustomAdapter extends AbstractHapinessMongoAdapter {
public static getInterfaceName(): string {
return 'custom-identifier-for-my-adapter';
}
constructor(options) { super(options); }
}
Hapiness.bootstrap(
MyModule,
[
MongoClientExt
.setConfig(
{
register: [ MyCustomAdapter ]
common: {
host: 'my.hostname.com',
port: 27017,
db: 'my_db'
}
load: [
{
name: 'custom-identifier-for-my-adapter'
},
{
name: 'mongoose'
}
]
}
)
]
);
Back to top
Get your adapter anywhere
To get your adapter and play with it, you need to inject the MongoClientService in your class and call theget()
function to get an instance of the adapter manager.Once you did it, you'll be able to get your adapter with its name only or with its name and options (if you have the same adapter in different DBs or host ...) calling the function
getAdapter(...)
.Example showing how to get mongoose adapter for
my_database
:@Injectable()
class MyModelDocument {
private _myModelConnection: any;
constructor(
private _mongoClient: MongoClientService
) {
this._myModelConnection = null;
}
init() {
// You can do that...
const dao = this._mongoClient.get().getAdapter('mongoose').getLibrary();
// ... or that
const connection = this._mongoClient.get().getAdapter('mongoose', { db: 'my_database' }).getConnection();
const MyModel = dao.Schema({
username: String,
});
this._myModelConnection = connection.model('MyModel', MyModel);
}
get() {
return this._myModelConnection;
}
}
Back to top
Model Management
You can implement and register models in the adapterExample:
@MongoModel({
adapter: 'mongoose',
collection: 'collection', // The name of the collection, will be pluralize using mongoose if no collectionName is explicitly given
collectionName: 'collectionName', // Optional, will force this name as the collection name
options: { ... } // @see HapinessMongoAdapterConstructorArgs type
})
class MyModel extends Model {
readonly schema;
constructor(private mongoClientService: MongoClientService) {
super(MyModel) // /!\ Important to get connection options
const DAO = mongoClientService.getDao(this.connectionOptions);
this.schema = new DAO.Schema({
id: String
});
...
}
}
@Route({
path: '/my-route',
method: 'get'
})
class MyRoute implements OnGet {
constructor(private mongoClientService: MongoClientService) {}
onGet(request, reply) {
const model = this.mongoClientService.getModel({ adapter: 'mongoose', options: {} }, MyModel);
...
}
}
@HapinessModule({
version: '1.0.0',
declarations: [ MyModel, MyRoute ]
})
class MyModule {}
Back to top
Helpers functions
The module gives you an helpers to perform some basic mongo-related operations.Just import the class from the module
import { MongoUtils } from '@hapiness/mongo'
There is 4 static functions (for now)
public static prepareUpdateObject(dto: any): any
: Give to this function an object like { "meta": { "key": "value" } }
and it returns you the object { "meta.key": "value" }
. Very usefull to perform update operations!public static toObjectId(id: string)
: Returns an ObjectID type from the given string (null
if the string is not a valid ObjectID)public static fieldsStringFromArray(fields: string[]): string
: If you want to select only some fields and you need for that to compute a string from an array of string, use this functionpublic static filterFindCondition(condition: any): any
: If you have a query object for mongo, this function will parse your condition, convert the field id
into _id
and then convert _id
to an ObjectID
before giving back the query objectBack to top
Contributing
To set up your development environment:- clone the repo to your workspace,
- in the shell
cd
to the main folder, - hit
npm or yarn install
, - run
npm or yarn run test
.
* It will lint the code and execute all tests.
* The test coverage report can be viewed from `./coverage/lcov-report/index.html`.
Back to topChange History
- v2.1.0
* Now set by default `useNewUrlParser: true`, `useCreateIndex: true` and `useFindAndModify: false` on the connectionOptions of mongoose.
- v2.0.2
* More debug and events for mongoose adapter
- v2.0.1
* Fix Mongo Utils - prepareUpdateObject
- v2.0.0
* Updated mongoose to latest version
* Removed the call to createConnection from the constructor of mongo adapter.
* Now catch connection errors and pipe them out to be catch by user later on. No more waiting for timeout to realize there is a connection error.
* MongooseGridfsAdapter is now deprecated. Use MongooseGridfsBucketAdapter
- v1.2.0 (2018-04-05)
* Updated packages' versions.
* added support of `OnShutdown` of `hapiness Core`
* added `close` functions to adapters.
* Fix typos in documentation.
- v1.1.3 (2018-01-16)
* Fix get adapter using adapter name
- v1.1.2 (2018-01-09)
* Latest packages' versions.
* Added connectionName options to identify an adapter by an alias
* Bug fix on an `indexOf !== 1` instead of `indexOf !== -1`
* Documentation.
- v1.1.1 (2017-12-12)
* Latest packages' versions.
* Add field `collectionName` to force using a specific name for a collection.
* Fix key computation when retrieving an adapter.
* Allow developers to not give all options for the adapter when getting a document.
* Documentation.
- v1.1.0 (2017-11-20)
* Latest packages' versions.
* Update Module + Tests related to latest `core` version.
* Documentation.
* Change packaging process.
- v1.0.0 (2017-11-14)
* `MongoDB` module implementation.
* Tests module API.
* Documentation.
Back to topMaintainers
Back to top
License
Copyright (c) 2017 Hapiness Licensed under the MIT license.Back to top