auto-increment-group
Version:
plugin mongoose auto increment
145 lines (137 loc) • 5.09 kB
JavaScript
const isDefined = (obj) => {
return obj !== undefined && obj !== null;
};
const getLastCount = async (model, opts, groupByField = {}, session) => {
const initCount = opts.startAt - opts.incrementBy;
const query = {};
if (opts?.groupBy) {
Object.assign(query, groupByField);
}
const last = await model.findOne(query).select(`${opts.field}`).sort({ _id: -1 }).session(session);
if (!last) {
return initCount;
}
return Number(last[opts.field] || initCount);
};
const resetCount = async (model, opts, groupByField = {}, session) => {
const query = {};
if (opts?.groupBy) {
Object.assign(query, groupByField);
}
const set = {};
set[opts.field] = `${opts.startAt}`.padStart(opts.digits, '0');
return model.findOneAndUpdate(query, {
$set: set
}, {
session,
returnDocument: 'after',
sort: { _id: -1 }
});
};
const manageField = (schema, opts) => {
const dataField = schema.path(opts.field);
if (dataField) {
if (!(dataField.instance === 'String')) {
throw Error('Field must be type of string');
}
} else {
const field = {};
field[opts.field] = {
type: String
};
schema.add(field);
}
};
const autoInc = (schema, pluginOpts = {}) => {
const opts = {
field: 'id',
digits: 5,
startAt: 0,
incrementBy: 1,
unique: false
};
Object.assign(opts, pluginOpts);
manageField(schema, opts);
if (opts.unique) {
const index = {};
index[opts.field] = 1;
if (opts?.groupBy) {
if (Array.isArray(opts.groupBy)) {
// eslint-disable-next-line no-return-assign
opts.groupBy.forEach((g) => index[g] = 1);
} else {
index[opts.groupBy] = 1;
}
}
schema.index(index, { unique: true, index: -1 });
}
schema.pre('save', async function (next) {
if (this.isNew) {
const groupByField = {};
if (opts?.groupBy) {
if (Array.isArray(opts.groupBy)) {
for (const groupByElement of opts.groupBy) {
if (!isDefined(this[groupByElement])) {
return next(Error(`${groupByElement} must be filled on before save`));
}
groupByField[groupByElement] = this[groupByElement];
}
} else {
if (!isDefined(this[opts.groupBy])) {
return next(Error('groupBy field must be filled on before save'));
}
groupByField[opts.groupBy] = this[opts.groupBy];
}
}
const count = await getLastCount(this.constructor, opts, groupByField, this.$session());
this[opts.field] = `${count + opts.incrementBy}`.padStart(opts.digits, '0');
}
return next();
});
schema.method('nextCount', async function () {
const groupByField = {};
if (opts?.groupBy) {
if (Array.isArray(opts.groupBy)) {
for (const groupByElement of opts.groupBy) {
if (!isDefined(this[groupByElement])) {
throw Error(`${groupByElement} must be filled on before save`)
}
groupByField[groupByElement] = this[groupByElement];
}
} else {
if (!isDefined(this[opts.groupBy])) {
throw Error('groupBy field must be filled');
}
groupByField[opts.groupBy] = this[opts.groupBy];
}
}
const count = await getLastCount(this.constructor, opts, groupByField, this.$session());
return `${count + opts.incrementBy}`.padStart(opts.digits, '0');
});
schema.static('nextCount', async function (groupByFieldNext, session) {
const groupByField = {};
if (opts?.groupBy) {
if (typeof groupByFieldNext === 'string') {
groupByField[opts.groupBy] = groupByFieldNext;
} else if (typeof groupByFieldNext === 'object' && groupByFieldNext !== null) {
Object.assign(groupByField, groupByFieldNext);
}
}
const count = await getLastCount(this, opts, groupByField, session);
return `${count + opts.incrementBy}`.padStart(opts.digits, '0');
});
schema.static('resetCount', async function (groupByFieldNext, session) {
const groupByField = {};
if (opts?.groupBy) {
if (typeof groupByFieldNext === 'string') {
groupByField[opts.groupBy] = groupByFieldNext;
} else if (typeof groupByFieldNext === 'object' && groupByFieldNext !== null) {
Object.assign(groupByField, groupByFieldNext);
}
}
return resetCount(this, opts, groupByField, session);
});
};
module.exports = {
autoInc
};