consistency fixes, updated readme, removed link storage if not specified

This commit is contained in:
Theodor Diaconu 2016-09-22 17:06:05 +03:00
parent 6aa1819f48
commit e844c93548
10 changed files with 142 additions and 135 deletions

View file

@ -109,7 +109,6 @@ OR from the collection directly:
```
const query = Posts.createQuery({
// $all: 1, // use this only when you want all fields without specifying them (NOT RECOMMENDED)
$filter({filters, options, params}) {
filters.isApproved = true;
options.limit = params.limit;

View file

@ -99,7 +99,6 @@ Notes:
- Use {} to specify a link, and 1 for a field.
- "_id" will always be fetched
- You must always specify the fields you need, otherwise it will only fetch _id
- If you want all fields, pass in {$all: 1}
```
const query = Posts.createQuery({
@ -116,7 +115,6 @@ const query = Posts.createQuery({
comments: {
text: 1,
// if you don't specify any local fields for the author, only "_id" field will be fetched
// use $all: 1, to get all fields
// this will enforce the use of query and retrieve only the data you need.
author: {
groups: {
@ -283,23 +281,6 @@ createQuery({
*posts* is the name of the collection. (when you create new Mongo.Collection("xxx"), "xxx" is the name of your collection)
Getting all the fields
======================
Though this is not recommended, sometimes especially when you are just testing around, you want to see all the fields
```
createQuery({
posts: {
$all: 1,
comments: {
$all: 1
}
}
});
```
The query above will fetch all the fields from every posts and every comment of every post.
#### React Integration
For integration with React try out [cultofcoders:grapher-react](https://github.com/cult-of-coders/grapher-react) package

View file

@ -42,6 +42,8 @@ export default class Exposure {
const collection = this.collection;
const firewall = this.firewall;
collection.__isExposedForGrapher = true;
if (firewall) {
collection.firewall = (filters, options, userId) => {
if (userId !== undefined) {

View file

@ -100,6 +100,10 @@ export default class Linker {
*/
isMeta()
{
if (this.isVirtual()) {
return this.linkConfig.relatedLinker.isMeta();
}
return !!this.linkConfig.metadata;
}
@ -108,6 +112,10 @@ export default class Linker {
*/
isSingle()
{
if (this.isVirtual()) {
return this.linkConfig.relatedLinker.isSingle();
}
return _.contains(this.oneTypes, this.linkConfig.type);
}

View file

@ -0,0 +1,40 @@
export default function (childCollectionNode, aggregateResults) {
const linker = childCollectionNode.linker;
const linkName = childCollectionNode.linkName;
let allResults = [];
if (linker.isMeta() && linker.isMany()) {
_.each(childCollectionNode.parent.results, parentResult => {
parentResult[linkName] = parentResult[linkName] || [];
const eligibleAggregateResults = _.filter(aggregateResults, aggregateResult => {
return _.contains(aggregateResult._id, parentResult._id)
});
if (eligibleAggregateResults.length) {
const datas = _.pluck(eligibleAggregateResults, 'data'); /// [ [x1, x2], [x2, x3] ]
_.each(datas, item => parentResult[linkName].push(item));
}
});
_.each(aggregateResults, aggregateResult => {
_.each(aggregateResult.data, item => allResults.push(item))
});
} else {
_.each(aggregateResults, aggregateResult => {
const parentResult = _.find(childCollectionNode.parent.results, (result) => {
return result._id === aggregateResult._id;
});
if (parentResult) {
parentResult[childCollectionNode.linkName] = aggregateResult.data;
}
_.each(aggregateResult.data, item => allResults.push(item))
});
}
childCollectionNode.results = allResults;
}

View file

@ -8,22 +8,25 @@ export default (childCollectionNode, limit) => {
const strategy = linker.strategy;
const isVirtual = linker.isVirtual();
const isSingle = linker.isSingle();
const oneResult = (isVirtual && linker.linkConfig.relatedLinker.linkConfig.unique)
|| (!isVirtual) && isSingle;
const removeStorageField = !childCollectionNode.parentHasMyLinkStorageFieldSpecified();
const oneResult = (isVirtual && linker.linkConfig.relatedLinker.linkConfig.unique) || (!isVirtual) && isSingle;
const fieldStorage = linker.linkStorageField;
_.each(parent.results, result => {
result[childCollectionNode.linkName] = assembleData(childCollectionNode, result, {
fieldStorage, strategy, isVirtual, isSingle, oneResult, limit
const data = assembleData(childCollectionNode, result, {
fieldStorage, strategy, isVirtual, isSingle
});
result[childCollectionNode.linkName] = filterAssembledData(data, {limit, oneResult})
});
if (removeStorageField) {
_.each(parent.results, result => delete result[fieldStorage]);
}
}
function assembleData(childCollectionNode, result, {fieldStorage, strategy, isVirtual, oneResult, limit}) {
const filters = createSearchFilters(result, fieldStorage, strategy, isVirtual);
const data = sift(filters, childCollectionNode.results);
function filterAssembledData(data, {limit, oneResult}) {
if (limit) {
return data.slice(limit);
}
@ -34,3 +37,9 @@ function assembleData(childCollectionNode, result, {fieldStorage, strategy, isVi
return data;
}
function assembleData(childCollectionNode, result, {fieldStorage, strategy, isVirtual}) {
const filters = createSearchFilters(result, fieldStorage, strategy, isVirtual);
return sift(filters, childCollectionNode.results);
}

View file

@ -0,0 +1,55 @@
export default function (childCollectionNode, filters, options, userId) {
const linker = childCollectionNode.linker;
const linkStorageField = linker.linkStorageField;
const collection = childCollectionNode.collection;
let pipeline = [];
if (collection.firewall) {
collection.firewall(filters, options, userId);
}
pipeline.push({$match: filters});
if (options.sort) {
pipeline.push({$sort: options.sort})
}
let _id = linkStorageField;
if (linker.isMeta()) {
_id += '._id';
}
let dataPush = {};
_.each(options.fields, (value, field) => {
dataPush[field] = '$' + field
});
if (!dataPush._id) {
dataPush['_id'] = '$_id';
}
pipeline.push({
$group: {
_id: "$" + _id,
data: {
$push: dataPush
}
}
});
if (options.limit || options.skip) {
let $slice = ["$data"];
if (options.skip) $slice.push(options.skip);
if (options.limit) $slice.push(options.limit);
pipeline.push({
$project: {
_id: 1,
data: {$slice}
}
})
}
return pipeline;
}

View file

@ -1,6 +1,8 @@
import applyProps from '../lib/applyProps.js';
import AggregateFilters from './aggregateSearchFilters.js';
import assemble from './assembler.js';
import assembleAggregateResults from './assembleAggregateResults.js';
import buildAggregatePipeline from './buildAggregatePipeline.js';
export default function storeHypernovaResults(childCollectionNode, userId) {
if (childCollectionNode.parent.results.length === 0) {
@ -26,102 +28,13 @@ export default function storeHypernovaResults(childCollectionNode, userId) {
childCollectionNode.results = collection.find(filters, filteredOptions, userId).fetch();
}
assemble(childCollectionNode);
return;
}
assemble(childCollectionNode, options.limit);
} else {
// virtuals arrive here
let pipeline = [];
const linkStorageField = aggregateFilters.linkStorageField;
if (collection.firewall) {
collection.firewall(filters, options, userId);
}
pipeline.push({$match: filters});
if (options.sort) {
pipeline.push({$sort: options.sort})
}
let _id = linkStorageField;
if (linker.isMeta()) {
_id += '._id';
}
let dataPush = {};
_.each(options.fields, (value, field) => {
dataPush[field] = '$' + field
});
if (!dataPush._id) {
dataPush['_id'] = '$_id';
}
dataPush[linkStorageField] = '$' + linkStorageField;
pipeline.push({
$group: {
_id: "$" + _id,
data: {
$push: dataPush
}
}
});
if (options.limit || options.skip) {
let $slice = ["$data"];
if (options.skip) $slice.push(options.skip);
if (options.limit) $slice.push(options.limit);
pipeline.push({
$project: {
_id: 1,
data: {$slice}
}
})
}
let pipeline = buildAggregatePipeline(childCollectionNode, filters, options, userId);
const aggregateResults = collection.aggregate(pipeline, {explains: true});
let results = [];
const linkName = childCollectionNode.linkName;
if (linker.isMany()) {
_.each(childCollectionNode.parent.results, parentResult => {
parentResult[linkName] = parentResult[linkName] || [];
const eligibleAggregateResults = _.filter(aggregateResults, aggregateResult => {
return _.contains(aggregateResult._id, parentResult._id)
});
if (eligibleAggregateResults.length) {
const datas = _.pluck(eligibleAggregateResults, 'data'); /// [ [x1, x2], [x2, x3] ]
_.each(datas, item => parentResult[linkName].push(item));
assembleAggregateResults(childCollectionNode, aggregateResults);
}
});
_.each(aggregateResults, aggregateResult => {
_.each(aggregateResult.data, item => results.push(item))
});
} else {
_.each(aggregateResults, aggregateResult => {
const parentResult = _.find(childCollectionNode.parent.results, (result) => {
return result._id === aggregateResult._id;
});
if (parentResult) {
parentResult[childCollectionNode.linkName] = aggregateResult.data;
}
_.each(aggregateResult.data, item => results.push(item))
});
}
childCollectionNode.results = results;
}

View file

@ -19,10 +19,6 @@ export default class CollectionNode {
return _.filter(this.nodes, n => n instanceof FieldNode);
}
hasGlobalFieldNode() {
return !!_.find(this.fieldNodes, n => n.isGlobal());
}
/**
* @param node
* @param linker
@ -41,10 +37,6 @@ export default class CollectionNode {
applyFields(filters, options) {
let hasAddedAnyField = false;
if (this.hasGlobalFieldNode()) {
return options.fields = undefined;
}
_.each(this.fieldNodes, n => {
hasAddedAnyField = true;
n.applyFields(options.fields)
@ -70,4 +62,16 @@ export default class CollectionNode {
options.fields = {_id: 1};
}
}
parentHasMyLinkStorageFieldSpecified() {
const storageField = this.linker.linkStorageField;
if (this.parent) {
return !!_.find(this.parent.fieldNodes, fieldNode => {
return fieldNode.name == storageField
})
}
return false;
}
}

View file

@ -1,11 +1,7 @@
export default class FieldNode {
constructor(name, body) {
this.name = name;
this.body = body;
}
isGlobal() {
return this.name === '$all';
this.body = _.isObject(body) ? 1 : body;
}
applyFields(fields) {