forked from bonaval/sequelize-temporal
-
-
Notifications
You must be signed in to change notification settings - Fork 5
/
index.js
113 lines (96 loc) · 3.74 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
var _ = require('lodash');
var temporalDefaultOptions = {
// runs the insert within the sequelize hook chain, disable
// for increased performance
blocking: true,
full: false
};
var excludeAttributes = function(obj, attrsToExclude){
// fancy way to exclude attributes
return _.omit(obj, attrsToExclude);
}
var Temporal = function(model, sequelize, temporalOptions){
temporalOptions = _.extend({},temporalDefaultOptions, temporalOptions);
var Sequelize = sequelize.Sequelize;
var historyName = model.name + 'History';
//var historyName = model.getTableName() + 'History';
//var historyName = model.options.name.singular + 'History';
var historyOwnAttrs = {
hid: {
type: Sequelize.BIGINT,
primaryKey: true,
autoIncrement: true,
unique: true
},
archivedAt: {
type: Sequelize.DATE,
allowNull: false,
defaultValue: Sequelize.NOW
}
};
var excludedAttributes = ["Model","unique","primaryKey","autoIncrement", "set", "get", "_modelAttribute"];
var historyAttributes = _(model.rawAttributes).mapValues(function(v){
v = excludeAttributes(v, excludedAttributes);
// remove the "NOW" defaultValue for the default timestamps
// we want to save them, but just a copy from our master record
if(v.fieldName == "createdAt" || v.fieldName == "updatedAt"){
v.type = Sequelize.DATE;
}
return v;
}).assign(historyOwnAttrs).value();
// If the order matters, use this:
//historyAttributes = _.assign({}, historyOwnAttrs, historyAttributes);
var historyOwnOptions = {
timestamps: false
};
var excludedNames = ["name", "tableName", "sequelize", "uniqueKeys", "hasPrimaryKey", "hooks", "scopes", "instanceMethods", "defaultScope"];
var modelOptions = excludeAttributes(model.options, excludedNames);
var historyOptions = _.assign({}, modelOptions, historyOwnOptions);
// We want to delete indexes that have unique constraint
var indexes = historyOptions.indexes;
if(Array.isArray(indexes)){
historyOptions.indexes = indexes.filter(function(index){return !index.unique && index.type != 'UNIQUE';});
}
var modelHistory = sequelize.define(historyName, historyAttributes, historyOptions);
// we already get the updatedAt timestamp from our models
var insertHook = function(obj, options){
var dataValues = (!temporalOptions.full && obj._previousDataValues) || obj.dataValues;
var historyRecord = modelHistory.create(dataValues, {transaction: options.transaction});
if(temporalOptions.blocking){
return historyRecord;
}
}
var insertBulkHook = function(options){
if(!options.individualHooks){
var queryAll = model.findAll({where: options.where, transaction: options.transaction}).then(function(hits){
if(hits){
hits = _.map(hits, 'dataValues');
return modelHistory.bulkCreate(hits, {transaction: options.transaction});
}
});
if(temporalOptions.blocking){
return queryAll;
}
}
}
// use `after` to be nonBlocking
// all hooks just create a copy
if (temporalOptions.full) {
model.addHook('afterCreate', insertHook);
model.addHook('afterUpdate', insertHook);
model.addHook('afterDestroy', insertHook);
model.addHook('afterRestore', insertHook);
} else {
model.addHook('beforeUpdate', insertHook);
model.addHook('beforeDestroy', insertHook);
}
model.addHook('beforeBulkUpdate', insertBulkHook);
model.addHook('beforeBulkDestroy', insertBulkHook);
var readOnlyHook = function(){
throw new Error("This is a read-only history database. You aren't allowed to modify it.");
};
modelHistory.addHook('beforeUpdate', readOnlyHook);
modelHistory.addHook('beforeDestroy', readOnlyHook);
return model;
};
module.exports = Temporal;