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 { _ } from 'meteor/underscore';
import {SAFE_DOTTED_FIELD_REPLACEMENT} from './constants';
export default function (childCollectionNode, filters, options, userId) { export default function (childCollectionNode, filters, options, userId) {
let containsDottedFields = false; let containsDottedFields = false;
@ -31,7 +32,7 @@ export default function (childCollectionNode, filters, options, userId) {
if (field.indexOf('.') >= 0) { if (field.indexOf('.') >= 0) {
containsDottedFields = true; containsDottedFields = true;
} }
const safeField = field.replace('.', '___'); const safeField = field.replace(/\./g, SAFE_DOTTED_FIELD_REPLACEMENT);
dataPush[safeField] = '$' + field 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 => { result.data = result.data.map(document => {
_.each(document, (value, key) => { _.each(document, (value, key) => {
if (key.indexOf(SAFE_DOTTED_FIELD_REPLACEMENT) >= 0) { 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]; delete document[key];
} }
}); });

View file

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

View file

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

View file

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

View file

@ -256,6 +256,8 @@ describe('Reducers', function() {
* *
* This necessitates the use of embedReducerWithLink() function while creating reducers, * This necessitates the use of embedReducerWithLink() function while creating reducers,
* which was failing for denormalized fields and also for nested fields. * 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({ const query = createQuery({
authors: { authors: {

View file

@ -1,4 +1,5 @@
import { createQuery } from 'meteor/cultofcoders:grapher'; import { createQuery } from 'meteor/cultofcoders:grapher';
import dot from 'dot-object';
import Comments from './bootstrap/comments/collection.js'; import Comments from './bootstrap/comments/collection.js';
import './metaFilters.server.test'; import './metaFilters.server.test';
import './reducers.server.test'; import './reducers.server.test';
@ -568,4 +569,31 @@ describe('Hypernova', function() {
assert.isArray(user.restaurants); assert.isArray(user.restaurants);
assert.lengthOf(user.restaurants, 1); 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);
});
});
});
}); });