Created
September 13, 2019 07:44
-
-
Save jskod/b0c8fc162b71b0eb8f931cf9bef7ba48 to your computer and use it in GitHub Desktop.
Multi-Tenant Mongoose Model Wrapper For NodeJS Based Applications
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
import mongoose, { Schema } from 'mongoose' | |
import { getCurrentTenantId } from './storage' | |
/** | |
Function will return another function, which will further return a mongoose discriminator. | |
The only difference here is that everytime you use the mongoose model, you will have to call a function, | |
but it will give you a freedom of passing tenant-based data. | |
*/ | |
export function tenantModel(name, schema, options) { | |
return (props = {}) => { | |
// add new props to the schema | |
schema.add({ tenantId: String }) | |
// create a mongoose model | |
const Model = mongoose.model(name, schema, options) | |
const { skipTenant } = props | |
// getCurrentTenantId() is a function will returns current tenant | |
// this function uses continuation-local-storage npm package | |
const tenantId = getCurrentTenantId() | |
// if no tenant or you want to skip tenant specific descrimintor, return actual model | |
if (!tenantId || skipTenant) return Model | |
// set the descriminatorKey for the model | |
Model.schema.set('discriminatorKey', 'tenantId') | |
// set the descriminator name | |
const discriminatorName = name + '-' + tenantId | |
// check if a descriminator already exists | |
const existingDiscriminator = (Model.discriminators || {})[discriminatorName] | |
// if it does exist, simply return that. Otherwise create new | |
return existingDiscriminator || Model.discriminator(discriminatorName, new Schema({}), `${tenantId}`) | |
} | |
} | |
// this function will return simple model, | |
// so that you write the consistent code like calling the Model function to access the model | |
export function tenantlessModel(name, schema, options) { | |
return () => mongoose.model(name, schema, options) | |
} |
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
import { createNamespace } from 'continuation-local-storage'; | |
// define namespace name | |
const namespaceName = 'request'; | |
// create namespace instance | |
const ns = createNamespace(namespaceName); | |
// export function to bind current namespace to the req and res | |
export function bindCurrentNamespace(req, res, next) { | |
ns.bindEmitter(req); | |
ns.bindEmitter(res); | |
ns.run(() => { | |
next(); | |
}); | |
} | |
// export function to set tenantId for current request being processed | |
export function setCurrentTenantId(tenantId) { | |
return ns.set('tenantId', tenantId); | |
} | |
// export function to get previously set tenantId of request | |
export function getCurrentTenantId() { | |
return ns.get('tenantId'); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment