Skip to content

Commit 8ee44b3

Browse files
davidpicarranodkz
authored andcommitted
feat(toMongoDottedObject): convert arrays without using element index
* feat: convert inner array without using element index * feat: add toMongoFilterDottedObject and keep toMongoDottedObject
1 parent a824ef5 commit 8ee44b3

File tree

7 files changed

+120
-28
lines changed

7 files changed

+120
-28
lines changed

src/resolvers/helpers/filter.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import type { TypeComposer, ComposeFieldConfigArgumentMap } from 'graphql-compose';
55
import type { MongooseModel } from 'mongoose';
66
import GraphQLMongoID from '../../types/mongoid';
7-
import { isObject, toMongoDottedObject, getIndexedFieldNamesForGraphQL } from '../../utils';
7+
import { isObject, toMongoFilterDottedObject, getIndexedFieldNamesForGraphQL } from '../../utils';
88
import type { ExtendedResolveParams } from '../index';
99
import {
1010
type FilterOperatorsOpts,
@@ -112,7 +112,7 @@ export function filterHelper(resolveParams: ExtendedResolveParams): void {
112112
});
113113
if (Object.keys(clearedFilter).length > 0) {
114114
// eslint-disable-next-line
115-
resolveParams.query = resolveParams.query.where(toMongoDottedObject(clearedFilter));
115+
resolveParams.query = resolveParams.query.where(toMongoFilterDottedObject(clearedFilter));
116116
}
117117

118118
processFilterOperators(filter, resolveParams);

src/resolvers/updateMany.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
sortHelper,
1515
sortHelperArgs,
1616
} from './helpers';
17-
import toMongoDottedObject from '../utils/toMongoDottedObject';
17+
import { toMongoDottedObject } from '../utils/toMongoDottedObject';
1818
import type { ExtendedResolveParams, GenResolverOpts } from './index';
1919

2020
export default function updateMany(

src/utils/__tests__/toMongoDottedObject-test.js

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* @flow */
22

33
import { Types } from 'mongoose';
4-
import toMongoDottedObject from '../toMongoDottedObject';
4+
import { toMongoDottedObject, toMongoFilterDottedObject } from '../toMongoDottedObject';
55

66
describe('toMongoDottedObject()', () => {
77
it('should dot nested objects', () => {
@@ -51,4 +51,62 @@ describe('toMongoDottedObject()', () => {
5151
'a.someField': id,
5252
});
5353
});
54+
55+
it('should dot array without index', () => {
56+
expect(toMongoDottedObject({ a: [{ b: 1 }, { c: 2 }] })).toEqual({ 'a.0.b': 1, 'a.1.c': 2 });
57+
});
58+
});
59+
60+
describe('toMongoFilterDottedObject()', () => {
61+
it('should dot nested objects', () => {
62+
expect(toMongoFilterDottedObject({ a: { b: { c: 1 } } })).toEqual({ 'a.b.c': 1 });
63+
});
64+
65+
it('should not dot query operators started with $', () => {
66+
expect(toMongoFilterDottedObject({ a: { $in: [1, 2, 3] } })).toEqual({
67+
a: { $in: [1, 2, 3] },
68+
});
69+
expect(toMongoFilterDottedObject({ a: { b: { $in: [1, 2, 3] } } })).toEqual({
70+
'a.b': { $in: [1, 2, 3] },
71+
});
72+
expect(toMongoFilterDottedObject({ $or: [{ age: 1 }, { age: 2 }] })).toEqual({
73+
$or: [{ age: 1 }, { age: 2 }],
74+
});
75+
});
76+
77+
it('should mix query operators started with $', () => {
78+
expect(toMongoFilterDottedObject({ a: { $in: [1, 2, 3], $exists: true } })).toEqual({
79+
a: { $in: [1, 2, 3], $exists: true },
80+
});
81+
});
82+
83+
it('should not mix query operators started with $ and regular fields', () => {
84+
expect(toMongoFilterDottedObject({ a: { $exists: true, b: 3 } })).toEqual({
85+
a: { $exists: true },
86+
'a.b': 3,
87+
});
88+
});
89+
90+
it('should handle date object values as scalars', () => {
91+
expect(toMongoFilterDottedObject({ dateField: new Date(100) })).toEqual({
92+
dateField: new Date(100),
93+
});
94+
});
95+
96+
it('should handle date object values when nested', () => {
97+
expect(toMongoFilterDottedObject({ a: { dateField: new Date(100) } })).toEqual({
98+
'a.dateField': new Date(100),
99+
});
100+
});
101+
102+
it('should keep BSON ObjectId untouched', () => {
103+
const id = new Types.ObjectId();
104+
expect(toMongoFilterDottedObject({ a: { someField: id } })).toEqual({
105+
'a.someField': id,
106+
});
107+
});
108+
109+
it('should dot array without index', () => {
110+
expect(toMongoFilterDottedObject({ a: [{ b: 1 }, { c: 2 }] })).toEqual({ 'a.b': 1, 'a.c': 2 });
111+
});
54112
});

src/utils/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export { isObject, upperFirst } from 'graphql-compose';
2-
export { default as toMongoDottedObject } from './toMongoDottedObject';
2+
export { toMongoDottedObject, toMongoFilterDottedObject } from './toMongoDottedObject';
33
export * from './getIndexesFromModel';

src/utils/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* @flow */
22

33
import { isObject, upperFirst } from 'graphql-compose';
4-
import toMongoDottedObject from './toMongoDottedObject';
4+
import { toMongoDottedObject, toMongoFilterDottedObject } from './toMongoDottedObject';
55

6-
export { toMongoDottedObject, isObject, upperFirst };
6+
export { toMongoDottedObject, toMongoFilterDottedObject, isObject, upperFirst };
77
export * from './getIndexesFromModel';

src/utils/toMongoDottedObject.d.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
export default function toMongoDottedObject(
1+
export function toMongoDottedObject(
2+
obj: object,
3+
target?: object,
4+
path?: string[],
5+
): { [dottedPath: string]: any };
6+
7+
export function toMongoFilterDottedObject(
28
obj: object,
39
target?: object,
410
path?: string[],

src/utils/toMongoDottedObject.js

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,7 @@ import { Types } from 'mongoose';
44

55
const ObjectId = Types.ObjectId;
66

7-
/**
8-
* Convert object to dotted-key/value pair
9-
* { a: { b: { c: 1 }}} -> { 'a.b.c': 1 }
10-
* { a: { $in: [ 1, 2, 3] }} -> { 'a': { $in: [ 1, 2, 3] } }
11-
* { a: { b: { $in: [ 1, 2, 3] }}} -> { 'a.b': { $in: [ 1, 2, 3] } }
12-
* Usage:
13-
* var dotObject(obj)
14-
* or
15-
* var target = {}; dotObject(obj, target)
16-
*
17-
* @param {Object} obj source object
18-
* @param {Object} target target object
19-
* @param {Array} path path array (internal)
20-
*/
21-
export default function toMongoDottedObject(
22-
obj: Object,
23-
target?: Object = {},
24-
path?: string[] = []
25-
): { [dottedPath: string]: mixed } {
7+
function _toMongoDottedObject(obj, target = {}, path = [], filter = false) {
268
const objKeys = Object.keys(obj);
279

2810
/* eslint-disable */
@@ -37,7 +19,7 @@ export default function toMongoDottedObject(
3719
};
3820
}
3921
} else if (Object(obj[key]) === obj[key] && !(obj[key] instanceof ObjectId)) {
40-
toMongoDottedObject(obj[key], target, path.concat(key));
22+
_toMongoDottedObject(obj[key], target, Array.isArray(obj) && filter ? path : path.concat(key), filter);
4123
} else {
4224
target[path.concat(key).join('.')] = obj[key];
4325
}
@@ -50,3 +32,49 @@ export default function toMongoDottedObject(
5032
return target;
5133
/* eslint-enable */
5234
}
35+
36+
/**
37+
* Convert object to dotted-key/value pair
38+
* { a: { b: { c: 1 }}} -> { 'a.b.c': 1 }
39+
* { a: { $in: [ 1, 2, 3] }} -> { 'a': { $in: [ 1, 2, 3] } }
40+
* { a: { b: { $in: [ 1, 2, 3] }}} -> { 'a.b': { $in: [ 1, 2, 3] } }
41+
* { a: [ { b: 1 }, { c: 2 }]} -> { 'a.0.b': 1, 'a.1.c': 2 }
42+
* Usage:
43+
* var toMongoDottedObject(obj)
44+
* or
45+
* var target = {}; toMongoDottedObject(obj, target)
46+
*
47+
* @param {Object} obj source object
48+
* @param {Object} target target object
49+
* @param {Array} path path array (internal)
50+
*/
51+
export function toMongoDottedObject(
52+
obj: Object,
53+
target?: Object = {},
54+
path?: string[] = []
55+
): { [dottedPath: string]: mixed } {
56+
return _toMongoDottedObject(obj, target, path);
57+
}
58+
59+
/**
60+
* Convert object to dotted-key/value pair
61+
* { a: { b: { c: 1 }}} -> { 'a.b.c': 1 }
62+
* { a: { $in: [ 1, 2, 3] }} -> { 'a': { $in: [ 1, 2, 3] } }
63+
* { a: { b: { $in: [ 1, 2, 3] }}} -> { 'a.b': { $in: [ 1, 2, 3] } }
64+
* { a: [ { b: 1 }, { c: 2 }]} -> { 'a.b': 1, 'a.c': 2 }
65+
* Usage:
66+
* var toMongoFilterDottedObject(obj)
67+
* or
68+
* var target = {}; toMongoFilterDottedObject(obj, target)
69+
*
70+
* @param {Object} obj source object
71+
* @param {Object} target target object
72+
* @param {Array} path path array (internal)
73+
*/
74+
export function toMongoFilterDottedObject(
75+
obj: Object,
76+
target?: Object = {},
77+
path?: string[] = []
78+
): { [dottedPath: string]: mixed } {
79+
return _toMongoDottedObject(obj, target, path, true);
80+
}

0 commit comments

Comments
 (0)