-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
619 additions
and
0 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 |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/** | ||
* Check if something looks like options | ||
* @param {MongoTenantOptions} options | ||
* @returns {boolean} | ||
*/ | ||
const isPluginOptions = (options) => ( | ||
options && | ||
options.accessorMethod && | ||
options.tenantIdKey && | ||
true | ||
); | ||
/** | ||
* Checks if instance is compatible to other plugin instance | ||
* | ||
* For population of referenced models it's necessary to detect if the tenant | ||
* plugin installed in these models is compatible to the plugin of the host | ||
* model. If they are compatible they are one the same "level". | ||
* | ||
* @param {MongoTenantOptions} a | ||
* @param {MongoTenantOptions} b | ||
* @returns {boolean} | ||
*/ | ||
module.exports = (a, b) => { | ||
return ( | ||
isPluginOptions(a) && | ||
isPluginOptions(b) && | ||
a.tenantIdKey === b.tenantIdKey | ||
); | ||
}; |
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,27 @@ | ||
const arePluginsCompatible = require('./are-plugins-compatible'); | ||
|
||
describe('are-plugins-compatible', () => { | ||
describe('when called with proper plugin options', () => { | ||
const options = { | ||
accessorMethod: 'byTenant', | ||
tenantIdKey: 'tenantId', | ||
}; | ||
|
||
it('returns true if they have equal tenantIdKey\'s', () => { | ||
const a = {...options}; | ||
const b = {...options}; | ||
const result = arePluginsCompatible(a, b); | ||
expect(result).toBe(true); | ||
}); | ||
|
||
it('returns false if they have different tenantIdKey\'s', () => { | ||
const a = {...options}; | ||
const b = { | ||
...options, | ||
tenantIdKey: 'dimensionId', | ||
}; | ||
const result = arePluginsCompatible(a, b); | ||
expect(result).toBe(false,); | ||
}); | ||
}); | ||
}); |
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,27 @@ | ||
const buildModelCache = require('./tenant-aware-model-cache'); | ||
const createTenantAwareModel = require('./tenant-aware-model'); | ||
|
||
/** | ||
* @param schema | ||
* @param {MongoTenantOptions} options | ||
*/ | ||
module.exports = ({schema, options}) => { | ||
const {accessorMethod} = options; | ||
const cache = buildModelCache(); | ||
|
||
Object.assign(schema.statics, { | ||
[accessorMethod]: function (tenantId) { | ||
if (!cache.has(this.modelName, tenantId)) { | ||
const base = this.model(this.modelName); | ||
const model = createTenantAwareModel({base, tenantId}); | ||
cache.set(this.modelName, tenantId, model); | ||
} | ||
return cache.get(this.modelName, tenantId); | ||
}, | ||
get mongoTenant() { | ||
return {...options}; | ||
} | ||
}); | ||
|
||
return this; | ||
}; |
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,25 @@ | ||
const arePluginsCompatible = require('./are-plugins-compatible'); | ||
|
||
/** | ||
* Create db connection bound to a specific tenant | ||
* | ||
* @param {Connection} db | ||
* @param {*} tenantId | ||
* @param {MongoTenantOptions} options | ||
* @returns {Connection} | ||
*/ | ||
module.exports = ({db, tenantId, options}) => { | ||
const awareDb = Object.create(db); | ||
awareDb.model = (name) => { | ||
const unawareModel = db.model(name); | ||
/** @type MongoTenantOptions */ | ||
const otherPluginOptions = unawareModel.mongoTenant; | ||
|
||
if (!arePluginsCompatible(options, otherPluginOptions)) { | ||
return unawareModel; | ||
} | ||
|
||
return unawareModel[otherPluginOptions.accessorMethod](tenantId); | ||
}; | ||
return awareDb; | ||
}; |
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,57 @@ | ||
const createTenantAwareDb = require('./tenant-aware-db'); | ||
const buildOptions = require('../options'); | ||
|
||
describe('tenant-aware-db', () => { | ||
describe('when called with proper parameters', () => { | ||
const tenantId = '23'; | ||
const options = buildOptions(); | ||
|
||
it('overwrites the model method', () => { | ||
const db = { | ||
model: () => {}, | ||
}; | ||
const result = createTenantAwareDb({db, tenantId, options}); | ||
expect(result).toHaveProperty('model'); | ||
expect(result.model).toBeInstanceOf(Function); | ||
expect(result.model).not.toBe(db.model); | ||
}); | ||
|
||
it('returns a tenant aware model if compatible', () => { | ||
const awareModel = { | ||
hasTenantContext: true, | ||
mongoTenant: {...options}, | ||
}; | ||
const unawareModel = { | ||
[options.accessorMethod]: () => awareModel, | ||
mongoTenant: {...options}, | ||
}; | ||
const db = { | ||
model: () => unawareModel, | ||
}; | ||
|
||
const awareDb = createTenantAwareDb({db, tenantId, options}); | ||
const result = awareDb.model('test'); | ||
|
||
expect(result).toBe(awareModel); | ||
}); | ||
|
||
it('returns a tenant unaware model if not compatible', () => { | ||
const unawareModel = { | ||
[options.accessorMethod]: () => { throw new Error; }, | ||
mongoTenant: { | ||
...options, | ||
tenantIdKey: 'dimension', | ||
}, | ||
}; | ||
const db = { | ||
model: () => unawareModel, | ||
}; | ||
|
||
const awareDb = createTenantAwareDb({db, tenantId, options}); | ||
const result = awareDb.model('test'); | ||
|
||
expect(result).toBe(unawareModel); | ||
}); | ||
}); | ||
}); | ||
|
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,13 @@ | ||
module.exports = () => { | ||
const cache = {}; | ||
return { | ||
has: (name, id) => (cache[name] && cache[name][id] && true || false), | ||
get: (name, id) => (cache[name] && cache[name][id]), | ||
set: (name, id, value) => { | ||
cache[name] = { | ||
...(cache[name] || {}), | ||
[id]: value, | ||
}; | ||
} | ||
}; | ||
}; |
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,44 @@ | ||
const buildTenantAwareModelCache = require('./tenant-aware-model-cache'); | ||
|
||
describe('tenant-aware-model-cache', () => { | ||
describe('builds a cache that', () => { | ||
it('returns a cached model', () => { | ||
const model = {}; | ||
const cache = buildTenantAwareModelCache(); | ||
|
||
cache.set('test', '23', model); | ||
const result = cache.get('test', '23'); | ||
|
||
expect(result).toBe(model); | ||
}); | ||
|
||
it('reports a stored model as cached', () => { | ||
const model = {}; | ||
const cache = buildTenantAwareModelCache(); | ||
|
||
cache.set('test', '23', model); | ||
const result = cache.has('test', '23'); | ||
|
||
expect(result).toBe(true); | ||
}); | ||
|
||
it('reports a unknown model as not cached', () => { | ||
const cache = buildTenantAwareModelCache(); | ||
|
||
const result = cache.has('test', '23'); | ||
|
||
expect(result).toBe(false); | ||
}); | ||
|
||
it('reports a unknown tenant as not cached', () => { | ||
const model = {}; | ||
const cache = buildTenantAwareModelCache(); | ||
|
||
cache.set('test', '23', model); | ||
const result = cache.has('test', '42'); | ||
|
||
expect(result).toBe(false); | ||
}); | ||
}); | ||
}); | ||
|
Oops, something went wrong.