monastery 1.40.1 → 1.40.3

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/changelog.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [1.40.3](https://github.com/boycce/monastery/compare/1.40.2...1.40.3) (2022-12-21)
6
+
7
+ ### [1.40.2](https://github.com/boycce/monastery/compare/1.40.1...1.40.2) (2022-12-15)
8
+
5
9
  ### [1.40.1](https://github.com/boycce/monastery/compare/1.40.0...1.40.1) (2022-12-14)
6
10
 
7
11
  ## [1.40.0](https://github.com/boycce/monastery/compare/1.39.2...1.40.0) (2022-12-14)
package/docs/readme.md CHANGED
@@ -95,11 +95,17 @@ Coming soon...
95
95
  - Automatic embedded document ids/createdAt/updatedAt fields
96
96
  - ~~Ability to change ACL default on the manager~~
97
97
  - ~~Public db.arrayWithSchema method~~
98
+ - ~~Added support for array population~~
99
+ - Change population warnings into errors
98
100
  - Global after/before hooks
99
101
  - before hooks can receive a data array, remove this
100
102
  - docs: Make the implicit ID query conversion more apparent
101
103
  - Split away from Monk (unless updated)
102
104
  - Add a warning if an invalid model is referenced in jthe schema
105
+ - Allow rules on image types, e.g. `required`
106
+ - test importing of models
107
+ - Docs: model.methods
108
+ -
103
109
 
104
110
  ## Versions
105
111
 
package/lib/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  let fs = require('fs')
2
2
  let debug = require('debug')
3
3
  let monk = require('monk')
4
- let util = require('./util')
5
4
  let path = require('path')
5
+ let rules = require('./rules')
6
+ let util = require('./util')
6
7
 
7
8
  // Apply monk monkey patches
8
9
  monk.manager.prototype.open = require('./monk-monkey-patches').open
@@ -72,6 +73,8 @@ module.exports = function(uri, opts, fn) {
72
73
  return manager
73
74
  }
74
75
 
76
+ module.exports.rules = rules
77
+
75
78
  let arrayWithSchema = function(array, schema) {
76
79
  array.schema = schema
77
80
  return array
package/lib/model-crud.js CHANGED
@@ -89,13 +89,37 @@ module.exports = {
89
89
  if (util.isObject(item)) {
90
90
  lookups.push({ $lookup: item })
91
91
  } else {
92
- let modelName = (path.split('.').reduce((o,i) => o[i], this.fields) ||{}).model
92
+ let arrayTarget
93
+ let arrayCount = 0
94
+ let schema = path.split('.').reduce((o, i) => {
95
+ if (util.isArray(o[i])) {
96
+ arrayCount++
97
+ arrayTarget = true
98
+ return o[i][0]
99
+ } else {
100
+ arrayTarget = false
101
+ return o[i]
102
+ }
103
+ }, this.fields)
104
+ let modelName = (schema||{}).model
93
105
  if (!modelName) {
94
106
  this.error(
95
107
  `The field "${path}" passed to populate is not of type model. You would ` +
96
108
  'need to add the field option e.g. { model: \'comment\' } in your schema.'
97
109
  )
98
110
  continue
111
+ } else if (arrayCount > 1) {
112
+ this.error(
113
+ `You cannot populate on array's nested in array's: ${path}: ` +
114
+ `{ model: "${modelName}" }`
115
+ )
116
+ continue
117
+ } else if (arrayCount == 1 && !arrayTarget) {
118
+ this.error(
119
+ `You cannot populate within an array of sub-documents: ${path}: ` +
120
+ `{ model: "${modelName}" }`
121
+ )
122
+ continue
99
123
  } else if (!this.manager.model[modelName]) {
100
124
  this.error(
101
125
  `The field's model defined in your schema does not exist: ${path}: ` +
@@ -103,8 +127,11 @@ module.exports = {
103
127
  )
104
128
  continue
105
129
  }
106
- // Populate model (convert array into document & create lookup)
107
- (opts.addFields = opts.addFields || {})[path] = { '$arrayElemAt': [ '$' + path, 0 ] }
130
+ // Convert array into a document for non-array targets
131
+ if (!arrayTarget) {
132
+ (opts.addFields = opts.addFields || {})[path] = { '$arrayElemAt': [ '$' + path, 0 ] }
133
+ }
134
+ // Create lookup
108
135
  lookups.push({ $lookup: {
109
136
  from: modelName,
110
137
  localField: path,
@@ -298,7 +325,6 @@ module.exports = {
298
325
  }
299
326
  try {
300
327
  opts = await this._queryObject(opts, 'remove')
301
- if (util.isEmpty(opts.query)) throw new Error('Please specify opts.query')
302
328
 
303
329
  // Remove
304
330
  await util.runSeries(this.beforeRemove.map(f => f.bind(opts)))
@@ -503,6 +529,9 @@ module.exports = {
503
529
  let parentModelData = util.toArray(data).map(o => ({ modelName: this.name, dataRef: o }))
504
530
  let modelData = this._recurseAndFindModels(this.fields, data).concat(parentModelData)
505
531
 
532
+ // Need to remove ////////////////// make sure blacklist default fields on populated arrays dont show
533
+ console.log(modelData)
534
+
506
535
  // Loop found model/deep-model data objects, and populate missing default-fields and call afterFind on each
507
536
  for (let item of modelData) {
508
537
  // Populate missing default fields if data !== null
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "monastery",
3
3
  "description": "⛪ A straight forward MongoDB ODM built around Monk",
4
4
  "author": "Ricky Boyce",
5
- "version": "1.40.1",
5
+ "version": "1.40.3",
6
6
  "license": "MIT",
7
7
  "repository": "github:boycce/monastery",
8
8
  "homepage": "https://boycce.github.io/monastery/",
package/test/crud.js CHANGED
@@ -460,6 +460,7 @@ module.exports = function(monastery, opendb) {
460
460
  addresses: [{ city: { type: 'string' }, country: { type: 'string', default: 'Germany' } }],
461
461
  address: { country: { type: 'string', default: 'Germany' }},
462
462
  pet: { dog: { model: 'dog' }},
463
+ pets: { dog: [{ model: 'dog' }]},
463
464
  dogs: [{ model: 'dog' }], // virtual association
464
465
  }
465
466
  })
@@ -489,18 +490,20 @@ module.exports = function(monastery, opendb) {
489
490
  // Note that addresses.1.country shouldn't be overridden
490
491
  // Insert documents (without defaults)
491
492
  let dog1 = await db.dog._insert({})
493
+ let dog2 = await db.dog._insert({})
492
494
  let user1 = await db.user._insert({
493
495
  addresses: [
494
496
  { city: 'Frankfurt' },
495
497
  { city: 'Christchurch', country: 'New Zealand' }
496
498
  ],
497
- pet: { dog: dog1._id }
499
+ pet: { dog: dog1._id },
500
+ pets: { dog: [dog1._id, dog2._id]},
498
501
  })
499
502
  await db.dog._update(dog1._id, { $set: { user: user1._id }})
500
503
 
501
504
  let find1 = await db.user.findOne({
502
505
  query: user1._id,
503
- populate: ['pet.dog', {
506
+ populate: ['pet.dog', 'pets.dog', {
504
507
  from: 'dog',
505
508
  localField: '_id',
506
509
  foreignField: 'user',
@@ -516,19 +519,25 @@ module.exports = function(monastery, opendb) {
516
519
  ],
517
520
  address: { country: 'Germany' },
518
521
  pet: { dog: { _id: dog1._id, name: 'Scruff', user: user1._id }},
522
+ pets: {
523
+ dog: [
524
+ { _id: dog1._id, name: 'Scruff', user: user1._id },
525
+ { _id: dog2._id, name: 'Scruff' },
526
+ ]
527
+ },
519
528
  dogs: [{ _id: dog1._id, name: 'Scruff', user: user1._id }]
520
529
  })
521
530
 
522
531
  // Blacklisted default field population test
523
532
  let find2 = await db.user.findOne({
524
533
  query: user1._id,
525
- populate: ['pet.dog', {
534
+ populate: ['pet.dog', 'pets.dog', {
526
535
  from: 'dog',
527
536
  localField: '_id',
528
537
  foreignField: 'user',
529
- as: 'dogs'
538
+ as: 'dogs',
530
539
  }],
531
- blacklist: ['address', 'addresses.country', 'dogs.name']
540
+ blacklist: ['address', 'addresses.country', 'pets.dog.name', 'dogs.name'],
532
541
  // ^ great test (address should cancel addresses if not stopping at the .)
533
542
  })
534
543
  expect(find2).toEqual({
@@ -536,14 +545,20 @@ module.exports = function(monastery, opendb) {
536
545
  name: 'Martin Luther',
537
546
  addresses: [{ city: 'Frankfurt' }, { city: 'Christchurch' }],
538
547
  pet: { dog: { _id: dog1._id, name: 'Scruff', user: user1._id }},
539
- dogs: [{ _id: dog1._id, user: user1._id }]
548
+ dogs: [{ _id: dog1._id, user: user1._id }],
549
+ pets: {
550
+ dog: [
551
+ { _id: dog1._id, user: user1._id }, //////////////////get this working
552
+ { _id: dog2._id },
553
+ ]
554
+ },
540
555
  })
541
556
 
542
557
  db.close()
543
558
  })
544
559
 
545
560
  test('findOneAndUpdate general', async () => {
546
- // todo: test all findOneAndUpdate options
561
+ // todo: test all findOneAndUpdate options (e.g. array population)
547
562
  // todo: test find & update hooks
548
563
  let db = (await opendb(null)).db
549
564
  let dog = db.model('dog', {
package/test/populate.js CHANGED
@@ -82,6 +82,78 @@ module.exports = function(monastery, opendb) {
82
82
  db.close()
83
83
  })
84
84
 
85
+ test('model populate array', async () => {
86
+ // Setup
87
+ let db = (await opendb(null)).db
88
+ let bird = db.model('bird', { fields: {
89
+ name: { type: 'string' }
90
+ }})
91
+ let user = db.model('user', { fields: {
92
+ birds: [{ model: 'bird' }],
93
+ animal: { birds: [{ model: 'bird' }] },
94
+ animals: [{ bird: { model: 'bird' }, num: { type: 'number' } }],
95
+ }})
96
+ let bird1 = await bird.insert({ data: { name: 'ponyo' }})
97
+ let bird2 = await bird.insert({ data: { name: 'jack' }})
98
+ let bird3 = await bird.insert({ data: { name: 'sophie' }})
99
+ let user1 = await user.insert({ data: {
100
+ birds: [bird1._id, bird2._id],
101
+ animal: { birds: [bird1._id, bird2._id] },
102
+ animals: [{ bird: bird1._id, num: 1 }, { bird: bird3._id, num: 2 }],
103
+ }})
104
+
105
+ // Array
106
+ let find1 = await user.findOne({ query: user1._id, populate: ['birds'] })
107
+ expect(find1).toEqual({
108
+ _id: user1._id,
109
+ birds: [
110
+ { _id: bird1._id, name: 'ponyo' },
111
+ { _id: bird2._id, name: 'jack' },
112
+ ],
113
+ animal: {
114
+ birds: [bird1._id, bird2._id],
115
+ },
116
+ animals: [
117
+ { bird: bird1._id, num: 1 },
118
+ { bird: bird3._id, num: 2 },
119
+ ],
120
+ })
121
+
122
+ // Nested array
123
+ let find2 = await user.findOne({ query: user1._id, populate: ['animal.birds'] })
124
+ expect(find2).toEqual({
125
+ _id: user1._id,
126
+ birds: [bird1._id, bird2._id],
127
+ animal: {
128
+ birds: [
129
+ { _id: bird1._id, name: 'ponyo' },
130
+ { _id: bird2._id, name: 'jack' },
131
+ ],
132
+ },
133
+ animals: [
134
+ { bird: bird1._id, num: 1 },
135
+ { bird: bird3._id, num: 2 },
136
+ ],
137
+ })
138
+
139
+ // modelId within an array of subdocuments (won't populate, but show a debug error)
140
+ user.error = () => {} // hide debug error
141
+ let find3 = await user.findOne({ query: user1._id, populate: ['animals.bird'] })
142
+ expect(find3).toEqual({
143
+ _id: user1._id,
144
+ birds: [bird1._id, bird2._id],
145
+ animal: {
146
+ birds: [bird1._id, bird2._id],
147
+ },
148
+ animals: [
149
+ { bird: bird1._id, num: 1 },
150
+ { bird: bird3._id, num: 2 },
151
+ ],
152
+ })
153
+
154
+ db.close()
155
+ })
156
+
85
157
  test('model populate type=any', async () => {
86
158
  let db = (await opendb(null)).db
87
159
  db.model('company', { fields: {