mirror of
https://github.com/vale981/grapher
synced 2025-03-05 17:41:41 -05:00
Merge pull request #75 from cult-of-coders/feature/promisify-queries
[RFC] added support for promises and sync, added autoremove support from inversedSide + other small ones
This commit is contained in:
commit
82be9fc76e
11 changed files with 175 additions and 27 deletions
|
@ -1,3 +1,8 @@
|
|||
## 1.2.5
|
||||
- Support for promises via .fetchSync and .fetchOneSync for client-side queries
|
||||
- Support for autoremove from inverse side as well
|
||||
- Fixed .fetchOne from client-side Query
|
||||
|
||||
## 1.2.4
|
||||
- Fixed #55, #60, #61, #66
|
||||
- Added Reducers Concept
|
||||
|
|
|
@ -133,22 +133,28 @@ export default class Exposure {
|
|||
const config = this.config;
|
||||
const getTransformedBody = this.getTransformedBody.bind(this);
|
||||
|
||||
const methodBody = function(body) {
|
||||
if (!config.blocking) {
|
||||
this.unblock();
|
||||
}
|
||||
|
||||
let transformedBody = getTransformedBody(body);
|
||||
|
||||
const rootNode = createGraph(collection, transformedBody);
|
||||
|
||||
enforceMaxDepth(rootNode, config.maxDepth);
|
||||
restrictLinks(rootNode, this.userId);
|
||||
|
||||
// if there is no exposure body defined, then we need to apply firewalls
|
||||
return hypernova(rootNode, this.userId, {
|
||||
bypassFirewalls: !!config.body
|
||||
});
|
||||
};
|
||||
|
||||
Meteor.methods({
|
||||
[this.name](body) {
|
||||
if (!config.blocking) {
|
||||
this.unblock();
|
||||
}
|
||||
|
||||
let transformedBody = getTransformedBody(body);
|
||||
|
||||
const rootNode = createGraph(collection, transformedBody);
|
||||
enforceMaxDepth(rootNode, config.maxDepth);
|
||||
|
||||
restrictLinks(rootNode, this.userId);
|
||||
|
||||
return hypernova(rootNode, this.userId, {
|
||||
bypassFirewalls: !!config.body
|
||||
});
|
||||
[this.name]: methodBody,
|
||||
[this.name + '_async']: async function(...args) {
|
||||
return methodBody.call(this, ...args);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -61,6 +61,10 @@ _.extend(Mongo.Collection.prototype, {
|
|||
} else {
|
||||
object = {_id: objectOrId};
|
||||
}
|
||||
|
||||
if (!object) {
|
||||
throw new Meteor.Error(`We could not find any object with _id: "${objectOrId}" within the collection: ${this._name}`);
|
||||
}
|
||||
}
|
||||
|
||||
return linkData[name].createLink(object);
|
||||
|
|
|
@ -24,12 +24,18 @@ export default class Linker {
|
|||
this._validateAndClean();
|
||||
this._extendSchema();
|
||||
|
||||
// if it's a virtual field make sure that when this is deleted, it will be removed from the references
|
||||
// initialize cascade removal hooks.
|
||||
if (linkConfig.autoremove) {
|
||||
this._initAutoremove();
|
||||
}
|
||||
|
||||
if (this.isVirtual()) {
|
||||
this._handleReferenceRemovalForVirtualLinks();
|
||||
// if it's a virtual field make sure that when this is deleted, it will be removed from the references
|
||||
if (!linkConfig.autoremove) {
|
||||
this._handleReferenceRemovalForVirtualLinks();
|
||||
}
|
||||
} else {
|
||||
this._initIndex();
|
||||
this._initAutoremove();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -343,7 +349,7 @@ export default class Linker {
|
|||
}
|
||||
|
||||
_initAutoremove() {
|
||||
if (this.linkConfig.autoremove) {
|
||||
if (!this.isVirtual()) {
|
||||
this.mainCollection.after.remove((userId, doc) => {
|
||||
this.getLinkedCollection().remove({
|
||||
_id: {
|
||||
|
@ -351,6 +357,15 @@ export default class Linker {
|
|||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
this.mainCollection.after.remove((userId, doc) => {
|
||||
const linker = this.mainCollection.getLink(doc, this.linkName);
|
||||
const ids = linker.find({}, {fields: {_id: 1}}).fetch().map(item => item._id);
|
||||
|
||||
this.getLinkedCollection().remove({
|
||||
_id: {$in: ids}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
|
@ -36,6 +36,11 @@ PostCollection.addLinks({
|
|||
field: 'autoRemoveIds',
|
||||
autoremove: true
|
||||
},
|
||||
'autoRemovingSelfComments': {
|
||||
type: '*',
|
||||
collection: CommentCollection,
|
||||
field: 'autoRemovingSelfCommentsIds',
|
||||
},
|
||||
'metaComments': {
|
||||
type: '*',
|
||||
collection: CommentCollection,
|
||||
|
@ -69,6 +74,11 @@ CommentCollection.addLinks({
|
|||
collection: PostCollection,
|
||||
inversedBy: 'comments'
|
||||
},
|
||||
autoRemovePosts: {
|
||||
collection: PostCollection,
|
||||
inversedBy: 'autoRemovingSelfComments',
|
||||
autoremove: true
|
||||
},
|
||||
metaPost: {
|
||||
collection: PostCollection,
|
||||
inversedBy: 'metaComments'
|
||||
|
@ -344,5 +354,34 @@ describe('Collection Links', function () {
|
|||
assert.equal(e.error, 'not-found');
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('Should work with autoremoval from inversed and direct link', function () {
|
||||
// autoremoval from direct side
|
||||
let postId = PostCollection.insert({text: 'autoremove'});
|
||||
const postAutoRemoveCommentsLink = PostCollection.getLink(postId, 'autoRemoveComments');
|
||||
|
||||
postAutoRemoveCommentsLink.add({text: 'hello'});
|
||||
|
||||
assert.lengthOf(postAutoRemoveCommentsLink.find().fetch(), 1);
|
||||
let commentId = postAutoRemoveCommentsLink.find().fetch()[0]._id;
|
||||
|
||||
assert.isObject(CommentCollection.findOne(commentId));
|
||||
PostCollection.remove(postId);
|
||||
assert.isUndefined(CommentCollection.findOne(commentId));
|
||||
|
||||
|
||||
// now from inversed side
|
||||
commentId = CommentCollection.insert({text: 'autoremove'});
|
||||
|
||||
const commentAutoRemovePostsLink = CommentCollection.getLink(commentId, 'autoRemovePosts');
|
||||
commentAutoRemovePostsLink.add({text: 'Hello'});
|
||||
|
||||
assert.lengthOf(commentAutoRemovePostsLink.find().fetch(), 1);
|
||||
postId = commentAutoRemovePostsLink.find().fetch()[0]._id;
|
||||
|
||||
assert.isObject(PostCollection.findOne(postId));
|
||||
CommentCollection.remove(commentId);
|
||||
assert.isUndefined(PostCollection.findOne(postId));
|
||||
})
|
||||
});
|
|
@ -1,6 +1,8 @@
|
|||
import createGraph from '../query/lib/createGraph.js';
|
||||
import recursiveFetch from '../query/lib/recursiveFetch.js';
|
||||
import prepareForProcess from '../query/lib/prepareForProcess.js';
|
||||
import { _ } from 'meteor/underscore';
|
||||
import callWithPromise from '../query/lib/callWithPromise';
|
||||
import Base from './namedQuery.base';
|
||||
|
||||
export default class extends Base {
|
||||
|
@ -31,6 +33,26 @@ export default class extends Base {
|
|||
this.subscriptionHandle = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches elements in sync using promises
|
||||
* @return {*}
|
||||
*/
|
||||
async fetchSync() {
|
||||
if (this.subscriptionHandle) {
|
||||
throw new Meteor.Error('This query is reactive, meaning you cannot use promises to fetch the data.');
|
||||
}
|
||||
|
||||
return await callWithPromise(this.name + '_async', prepareForProcess(this.body, this.params));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches one element in sync
|
||||
* @return {*}
|
||||
*/
|
||||
async fetchOneSync() {
|
||||
return _.first(await this.fetchSync())
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the data.
|
||||
* @param callbackOrOptions
|
||||
|
|
9
lib/query/lib/callWithPromise.js
Normal file
9
lib/query/lib/callWithPromise.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
export default (method, myParameters) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
Meteor.call(method, myParameters, (err, res) => {
|
||||
if (err) reject(err.reason || 'Something went wrong.');
|
||||
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
};
|
|
@ -1,7 +1,8 @@
|
|||
import { _ } from 'meteor/underscore';
|
||||
import createGraph from './lib/createGraph.js';
|
||||
import recursiveFetch from './lib/recursiveFetch.js';
|
||||
import prepareForProcess from './lib/prepareForProcess.js';
|
||||
import deepClone from './lib/deepClone.js';
|
||||
import callWithPromise from './lib/callWithPromise';
|
||||
import Base from './query.base';
|
||||
|
||||
export default class Query extends Base {
|
||||
|
@ -32,6 +33,26 @@ export default class Query extends Base {
|
|||
this.subscriptionHandle = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches elements in sync using promises
|
||||
* @return {*}
|
||||
*/
|
||||
async fetchSync() {
|
||||
if (this.subscriptionHandle) {
|
||||
throw new Meteor.Error('This query is reactive, meaning you cannot use promises to fetch the data.');
|
||||
}
|
||||
|
||||
return await callWithPromise(this.name + '_async', prepareForProcess(this.body, this.params));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches one element in sync
|
||||
* @return {*}
|
||||
*/
|
||||
async fetchOneSync() {
|
||||
return _.first(await this.fetchSync())
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the data.
|
||||
* @param callbackOrOptions
|
||||
|
@ -45,6 +66,14 @@ export default class Query extends Base {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param args
|
||||
* @returns {*}
|
||||
*/
|
||||
fetchOne(...args) {
|
||||
return _.first(this.fetch(...args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the count of matching elements.
|
||||
* @param callback
|
||||
|
|
|
@ -186,4 +186,29 @@ describe('Query Client Tests', function () {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('Should work with promises', async function () {
|
||||
let query = createQuery({
|
||||
groups: {
|
||||
posts: {
|
||||
title: 1
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let result = await query.fetchSync();
|
||||
|
||||
assert.isArray(result);
|
||||
assert.isTrue(result.length > 0);
|
||||
result.forEach(item => {
|
||||
assert.isArray(item.posts);
|
||||
assert.isTrue(item.posts.length > 0);
|
||||
});
|
||||
|
||||
result = await query.fetchOneSync();
|
||||
|
||||
assert.isObject(result);
|
||||
assert.isString(result._id);
|
||||
assert.isArray(result.posts);
|
||||
})
|
||||
});
|
|
@ -5,12 +5,6 @@ import './lib/query/reducers/extension.js';
|
|||
import './lib/namedQuery/expose/extension.js';
|
||||
import './lib/namedQuery/extension.js';
|
||||
|
||||
import { checkNpmVersions } from 'meteor/tmeasday:check-npm-versions';
|
||||
|
||||
checkNpmVersions({
|
||||
'sift': '3.2.x'
|
||||
}, 'cultofcoders:grapher');
|
||||
|
||||
export {
|
||||
default as createQuery
|
||||
} from './lib/query/createQuery.js';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Package.describe({
|
||||
name: 'cultofcoders:grapher',
|
||||
version: '1.2.4',
|
||||
version: '1.2.5',
|
||||
// Brief, one-line summary of the package.
|
||||
summary: 'Grapher makes linking collections easily. And fetching data as a graph.',
|
||||
// URL to the Git repository containing the source code for this package.
|
||||
|
|
Loading…
Add table
Reference in a new issue