Skip to content

Commit

Permalink
Fix findByFields for nested fields
Browse files Browse the repository at this point in the history
  • Loading branch information
lorensr committed Sep 4, 2021
1 parent b589d16 commit a35bba8
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 8 deletions.
19 changes: 17 additions & 2 deletions src/__tests__/cache.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,22 @@ import {
import { log } from '../helpers'

const hexId = '5cf82e14a220a607eb64a7d4'
const objectID = ObjectId(hexId)

const docs = {
one: {
_id: ObjectId(hexId),
_id: objectID,
foo: 'bar',
tags: ['foo', 'bar']
},
two: {
_id: ObjectId(),
foo: 'bar'
},
three: {
nested: {
_id: objectID
}
}
}

Expand Down Expand Up @@ -150,14 +156,23 @@ describe('createCachingMethods', () => {
})

it('finds by ObjectID field', async () => {
const foundDocs = await api.findByFields({ _id: ObjectId(hexId) })
const foundDocs = await api.findByFields({ _id: objectID })

expect(foundDocs[0]).toBe(docs.one)
expect(foundDocs.length).toBe(1)

expect(collection.find.mock.calls.length).toBe(1)
})

// it('finds by nested ObjectID field', async () => {
// const foundDocs = await api.findByFields({ 'nested._id': objectID })

// expect(foundDocs[0]).toBe(docs.three)
// expect(foundDocs.length).toBe(1)

// expect(collection.find.mock.calls.length).toBe(1)
// })

it('finds by array field', async () => {
const foundDocs = await api.findByFields({ tags: 'bar' })

Expand Down
26 changes: 24 additions & 2 deletions src/__tests__/datasource.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MongoClient } from 'mongodb'
import { MongoClient, ObjectId } from 'mongodb'
import mongoose, { Schema, model } from 'mongoose'

import { MongoDataSource } from '../datasource'
Expand All @@ -25,7 +25,7 @@ describe('MongoDataSource', () => {
})
})

const URL = 'mongodb://localhost:27017/test'
const URL = 'mongodb://localhost:27017/test-apollo-datasource'
const connectArgs = [
URL,
{
Expand All @@ -41,10 +41,14 @@ const connect = async () => {
return client.db()
}

const hexId = '5cf82e14a220a607eb64a7d4'
const objectID = ObjectId(hexId)

describe('Mongoose', () => {
let UserModel
let userCollection
let alice
let nestedBob

beforeAll(async () => {
const userSchema = new Schema({ name: 'string' })
Expand All @@ -57,6 +61,12 @@ describe('Mongoose', () => {
{ name: 'Alice' },
{ upsert: true, new: true }
)

nestedBob = await userCollection.findOneAndReplace(
{ name: 'Bob' },
{ name: 'Bob', nested: [{ _id: objectID }] },
{ new: true, upsert: true }
)
})

test('isCollectionOrModel', () => {
Expand Down Expand Up @@ -103,8 +113,20 @@ describe('Mongoose', () => {
test('Data Source with Collection', async () => {
const users = new Users(userCollection)
users.initialize()

const user = await users.findOneById(alice._id)

expect(user.name).toBe('Alice')
expect(user.id).toBeUndefined()
})

test('nested findByFields', async () => {
const users = new Users(userCollection)
users.initialize()

const [user] = await users.findByFields({ 'nested._id': objectID })

expect(user).toBeDefined()
expect(user.name).toBe('Bob')
})
})
28 changes: 25 additions & 3 deletions src/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,31 @@ export function prepFields(fields) {
return { loaderKey: EJSON.stringify(cleanedFields), cleanedFields }
}

// getNestedValue({ nested: { foo: 'bar' } }, 'nested.foo')
// => 'bar'
function getNestedValue(object, string) {
string = string.replace(/\[(\w+)\]/g, '.$1') // convert indexes to properties
string = string.replace(/^\./, '') // strip a leading dot
var a = string.split('.')
for (var i = 0, n = a.length; i < n; ++i) {
var k = a[i]
if (k in object) {
object = object[k]
} else {
return
}
}
return object
}

// https://github.com/graphql/dataloader#batch-function
// "The Array of values must be the same length as the Array of keys."
// "Each index in the Array of values must correspond to the same index in the Array of keys."
const orderDocs = fieldsArray => docs =>
const orderDocs = (fieldsArray, docs) =>
fieldsArray.map(fields =>
docs.filter(doc => {
for (let fieldName of Object.keys(fields)) {
const fieldValue = fields[fieldName]
const fieldValue = getNestedValue(fields, fieldName)

if (typeof fieldValue === 'undefined') continue

Expand Down Expand Up @@ -107,21 +124,26 @@ export const createCachingMethods = ({ collection, model, cache }) => {
if (existingFieldsFilter) return filterArray
return [...filterArray, filter]
}, [])
log('filterArray: ', filterArray)

const filter =
filterArray.length === 1
? filterArray[0]
: {
$or: filterArray
}
log('filter: ', filter)

const findPromise = model
? model.find(filter).exec()
: collection.find(filter).toArray()

const results = await findPromise
const orderedDocs = orderDocs(fieldsArray)(results)
log('results: ', results)

const orderedDocs = orderDocs(fieldsArray, results)
log('orderedDocs: ', orderedDocs)

return orderedDocs
})

Expand Down
2 changes: 1 addition & 1 deletion src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ export const isCollectionOrModel = x =>

export const getCollection = x => (isModel(x) ? x.collection : x)

const DEBUG = false
const DEBUG = true

export const log = (...args) => DEBUG && console.log(...args)

0 comments on commit a35bba8

Please sign in to comment.