mirror of
https://github.com/vale981/grapher
synced 2025-03-05 17:41:41 -05:00
some small updates
This commit is contained in:
parent
4abcbe777d
commit
324e2b78fd
20 changed files with 125 additions and 102 deletions
5
lib/compose.js
Normal file
5
lib/compose.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import deepExtend from 'deep-extend';
|
||||||
|
|
||||||
|
export default function (...args) {
|
||||||
|
return deepExtend({}, ...args);
|
||||||
|
}
|
|
@ -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';
|
||||||
|
|
|
@ -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'};
|
||||||
|
|
||||||
|
|
39
lib/namedQuery/cache/BaseResultCacher.js
vendored
Normal file
39
lib/namedQuery/cache/BaseResultCacher.js
vendored
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
lib/namedQuery/cache/MemoryResultCacher.js
vendored
33
lib/namedQuery/cache/MemoryResultCacher.js
vendored
|
@ -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);
|
||||||
|
|
||||||
|
|
5
lib/namedQuery/cache/generateQueryId.js
vendored
5
lib/namedQuery/cache/generateQueryId.js
vendored
|
@ -1,5 +0,0 @@
|
||||||
import {EJSON} from 'meteor/ejson';
|
|
||||||
|
|
||||||
export default function(queryName, params) {
|
|
||||||
return `${queryName}::${EJSON.stringify(params)}`;
|
|
||||||
}
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -181,7 +181,8 @@ export default class Query extends Base {
|
||||||
}
|
}
|
||||||
|
|
||||||
return recursiveFetch(
|
return recursiveFetch(
|
||||||
createGraph(this.collection, body)
|
createGraph(this.collection, body),
|
||||||
|
this.params
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -43,7 +43,9 @@ function cleanNestedFields(parts, results) {
|
||||||
if (parts.length === 1) {
|
if (parts.length === 1) {
|
||||||
|
|
||||||
results.forEach(result => {
|
results.forEach(result => {
|
||||||
|
if (fieldName !== '_id') {
|
||||||
delete result[fieldName];
|
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) {
|
||||||
|
if (fieldName !== '_id') {
|
||||||
delete result[fieldName];
|
delete result[fieldName];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
Loading…
Add table
Reference in a new issue