Merge pull request #302 from cult-of-coders/fix/many-uniqueness

Removed exception for uniqueness on many field
This commit is contained in:
Theodor Diaconu 2018-10-23 09:16:33 +03:00 committed by GitHub
commit 24a140ae08
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -2,11 +2,11 @@ import LinkMany from './linkTypes/linkMany.js';
import LinkManyMeta from './linkTypes/linkManyMeta.js';
import LinkOne from './linkTypes/linkOne.js';
import LinkOneMeta from './linkTypes/linkOneMeta.js';
import {LinkConfigSchema, LinkConfigDefaults} from './config.schema.js';
import { LinkConfigSchema, LinkConfigDefaults } from './config.schema.js';
import smartArguments from './linkTypes/lib/smartArguments';
import dot from 'dot-object';
import {check} from 'meteor/check';
import {_} from 'meteor/underscore';
import { check } from 'meteor/check';
import { _ } from 'meteor/underscore';
export default class Linker {
/**
@ -118,8 +118,9 @@ export default class Linker {
*/
isOneResult() {
return (
(this.isVirtual() && this.linkConfig.relatedLinker.linkConfig.unique)
|| (!this.isVirtual() && this.isSingle())
(this.isVirtual() &&
this.linkConfig.relatedLinker.linkConfig.unique) ||
(!this.isVirtual() && this.isSingle())
);
}
@ -141,15 +142,23 @@ export default class Linker {
*/
_validateAndClean() {
if (!this.linkConfig.collection) {
throw new Meteor.Error('invalid-config', `For the link ${this.linkName} you did not provide a collection.`)
throw new Meteor.Error(
'invalid-config',
`For the link ${
this.linkName
} you did not provide a collection.`
);
}
if (typeof(this.linkConfig.collection) === 'string') {
if (typeof this.linkConfig.collection === 'string') {
const collectionName = this.linkConfig.collection;
this.linkConfig.collection = Mongo.Collection.get(collectionName);
if (!this.linkConfig.collection) {
throw new Meteor.Error('invalid-collection', `Could not find a collection with the name: ${collectionName}`);
throw new Meteor.Error(
'invalid-collection',
`Could not find a collection with the name: ${collectionName}`
);
}
}
@ -164,7 +173,12 @@ export default class Linker {
this.linkConfig.field = this._generateFieldName();
} else {
if (this.linkConfig.field == this.linkName) {
throw new Meteor.Error('invalid-config', `For the link ${this.linkName} you must not use the same name for the field, otherwise it will cause conflicts when fetching data`);
throw new Meteor.Error(
'invalid-config',
`For the link ${
this.linkName
} you must not use the same name for the field, otherwise it will cause conflicts when fetching data`
);
}
}
}
@ -177,7 +191,7 @@ export default class Linker {
* @private
*/
_prepareVirtual() {
const {collection, inversedBy} = this.linkConfig;
const { collection, inversedBy } = this.linkConfig;
let linker = collection.getLinker(inversedBy);
if (!linker) {
@ -186,11 +200,17 @@ export default class Linker {
Meteor.startup(() => {
linker = collection.getLinker(inversedBy);
if (!linker) {
throw new Meteor.Error(`You tried setting up an inversed link in "${this.mainCollection._name}" pointing to collection: "${collection._name}" link: "${inversedBy}", but no such link was found. Maybe a typo ?`)
throw new Meteor.Error(
`You tried setting up an inversed link in "${
this.mainCollection._name
}" pointing to collection: "${
collection._name
}" link: "${inversedBy}", but no such link was found. Maybe a typo ?`
);
} else {
this._setupVirtualConfig(linker);
}
})
});
} else {
this._setupVirtualConfig(linker);
}
@ -204,12 +224,14 @@ export default class Linker {
const virtualLinkConfig = linker.linkConfig;
if (!virtualLinkConfig) {
throw new Meteor.Error(`There is no link-config for the related collection on ${inversedBy}. Make sure you added the direct links before specifying virtual ones.`)
throw new Meteor.Error(
`There is no link-config for the related collection on ${inversedBy}. Make sure you added the direct links before specifying virtual ones.`
);
}
_.extend(this.linkConfig, {
metadata: virtualLinkConfig.metadata,
relatedLinker: linker
relatedLinker: linker,
});
}
@ -229,7 +251,10 @@ export default class Linker {
return LinkOne;
}
throw new Meteor.Error('invalid-strategy', `${this.strategy} is not a valid strategy`);
throw new Meteor.Error(
'invalid-strategy',
`${this.strategy} is not a valid strategy`
);
}
/**
@ -237,7 +262,10 @@ export default class Linker {
* @private
*/
_generateFieldName() {
let cleanedCollectionName = this.linkConfig.collection._name.replace(/\./g, '_');
let cleanedCollectionName = this.linkConfig.collection._name.replace(
/\./g,
'_'
);
let defaultFieldPrefix = this.linkName + '_' + cleanedCollectionName;
switch (this.strategy) {
@ -260,14 +288,20 @@ export default class Linker {
this.mainCollection.after.remove((userId, doc) => {
// this problem may occur when you do a .remove() before Meteor.startup()
if (!this.linkConfig.relatedLinker) {
console.warn(`There was an error finding the link for removal for collection: "${this.mainCollection._name}" with link: "${this.linkName}". This may occur when you do a .remove() before Meteor.startup()`);
console.warn(
`There was an error finding the link for removal for collection: "${
this.mainCollection._name
}" with link: "${
this.linkName
}". This may occur when you do a .remove() before Meteor.startup()`
);
return;
}
let accessor = this.createLink(doc);
_.each(accessor.fetch(), linkedObj => {
const {relatedLinker} = this.linkConfig;
const { relatedLinker } = this.linkConfig;
// We do this check, to avoid self-referencing hell when defining virtual links
// Virtual links if not found "compile-time", we will try again to reprocess them on Meteor.startup
// if a removal happens before Meteor.startup this may fail
@ -281,7 +315,7 @@ export default class Linker {
}
}
});
})
});
}
_initIndex() {
@ -293,32 +327,31 @@ export default class Linker {
if (this.linkConfig.index) {
if (this.isVirtual()) {
throw new Meteor.Error('You cannot set index on an inversed link.');
throw new Meteor.Error(
'You cannot set index on an inversed link.'
);
}
let options;
if (this.linkConfig.unique) {
if (this.isMany()) {
throw new Meteor.Error('You cannot set unique property on a multi field.');
}
options = {unique: true}
options = { unique: true };
}
this.mainCollection._ensureIndex({[field]: 1}, options);
this.mainCollection._ensureIndex({ [field]: 1 }, options);
} else {
if (this.linkConfig.unique) {
if (this.isVirtual()) {
throw new Meteor.Error('You cannot set unique property on an inversed link.');
throw new Meteor.Error(
'You cannot set unique property on an inversed link.'
);
}
if (this.isMany()) {
throw new Meteor.Error('You cannot set unique property on a multi field.');
}
this.mainCollection._ensureIndex({
[field]: 1
}, {unique: true})
this.mainCollection._ensureIndex(
{
[field]: 1,
},
{ unique: true }
);
}
}
}
@ -333,19 +366,22 @@ export default class Linker {
this.mainCollection.after.remove((userId, doc) => {
this.getLinkedCollection().remove({
_id: {
$in: smartArguments.getIds(doc[this.linkStorageField])
}
})
})
$in: smartArguments.getIds(doc[this.linkStorageField]),
},
});
});
} else {
this.mainCollection.after.remove((userId, doc) => {
const linker = this.mainCollection.getLink(doc, this.linkName);
const ids = linker.find({}, {fields: {_id: 1}}).fetch().map(item => item._id);
const ids = linker
.find({}, { fields: { _id: 1 } })
.fetch()
.map(item => item._id);
this.getLinkedCollection().remove({
_id: {$in: ids}
})
})
_id: { $in: ids },
});
});
}
}
@ -360,21 +396,25 @@ export default class Linker {
const packageExists = !!Package['herteby:denormalize'];
if (!packageExists) {
throw new Meteor.Error('missing-package', `Please add the herteby:denormalize package to your Meteor application in order to make caching work`)
throw new Meteor.Error(
'missing-package',
`Please add the herteby:denormalize package to your Meteor application in order to make caching work`
);
}
const {field, body, bypassSchema} = this.linkConfig.denormalize;
const { field, body, bypassSchema } = this.linkConfig.denormalize;
let cacheConfig;
let referenceFieldSuffix = '';
if (this.isMeta()) {
referenceFieldSuffix = (this.isSingle() ? '._id' : ':_id');
referenceFieldSuffix = this.isSingle() ? '._id' : ':_id';
}
if (this.isVirtual()) {
let inversedLink = this.linkConfig.relatedLinker.linkConfig;
let type = inversedLink.type == 'many' ? 'many-inverse' : 'inversed';
let type =
inversedLink.type == 'many' ? 'many-inverse' : 'inversed';
cacheConfig = {
type: type,
@ -382,7 +422,7 @@ export default class Linker {
fields: body,
referenceField: inversedLink.field + referenceFieldSuffix,
cacheField: field,
bypassSchema: !!bypassSchema
bypassSchema: !!bypassSchema,
};
} else {
cacheConfig = {
@ -391,14 +431,14 @@ export default class Linker {
fields: body,
referenceField: this.linkConfig.field + referenceFieldSuffix,
cacheField: field,
bypassSchema: !!bypassSchema
bypassSchema: !!bypassSchema,
};
}
if (this.isVirtual()) {
Meteor.startup(() => {
this.mainCollection.cache(cacheConfig);
})
});
} else {
this.mainCollection.cache(cacheConfig);
}
@ -425,12 +465,8 @@ export default class Linker {
const cacheBody = this.linkConfig.denormalize.body;
const cacheBodyFields = _.keys(dot.dot(cacheBody));
const bodyFields = _.keys(
dot.dot(
_.omit(body, '_id')
)
);
const bodyFields = _.keys(dot.dot(_.omit(body, '_id')));
return _.difference(bodyFields, cacheBodyFields).length === 0;
}
}
}