• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

monolithst / functional-models-orm-mongo / 15654991831

14 Jun 2025 06:36PM UTC coverage: 100.0%. Remained the same
15654991831

push

github

macornwell
Add bulk delete.

47 of 47 branches covered (100.0%)

Branch coverage included in aggregate %.

6 of 6 new or added lines in 1 file covered. (100.0%)

128 of 128 relevant lines covered (100.0%)

16.71 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/src/datastoreAdapter.ts
1
import {
2
  DataDescription,
3
  DatastoreAdapter,
4
  ModelInstance,
5
  ModelType,
6
  OrmSearch,
7
  PrimaryKeyType,
8
} from 'functional-models'
9
import groupBy from 'lodash/groupBy'
3✔
10
import merge from 'lodash/merge'
3✔
11
import omit from 'lodash/omit'
3✔
12
import {
3✔
13
  getCollectionNameForModel as defaultCollectionName,
14
  formatForMongo,
15
  toMongo,
16
} from './lib'
17

18
type WithRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] }
19

20
const create = ({
3✔
21
  mongoClient,
22
  databaseName,
23
  getCollectionNameForModel = defaultCollectionName,
3✔
24
}: {
25
  mongoClient: any
26
  databaseName: string
27
  getCollectionNameForModel?: <T extends DataDescription>(
28
    model: ModelType<T>
29
  ) => string
30
}): WithRequired<DatastoreAdapter, 'bulkInsert' | 'count' | 'bulkDelete'> => {
31
  const db = mongoClient.db(databaseName)
45✔
32

33
  const search = <T extends DataDescription>(
45✔
34
    model: ModelType<T>,
35
    ormQuery: OrmSearch
36
  ) => {
37
    return Promise.resolve().then(async () => {
18✔
38
      const collectionName = getCollectionNameForModel(model)
18✔
39
      const collection = db.collection(collectionName)
18✔
40
      const query = toMongo(ormQuery)
18✔
41

42
      const cursor =
43
        ormQuery.query.length > 0
18✔
44
          ? collection.aggregate(query)
45
          : collection.find({})
46

47
      const sorted = ormQuery.sort
18✔
48
        ? cursor.sort({
49
            [ormQuery.sort.key]: ormQuery.sort.order === 'asc' ? 1 : -1,
6✔
50
          })
51
        : cursor
52
      const take = ormQuery.take
18✔
53
      const limited = take ? sorted.limit(take) : sorted
18✔
54

55
      return limited.toArray().then((result: any[]) => {
18✔
56
        return {
18✔
57
          instances: result.map(x => omit(x, '_id')),
9✔
58
          page: undefined,
59
        }
60
      })
61
    })
62
  }
63

64
  const retrieve = <T extends DataDescription>(
45✔
65
    model: ModelType<T>,
66
    id: PrimaryKeyType
67
  ) => {
68
    return Promise.resolve().then(() => {
6✔
69
      const collectionName = getCollectionNameForModel(model)
6✔
70
      const collection = db.collection(collectionName)
6✔
71
      return collection.findOne({ _id: id }).then((x: any) => {
6✔
72
        if (!x) {
6✔
73
          return null
3✔
74
        }
75
        return omit(x, '_id')
3✔
76
      })
77
    })
78
  }
79

80
  const save = async <T extends DataDescription>(
45✔
81
    instance: ModelInstance<T>
82
  ) => {
3✔
83
    return Promise.resolve().then(async () => {
3✔
84
      const model = instance.getModel()
3✔
85
      const collectionName = getCollectionNameForModel<T>(model)
3✔
86
      const collection = db.collection(collectionName)
3✔
87
      const key = model.getModelDefinition().primaryKeyName
3✔
88
      const data = (await instance.toObj<T>()) as T
3✔
89
      const cleanedUp = formatForMongo(data, model)
3✔
90
      const options = { upsert: true }
3✔
91
      // @ts-ignore
92
      const insertData = merge(cleanedUp, { _id: cleanedUp[key] })
3✔
93
      return (
3✔
94
        collection
95
          // @ts-ignore
96
          .updateOne({ _id: cleanedUp[key] }, { $set: insertData }, options)
97
          .then(() => {
98
            return cleanedUp
3✔
99
          })
100
      )
101
    })
102
  }
103

104
  const bulkInsert = async <T extends DataDescription>(
45✔
105
    model: ModelType<T>,
106
    instances: readonly ModelInstance<T>[]
107
  ) => {
6✔
108
    return Promise.resolve().then(async () => {
6✔
109
      const groups = groupBy(instances, x => x.getModel().getName())
15✔
110
      if (Object.keys(groups).length > 1) {
6✔
111
        throw new Error(`Cannot have more than one model type.`)
3✔
112
      }
113

114
      const model = instances[0].getModel()
3✔
115
      const collectionName = getCollectionNameForModel(model)
3✔
116
      const collection = db.collection(collectionName)
3✔
117
      const key = model.getModelDefinition().primaryKeyName
3✔
118

119
      const query = (await Promise.all(instances.map(x => x.toObj<T>()))).map(
9✔
120
        obj => {
121
          // @ts-ignore
122
          const doc = merge({}, obj, { _id: obj[key] })
9✔
123
          return {
9✔
124
            updateOne: {
125
              filter: { _id: doc._id },
126
              update: { $set: doc },
127
              upsert: true,
128
            },
129
          }
130
        }
131
      )
132
      // TODO: This wasn't used but i'm not sure if it needed to be.
133
      //const options = { upsert: true, ordered: true }
134
      return collection.bulkWrite(query).then(() => {
3✔
135
        return undefined
3✔
136
      })
137
    })
138
  }
139

140
  const deleteObj = <T extends DataDescription>(
45✔
141
    model: ModelType<T>,
142
    id: PrimaryKeyType
143
  ) => {
144
    return Promise.resolve().then(async () => {
3✔
145
      const collectionName = getCollectionNameForModel<T>(model)
3✔
146
      const collection = db.collection(collectionName)
3✔
147
      return collection.deleteOne({ _id: id }).then(() => {
3✔
148
        return null
3✔
149
      })
150
    })
151
  }
152

153
  const count = <T extends DataDescription>(
45✔
154
    model: ModelType<T>
155
  ): Promise<number> => {
156
    const collectionName = getCollectionNameForModel<T>(model)
3✔
157
    const collection = db.collection(collectionName)
3✔
158
    return collection.count()
3✔
159
  }
160

161
  const bulkDelete = <T extends DataDescription>(
45✔
162
    model: ModelType<T>,
163
    ids: readonly PrimaryKeyType[]
164
  ) => {
165
    return Promise.resolve().then(async () => {
3✔
166
      const collectionName = getCollectionNameForModel<T>(model)
3✔
167
      const collection = db.collection(collectionName)
3✔
168
      return collection.deleteMany({ _id: { $in: ids } }).then(() => {
3✔
169
        return undefined
3✔
170
      })
171
    })
172
  }
173

174
  return {
45✔
175
    bulkInsert,
176
    bulkDelete,
177
    // @ts-ignore
178
    search,
179
    retrieve,
180
    save,
181
    delete: deleteObj,
182
    count,
183
  }
184
}
185

186
export { create }
3✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc