The communications platform that puts data protection first.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
Rocket.Chat/packages/rocketchat-lib/server/models/_Base.js

253 lines
5.0 KiB

const {EventEmitter} = Npm.require('events');
const baseName = 'rocketchat_';
const trash = new Mongo.Collection(baseName + '_trash');
try {
trash._ensureIndex({ collection: 1 });
trash._ensureIndex({ _deletedAt: 1 }, { expireAfterSeconds: 60 * 60 * 24 * 30 });
} catch (e) {
console.log(e);
}
class ModelsBase extends EventEmitter {
constructor(model) {
super();
if (Match.test(model, String)) {
this.name = model;
this.collectionName = this.baseName + this.name;
this.model = new Mongo.Collection(this.collectionName);
} else {
this.name = model._name;
this.collectionName = this.name;
this.model = model;
}
this.tryEnsureIndex({ '_updatedAt': 1 });
}
get baseName() {
return baseName;
}
setUpdatedAt(record = {}, checkQuery = false, query) {
if (checkQuery === true) {
if (!query || Object.keys(query).length === 0) {
throw new Meteor.Error('Models._Base: Empty query');
}
}
if (/(^|,)\$/.test(Object.keys(record).join(','))) {
record.$set = record.$set || {};
record.$set._updatedAt = new Date;
} else {
record._updatedAt = new Date;
}
return record;
}
find() {
return this.model.find(...arguments);
}
findOne() {
return this.model.findOne(...arguments);
}
insert(record) {
this.setUpdatedAt(record);
const result = this.model.insert(...arguments);
record._id = result;
this.emit('insert', record);
this.emit('change', 'insert', record);
return result;
}
update(query, update, options = {}) {
this.setUpdatedAt(update, true, query);
if (options.upsert) {
return this.upsert(query, update);
}
let ids = [];
if (options.multi === true) {
const updated = this.model.find(query, { fields: { _id: 1 } }).fetch();
if (updated) {
ids = ids.concat(updated);
}
} else {
const updated = this.model.findOne(query, { fields: { _id: 1 } });
if (updated) {
ids.push(updated);
}
}
const result = this.model.update(query, update, options);
const idQuery = { _id: { $in: _.pluck(ids, '_id') } };
this.emit('update', idQuery, update);
this.emit('change', 'update', idQuery, update);
return result;
}
upsert(query, update) {
this.setUpdatedAt(update, true, query);
const id = this.model.findOne(query, { fields: { _id: 1 } });
const result = this.model.upsert(...arguments);
let record = id;
if (result.insertedId) {
record = { _id: result.insertedId };
}
this.emit('update', record);
this.emit('change', 'update', record);
return result;
}
remove(query) {
const records = this.model.find(query).fetch();
const ids = [];
for (const record of records) {
ids.push(record._id);
record._deletedAt = new Date;
record.__collection__ = this.name;
trash.upsert({_id: record._id}, _.omit(record, '_id'));
}
query = { _id: { $in: ids } };
this.emit('remove', records);
this.emit('change', 'remove', records);
return this.model.remove(query);
}
insertOrUpsert(...args) {
if (args[0] && args[0]._id) {
const _id = args[0]._id;
delete args[0]._id;
args.unshift({
_id: _id
});
this.upsert(...args);
return _id;
} else {
return this.insert(...args);
}
}
allow() {
return this.model.allow(...arguments);
}
deny() {
return this.model.deny(...arguments);
}
ensureIndex() {
return this.model._ensureIndex(...arguments);
}
dropIndex() {
return this.model._dropIndex(...arguments);
}
tryEnsureIndex() {
try {
return this.ensureIndex(...arguments);
} catch (e) {
console.log(e);
}
}
tryDropIndex() {
try {
return this.dropIndex(...arguments);
} catch (e) {
console.log(e);
}
}
getChangedRecords(type, recordOrQuery, fields) {
if (type === 'insert') {
return [recordOrQuery];
}
if (type === 'remove') {
return recordOrQuery;
}
if (type === 'update') {
const options = {};
if (fields) {
options.fields = fields;
}
return this.find(recordOrQuery, options).fetch();
}
}
trashFind(query, options) {
query.__collection__ = this.name;
return trash.find(query, options);
}
trashFindDeletedAfter(deletedAt, query = {}, options) {
query.__collection__ = this.name;
query._deletedAt = {
$gt: deletedAt
};
return trash.find(query, options);
}
dinamicTrashFindAfter(method, deletedAt, ...args) {
const scope = {
find: (query={}) => {
return this.trashFindDeletedAfter(deletedAt, query, { fields: {_id: 1, _deletedAt: 1} });
}
};
scope.model = {
find: scope.find
};
return this[method].apply(scope, args);
}
dinamicFindAfter(method, updatedAt, ...args) {
const scope = {
find: (query={}, options) => {
query._updatedAt = {
$gt: updatedAt
};
return this.find(query, options);
}
};
scope.model = {
find: scope.find
};
return this[method].apply(scope, args);
}
dinamicFindChangesAfter(method, updatedAt, ...args) {
return {
update: this.dinamicFindAfter(method, updatedAt, ...args).fetch(),
remove: this.dinamicTrashFindAfter(method, updatedAt, ...args).fetch()
};
}
}
RocketChat.models._Base = ModelsBase;