const Model = require('flitter-orm/src/model/Model'); const uuid = require('uuid/v4'); class VersionedModel extends Model { static get schema() { return { version_archive: [Object], version_num: { type: Number, default: 1 }, version_create_date: { type: Date, default: () => new Date }, version_user_id: String, } } __is_version_instantation = false __version_base = undefined __version_data = undefined is_a_version() { return this.__is_version_instantation } version_base() { return this.__version_base } raw_version_data() { return this.__version_data } __initialize_version(base, data = {}) { this.__is_version_instantation = true this.__version_base = base this.__version_data = data } async version_save(message = undefined, user_id = undefined) { await this.new_version(message, user_id) return this.save() } async new_version(message = undefined, user_id = undefined) { if ( !this.version_num ) this.version_num = 1 if ( !this.version_archive ) this.version_archive = [] this.version_num += 1 this.version_create_date = new Date() this.version_user_id = user_id const version_data = await this.cast_to_version_data() version_data.version_UUID = uuid() version_data.version_message = message this.version_archive.push(version_data) } async cast_to_version_data() { const schema = this.constructor.__schema const shallow_object = {} for ( const prop in schema.schema ) { if ( prop in this ) { shallow_object[prop] = this[prop] } } const data = await this.__scope_limit_save(schema.cast_to_schema(shallow_object)) delete data.version_archive return data } async get_version_data(version_num = undefined) { if ( typeof version_num === 'undefined' ) { return await this.cast_to_version_data() } else { return this.version_archive.find(data => Number(data.version_num) === Number(version_num)) } } has_version(version_num = undefined) { return !!this.version_archive.find(data => { return Number(data.version_num) === Number(version_num) }) } toJSON() { const data = {...this} delete data.__version_data delete data.__version_base delete data.__is_version_instantation delete data.version_archive if ( this.is_a_version() ) { data.version_message = this.__version_data.version_message data.version_user_id = this.__version_data.version_user_id } return data } async as_version(version_num = undefined) { const data = await this.get_version_data(version_num) const inst = new this.constructor(data) inst.__initialize_version(this, data) return inst } async revert_to_version(version_num, user_id = undefined) { const inst = await this.as_version(version_num) inst.version_archive = this.version_archive inst._id = this._id inst.__is_version_instantation = false inst.__version_base = undefined inst.__version_data = undefined inst.version_num = this.version_num await inst.new_version(`Revert to version ${version_num}`, user_id) await inst.save() return inst } } module.exports = exports = VersionedModel