adapt-authoring-mongodb 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/new.yml +7 -11
- package/.github/workflows/releases.yml +9 -2
- package/adapt-authoring.json +1 -1
- package/docs/using-mongodb.md +229 -41
- package/package.json +10 -10
- package/.github/workflows/labelled_prs.yml +0 -16
|
@@ -1,19 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
# Calls the org-level reusable workflow to add PRs to the TODO Board
|
|
2
|
+
|
|
3
|
+
name: Add PR to Project
|
|
2
4
|
|
|
3
5
|
on:
|
|
4
|
-
issues:
|
|
5
|
-
types:
|
|
6
|
-
- opened
|
|
7
6
|
pull_request:
|
|
8
7
|
types:
|
|
9
8
|
- opened
|
|
9
|
+
- reopened
|
|
10
10
|
|
|
11
11
|
jobs:
|
|
12
12
|
add-to-project:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
- uses: actions/add-to-project@v0.1.0
|
|
17
|
-
with:
|
|
18
|
-
project-url: https://github.com/orgs/adapt-security/projects/5
|
|
19
|
-
github-token: ${{ secrets.PROJECTS_SECRET }}
|
|
13
|
+
uses: adapt-security/.github/.github/workflows/new.yml@main
|
|
14
|
+
secrets:
|
|
15
|
+
PROJECTS_SECRET: ${{ secrets.PROJECTS_SECRET }}
|
|
@@ -3,10 +3,16 @@ on:
|
|
|
3
3
|
push:
|
|
4
4
|
branches:
|
|
5
5
|
- master
|
|
6
|
+
|
|
6
7
|
jobs:
|
|
7
8
|
release:
|
|
8
9
|
name: Release
|
|
9
10
|
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write # to be able to publish a GitHub release
|
|
13
|
+
issues: write # to be able to comment on released issues
|
|
14
|
+
pull-requests: write # to be able to comment on released pull requests
|
|
15
|
+
id-token: write # to enable use of OIDC for trusted publishing and npm provenance
|
|
10
16
|
steps:
|
|
11
17
|
- name: Checkout
|
|
12
18
|
uses: actions/checkout@v3
|
|
@@ -16,10 +22,11 @@ jobs:
|
|
|
16
22
|
uses: actions/setup-node@v3
|
|
17
23
|
with:
|
|
18
24
|
node-version: 'lts/*'
|
|
25
|
+
- name: Update npm
|
|
26
|
+
run: npm install -g npm@latest
|
|
19
27
|
- name: Install dependencies
|
|
20
28
|
run: npm ci
|
|
21
29
|
- name: Release
|
|
22
30
|
env:
|
|
23
31
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
24
|
-
|
|
25
|
-
run: npx semantic-release
|
|
32
|
+
run: npx semantic-release
|
package/adapt-authoring.json
CHANGED
package/docs/using-mongodb.md
CHANGED
|
@@ -1,66 +1,254 @@
|
|
|
1
1
|
# Using MongoDB
|
|
2
|
-
|
|
2
|
+
> This guide assumes you have a working MongoDB instance. See the [installation guide](install) for more information.
|
|
3
|
+
---
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
To save data with the authoring tool, you'll need either a local MongoDB install, or a hosted solution.
|
|
5
|
+
The Adapt authoring tool provides two ways to interact with a MongoDB database:
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
1. Via functions inherited from **AbstractApiModule** - _recommended for most use cases_
|
|
8
|
+
2. Directly via **MongoDBModule**
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
### Which approach should I use?
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
The `adapt-authoring-mongodb` module uses MongoDB's [Node.js driver](https://mongodb.github.io/node-mongodb-native/4.2) behind-the-scenes for communicating with MongoDB.
|
|
12
|
+
Use `AbstractApiModule` when you're building a full-featured API module that manages a collection of documents. It provides various functionality by default, such as schema validation, lifecycle hooks, caching, and automatic REST endpoint generation.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Use `MongoDBModule` directly when you don't need the extra functionality provided by `AbstractApiModule`, need low-level database access, such as aggregation pipelines, bulk operations, or working with collections outside your module's scope.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
---
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
The following functions provide the most common functionality, and will likely be the functions you use most often. Please see the [API reference]([/class/node_modules/adapt-authoring-mongodb/lib/MongoDBModule.js~MongoDBModule.html](https://tomtaylor.codes/ls/jsdoc3/MongoDBModule.html)) for full details.
|
|
18
|
+
## Using AbstractApiModule
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
Retrieves a document.
|
|
20
|
+
If your module extends `AbstractApiModule`, you get a complete set of database operations with built-in validation and hooks.
|
|
23
21
|
|
|
24
|
-
|
|
25
|
-
Inserts a new document.
|
|
22
|
+
### Inserting documents
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
```javascript
|
|
25
|
+
// Validates and inserts a new document. Returns the inserted document.
|
|
26
|
+
const doc = await this.insert({ title: 'My Document', status: 'draft' }, { schemaName: 'myresource' })
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Querying documents
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
/**
|
|
33
|
+
* find()
|
|
34
|
+
* Returns an array of documents matching the query (empty if no matches are found)
|
|
35
|
+
*/
|
|
29
36
|
|
|
30
|
-
|
|
31
|
-
|
|
37
|
+
// Find all
|
|
38
|
+
const docs = await this.find()
|
|
32
39
|
|
|
33
|
-
|
|
34
|
-
|
|
40
|
+
// Find with query
|
|
41
|
+
const drafts = await this.find({ status: 'draft' })
|
|
35
42
|
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
// Find with pagination
|
|
44
|
+
const page = await this.find({}, {}, { limit: 10, skip: 20 })
|
|
38
45
|
|
|
39
46
|
|
|
40
|
-
|
|
41
|
-
|
|
47
|
+
/**
|
|
48
|
+
* findOne()
|
|
49
|
+
* Returns single document matching the query
|
|
50
|
+
* if the strict option is NOT set to false, an error will be thrown if no results are found
|
|
51
|
+
*/
|
|
42
52
|
|
|
43
|
-
|
|
53
|
+
const doc = await this.findOne({ _id: '507f1f77bcf86cd799439011' })
|
|
54
|
+
|
|
55
|
+
// Allow no results (returns undefined instead of throwing)
|
|
56
|
+
const doc = await this.findOne({ _id: id }, { strict: false })
|
|
44
57
|
```
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
58
|
+
|
|
59
|
+
### Updating documents
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
// Update a single document
|
|
63
|
+
const updated = await this.update({ _id: '507f1f77bcf86cd799439011' }, { status: 'published' })
|
|
64
|
+
|
|
65
|
+
// Perform a raw update (gives direct access to extra MongoDB update functionality)
|
|
66
|
+
const updated = await this.update({ _id: id }, { $inc: { viewCount: 1 } }, { rawUpdate: true })
|
|
67
|
+
|
|
68
|
+
// Update all documents which match a query
|
|
69
|
+
const updated = await this.updateMany({ status: 'draft' }, { status: 'archived' })
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Deleting documents
|
|
73
|
+
|
|
74
|
+
```javascript
|
|
75
|
+
// Remove a single document. Returns the deleted document
|
|
76
|
+
const deleted = await this.delete({ _id: '507f1f77bcf86cd799439011' })
|
|
77
|
+
|
|
78
|
+
// Remove multiple documents. Returns an array of deleted documents
|
|
79
|
+
const deleted = await this.deleteMany({ status: 'archived' })
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
### Options reference
|
|
84
|
+
|
|
85
|
+
The following options can be specified when using the above functions. If the option relates to specific functions, this has been noted.
|
|
86
|
+
|
|
87
|
+
| Option | Type | Description |
|
|
88
|
+
| ------ | ---- | ----------- |
|
|
89
|
+
| `schemaName` | String | Schema to validate against (defaults to module's schema) |
|
|
90
|
+
| `collectionName` | String | Collection to operate on (defaults to module's collection) |
|
|
91
|
+
| `validate` | Boolean | Whether to validate data (default: `true`) |
|
|
92
|
+
| `invokePreHook` | Boolean | Whether to invoke pre-operation hooks (default: `true`) |
|
|
93
|
+
| `invokePostHook` | Boolean | Whether to invoke post-operation hooks (default: `true`) |
|
|
94
|
+
| `rawUpdate` | Boolean | **For `update`/`updateMany`**: pass data directly to MongoDB without wrapping in `$set` |
|
|
95
|
+
| `strict` | Boolean | **For `findOne`**: throw error if no document found (default: `true`) |
|
|
96
|
+
|
|
97
|
+
### Lifecycle hooks
|
|
98
|
+
|
|
99
|
+
In addition to the CRUD functions, `AbstractApiModule` provides hooks that allow you to intercept and modify data at various points. These hooks are accessible both internally and externally (i.e. from other modules).
|
|
100
|
+
|
|
101
|
+
For more detail on the hook system, see this [page](hooks).
|
|
102
|
+
|
|
103
|
+
| Hook | Parameters | Mutable | Description |
|
|
104
|
+
| ---- | ---------- | :-----: | ----------- |
|
|
105
|
+
| `preInsertHook` | `(data, options, mongoOptions)` | Yes | Before insert |
|
|
106
|
+
| `postInsertHook` | `(doc)` | No | After insert |
|
|
107
|
+
| `preUpdateHook` | `(originalDoc, newData, options, mongoOptions)` | Yes | Before update |
|
|
108
|
+
| `postUpdateHook` | `(originalDoc, updatedDoc)` | No | After update |
|
|
109
|
+
| `preDeleteHook` | `(doc, options, mongoOptions)` | No | Before delete |
|
|
110
|
+
| `postDeleteHook` | `(doc)` | No | After delete |
|
|
111
|
+
|
|
112
|
+
### Examples
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
// INTERNAL: Modify data before insert
|
|
116
|
+
this.preInsertHook.tap(data => {
|
|
117
|
+
data.createdAt = new Date()
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
// EXTERNAL: React after insert
|
|
121
|
+
mymodule.postInsertHook.tap(doc => {
|
|
122
|
+
this.log('info', `mymodule created document ${doc._id}`)
|
|
123
|
+
})
|
|
50
124
|
```
|
|
51
125
|
|
|
52
|
-
|
|
53
|
-
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Using MongoDBModule directly
|
|
54
129
|
|
|
55
|
-
|
|
56
|
-
- Using the MongoDB client instance [[Adapt docs](https://tomtaylor.codes/ls/jsdoc3/MongoDBModule.html#client), [MongoDB Node.js driver docs](https://mongodb.github.io/node-mongodb-native/3.6/api/MongoClient.html)]
|
|
57
|
-
- Using the MongoDB collection [[Adapt docs](), [MongoDB Node.js driver docs](https://tomtaylor.codes/ls/jsdoc3/MongoDBModule.html#getCollection)]
|
|
130
|
+
For operations not covered by `AbstractApiModule`, use the MongoDB module directly.
|
|
58
131
|
|
|
132
|
+
Note that this module follows the MongoDB Node.js driver API fairly closely. As such, there are some (less user-friendly) differences between the functions found in `AbstractApiModule`.
|
|
133
|
+
|
|
134
|
+
**Warning:** the `mongodb` module provides low-level access to the database, and does not perform any tasks such as data validation. Proceed with caution.
|
|
135
|
+
|
|
136
|
+
### Accessing the mongodb module
|
|
137
|
+
|
|
138
|
+
```javascript
|
|
139
|
+
const mongodb = await this.app.waitForModule('mongodb')
|
|
59
140
|
```
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
141
|
+
|
|
142
|
+
### Inserting documents
|
|
143
|
+
|
|
144
|
+
```javascript
|
|
145
|
+
const doc = await mongodb.insert('users', { email: 'user@example.com', name: 'Test User' })
|
|
64
146
|
```
|
|
65
147
|
|
|
66
|
-
|
|
148
|
+
### Querying documents
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
// Find all
|
|
152
|
+
const allUsers = await mongodb.find('users')
|
|
153
|
+
|
|
154
|
+
// Find with query
|
|
155
|
+
const user = await mongodb.find('users', { email: 'user@example.com' })
|
|
156
|
+
|
|
157
|
+
// Find with options
|
|
158
|
+
const page = await mongodb.find('users', {}, { limit: 10, skip: 20, sort: { createdAt: -1 }})
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Updating documents
|
|
162
|
+
|
|
163
|
+
```javascript
|
|
164
|
+
// Update a single document
|
|
165
|
+
const updated = await mongodb.update('users', { _id: '507f1f77bcf86cd799439011' }, { $set: { name: 'Updated Name' } })
|
|
166
|
+
|
|
167
|
+
// Update multiple documents
|
|
168
|
+
const updated = await mongodb.updateMany('users', { role: 'guest' }, { $set: { active: false } })
|
|
169
|
+
|
|
170
|
+
// Replace an entire document
|
|
171
|
+
const replaced = await mongodb.replace('users', { _id: '507f1f77bcf86cd799439011' }, { ...data })
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Deleting documents
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
// Remove a single document
|
|
178
|
+
await mongodb.delete('users', { _id: '507f1f77bcf86cd799439011' })
|
|
179
|
+
|
|
180
|
+
// Removing multiple documents
|
|
181
|
+
await mongodb.deleteMany('users', { active: false })
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Advanced operations
|
|
185
|
+
|
|
186
|
+
For aggregation pipelines and other advanced features, access the underlying driver:
|
|
187
|
+
|
|
188
|
+
```javascript
|
|
189
|
+
// Get a collection reference
|
|
190
|
+
const collection = mongodb.getCollection('users')
|
|
191
|
+
|
|
192
|
+
// Aggregation pipeline
|
|
193
|
+
const results = await collection.aggregate([
|
|
194
|
+
{ $match: { active: true } },
|
|
195
|
+
{ $group: { _id: '$role', count: { $sum: 1 } } }
|
|
196
|
+
]).toArray()
|
|
197
|
+
|
|
198
|
+
// Database statistics
|
|
199
|
+
const stats = await mongodb.client.db().stats()
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Working with ObjectIds
|
|
203
|
+
|
|
204
|
+
The module automatically converts string IDs to ObjectIds. You can also work with them directly:
|
|
205
|
+
|
|
206
|
+
```javascript
|
|
207
|
+
// Create a new ObjectId
|
|
208
|
+
const id = mongodb.ObjectId.create()
|
|
209
|
+
|
|
210
|
+
// Check if a string is valid
|
|
211
|
+
const isValid = mongodb.ObjectId.isValid('507f1f77bcf86cd799439011')
|
|
212
|
+
|
|
213
|
+
// Parse a string to ObjectId
|
|
214
|
+
const objectId = mongodb.ObjectId.parse('507f1f77bcf86cd799439011')
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Indexes
|
|
218
|
+
|
|
219
|
+
Set indexes for better query performance:
|
|
220
|
+
|
|
221
|
+
```javascript
|
|
222
|
+
// Simple unique index
|
|
223
|
+
await mongodb.setIndex('users', 'email', { unique: true })
|
|
224
|
+
|
|
225
|
+
// Compound index
|
|
226
|
+
await mongodb.setIndex('content', { courseId: 1, type: 1 })
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
See the [MongoDB Node.js driver documentation](https://mongodb.github.io/node-mongodb-native/) for the full driver API.
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Error handling
|
|
234
|
+
|
|
235
|
+
Common database errors:
|
|
236
|
+
|
|
237
|
+
| Error | Description |
|
|
238
|
+
| ----- | ----------- |
|
|
239
|
+
| `MONGO_CONN_FAILED` | Failed to connect to the database |
|
|
240
|
+
| `MONGO_DUPL_INDEX` | Duplicate key violation (unique index) |
|
|
241
|
+
| `MONGO_IMMUTABLE_FIELD` | Attempted to modify an immutable field |
|
|
242
|
+
| `INVALID_OBJECTID` | Invalid ObjectId string format |
|
|
243
|
+
| `NOT_FOUND` | Document not found (AbstractApiModule only) |
|
|
244
|
+
| `TOO_MANY_RESULTS` | Multiple documents found when one expected |
|
|
245
|
+
|
|
246
|
+
```javascript
|
|
247
|
+
try {
|
|
248
|
+
await this.insert({ email: 'existing@example.com' })
|
|
249
|
+
} catch (e) {
|
|
250
|
+
if (e.code === 'MONGO_DUPL_INDEX') {
|
|
251
|
+
// Handle duplicate
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adapt-authoring-mongodb",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Module for saving to a MongoDB instance",
|
|
5
5
|
"homepage": "https://github.com/adapt-security/adapt-authoring-mongodb",
|
|
6
6
|
"license": "GPL-3.0",
|
|
@@ -8,21 +8,21 @@
|
|
|
8
8
|
"main": "index.js",
|
|
9
9
|
"repository": "github:adapt-security/adapt-authoring-mongodb",
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"mongodb": "^
|
|
11
|
+
"mongodb": "^7.0.0"
|
|
12
12
|
},
|
|
13
13
|
"peerDependencies": {
|
|
14
14
|
"adapt-authoring-core": "github:adapt-security/adapt-authoring-core"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"
|
|
18
|
-
"@semantic-release/commit-analyzer": "^9.0.2",
|
|
17
|
+
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
19
18
|
"@semantic-release/git": "^10.0.1",
|
|
20
|
-
"@semantic-release/github": "^
|
|
21
|
-
"@semantic-release/npm": "^
|
|
22
|
-
"@semantic-release/release-notes-generator": "^
|
|
23
|
-
"conventional-changelog-eslint": "^
|
|
24
|
-
"semantic-release": "^
|
|
25
|
-
"semantic-release-replace-plugin": "^1.2.7"
|
|
19
|
+
"@semantic-release/github": "^12.0.2",
|
|
20
|
+
"@semantic-release/npm": "^13.1.2",
|
|
21
|
+
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
22
|
+
"conventional-changelog-eslint": "^6.0.0",
|
|
23
|
+
"semantic-release": "^25.0.2",
|
|
24
|
+
"semantic-release-replace-plugin": "^1.2.7",
|
|
25
|
+
"standard": "^17.1.0"
|
|
26
26
|
},
|
|
27
27
|
"release": {
|
|
28
28
|
"plugins": [
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
name: Add labelled PRs to project
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
types: [ labeled ]
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
add-to-project:
|
|
9
|
-
if: ${{ github.event.label.name == 'dependencies' }}
|
|
10
|
-
name: Add to main project
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
|
-
steps:
|
|
13
|
-
- uses: actions/add-to-project@v0.1.0
|
|
14
|
-
with:
|
|
15
|
-
project-url: https://github.com/orgs/adapt-security/projects/5
|
|
16
|
-
github-token: ${{ secrets.PROJECTS_SECRET }}
|