Jelajahi Sumber

worked on routeGen

Tomislav Cvetic 8 tahun lalu
induk
melakukan
2ffc43f2ea
5 mengubah file dengan 205 tambahan dan 53 penghapusan
  1. 70 0
      _samples.js
  2. 1 1
      project/_sampleData.js
  3. 6 4
      project/route.js
  4. 42 46
      routeGen.js
  5. 86 2
      routeGen.test.js

+ 70 - 0
_samples.js

@@ -0,0 +1,70 @@
+export const model = [{
+  _id: '58d3d6883d34293254afae42',
+  name: 'Gisele',
+  description: 'A model',
+  agency_id: [
+    '4b00d6883d34293254afae42',
+    '3ab1d6883d34293254afae42'
+  ],
+  jobs: [{
+    type: 'photoshoot',
+    salery: 100000,
+    fun: false
+  }, {
+    type: 'catwalk',
+    salery: 50000,
+    fun: false
+  }, {
+    type: 'commercial',
+    salery: 150000,
+    fun: true
+  }]
+}, {
+  _id: '2d3ad6883d34293254afae42',
+  name: 'Adriana',
+  description: 'Another model',
+  agency_id: [
+    '3ab1d6883d34293254afae42'
+  ],
+  jobs: [{
+    type: 'catwalk',
+    salery: 50000,
+    fun: false
+  }, {
+    type: 'commercial',
+    salery: 150000,
+    fun: true
+  }]
+}, {
+  _id: '66c1d6883d34293254afae42',
+  name: 'Heidi',
+  description: 'Yet another model',
+  agency_id: [
+    '3ab1d6883d34293254afae42'
+  ],
+  jobs: [{
+    type: 'commercial',
+    salery: 150000,
+    fun: false
+  }]
+}, {
+  _id: '58d3d6883d34293254afae42',
+  name: 'Tyra',
+  description: 'The last model here',
+  agency_id: [],
+  jobs: [{
+    type: 'fund raiser',
+    salery: 500000,
+    fun: true
+  }]
+}]
+
+export const agency = [{
+  _id: '4b00d6883d34293254afae42',
+  name: 'Agency 1',
+  country: 'UK'
+}, {
+  _id: '3ab1d6883d34293254afae42',
+  name: 'Agency 2',
+  country: 'USA'
+}]

+ 1 - 1
project/_sampleData.js

@@ -13,7 +13,7 @@ const projects = [{
 }, {
   name: 'G6',
   tag: 'G6',
-  description: 'Carmines first choise'
+  description: 'Carmines favourite flavor'
 }]
 
 export default projects

+ 6 - 4
project/route.js

@@ -65,6 +65,7 @@ export function putHandler (req, res) {
     if (err) {
       res.status(404)
       res.send(err)
+      return
     }
 
     console.log(project, req.body)
@@ -76,6 +77,7 @@ export function putHandler (req, res) {
       if (err) {
         res.status(422)
         res.send(err)
+        return
       }
       res.send()
     })
@@ -84,11 +86,11 @@ export function putHandler (req, res) {
 
 export function deleteHandler (req, res) {
   /** DELETE handler (delete project) */
-  const id = mongoose.Types.ObjectId(req.params['0'].substring(1))
-
-  Project.remove({ _id: id }, function (err, project) {
+  const id = mongoose.Types.ObjectId(req.params['0'])
+  Project.remove({ _id: id }, function (err) {
     if (err) {
       res.send(err)
+      return
     }
     res.send()
   })
@@ -98,6 +100,6 @@ const router = express.Router()
 router.get(/\/(\w+)?\/?$/, getHandler)
 router.post('/', postHandler)
 router.put(/\/(\w+)?\/?$/, putHandler)
-router.delete('/', deleteHandler)
+router.delete(/\/(\w+)?\/?$/, deleteHandler)
 
 export default router

+ 42 - 46
routeGen.js

@@ -1,23 +1,29 @@
+/**
+ * @module mongoRouter
+ *
+ * Backend module to store React-Redux components in MongoDB.
+ */
 import mongoose from 'mongoose'
-import { History } from './basicSchema'
+import { History } from './core/basicSchema'
 
-function routeGen (model) {
+/**
+ * Generates GET, POST, UPDATE and DELETE handlers which interact with
+ * MongoDB.
+ *
+ * @param  {object} Model - mongoose model to use
+ * @param  {boolean} versioned - use a revision control mechanism
+ * @return {[type]}
+ */
+function routeGen (Model, versioned = true) {
   /** GET handler (request one item or a list of items) */
-  function get (req, res, next) {
-    const path = req.params['0']
-    /** If the path doesn't match, call the next router */
-    if (path !== model.modelName.toLowerCase()) {
-      next()
-    }
+  const get = (req, res) => {
+    let { id } = req.params
 
-    let id = req.params['1']
     /** check whether an id was specified. */
     if (typeof id === 'string' && id.length > 1) {
-      // remove leading slash
-      id = id.substring(1)
       try {
         // try to convert the id string to a valid ObjectId
-        id = mongoose.Types.ObjectId(req.params['1'].substring(1))
+        id = mongoose.Types.ObjectId(id)
       } catch (err) {
         // If id couldn't be converted, return an error message.
         res.status(422)
@@ -25,7 +31,7 @@ function routeGen (model) {
         return
       }
       // if yes, return the one item
-      model.findOne({ _id: id }, function (err, item) {
+      Model.findOne({ _id: id }, function (err, item) {
         if (err) {
           res.status(404)
           res.send(err)
@@ -37,8 +43,8 @@ function routeGen (model) {
       // if not, return a list of items
       // limit the number of returned items and use an offset
       const limit = req.query.limit ? Math.min(Math.max(parseInt(req.query.limit), 1), 100) : 20
-      const offset = req.query.offset ? Math.min(Math.max(parseInt(req.query.offset), 1), 100) : 20
-      model.find({}, {limit: limit, skip: offset}, function (err, items) {
+      const offset = req.query.offset ? Math.max(parseInt(req.query.offset), 0) : 0
+      Model.find({}, {limit: limit, skip: offset}, function (err, items) {
         if (err) {
           res.status(404)
           res.send(err)
@@ -50,18 +56,12 @@ function routeGen (model) {
   }
 
   /** POST handler (insert a new item into the database) */
-  function post (req, res, next) {
-    const path = req.params['0']
-    // If the path doesn't match, call the next router
-    if (path !== model.modelName.toLowerCase()) {
-      next()
-    }
-
+  const post = (req, res) => {
     // create the new item
-    const item = new model(req.body)
+    const item = new Model(req.body)
 
     // Check, if the model supports revision control
-    if (typeof model.schema.obj.__history !== 'undefined') {
+    if (typeof Model.schema.obj.__history !== 'undefined') {
       item.__history = new History({
         author: '',
         created: Date(),
@@ -78,19 +78,13 @@ function routeGen (model) {
         res.send(err)
         return
       }
-      res.send({ success: `${model.modelName} added.` })
+      res.send({ success: `${Model.modelName} added.` })
     })
   }
 
   /** PUT handler (update existing project) */
-  function put (req, res, next) {
-    const path = req.params['0']
-    /** If the path doesn't match, call the next router */
-    if (path !== model.modelName.toLowerCase()) {
-      next()
-    }
-
-    let id = req.params['1']
+  const put = (req, res) => {
+    let id = req.params['0']
     /** check whether an id was specified. */
     if (typeof id === 'string' && id.length > 1) {
       // remove leading slash
@@ -107,16 +101,16 @@ function routeGen (model) {
     }
 
     // Find the object in the database
-    model.findOne({ _id: id }, function (err, item) {
+    Model.findOne({ _id: id }, function (err, item) {
       if (err) {
         res.status(404)
         res.send(err)
       }
 
       // Check, if the model supports revision control
-      if (typeof model.schema.obj.__history !== 'undefined') {
+      if (typeof Model.schema.obj.__history !== 'undefined') {
         // If yes, don't update the item, but create a new one based on the original
-        const newItem = model(item)
+        const newItem = Model(item)
         // replace the requested elements
         for (let prop in req.body) {
           newItem[prop] = req.body[prop]
@@ -137,7 +131,7 @@ function routeGen (model) {
             res.status(422)
             res.send(err)
           }
-          res.json({ message: `${model.modelName} updated.` })
+          res.json({ message: `${Model.modelName} updated.` })
         })
       } else {
         for (let prop in req.body) {
@@ -150,27 +144,29 @@ function routeGen (model) {
           res.status(422)
           res.send(err)
         }
-        res.json({ message: `${model.modelName} updated.` })
+        res.json({ message: `${Model.modelName} updated.` })
       })
     })
   }
 
   /** DELETE handler (delete project) */
-  function del (req, res, next) {
-    const path = req.params['0']
-    const id = mongoose.Types.ObjectId(req.params['1'].substring(1))
-    /** If the path doesn't match, call the next router */
-    if (path !== '/project') {
-      next()
-    }
+  const del = (req, res) => {
+    const id = mongoose.Types.ObjectId(req.params['0'])
 
-    Project.remove({ _id: id }, function (err, project) {
+    Model.remove({ _id: id }, function (err, project) {
       if (err) {
         res.send(err)
       }
       res.json({ message: 'Movie deleted.' })
     })
   }
+
+  return {
+    get,
+    post,
+    put,
+    del
+  }
 }
 
 export default routeGen

+ 86 - 2
routeGen.test.js

@@ -1,5 +1,89 @@
 import routeGen from './routeGen'
+import { model, agency } from './_samples'
+import mongoose from 'mongoose'
 
-// mock mongodb
-describe('generates routes for GET, POST, PUT, DELETE', () => {
+class Model {
+  constructor () {
+    this.modelName = 'Gisele'
+  }
+  static find (criteria, options, callback) {
+    let { skip, limit } = options
+    const myModel = model.slice(skip, skip + limit)
+    if (myModel) {
+      callback(undefined, myModel)
+    } else {
+      callback(Error('model not found'), undefined)
+    }
+  }
+  static findOne (criteria, callback) {
+    let { _id } = criteria
+    const myModel = model.find((m) => {
+      return (mongoose.Types.ObjectId(m._id) === _id)
+    })
+    if (myModel) {
+      callback(undefined, myModel)
+    } else {
+      callback(Error('model not found'), undefined)
+    }
+  }
+  save () {
+    throw Error('save not implemented.')
+  }
+  remove () {
+    throw Error('remove not implemented.')
+  }
+}
+class Result {
+  constructor () {
+    this._body = null
+    this._status = null
+  }
+  status (value) {
+    this._status = value
+  }
+  send (data) {
+    this._body = data
+  }
+  json (data) {
+    this._status = 200
+    this._body = data
+  }
+}
+
+describe('routeGen for versioned models', () => {
+  const route = routeGen(Model)
+  const res = new Result()
+  it('generates the handlers', () => {
+    // Generate a version controlled model
+    expect(route.get).not.toBeUndefined()
+    expect(route.post).not.toBeUndefined()
+    expect(route.put).not.toBeUndefined()
+    expect(route.del).not.toBeUndefined()
+  })
+  it('get without arguments calls Model.find with the right parameters', () => {
+    // call the GET handler
+    const reqList = { params: {}, query: { limit: 2, offset: 1 } }
+    route.get(reqList, res)
+    expect(res._body).toEqual(model.slice(1, 3))
+    expect(res._status).toBe(200)
+  })
+  it('return empty lists.', () => {
+    // call the GET handler
+    const reqList = { params: {}, query: { limit: 1, offset: 100 } }
+    route.get(reqList, res)
+    expect(res._body).toEqual([])
+    expect(res._status).toBe(200)
+  })
+  it('get with arguments calls Model.findOne with the right parameters', () => {
+    const reqElem = { params: { id: '58d3d6883d34293254afae42' }, query: {} }
+    route.get(reqElem, res)
+    expect(res._body).toEqual(model[0])
+    expect(res._status).toBe(200)
+  })
+  it('return error when item is not found', () => {
+    const reqElem = { params: { id: '58d3d6883d34343254afae42' }, query: {} }
+    route.get(reqElem, res)
+    expect(res._body).toEqual(model[0])
+    expect(res._status).toBe(200)
+  })
 })