Skip to content

Commit

Permalink
Merge pull request #2 from mernxl/dev-mern
Browse files Browse the repository at this point in the history
feat: optimise and test code for various versions of MongoDB i.e. v3.4, v3.6, v4.0, v4.2
  • Loading branch information
mernxl authored Dec 5, 2019
2 parents c4c9f86 + caa1b0a commit 215de33
Show file tree
Hide file tree
Showing 21 changed files with 3,192 additions and 2,174 deletions.
3 changes: 2 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"singleQuote": true,
"trailingComma": "all",
"bracketSpacing": true,
"parser": "typescript"
"parser": "typescript",
"printWidth": 100
}
8 changes: 5 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
sudo: false
dist: xenial
language: node_js
cache:
yarn: true
directories:
- node_modules
- $HOME/.mongodb-binaries
- $HOME/.cache
notifications:
email: true
node_js:
- "9"
- "12"
- "10"
- "8"
env:
global:
- TEST_SITE=travis-ci
script:
- yarn run test
- yarn run test-ci
- yarn run build
after_success:
- 'curl -Lo travis_after_all.py https://git.io/travis_after_all'
Expand Down
219 changes: 120 additions & 99 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ This is the perfect tool if you wish to work with `discriminators` and have `_id
# Table of Content
- [Installation](#installation)
- [Basic Usage](#basic-usage)
- [Plugin Options](#plugin-options)
- [Point to Note](#point-to-note)
- [AssignerPluginOptions](#assignerpluginoptions)
- [Point to Note](#points-to-note)
- [Examples](#examples)
- [Configuration Methods](#configuration-methods)
- [Working with Discriminators](#working-with-discriminators)
- [Strain Test](#strain-test)
- [TypeDefinitions](#typedefinitions)
- [Strain Test](#strain-test,-performs-the-task-below-on-a-locally-hosted-db-instance.)
- [Contributions](#contributions)
- [NextIdFunctions](#nextidfunctions-(incrementer))
- [NextIdFunctions](#nextidfunctions-incrementer)
- [License](#license)

## Installation
Expand All @@ -45,15 +45,33 @@ yarn add uuid
```

## Basic Usage
### Plugin Options
TypeName: **AssignerPluginOptions**
- `modelName`: **String** Name of the Model your are working with. If discriminators, then provide baseModel Name.
- `fields`: **AssignerFieldsConfigMap?** The configuration Map of the fields you want the assigner to assign ids to.
If undefined, then plugin assigns ids to `_id` field, (ObjectId).
- [fieldName: string]: FieldConfig | string | number | boolean | 'GUID' | 'UUID'
- `discriminators`: **[discriminatorName: string]: AssignerFieldsConfigMap?** An Object with Keys `discriminatorName`
and value a Configuration Map for fields on that discriminator that need unique values. Any discriminator without a
fieldConfig will use that of the baseModel.
You could create the plugin from the `MongooseIdAssigner` Constructor, which returns a instance which you could use to query `nextIds`.
#### `from constructor(schema: Schema, options: AssignerPluginOptions): MongooseIdAssigner`
```js
...
const ExampleIA = new MongooseIdAssigner(exampleSchema, options);
exampleModel = mongoose.model('Example', exampleSchema);

// always call the initialise, to ensure assigner initialised before calling getNextId
// assigners are always auto initialised on every first save
await ExampleIA.initialise(exampleModel);
await ExampleIA.getNextId('fieldName'); // nextId
...
```

Alternatively you have the plugin setup by calling the static `plugin` method.
#### `static plugin(schema: Schema, options: AssignerPluginOptions): MongooseIdAssigner`
```js
...
exampleSchema.plugin(MongooseIdAssigner.plugin, options);
...
```
### AssignerPluginOptions
| Parameter | Type | Description |
|----------------|:------------------------------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|
| modelName | String(Required) | Name of the Model your are working with. If discriminators, then provide baseModel Name. |
| fields | [AssignerFieldsConfigMap](#typedefinitions) (Optional) | The configuration Map of the fields you want the assigner to assign ids to. If undefined, then plugin assigns ids to `_id` field, (ObjectId). |
| discriminators | [DiscriminatorConfigMap](#typedefinitions) (Optional) | An Object with key being a `discriminatorName` and value a Configuration Map for fields on that discriminator that need unique values. Any discriminator without a fieldConfig will use that of the baseModelk |

### Points to Note
- At every Network Assigner init(i.e Assigner with Number, String FieldConfigTypes), the Assigner(for a Model) refreshes and syncs with the db stored options. Take example micro-service cluster,
Expand Down Expand Up @@ -232,6 +250,95 @@ console.log(droid1.make) ---> '18Y4434'
It may arise that you need to query and use the nextId to at the front-end. In this case, you just need to
get an instance of the Assigner, then use the `getNextId` method. It is async method as it queries for `Number` and `String` cases.
### Strain test
* Performs the task below on a locally hosted db instance.
* On CI/CD environment, tests ran using [mongodb-memory-server](https://github.com/nodkz/mongodb-memory-server), on v3.4, v3.6, v4.0 and v4.2 on node v12, v10, v8
```typescript
// using ts :)
import * as mongoose from 'mongoose';
import { AssignerOptions, FieldConfigTypes, localStateStore, MongooseIdAssigner } from './src';

describe('MongooseIdAssigner', () => {

it('should be robust enough to avoid duplicates', async () => {
const options: AssignerPluginOptions = {
modelName: 'example8',
fields: {
_id: '33333',
photoId: 44444,
emailId: '55555',
personId: {
type: FieldConfigTypes.String,
nextId: 'SPEC-7382-4344-3232',
separator: '-',
},
uuidFieldString: {
type: FieldConfigTypes.UUID,
},
uuidFieldBuffer: {
type: FieldConfigTypes.UUID,
version: 1,
asBinary: true,
},
objectIdField: FieldConfigTypes.ObjectId,
},
};

try {
const ExampleIA = new MongooseIdAssigner(exampleSchema, options);

exampleModel = mongoose.model('example8', exampleSchema);
expect(ExampleIA.readyState).toBe(0); // initialising

// initialise to ensure that
// model is set and db is connected
// before performing heavy tasks
// or you can set max event listeners to 100 to suppress warnings on waits
await ExampleIA.initialise(exampleModel);

expect(ExampleIA.readyState).toBe(1);

const promises = [];
for (let i = 0; i < 100; i++) {
promises.push(exampleModel.create({ personId: 'mernxl' }));
}

const docs: any[] = await Promise.all(promises);
for (let i = 0; i < 100; i++) {
const _id = docs[i]._id;
const photoId = docs[i].photoId;
const emailId = docs[i].emailId;
const personId = docs[i].personId;
const uuidFieldString = docs[i].uuidFieldString;
const uuidFieldBuffer = docs[i].uuidFieldBuffer;
const objectIdField = docs[i].objectIdField;
expect(typeof photoId).toBe('number');
expect(typeof emailId).toBe('string');
expect(personId).toMatch(/(SPEC-7382-4344-3)\d+/);
expect(objectIdField).toBeInstanceOf(Types.ObjectId);
expect(typeof uuidFieldString).toBe('string');
expect(uuidFieldBuffer).toBeInstanceOf(Binary);

for (const cDoc of docs) {
if (_id === cDoc._id) {
continue;
}
expect(photoId).not.toBe(cDoc.photoId);
expect(emailId).not.toBe(cDoc.emailId);
expect(personId).not.toBe(cDoc.personId);
expect(objectIdField).not.toBe(cDoc.objectIdField);
expect(uuidFieldString).not.toEqual(cDoc.uuidFieldString);
expect(uuidFieldBuffer).not.toEqual(cDoc.uuidFieldBuffer);
}
}
} catch (e) {
expect(e).toBeUndefined();
}
});
});
```
## TypeDefinitions
```typescript
/**
Expand Down Expand Up @@ -327,92 +434,6 @@ export interface UUIDFieldConfig {
}
```
### Strain test, Performs the task below on a locally hosted db instance.
```typescript
// using ts :)
import * as mongoose from 'mongoose';
import { AssignerOptions, FieldConfigTypes, localStateStore, MongooseIdAssigner } from './src';

describe('MongooseIdAssigner', () => {

it('should be robust enough to avoid duplicates', async () => {
const options: AssignerPluginOptions = {
modelName: 'example8',
fields: {
_id: '33333',
photoId: 44444,
emailId: '55555',
personId: {
type: FieldConfigTypes.String,
nextId: 'SPEC-7382-4344-3232',
separator: '-',
},
uuidFieldString: {
type: FieldConfigTypes.UUID,
},
uuidFieldBuffer: {
type: FieldConfigTypes.UUID,
version: 1,
asBinary: true,
},
objectIdField: FieldConfigTypes.ObjectId,
},
};

try {
const ExampleIA = new MongooseIdAssigner(exampleSchema, options);

exampleModel = mongoose.model('example8', exampleSchema);
expect(ExampleIA.readyState).toBe(0); // initialising

// initialise to ensure that
// model is set and db is connected
// before performing heavy tasks
// or you can set max event listeners to 100 to suppress warnings on waits
await ExampleIA.initialise(exampleModel);

expect(ExampleIA.readyState).toBe(1);

const promises = [];
for (let i = 0; i < 100; i++) {
promises.push(exampleModel.create({ personId: 'mernxl' }));
}

const docs: any[] = await Promise.all(promises);
for (let i = 0; i < 100; i++) {
const _id = docs[i]._id;
const photoId = docs[i].photoId;
const emailId = docs[i].emailId;
const personId = docs[i].personId;
const uuidFieldString = docs[i].uuidFieldString;
const uuidFieldBuffer = docs[i].uuidFieldBuffer;
const objectIdField = docs[i].objectIdField;
expect(typeof photoId).toBe('number');
expect(typeof emailId).toBe('string');
expect(personId).toMatch(/(SPEC-7382-4344-3)\d+/);
expect(objectIdField).toBeInstanceOf(Types.ObjectId);
expect(typeof uuidFieldString).toBe('string');
expect(uuidFieldBuffer).toBeInstanceOf(Binary);

for (const cDoc of docs) {
if (_id === cDoc._id) {
continue;
}
expect(photoId).not.toBe(cDoc.photoId);
expect(emailId).not.toBe(cDoc.emailId);
expect(personId).not.toBe(cDoc.personId);
expect(objectIdField).not.toBe(cDoc.objectIdField);
expect(uuidFieldString).not.toEqual(cDoc.uuidFieldString);
expect(uuidFieldBuffer).not.toEqual(cDoc.uuidFieldBuffer);
}
}
} catch (e) {
expect(e).toBeUndefined();
}
});
});
```
## CONTRIBUTIONS
If you find a bug, do well to create an [issue](https://github.com/mernxl/mongoose-id-assigner/issues) so we fix things up in a flash.
Have an awesome new feature to add to library, feel free to open a [PR](https://github.com/mernxl/mongoose-id-assigner/pulls)
Expand Down
34 changes: 17 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,11 @@
"flow": "./node_modules/.bin/flow",
"lint": "tslint -p ./",
"jest:watch": "IN_MEM=true jest --watch",
"coverage": "IN_MEM=true jest --coverage --maxWorkers 2",
"jest": "jest --maxWorkers 2",
"coverage": "jest --coverage --maxWorkers 2",
"test-mongo-vers": "export MONGOMS_DOWNLOAD_MIRROR=\"http://downloads.mongodb.org\" && IN_MEM=true MONGOMS_VERSION=v3.4-latest yarn run jest && IN_MEM=true MONGOMS_VERSION=v3.6-latest yarn run jest && IN_MEM=true MONGOMS_VERSION=v4.0-latest yarn run jest && IN_MEM=true MONGOMS_VERSION=v4.2-latest yarn run coverage",
"test": "yarn run lint && yarn run coverage && yarn run tsc && yarn run flow",
"test-ci": "yarn run lint && yarn run test-mongo-vers && yarn run tsc && yarn run flow",
"clean": "rimraf lib",
"prettier": "yarn run prettier-ts && yarn run prettier-flow",
"prettier-ts": "prettier --write --config .prettierrc \"src/**/*.ts\"",
Expand Down Expand Up @@ -64,24 +67,21 @@
},
"devDependencies": {
"@types/event-to-promise": "^0.7.0",
"@types/jest": "^23.3.0",
"@types/mongodb-memory-server": "^1.8.0",
"@types/mongoose": "^5.5.0",
"@types/jest": "^24.0.23",
"@types/mongoose": "^5.5.32",
"@types/uuid": "^3.4.3",
"babel-core": "^6.26.3",
"babel-jest": "^23.4.2",
"flow-bin": "^0.77.0",
"jest": "^23.4.1",
"mongodb-memory-server": "^1.9.0",
"mongoose": "^5.5.7",
"prettier": "^1.13.7",
"flow-bin": "^0.113.0",
"jest": "^24.9.0",
"mongodb-memory-server-global": "^6.0.2",
"mongoose": "^5.7.13",
"prettier": "^1.19.1",
"rimraf": "^2.6.2",
"semantic-release": "^15.8.1",
"ts-jest": "^23.0.1",
"tslint": "^5.11.0",
"tslint-config-prettier": "^1.14.0",
"tslint-plugin-prettier": "^1.3.0",
"typescript": "^3.0.1",
"semantic-release": "^15.13.31",
"ts-jest": "^24.2.0",
"tslint": "^5.20.1",
"tslint-config-prettier": "^1.18.0",
"tslint-plugin-prettier": "^2.0.1",
"typescript": "^3.7.3",
"uuid": ">=3.0.1"
}
}
Loading

0 comments on commit 215de33

Please sign in to comment.