Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite client side date converter to handle nesting #2465

Merged
merged 4 commits into from Dec 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/vulcan-core/lib/modules/containers/multi2.js
Expand Up @@ -107,7 +107,7 @@ const buildResult = (
) => {
//console.log('returnedProps', returnedProps);
const { refetch, networkStatus, error, fetchMore, data } = returnedProps;
// results = Utils.convertDates(collection, props.data[listResolverName]),
// Note: Scalar types like Dates are NOT converted. It should be done at the UI level.
const results = data && data[resolverName] && data[resolverName].results;
const totalCount = data && data[resolverName] && data[resolverName].totalCount;
// see https://github.com/apollographql/apollo-client/blob/master/packages/apollo-client/src/core/networkStatus.ts
Expand Down Expand Up @@ -153,7 +153,7 @@ const buildResult = (
const newInput = providedInput || {
...paginationInput,
offset: results.length,
}
};

return fetchMore({
variables: { input: newInput },
Expand Down
2 changes: 1 addition & 1 deletion packages/vulcan-core/lib/modules/containers/single2.js
Expand Up @@ -78,7 +78,7 @@ const buildResult = (
const propertyName = options.propertyName || 'document';
const props = {
...returnedProps,
// document: Utils.convertDates(collection, data[singleResolverName]),
// Note: Scalar types like Dates are NOT converted. It should be done at the UI level.
[propertyName]: data && data[resolverName] && data[resolverName].result,
fragmentName,
fragment,
Expand Down
7 changes: 7 additions & 0 deletions packages/vulcan-lib/lib/modules/simpleSchema_utils.js
Expand Up @@ -22,6 +22,13 @@ export const hasAllowedValues = field => {

export const isBlackbox = (field) => field.type.definitions[0].blackbox;

export const getFieldType = field => field.type.singleType;
export const getFieldTypeName = fieldType =>
typeof fieldType === 'object'
? 'Object'
: typeof fieldType === 'function'
? fieldType.name
: fieldType;

export const getArrayChild = (fieldName, schema) => schema[`${fieldName}.$`];

Expand Down
26 changes: 15 additions & 11 deletions packages/vulcan-lib/lib/modules/utils.js
Expand Up @@ -15,6 +15,8 @@ import set from 'lodash/set';
import get from 'lodash/get';
import isFunction from 'lodash/isFunction';
import pluralize from 'pluralize';
import { getFieldType } from './simpleSchema_utils';
import { forEachDocumentField } from './schema_utils';

registerSetting('debug', false, 'Enable debug mode (more verbose logging)');

Expand Down Expand Up @@ -452,21 +454,23 @@ Utils.getComponentDisplayName = WrappedComponent => {
*/
Utils.convertDates = (collection, listOrDocument) => {
// if undefined, just return
if (!listOrDocument || !listOrDocument.length) return listOrDocument;

const list = Array.isArray(listOrDocument) ? listOrDocument : [listOrDocument];
if (!listOrDocument) return listOrDocument;
const isArray = listOrDocument && Array.isArray(listOrDocument);
if (isArray && !listOrDocument.length) return listOrDocument;
const list = isArray ? listOrDocument : [listOrDocument];
const schema = collection.simpleSchema()._schema;
const dateFields = _.filter(_.keys(schema), fieldName => schema[fieldName].type === Date);
const convertedList = list.map(result => {
dateFields.forEach(fieldName => {
if (result[fieldName] && typeof result[fieldName] === 'string') {
result[fieldName] = new Date(result[fieldName]);
//Nested version
const convertedList = list.map((document) => {
forEachDocumentField(document, schema, ({ fieldName, fieldSchema, currentPath }) => {
if (fieldSchema && getFieldType(fieldSchema) === Date) {
const valuePath = `${currentPath}${fieldName}`;
const value = get(document, valuePath);
set(document, valuePath, new Date(value));
}
});
return result;
return document;
});

return Array.isArray(listOrDocument) ? convertedList : convertedList[0];
return isArray ? convertedList : convertedList[0];
};

Utils.encodeIntlError = error => (typeof error !== 'object' ? error : JSON.stringify(error));
Expand Down
9 changes: 1 addition & 8 deletions packages/vulcan-lib/lib/server/graphql/schemaFields.js
Expand Up @@ -240,7 +240,7 @@ export const getSchemaFields = (schema, typeName) => {
*/
/* eslint-disable no-console */
import { isIntlField } from '../../modules/intl.js';
import { isBlackbox, unarrayfyFieldName, getArrayChild, getNestedSchema } from '../../modules/simpleSchema_utils';
import { isBlackbox, unarrayfyFieldName, getFieldType, getFieldTypeName, getArrayChild, getNestedSchema } from '../../modules/simpleSchema_utils';
import { shouldAddOriginalField } from '../../modules/schema_utils';
import relations from './relations.js';

Expand All @@ -255,13 +255,6 @@ export const getNestedGraphQLType = (typeName, fieldName, isInput) =>
`${typeName}${capitalize(unarrayfyFieldName(fieldName))}${isInput ? 'Input' : ''}`;


const getFieldType = field => field.type.singleType;
const getFieldTypeName = fieldType =>
typeof fieldType === 'object'
? 'Object'
: typeof fieldType === 'function'
? fieldType.name
: fieldType;

// get GraphQL type for a given schema and field name
export const getGraphQLType = ({ schema, fieldName, typeName, isInput = false }) => {
Expand Down
73 changes: 63 additions & 10 deletions packages/vulcan-lib/test/utils.test.js
@@ -1,12 +1,14 @@
import { Utils } from '../lib/modules/utils';
import expect from 'expect';
import { createDummyCollection } from "meteor/vulcan:test"
import SimpleSchema from "simpl-schema"


describe('vulcan:lib/utils', function () {

const collection = {
findOne: function ({ slug }) {
switch(slug) {
switch (slug) {
case 'duplicate-name':
return {
_id: 'duplicate-name',
Expand Down Expand Up @@ -36,45 +38,96 @@ describe('vulcan:lib/utils', function () {
}
}
};

it('returns the same slug when there are no conflicts', function () {
const slug = 'unique-name';
const unusedSlug = Utils.getUnusedSlug(collection, slug);

expect(unusedSlug).toEqual(slug);
});

it('appends integer to slug when there is a conflict', function () {
const slug = 'duplicate-name';
const unusedSlug = Utils.getUnusedSlug(collection, slug);

expect(unusedSlug).toEqual(slug + '-1');
});

it('appends incremented integer to slug when there is a conflict', function () {
const slug = 'triplicate-name';
const unusedSlug = Utils.getUnusedSlug(collection, slug);

expect(unusedSlug).toEqual(slug + '-2');
});

it('returns the same slug when the conflict has the same _id', function () {
// This tests the case where a document is renamed, but its slug remains the same
// For example 'RENAMED NAME' is changed to 'Renamed name'; the slug should not increment
const slug = 'renamed-name';
const documentId = 'renamed-name';
const unusedSlug = Utils.getUnusedSlug(collection, slug, documentId);

expect(unusedSlug).toEqual(slug);
});

it('appends integer to slug when the conflict has the same _id, but it’s not passed to getUnusedSlug', function () {
// This tests the case where a document is renamed, but its slug remains the same
// For example 'RENAMED NAME' is changed to 'Renamed name'; the slug should not increment
const slug = 'renamed-name';
const unusedSlug = Utils.getUnusedSlug(collection, slug);

expect(unusedSlug).toEqual(slug + '-1');
});



describe("convertDates", () => {
it("convert date string to object", () => {
const Dummies = createDummyCollection({
schema: {
begin: {
type: Date,
}
}
})
const now = new Date()
const res = Utils.convertDates(Dummies, { begin: now.toISOString() })
expect(res.begin).toBeInstanceOf(Date)
})
it("convert date string in nested objects", () => {
const Dummies = createDummyCollection({
schema: {
nested: {
type: new SimpleSchema({
begin: {
type: Date,
}
})
}
}
})
const now = new Date()
const res = Utils.convertDates(Dummies, { nested: { begin: now.toISOString() } })
expect(res.nested.begin).toBeInstanceOf(Date)

})
it("convert date string in arrays of nested objects", () => {
const Dummies = createDummyCollection({
schema: {
array: {
type: Array,
},
"array.$": {
type: new SimpleSchema({
begin: {
type: Date,
}
})
}
}
})
const now = new Date()
const res = Utils.convertDates(Dummies, { array: [{ begin: now.toISOString() }] })
expect(res.array[0].begin).toBeInstanceOf(Date)
})
})
});