Handle deeply nested fields inside links in the query and handle cleaning reducer leftovers for snapCache fields

This commit is contained in:
Berislav 2018-06-12 13:27:06 +02:00
parent b49c168fe8
commit 4cdcbea195
7 changed files with 48 additions and 6 deletions

3
lib/query/hypernova/buildAggregatePipeline.js Normal file → Executable file
View file

@ -1,4 +1,5 @@
import { _ } from 'meteor/underscore';
import {SAFE_DOTTED_FIELD_REPLACEMENT} from './constants';
export default function (childCollectionNode, filters, options, userId) {
let containsDottedFields = false;
@ -31,7 +32,7 @@ export default function (childCollectionNode, filters, options, userId) {
if (field.indexOf('.') >= 0) {
containsDottedFields = true;
}
const safeField = field.replace('.', '___');
const safeField = field.replace(/\./g, SAFE_DOTTED_FIELD_REPLACEMENT);
dataPush[safeField] = '$' + field
});

2
lib/query/hypernova/lib/snapBackDottedFields.js Normal file → Executable file
View file

@ -6,7 +6,7 @@ export default function (aggregationResult) {
result.data = result.data.map(document => {
_.each(document, (value, key) => {
if (key.indexOf(SAFE_DOTTED_FIELD_REPLACEMENT) >= 0) {
document[key.replace(SAFE_DOTTED_FIELD_REPLACEMENT, '.')] = value;
document[key.replace(new RegExp(SAFE_DOTTED_FIELD_REPLACEMENT, 'g'), '.')] = value;
delete document[key];
}
});

View file

@ -1,3 +1,5 @@
import dot from 'dot-object';
/**
* @param root
*/
@ -16,7 +18,7 @@ export default function cleanReducerLeftovers(root) {
_.each(root.fieldNodes, node => {
if (node.scheduledForDeletion) {
cleanNestedFields(node.name.split('.'), root.results);
cleanNestedFields(node.name.split('.'), root.results, root);
}
});
@ -38,8 +40,10 @@ export default function cleanReducerLeftovers(root) {
* @param parts
* @param results
*/
function cleanNestedFields(parts, results) {
const fieldName = parts[0];
function cleanNestedFields(parts, results, root) {
const snapCacheField = root.snapCaches[parts[0]];
const fieldName = snapCacheField ? snapCacheField : parts[0];
if (parts.length === 1) {
results.forEach(result => {
@ -52,7 +56,7 @@ function cleanNestedFields(parts, results) {
}
parts.shift();
cleanNestedFields(parts, results.map(result => result[fieldName]));
cleanNestedFields(parts, results.map(result => result[fieldName]), root);
results.forEach(result => {
if (_.isObject(result[fieldName]) && _.keys(result[fieldName]).length === 0) {

View file

@ -94,6 +94,10 @@ Authors.addReducers({
posts: {
authorCached: {
name: 1,
// this tests cleanReducerLeftovers for snapCache fields
profile: {
lastName: 1,
}
},
metadata: {
keywords: 1

View file

@ -55,6 +55,9 @@ _.each(authors, (author) => {
title: `User Post - ${idx}`,
metadata: {
keywords: _.sample(TAGS, _.random(1, 2)),
language: {
..._.sample([{abbr: 'en', title: 'English'}, {abbr: 'de', title: 'Deutsch'}]),
}
},
createdAt: new Date(),
};

View file

@ -256,6 +256,8 @@ describe('Reducers', function() {
*
* This necessitates the use of embedReducerWithLink() function while creating reducers,
* which was failing for denormalized fields and also for nested fields.
*
* Also, the commentsReducer2 uses nested item in the body, profile: {lastName: 1}
*/
const query = createQuery({
authors: {

View file

@ -1,4 +1,5 @@
import { createQuery } from 'meteor/cultofcoders:grapher';
import dot from 'dot-object';
import Comments from './bootstrap/comments/collection.js';
import './metaFilters.server.test';
import './reducers.server.test';
@ -568,4 +569,31 @@ describe('Hypernova', function() {
assert.isArray(user.restaurants);
assert.lengthOf(user.restaurants, 1);
});
it('Should fetch deeply nested fields inside links', function() {
const query = createQuery({
authors: {
posts: {
metadata: {
language: {
abbr: 1,
}
}
}
}
});
const data = query.fetch();
assert.isTrue(data.length > 0);
data.forEach(author => {
author.posts.forEach(post => {
assert.isObject(post.metadata);
assert.isObject(post.metadata.language);
assert.isDefined(post.metadata.language.abbr);
});
});
});
});