vuexorm-softdelete-plugin
Version:
Vuex ORM plugin adding soft delete capability. Based on an original idea from Conan Crawford.
219 lines (186 loc) • 6.98 kB
JavaScript
export const defaultOptions = {
key: 'deleted_at',
flagName: '$isDeleted',
debug: false,
exposeFlagsExternally: true,
mode: null // [hide, deleted, all]
}
export default {
install(components, installOptions) {
const pluginOptions = {
...defaultOptions,
...installOptions
}
const {
Model,
Query,
RootGetters,
Getters,
RootMutations,
RootActions,
Actions
} = components;
Query.prototype.softDeleteOptions = {
...pluginOptions
}
/**
* Flags are exposed by default when stringiying into JSON.
* This can be deactivated by setting the flag to false
*/
if (pluginOptions.exposeFlagsExternally) {
const localFieldModel = {
[pluginOptions.key]: Model.attr(false),
[pluginOptions.flagName]: Model.attr(false)
};
const _saveGetFiedsMethod = Model.prototype.$fields;
Model.prototype.$fields = function () {
const existing = _saveGetFiedsMethod.call(this);
return Object.assign({}, existing, localFieldModel);
}
}
/**
* Overwriting the $fill method used when calling
* new Model() to inject automatically the flag
* with default value to false and set value to the
* provided record if it exists
*/
// Save
const _saveFillMethod = Model.prototype.$fill;
// Overwrite
Model.prototype.$fill = function (record) {
_saveFillMethod.call(this, record); // Calling initial
this[pluginOptions.flagName] =
(record && record[pluginOptions.flagName]) || false;
this[pluginOptions.key] =
(record && record[pluginOptions.key]) || null;
};
/**
* We had a filter to every processed query to respond
* to the current softDeleteOptions.mode
*/
const softDeleteCallback = function (records, entity) {
const {
debug,
key,
mode,
flagName
} = this.softDeleteOptions
// if (debug || process.env.ENVIRONMENT === 'testing') {
// console.log(' ---------- PROCESS SOFT DELETE HOOK CALLED -------------- ')
// console.log(' > Mode: ', mode)
// console.log(' > Key: ', key)
// console.log(' > Flag: ', flagName)
// console.log(' > Records Count: ', records.length)
// console.log(' > Entity: ', entity)
// console.log(' > Options', this.softDeleteOptions)
// }
switch (mode) {
case 'deleted': // Show only soft-deleted data
this.softDeleteOptions.mode = null
return records.filter(r => !!r[flagName])
case 'all': // Show all (no filter)
this.softDeleteOptions.mode = null
return records
default: // "hide": only show non-soft-deleted data
return records.filter(r => !r[flagName])
}
}
Query.on('beforeSelect', softDeleteCallback)
Query.prototype.softDelete = function (condition) {
const {
key,
flagName
} = this.softDeleteOptions
const _date = new Date();
return this.model.update({
where: condition,
data: {
[key]: _date,
[flagName]: true
}
});
}
Model.softDelete = function (payload) {
this.dispatch('softDelete', payload);
}
Model.prototype.softDelete = async function (condition) {
if (condition) {
return this.$dispatch('softDelete', condition);
}
if (this.$id === null) {
return null;
}
return this.$dispatch('softDelete', this.$id);
}
RootMutations.softDelete = function (state, payload) {
const entity = payload.entity;
const result = payload.result;
const where = payload.where
result.data = (new Query(state, entity)).softDelete(where);
};
RootActions.softDelete = function (context, payload) {
const result = {
data: {}
};
context.commit('softDelete', {
...payload,
result
});
return result.data;
}
Actions.softDelete = function (context, payload) {
const state = context.state;
const entity = state.$name;
const where = typeof payload === 'object' ? payload.where : payload
return context.dispatch(`${state.$connection}/softDelete`, {
entity,
where
}, {
root: true
})
};
/**
* Providing addition Query modifiers:
* => withTrashed to include all data even soft-deleted ones
* => trashed => to include only trashed data
*/
Query.prototype.withTrashed = function () {
this.softDeleteOptions.mode = 'all'
return this
}
Query.prototype.trashed = function () {
this.softDeleteOptions.mode = 'deleted'
return this
}
/**
* Providing the allTrashed getter
* Returning only trashed data
*/
RootGetters.allTrashed = function (state) {
return function (entity) {
if (entity) {
return new Query(state, entity)
.trashed()
.get();
} else {
let result = [];
const allEntities = Model.database().entities;
allEntities.forEach(e => {
let elts = new Query(state, e.name)
.trashed()
.get();
result = result.concat(elts);
});
return result;
}
};
};
Getters.allTrashed = function (state, _getters, _rootState, rootGetters) {
return function () {
return rootGetters[`${state.$connection}/allTrashed`](
state.$name
);
};
};
}
}