buildMongoPipeline.ts 2.77 KB
Newer Older
aleclofabbro's avatar
aleclofabbro committed
1
import { isUnionLookupField } from '../documentSelection/helpers'
2
import { DocumentSelection } from '../types'
aleclofabbro's avatar
aleclofabbro committed
3
export const buildMongoPipeline = (docS: DocumentSelection, notTop?: boolean) => {
4
  const lookups = [] as any[]
5
  const project = (notTop ? { __typename: true } : { _id: false }) as Record<string, any>
6

7
  Object.entries(docS).forEach(([_alias, field]) => {
aleclofabbro's avatar
aleclofabbro committed
8
    if (isUnionLookupField(field)) {
9
10
11
      const unionLookupPipeline = [] as any[]
      let _let: any = undefined
      const mainLookup = {
aleclofabbro's avatar
aleclofabbro committed
12
        as: field.alias,
13
        from: 'Graph',
14
15
        pipeline: [],
      } as any
aleclofabbro's avatar
aleclofabbro committed
16
17
      if (field.traverseRelation) {
        if (field.traverseRelation === '_rel') {
18
          _let = { nodeId: '$_id' }
aleclofabbro's avatar
aleclofabbro committed
19
20

          notTop &&
21
22
23
24
25
26
            unionLookupPipeline.push({
              $match: {
                // $expr: { $eq: [`$${field.traverseRelation}`, '$$nodeId'] },
                $expr: { $eq: [`$_subj`, '$$nodeId'] },
              },
            })
aleclofabbro's avatar
aleclofabbro committed
27
        } else {
28
29
          _let = { edgeSide: `$${field.traverseRelation}` } //=== '_obj' ? '$_subj' : '$_obj'
          notTop && unionLookupPipeline.push({ $match: { $expr: { $eq: [`$_id`, '$$edgeSide'] } } })
aleclofabbro's avatar
aleclofabbro committed
30
        }
31
      }
aleclofabbro's avatar
aleclofabbro committed
32

33
      field.lookups.forEach((fieldLookup, index) => {
aleclofabbro's avatar
aleclofabbro committed
34
        const $match = { $and: [{ __typename: fieldLookup.__typename }] as any[] }
35
        fieldLookup.match && $match.$and.push(renameMatchFields(fieldLookup.match))
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

        if (!index) {
          mainLookup.pipeline = [
            ...unionLookupPipeline,
            { $match },
            ...buildMongoPipeline(fieldLookup.select, true),
          ]
          _let && (mainLookup.let = _let)
          lookups.push({ $lookup: mainLookup })
        } else {
          mainLookup.pipeline.push({
            $unionWith: {
              coll: 'Graph',
              pipeline: [
                ...unionLookupPipeline,
                { $match },
                ...buildMongoPipeline(fieldLookup.select, true) /* [0].$lookup.pipeline */,
              ],
            },
          })
        }
57
      })
58
      project[field.alias] = true
aleclofabbro's avatar
aleclofabbro committed
59
    } else {
60
      project[field.alias] = field.alias === field.fieldName ? true : `$${field.fieldName}`
61
62
    }
  })
63
  // if (notTop) {
aleclofabbro's avatar
aleclofabbro committed
64
  const stages = [...lookups, { $limit: 10 }]
65
66
  if (Object.keys(project).length) {
    stages.push({ $project: project })
67
  }
68
69
70
71
72
  return stages
  // } else {
  //   const stages = lookups[0].$lookup.pipeline
  //   return stages
  // }
73
}
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

function renameMatchFields(match: any): any {
  if (Array.isArray(match)) {
    return match.map((_) => renameMatchFields(_))
  } else if ('object' === typeof match) {
    return Object.entries(match).reduce((_, [key, val]) => {
      return {
        ..._,
        [key.replace(/^_/, '$')]: renameMatchFields(val),
      }
    }, {})
  } else {
    return match
  }
}