some small updates

This commit is contained in:
Theodor Diaconu 2017-11-30 22:11:25 +02:00
parent 4abcbe777d
commit 324e2b78fd
20 changed files with 125 additions and 102 deletions

5
lib/compose.js Normal file
View file

@ -0,0 +1,5 @@
import deepExtend from 'deep-extend';
export default function (...args) {
return deepExtend({}, ...args);
}

View file

@ -2,7 +2,6 @@ import LinkMany from './linkTypes/linkMany.js';
import LinkManyMeta from './linkTypes/linkManyMeta.js'; import LinkManyMeta from './linkTypes/linkManyMeta.js';
import LinkOne from './linkTypes/linkOne.js'; import LinkOne from './linkTypes/linkOne.js';
import LinkOneMeta from './linkTypes/linkOneMeta.js'; import LinkOneMeta from './linkTypes/linkOneMeta.js';
import LinkResolve from './linkTypes/linkResolve.js';
import {LinkConfigSchema, LinkConfigDefaults} from './config.schema.js'; import {LinkConfigSchema, LinkConfigDefaults} from './config.schema.js';
import smartArguments from './linkTypes/lib/smartArguments'; import smartArguments from './linkTypes/lib/smartArguments';
import dot from 'dot-object'; import dot from 'dot-object';

View file

@ -42,13 +42,6 @@ PostCollection.addLinks({
collection: CategoryCollection, collection: CategoryCollection,
type: '1' type: '1'
}, },
pictures: {
resolve(object) {
return ResolverCollection.find({
resourceId: object._id
}).fetch();
}
},
inversedComment: { inversedComment: {
collection: CommentCollection, collection: CommentCollection,
inversedBy: 'inversedPost' inversedBy: 'inversedPost'
@ -90,7 +83,6 @@ describe('Collection Links', function () {
PostCollection.remove({}); PostCollection.remove({});
CategoryCollection.remove({}); CategoryCollection.remove({});
CommentCollection.remove({}); CommentCollection.remove({});
ResolverCollection.remove({});
it('Test Many', function () { it('Test Many', function () {
let postId = PostCollection.insert({'text': 'abc'}); let postId = PostCollection.insert({'text': 'abc'});
@ -254,16 +246,6 @@ describe('Collection Links', function () {
assert.notInclude(post.commentIds, comment._id); assert.notInclude(post.commentIds, comment._id);
}); });
it('Tests proper resolver', function () {
let postId = PostCollection.insert({'text': 'abc'});
let uploadId = ResolverCollection.insert({'resourceId': postId});
let post = PostCollection.findOne(postId);
const link = PostCollection.getLink(post, 'pictures');
assert.lengthOf(link.fetch(), 1);
});
it ('Should auto-save object', function () { it ('Should auto-save object', function () {
let comment = {text: 'abc'}; let comment = {text: 'abc'};

View file

@ -0,0 +1,39 @@
import {EJSON} from 'meteor/ejson';
/**
* This is a very basic in-memory result caching functionality
*/
export default class BaseResultCacher {
constructor(config = {}) {
this.config = config;
}
/**
* @param queryName
* @param params
* @returns {string}
*/
generateQueryId(queryName, params) {
return `${queryName}::${EJSON.stringify(params)}`;
}
/**
* Dummy function
*/
fetch(cacheId, {query, countCursor}) {
throw 'Not implemented';
}
/**
* @param query
* @param countCursor
* @returns {*}
*/
static fetchData({query, countCursor}) {
if (query) {
return query.fetch();
} else {
return countCursor.count();
}
}
}

View file

@ -1,39 +1,42 @@
import {Meteor} from 'meteor/meteor'; import {Meteor} from 'meteor/meteor';
import cloneDeep from 'lodash.clonedeep'; import cloneDeep from 'lodash.clonedeep';
import BaseResultCacher from './BaseResultCacher';
const DEFAULT_TTL = 60000; const DEFAULT_TTL = 60000;
/** /**
* This is a very basic in-memory result caching functionality * This is a very basic in-memory result caching functionality
*/ */
export default class MemoryResultCacher { export default class MemoryResultCacher extends BaseResultCacher {
constructor(config = {}) { constructor(config = {}) {
super(config);
this.store = {}; this.store = {};
this.config = config;
} }
get(cacheId, { /**
query, * @param cacheId
countCursor, * @param query
}) { * @param countCursor
* @returns {*}
*/
fetch(cacheId, {query, countCursor}) {
const cacheData = this.store[cacheId]; const cacheData = this.store[cacheId];
if (cacheData !== undefined) { if (cacheData !== undefined) {
return cloneDeep(cacheData); return cloneDeep(cacheData);
} }
let data; const data = BaseResultCacher.fetchData({query, countCursor});
if (query) { this.storeData(cacheId, data);
data = query.fetch();
} else {
data = countCursor.count();
}
this.set(cacheId, data);
return data; return data;
} }
set(cacheId, data) {
/**
* @param cacheId
* @param data
*/
storeData(cacheId, data) {
const ttl = this.config.ttl || DEFAULT_TTL; const ttl = this.config.ttl || DEFAULT_TTL;
this.store[cacheId] = cloneDeep(data); this.store[cacheId] = cloneDeep(data);

View file

@ -1,5 +0,0 @@
import {EJSON} from 'meteor/ejson';
export default function(queryName, params) {
return `${queryName}::${EJSON.stringify(params)}`;
}

View file

@ -1,8 +1,8 @@
import deepClone from 'lodash.clonedeep'; import deepClone from 'lodash.clonedeep';
const specialParameters = ['$body'];
export default class NamedQueryBase { export default class NamedQueryBase {
isNamedQuery = true;
constructor(name, collection, body, options = {}) { constructor(name, collection, body, options = {}) {
this.queryName = name; this.queryName = name;
@ -23,6 +23,10 @@ export default class NamedQueryBase {
return `named_query_${this.queryName}`; return `named_query_${this.queryName}`;
} }
get isResolver() {
return !!this.resolver;
}
setParams(params) { setParams(params) {
this.params = _.extend({}, this.params, params); this.params = _.extend({}, this.params, params);
@ -34,7 +38,6 @@ export default class NamedQueryBase {
*/ */
doValidateParams(params) { doValidateParams(params) {
params = params || this.params; params = params || this.params;
params = _.omit(params, ...specialParameters);
const {validateParams} = this.options; const {validateParams} = this.options;
if (!validateParams) return; if (!validateParams) return;

View file

@ -2,7 +2,6 @@ import prepareForProcess from '../query/lib/prepareForProcess.js';
import Base from './namedQuery.base'; import Base from './namedQuery.base';
import deepClone from 'lodash.clonedeep'; import deepClone from 'lodash.clonedeep';
import MemoryResultCacher from './cache/MemoryResultCacher'; import MemoryResultCacher from './cache/MemoryResultCacher';
import generateQueryId from './cache/generateQueryId';
export default class extends Base { export default class extends Base {
/** /**
@ -23,8 +22,8 @@ export default class extends Base {
); );
if (this.cacher) { if (this.cacher) {
const cacheId = generateQueryId(this.queryName, this.params); const cacheId = this.cacher.generateQueryId(this.queryName, this.params);
return this.cacher.get(cacheId, {query}); return this.cacher.fetch(cacheId, {query});
} }
return query.fetch(); return query.fetch();
@ -50,9 +49,9 @@ export default class extends Base {
const countCursor = this.getCursorForCounting(); const countCursor = this.getCursorForCounting();
if (this.cacher) { if (this.cacher) {
const cacheId = 'count::' + generateQueryId(this.queryName, this.params); const cacheId = 'count::' + this.cacher.generateQueryId(this.queryName, this.params);
return this.cacher.get(cacheId, {countCursor}); return this.cacher.fetch(cacheId, {countCursor});
} }
return countCursor.count(); return countCursor.count();
@ -105,8 +104,8 @@ export default class extends Base {
}; };
if (this.cacher) { if (this.cacher) {
const cacheId = generateQueryId(this.queryName, this.params); const cacheId = this.cacher.generateQueryId(this.queryName, this.params);
return this.cacher.get(cacheId, {query}); return this.cacher.fetch(cacheId, {query});
} }
return query.fetch(); return query.fetch();

View file

@ -11,7 +11,7 @@ function hypernova(collectionNode, userId) {
}); });
} }
export default function hypernovaInit(collectionNode, userId, config = {bypassFirewalls: false}) { export default function hypernovaInit(collectionNode, userId, config = {bypassFirewalls: false, params: {}}) {
let {filters, options} = applyProps(collectionNode); let {filters, options} = applyProps(collectionNode);
const collection = collectionNode.collection; const collection = collectionNode.collection;
@ -21,7 +21,7 @@ export default function hypernovaInit(collectionNode, userId, config = {bypassFi
const userIdToPass = (config.bypassFirewalls) ? undefined : userId; const userIdToPass = (config.bypassFirewalls) ? undefined : userId;
hypernova(collectionNode, userIdToPass); hypernova(collectionNode, userIdToPass);
prepareForDelivery(collectionNode); prepareForDelivery(collectionNode, params);
return collectionNode.results; return collectionNode.results;
} }

View file

@ -81,6 +81,11 @@ export function createNodes(root) {
} }
} }
/**
* @param body
* @param fieldName
* @param root
*/
export function addFieldNode(body, fieldName, root) { export function addFieldNode(body, fieldName, root) {
// it's not a link and not a special variable => we assume it's a field // it's not a link and not a special variable => we assume it's a field
if (_.isObject(body)) { if (_.isObject(body)) {
@ -94,6 +99,11 @@ export function addFieldNode(body, fieldName, root) {
} }
} }
/**
* @param collection
* @param body
* @returns {CollectionNode}
*/
export default function (collection, body) { export default function (collection, body) {
let root = new CollectionNode(collection, body); let root = new CollectionNode(collection, body);
createNodes(root); createNodes(root);

View file

@ -7,9 +7,9 @@ import cleanReducerLeftovers from '../reducers/lib/cleanReducerLeftovers';
import sift from 'sift'; import sift from 'sift';
import {Minimongo} from 'meteor/minimongo'; import {Minimongo} from 'meteor/minimongo';
export default (node) => { export default (node, params) => {
snapBackCaches(node); snapBackCaches(node);
applyReducers(node); applyReducers(node, params);
cleanReducerLeftovers(node); cleanReducerLeftovers(node);
_.each(node.collectionNodes, collectionNode => { _.each(node.collectionNodes, collectionNode => {
@ -24,8 +24,7 @@ export default (node) => {
storeOneResults(node, node.results); storeOneResults(node, node.results);
applyPostFilters(node); applyPostFilters(node);
applyPostOptions(node); applyPostOptions(node);
applyPostFilter(node, params);
node.postFilter();
} }
export function applyPostFilters(node) { export function applyPostFilters(node) {
@ -50,6 +49,24 @@ export function applyPostOptions(node) {
} }
} }
/**
* Optionally applies a post filtering option
*/
function applyPostFilter(node, params) {
if (node.props.$postFilter) {
const filter = node.props.$postFilter;
if (_.isArray(filter)) {
filter.forEach(f => {
node.results = f(node.results, params);
})
} else {
node.results = filter(node.results, params);
}
}
}
export function removeLinkStorages(node, sameLevelResults) { export function removeLinkStorages(node, sameLevelResults) {
if (!sameLevelResults) { if (!sameLevelResults) {
return; return;

View file

@ -39,10 +39,10 @@ function fetch(node, parentObject) {
return results; return results;
} }
export default (node) => { export default (node, params) => {
node.results = fetch(node); node.results = fetch(node);
prepareForDelivery(node); prepareForDelivery(node, params);
return node.results; return node.results;
} }

View file

@ -201,23 +201,6 @@ export default class CollectionNode {
} }
} }
/**
* Optionally applies a post filtering option
*/
postFilter() {
if (this.props.$postFilter) {
const filter = this.props.$postFilter;
if (_.isArray(filter)) {
filter.forEach(f => {
this.results = f(this.results, this.params);
})
} else {
this.results = filter(this.results, this.params);
}
}
}
/** /**
* This method verifies whether to remove the linkStorageField form the results * This method verifies whether to remove the linkStorageField form the results
* unless you specify it in your query. * unless you specify it in your query.

View file

@ -2,6 +2,8 @@ import deepClone from 'lodash.clonedeep';
import {check} from 'meteor/check'; import {check} from 'meteor/check';
export default class QueryBase { export default class QueryBase {
isGlobalQuery = true;
constructor(collection, body, options = {}) { constructor(collection, body, options = {}) {
this.collection = collection; this.collection = collection;

View file

@ -181,7 +181,8 @@ export default class Query extends Base {
} }
return recursiveFetch( return recursiveFetch(
createGraph(this.collection, body) createGraph(this.collection, body),
this.params
); );
} }
} }

View file

@ -6,16 +6,16 @@ import Base from './query.base';
export default class Query extends Base { export default class Query extends Base {
/** /**
* Retrieves the data. * Retrieves the data.
* @param options * @param context
* @returns {*} * @returns {*}
*/ */
fetch(options = {}) { fetch(context = {}) {
const node = createGraph( const node = createGraph(
this.collection, this.collection,
prepareForProcess(this.body, this.params) prepareForProcess(this.body, this.params)
); );
return hypernova(node, options.userId); return hypernova(node, context.userId, {params: this.params});
} }
/** /**

View file

@ -1,11 +1,11 @@
export default function applyReducers(root) { export default function applyReducers(root, params) {
_.each(root.collectionNodes, node => { _.each(root.collectionNodes, node => {
applyReducers(node); applyReducers(node, params);
}); });
_.each(root.reducerNodes, reducerNode => { _.each(root.reducerNodes, reducerNode => {
root.results.forEach(result => { root.results.forEach(result => {
reducerNode.compute(result); reducerNode.compute(result, params);
}); });
}); });
} }

View file

@ -43,7 +43,9 @@ function cleanNestedFields(parts, results) {
if (parts.length === 1) { if (parts.length === 1) {
results.forEach(result => { results.forEach(result => {
delete result[fieldName]; if (fieldName !== '_id') {
delete result[fieldName];
}
}); });
return; return;
@ -54,7 +56,9 @@ function cleanNestedFields(parts, results) {
results.forEach(result => { results.forEach(result => {
if (_.keys(result[fieldName]).length === 0) { if (_.keys(result[fieldName]).length === 0) {
delete result[fieldName]; if (fieldName !== '_id') {
delete result[fieldName];
}
} }
}) })
} }

View file

@ -21,11 +21,6 @@ Posts.addLinks({
field: 'tagIds', field: 'tagIds',
index: true index: true
}, },
commentsCount: {
resolve(post) {
return Comments.find({postId: post._id}).count();
}
},
group: { group: {
type: 'one', type: 'one',
collection: Groups, collection: Groups,

View file

@ -276,20 +276,6 @@ describe('Hypernova', function () {
}) })
}); });
it('Should fetch Resolver links properly', function () {
const data = createQuery({
posts: {
$options: {limit: 5},
commentsCount: 1
}
}).fetch();
assert.lengthOf(data, 5);
_.each(data, post => {
assert.equal(6, post.commentsCount);
})
});
it('Should fetch in depth properly at any given level.', function () { it('Should fetch in depth properly at any given level.', function () {
const data = createQuery({ const data = createQuery({
authors: { authors: {