fixed to pass tests

This commit is contained in:
Theodor Diaconu 2016-09-22 13:46:27 +03:00
parent 233a074dab
commit d5f8eeaf49
13 changed files with 100 additions and 60 deletions

View file

@ -43,10 +43,14 @@ export default class Exposure {
const firewall = this.firewall; const firewall = this.firewall;
if (firewall) { if (firewall) {
collection.findSecure = (filters, options, userId) => { collection.firewall = (filters, options, userId) => {
if (userId !== undefined) { if (userId !== undefined) {
firewall(filters, options, userId); firewall(filters, options, userId);
} }
};
collection.findSecure = (filters, options, userId) => {
collection.firewall(filters, options, userId);
return collection.find(filters, options); return collection.find(filters, options);
} }

View file

@ -35,6 +35,11 @@ export default new SimpleSchema({
type: Boolean, type: Boolean,
defaultValue: false, defaultValue: false,
optional: true optional: true
},
unique: {
type: Boolean,
defaultValue: false,
optional: true
} }
}); });

View file

@ -20,19 +20,19 @@ export default function createSearchFilters(object, fieldStorage, strategy, isVi
} }
} }
function createOne(object, fieldStorage) { export function createOne(object, fieldStorage) {
return { return {
_id: object[fieldStorage] _id: object[fieldStorage]
}; };
} }
function createOneVirtual(object, fieldStorage) { export function createOneVirtual(object, fieldStorage) {
return { return {
[fieldStorage]: object._id [fieldStorage]: object._id
}; };
} }
function createOneMeta(object, fieldStorage) { export function createOneMeta(object, fieldStorage) {
const value = object[fieldStorage]; const value = object[fieldStorage];
return { return {
@ -40,13 +40,13 @@ function createOneMeta(object, fieldStorage) {
}; };
} }
function createOneMetaVirtual(object, fieldStorage) { export function createOneMetaVirtual(object, fieldStorage) {
return { return {
[fieldStorage + '._id']: object._id [fieldStorage + '._id']: object._id
}; };
} }
function createMany(object, fieldStorage) { export function createMany(object, fieldStorage) {
return { return {
_id: { _id: {
$in: object[fieldStorage] || [] $in: object[fieldStorage] || []
@ -54,13 +54,13 @@ function createMany(object, fieldStorage) {
}; };
} }
function createManyVirtual(object, fieldStorage) { export function createManyVirtual(object, fieldStorage) {
return { return {
[fieldStorage]: object._id [fieldStorage]: object._id
}; };
} }
function createManyMeta(object, fieldStorage) { export function createManyMeta(object, fieldStorage) {
const value = object[fieldStorage]; const value = object[fieldStorage];
return { return {
@ -68,7 +68,7 @@ function createManyMeta(object, fieldStorage) {
}; };
} }
function createManyMetaVirtual(object, fieldStorage) { export function createManyMetaVirtual(object, fieldStorage) {
return { return {
[fieldStorage + '._id']: object._id [fieldStorage + '._id']: object._id
}; };

View file

@ -66,6 +66,10 @@ export default class Linker {
*/ */
get linkStorageField() get linkStorageField()
{ {
if (this.isVirtual()) {
return this.linkConfig.relatedLinker.linkConfig.linkStorageField;
}
return this.linkConfig.field; return this.linkConfig.field;
} }
@ -264,15 +268,42 @@ export default class Linker {
} }
_initIndex() { _initIndex() {
if (Meteor.isServer && this.linkConfig.index) { if (Meteor.isServer) {
let field = this.linkConfig.field; let field = this.linkConfig.field;
if (this.linkConfig.metadata) { if (this.linkConfig.metadata) {
field = field + '._id'; field = field + '._id';
} }
if (this.linkConfig.index) {
if (this.isVirtual()) {
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}
}
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.');
}
if (this.isMany()) {
throw new Meteor.Error('You cannot set unique property on a multi field.');
}
this.mainCollection._ensureIndex({ this.mainCollection._ensureIndex({
[field]: 1 [field]: 1
}) }, {unique: true})
}
}
} }
} }

View file

@ -5,12 +5,8 @@ export default class AggregateFilters {
this.isVirtual = this.linker.isVirtual(); this.isVirtual = this.linker.isVirtual();
if (this.isVirtual) {
this.linkStorageField = this.linker.linkConfig.relatedLinker.linkStorageField;
} else {
this.linkStorageField = this.linker.linkStorageField; this.linkStorageField = this.linker.linkStorageField;
} }
}
get parentObjects() { get parentObjects() {
return this.collectionNode.parent.results; return this.collectionNode.parent.results;

View file

@ -1,25 +1,36 @@
import createSearchFilters from './createSearchFilters'; import createSearchFilters from '../../links/lib/createSearchFilters';
import sift from 'sift'; import sift from 'sift';
export default (childCollectionNode) => { export default (childCollectionNode, limit) => {
const parent = childCollectionNode.parent; const parent = childCollectionNode.parent;
const linker = childCollectionNode.linker;
const strategy = childCollectionNode.linker.strategy; const strategy = linker.strategy;
const isVirtual = childCollectionNode.linker.isVirtual(); const isVirtual = linker.isVirtual();
const fieldStorage = (isVirtual) const isSingle = linker.isSingle();
? childCollectionNode.linker.linkConfig.relatedLinker.linkStorageField const oneResult = (isVirtual && linker.linkConfig.relatedLinker.linkConfig.unique)
: childCollectionNode.linker.linkStorageField; || (!isVirtual) && isSingle;
const fieldStorage = linker.linkStorageField;
_.each(parent.results, result => { _.each(parent.results, result => {
result[childCollectionNode.linkName] = assembleData(childCollectionNode, result, { result[childCollectionNode.linkName] = assembleData(childCollectionNode, result, {
fieldStorage, strategy, isVirtual fieldStorage, strategy, isVirtual, isSingle, oneResult, limit
}) });
}) });
} }
function assembleData(childCollectionNode, result, {fieldStorage, strategy, isVirtual}) { function assembleData(childCollectionNode, result, {fieldStorage, strategy, isVirtual, oneResult, limit}) {
const filters = createSearchFilters(result, fieldStorage, strategy, isVirtual); const filters = createSearchFilters(result, fieldStorage, strategy, isVirtual);
const data = sift(filters, childCollectionNode.results);
return sift(filters, childCollectionNode.results); if (limit) {
return data.slice(limit);
}
if (oneResult) {
return _.first(data);
}
return data;
} }

View file

@ -11,15 +11,12 @@ function hypernova(collectionNode, userId) {
_.each(collectionNode.results, result => { _.each(collectionNode.results, result => {
const accessor = childCollectionNode.linker.createLink(result); const accessor = childCollectionNode.linker.createLink(result);
childCollectionNode.results = accessor.find(filters, options); result[childCollectionNode.linkName] = accessor.find(filters, options);
}); });
} else { } else {
storeHypernovaResults(childCollectionNode, userId); storeHypernovaResults(childCollectionNode, userId);
let start = new Date();
hypernova(childCollectionNode, userId); hypernova(childCollectionNode, userId);
let end = new Date();
console.log(`hypernova: ${end.getTime() - start.getTime()}`);
} }
}); });
} }

View file

@ -16,8 +16,7 @@ export default function storeHypernovaResults(childCollectionNode, userId) {
_.extend(filters, aggregateFilters.create()); _.extend(filters, aggregateFilters.create());
// for one, one-meta, virtual or not, there is no need for aggregate query. // if it's not virtual then we retrieve them and assemble them here.
// same rule applies for many, many-meta but no virtual
if (!isVirtual) { if (!isVirtual) {
const filteredOptions = _.omit(options, 'limit'); const filteredOptions = _.omit(options, 'limit');
@ -28,11 +27,17 @@ export default function storeHypernovaResults(childCollectionNode, userId) {
} }
assemble(childCollectionNode); assemble(childCollectionNode);
return;
} }
// many, many-meta and virtual arrive here // virtuals arrive here
let pipeline = []; let pipeline = [];
if (collection.firewall) {
collection.firewall(filters, options, userId);
}
pipeline.push({$match: filters}); pipeline.push({$match: filters});
if (options.sort) { if (options.sort) {

View file

@ -14,7 +14,7 @@ export default function compose(node, userId) {
if (linker.isVirtual()) { if (linker.isVirtual()) {
options.fields = options.fields || {}; options.fields = options.fields || {};
_.extend(options.fields, { _.extend(options.fields, {
[linker.linkConfig.relatedLinker.linkStorageField]: 1 [linker.linkStorageField]: 1
}); });
} }

View file

@ -1,5 +1,5 @@
import applyProps from './applyProps.js'; import applyProps from './applyProps.js';
import createSearchFilters from '../hypernova/createSearchFilters.js'; import createSearchFilters from '../../links/lib/createSearchFilters.js';
import LinkResolve from '../../links/linkTypes/linkResolve.js'; import LinkResolve from '../../links/linkTypes/linkResolve.js';
import sift from 'sift'; import sift from 'sift';
@ -11,16 +11,13 @@ export default function fetch(node, parentObject, userId) {
if (parentObject) { if (parentObject) {
if (node.linker.isResolver()) { if (node.linker.isResolver()) {
let accessor = node.linker.createLink(parentObject, node.collection); let accessor = node.linker.createLink(parentObject, node.collection);
if (accessor instanceof LinkResolve) {
accessor.object = node.parent.collection.findOne(parentObject._id); accessor.object = node.parent.collection.findOne(parentObject._id);
}
results = accessor.fetch(filters, options, userId); results = accessor.fetch(filters, options, userId);
} else { } else {
const strategy = node.linker.strategy; const strategy = node.linker.strategy;
const isVirtual = node.linker.isVirtual(); const isVirtual = node.linker.isVirtual();
const fieldStorage = (isVirtual) ? node.linker.linkConfig.relatedLinker.linkStorageField : node.linker.linkStorageField; const fieldStorage = node.linker.linkStorageField;
_.extend(filters, createSearchFilters(parentObject, fieldStorage, strategy, isVirtual)); _.extend(filters, createSearchFilters(parentObject, fieldStorage, strategy, isVirtual));
@ -38,7 +35,6 @@ export default function fetch(node, parentObject, userId) {
} }
} }
// merge filters
_.each(results, result => { _.each(results, result => {
_.each(node.collectionNodes, collectionNode => { _.each(node.collectionNodes, collectionNode => {
result[collectionNode.linkName] = fetch(collectionNode, result, userId); result[collectionNode.linkName] = fetch(collectionNode, result, userId);
@ -46,7 +42,5 @@ export default function fetch(node, parentObject, userId) {
}) })
}); });
// assemble filters
return results; return results;
} }

View file

@ -81,9 +81,7 @@ export default class Query {
applyFilterFunction(this.body, this.params) applyFilterFunction(this.body, this.params)
); );
//return hypernova(node, options.userId); return hypernova(node, options.userId);
return recursiveFetch(node, null, options.userId);
} }
} }

View file

@ -17,7 +17,8 @@ PostCollection.addLinks({
}, },
author: { author: {
collection: AuthorCollection, collection: AuthorCollection,
type: 'one' type: 'one',
unique: true
}, },
comment_resolve: { comment_resolve: {
resolve(object) { resolve(object) {

View file

@ -37,8 +37,6 @@ describe('Query Server Tests', function () {
assert.isObject(post.author); assert.isObject(post.author);
assert.equal('John McSmithie', post.author.name); assert.equal('John McSmithie', post.author.name);
assert.lengthOf(post.comment_resolve, 1);
_.each(post.comments, comment => { _.each(post.comments, comment => {
assert.isString(comment.author.name); assert.isString(comment.author.name);
}) })