updating reducer implementation

This commit is contained in:
Theodor Diaconu 2016-11-18 18:33:21 +02:00
parent 91c1f49f6f
commit 5c21c0f5e9
7 changed files with 229 additions and 17 deletions

View file

@ -103,6 +103,9 @@ export default class Exposure {
}
}
/**
* Initializing the publication for reactive query fetching
*/
initPublication() {
const collection = this.collection;
const config = this.config;
@ -122,6 +125,9 @@ export default class Exposure {
});
}
/**
* Initializez the method to retrieve the data via Meteor.call
*/
initMethod() {
const collection = this.collection;
const config = this.config;
@ -147,6 +153,10 @@ export default class Exposure {
});
}
/**
* Initializez the method to retrieve the count of the data via Meteor.call
* @returns {*}
*/
initCountMethod() {
const collection = this.collection;
@ -159,6 +169,10 @@ export default class Exposure {
})
}
/**
* Initializes security enforcement
* THINK: Maybe instead of overriding .find, I could store this data of security inside the collection object.
*/
initSecurity() {
const collection = this.collection;
const {firewall, maxLimit, restrictedFields} = this.config;

View file

@ -8,21 +8,26 @@ const specialFields = ['$filters', '$options'];
* Creates node objects from the body
* @param root
*/
function createNodes(root) {
// fix for phantomjs tests
export function createNodes(root) {
// this is a fix for phantomjs tests (don't really understand it.)
if (!_.isObject(root.body)) {
return;
}
let reducers = {};
_.each(root.body, (body, fieldName) => {
if (!body) {
return;
}
// if it's a prop
if (_.contains(specialFields, fieldName)) {
return _.extend(root.props, {
_.extend(root.props, {
[fieldName]: body
});
return;
}
// checking if it is a link.
@ -32,26 +37,42 @@ function createNodes(root) {
let subroot = new CollectionNode(linker.getLinkedCollection(), body, fieldName);
root.add(subroot, linker);
return createNodes(subroot);
createNodes(subroot);
return;
}
// it's not a link and not a special variable => we assume it's a field.
if (_.isObject(body)) {
let dotted = dotize.convert({[fieldName]: body});
_.each(dotted, (value, key) => {
root.add(new FieldNode(key, value));
});
} else {
let fieldNode = new FieldNode(fieldName, body);
root.add(fieldNode);
// checking if it's a reducer
const reducer = root.collection.getReducer(fieldName);
if (reducer) {
reducers[fieldName] = reducer;
return;
}
// it's most likely a field then
addFieldNode(body, fieldName, root);
});
// applyReducersOnGraph(root, reducers);
if (root.fieldNodes.length === 0) {
root.add(new FieldNode('_id', 1));
}
}
export function addFieldNode(body, fieldName, root) {
// it's not a link and not a special variable => we assume it's a field
if (_.isObject(body)) {
let dotted = dotize.convert({[fieldName]: body});
_.each(dotted, (value, key) => {
root.add(new FieldNode(key, value));
});
} else {
let fieldNode = new FieldNode(fieldName, body);
root.add(fieldNode);
}
}
export default function (collection, body) {
let root = new CollectionNode(collection, body);
createNodes(root);

View file

@ -16,6 +16,8 @@ export default class CollectionNode {
this.parent = null;
this.linker = null;
this.linkStorageField = null;
this.reducers = [];
this.scheduledForDeletion = false;
}
get collectionNodes() {
@ -52,7 +54,7 @@ export default class CollectionNode {
* @param _node
*/
remove(_node) {
this.nodes = _.filter(this.nodes, node => _node !== node);
this.nodes = _.filter(this.nodes, node => _node !== node);
}
/**
@ -103,6 +105,39 @@ export default class CollectionNode {
})
}
/**
* @param fieldName
* @returns {FieldNode}
*/
getField(fieldName) {
return _.find(this.fieldNodes, fieldNode => {
return fieldNode.name == fieldName
})
}
/**
* @param name
* @returns {boolean}
*/
hasCollectionNode(name) {
return !!_.find(this.collectionNodes, node => {
return node.linkName == name
})
}
/**
* @param name
* @returns {CollectionNode}
*/
getCollectionNode(name) {
return _.find(this.collectionNodes, node => {
return node.linkName == name
})
}
/**
* @returns {*}
*/
getName() {
return this.linkName
? this.linkName

View file

@ -2,6 +2,7 @@ export default class FieldNode {
constructor(name, body) {
this.name = name;
this.body = _.isObject(body) ? 1 : body;
this.scheduledForDeletion = false;
}
applyFields(fields) {

View file

@ -1,13 +1,17 @@
import dot from 'dot-object';
export default class ReducerNode {
constructor(name, body, reducer) {
this.collectionNode = collectionNode;
this.name = name;
this.body = body;
this.reducer = reducer;
}
// reducer nodes should always be added last.
init(collectionNode) {
// store fields that are needed, but not specified are fields
// so when we prepare data for delivery it we can clean-it-up
}
applyFields(fields) {

View file

@ -0,0 +1,136 @@
import dot from 'dot-object';
import { createNodes } from '../../lib/createGraph';
import CollectionNode from '../../nodes/collectionNode';
import FieldNode from '../../nodes/fieldNode';
export default function addReducers(root, reducers, addToRoot = true) {
// we add reducers last, after we have added all the fields.
const collection = root.collection;
reducers.forEach(reducer => {
if (addToRoot) {
root.reducers.push(reducer);
}
_.each(reducer.body, (body, fieldName) => {
// if it's a link
const linker = collection.getLinker(fieldName);
if (linker) {
if (root.hasCollectionNode(fieldName)) {
// TODO: go deep and perform the same process
const collectionNode = root.getCollectionNode(fieldName);
diffWithReducerBody(body, collectionNode);
return;
} else {
// add
let collectionNode = new CollectionNode(linker.getLinkedCollection(), body, fieldName);
collectionNode.scheduledForDeletion = true;
root.add(collectionNode, linker);
createNodes(collectionNode);
}
return;
}
const reducer = collection.getReducer(fieldName);
if (reducer) {
addReducers(root, [reducer]);
return;
}
// we assume it's a field in this case
handleAddField(body, root, fieldName);
})
});
}
/**
* @param body
* @param root
* @param fieldName
*/
function handleAddField(body, fieldName, root) {
if (_.isObject(body)) {
// if reducer specifies a nested field
const dots = dot.dot(body);
_.each(dots, (value, key) => {
if (!root.hasField(fieldName)) {
let fieldNode = new FieldNode(key, value);
fieldNode.scheduledForDeletion = true;
root.add(fieldNode);
}
});
} else {
// if reducer does not specify a nested field, and the field does not exist.
if (!root.hasField(fieldName)) {
let fieldNode = new FieldNode(fieldName, body);
fieldNode.scheduledForDeletion = true;
root.add(fieldNode);
}
}
}
/**
* @param reducerBody
* @param collectionNode
*/
function diffWithReducerBody(reducerBody, collectionNode) {
_.each(reducerBody, (value, key) => {
const collection = collectionNode.collection;
if (_.isObject(value)) {
// nested field or link
if (collectionNode.body[key]) {
// if it exists
const linker = collection.getLinker(key);
// if it's a link
if (linker) {
diffWithReducerBody(value, collectionNode.getCollectionNode(key));
return;
}
handleAddField(value, key, collectionNode);
} else {
// does not exist, so it may be a field or a linker
const linker = collection.getLinker(key);
// if it's a link
if (linker) {
let childCollectionNode = new CollectionNode(linker.getLinkedCollection(), value, key);
childCollectionNode.scheduledForDeletion = true;
collectionNode.add(collectionNode, linker);
createNodes(childCollectionNode);
return;
}
const reducer = collection.getReducer(key);
if (reducer) {
// if it's another reducer
addReducers(collectionNode, [reducer], false);
return;
}
// it's a field
handleAddField(value, key, collectionNode)
}
} else {
const reducer = collection.getReducer(key);
if (reducer) {
// if it's another reducer
addReducers(collectionNode, [reducer], false);
return;
}
handleAddField(value, key, collectionNode);
}
})
}

View file

@ -11,7 +11,8 @@ Package.describe({
});
Npm.depends({
'sift': '3.2.6'
'sift': '3.2.6',
'dot-object': '1.5.4',
});
Package.onUse(function (api) {