Skip to content

Commit

Permalink
Merge pull request #1 from agco/feature/GLBLAGCTWO-1147
Browse files Browse the repository at this point in the history
Feature/glblagctwo 1147
  • Loading branch information
kristofsajdak committed Oct 26, 2015
2 parents 100e645 + 359edac commit b0c5656
Show file tree
Hide file tree
Showing 22 changed files with 1,647 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.iml
.idea
node_modules
41 changes: 41 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"version": "0.1.0",
// List of configurations. Add new configurations or edit existing ones.
"configurations": [
{
// Name of configuration; appears in the launch configuration drop down menu.
"name": "Launch Mocha",
// Type of configuration.
"type": "node",
// Workspace relative or absolute path to the program.
"program": "node_modules/mocha/bin/_mocha",
// Automatically stop program after launch.
"stopOnEntry": false,
// Command line arguments passed to the program.
"args": ["--debug-brk", "--timeout", "10000"],
// Workspace relative or absolute path to the working directory of the program being debugged. Default is the current workspace.
"cwd": ".",
// Workspace relative or absolute path to the runtime executable to be used. Default is the runtime executable on the PATH.
"runtimeExecutable": null,
// Optional arguments passed to the runtime executable.
"runtimeArgs": ["--nolazy"],
// Environment variables passed to the program.
"env": {
"NODE_ENV": "development"
},
// Use JavaScript source maps (if they exist).
"sourceMaps": false,
// If JavaScript source maps are enabled, the generated code is expected in this directory.
"outDir": null
},
{
"name": "Attach",
"type": "node",
// TCP/IP address. Default is "localhost".
"address": "localhost",
// Port to attach to.
"port": 5858,
"sourceMaps": false
}
]
}
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require ('./lib/plugin')
6 changes: 6 additions & 0 deletions jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs"
}
}
94 changes: 94 additions & 0 deletions lib/adapters/mongodb/converters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
'use strict'

const Hapi = require('hapi')
const _ = require('lodash')
const Hoek = require('hoek')
const mongoose = require('mongoose')
const uuid = require('node-uuid')

module.exports = function() {
const toJsonApi = function (resources) {
if (_.isArray(resources)) {
return _.map(resources, (resource) => {
return toJsonApiSingle(resource);
})
} else {
return toJsonApiSingle(resources);
}

function toJsonApiSingle(resource) {
var mapped = _.mapKeys(resource, function (val, key) {
if (key === '_id') return 'id'
else return key
});
return _.omit(mapped, '__v')
}
}

const toMongooseModel = function (hhSchema) {

const mongooseSchema = {}
mongooseSchema._id = {
type: String,
default: () => {
return uuid.v4()
}
}

var schemaMap = {
'string': String,
'number': Number,
'date': Date,
'buffer': Buffer,
'boolean': Boolean,
'array': Array,
'any': Object
}

mongooseSchema.type = 'string'
mongooseSchema.attributes =
_.mapValues(hhSchema.attributes, function (val) {
Hoek.assert(val.isJoi, 'attribute values in the hh schema should be defined with Joi')
return schemaMap[val._type]
})

const schema = mongoose.Schema(mongooseSchema)
return mongoose.model(hhSchema.type, schema)
}

const toMongoosePredicate = function(query) {
const mappedToModel = _.mapKeys(query.filter, function (val, key) {
if (key === 'id') return '_id'
else return `attributes.${key}`
})

return _.mapValues(mappedToModel, function (val, key) {
const supportedComparators = ['lt', 'lte', 'gt', 'gte']

//if it's a normal value strig, do a $in query
if (_.isString(val) && val.indexOf(',') !== -1) {
return {$in: val.split(',')}
}

//if it's a comparator, translate to $gt, $lt etc
const valueKey = _.keys(val)[0]
if (_.contains(supportedComparators, valueKey)) {
return {[`$${valueKey}`] : val[valueKey]}
}

else return val
})
}

const toMongooseSort = function(sort) {
if (!sort) return {'_id' : -1}
if(sort.indexOf('-') === 0) {
return {[`attributes.${sort.substr(1)}`] : -1}
}

return {[`attributes.${sort}`] : 1}
}

return { toJsonApi, toMongooseModel, toMongoosePredicate, toMongooseSort }
}

118 changes: 118 additions & 0 deletions lib/adapters/mongodb/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
'use strict'

const Hapi = require('hapi')
const Boom = require('boom')
const _ = require('lodash')
const mongoose = require('mongoose')
const converters = require('./converters')()
const utils = require('./utils')()

mongoose.Promise = require('bluebird')

module.exports = function (options) {

const models = {}

const connect = function(cb) {
mongoose.connect(options.mongodbUrl, cb)
}

const disconnect = function(cb) {
//clear out events
mongoose.connection._events = {}
mongoose.disconnect(cb)
}

mongoose.connection.on('error', connect)

const find = function (type, req) {
const model = models[type]
const query = req.query
const limit = (query.page && query.page.limit) || 1000
const skip = (query.page && query.page.offset) || 0
const sort = converters.toMongooseSort(query.sort)
const sparse = query.fields && query.fields[type].split(',')
var predicate = converters.toMongoosePredicate(query)
return model.find(predicate).skip(skip).sort(sort).limit(limit).lean().exec()
.then((resources)=> {
let data = converters.toJsonApi(resources);
if (sparse) {
data = _.map(data, (datum) => {
datum.attributes = _.pick(datum.attributes, sparse)
return datum
})
}

return {data}
})
}

const findById = function(type, req) {

const model = models[type]
return model.findById(req.params.id).lean().exec()
.then((resources) => {
if (!resources) {
return Boom.notFound()
}
return {data: converters.toJsonApi(resources)}
})
}

const create = function(type, req) {
const model = models[type]
var data = utils.getPayload(req)
return model.create(data)
.then((created) => {
return {data: converters.toJsonApi(created.toObject())}
})
}

const update = function(type, req) {

const model = models[type]
var data = utils.getPayload(req)
return model.findByIdAndUpdate(req.params.id, data)
.then((resource) => {
if (!resource) {
return Boom.notFound()
}
return findById(type, req)
})
}

const del = function(type, req) {
const model = models[type]
var predicate = converters.toMongoosePredicate({id: req.params.id})
return model.remove(predicate)
.then(() => {
return {}
})
}

const processSchema = function(hhSchema) {

if (!models[hhSchema.type]) {

// clean up existing models and schemas
delete mongoose.models[hhSchema.type]
delete mongoose.modelSchemas[hhSchema.type]

models[hhSchema.type] = converters.toMongooseModel(hhSchema)
}
return models[hhSchema.type]
}

return {
connect,
disconnect,
find,
findById,
create,
update,
delete: del,
models,
processSchema
}

}
15 changes: 15 additions & 0 deletions lib/adapters/mongodb/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use strict'

const Hapi = require('hapi')
const _ = require('lodash')
const Hoek = require('hoek')
const mongoose = require('mongoose')
const uuid = require('node-uuid')

module.exports = function() {
const getPayload = function (req) {
return (req.payload) ? req.payload.data : {}
}

return { getPayload }
}
88 changes: 88 additions & 0 deletions lib/plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
'use strict'

const _ = require('lodash')
const routes = require('./routes')()
const adapterUtils = require('./utils/adapter')()
const routeUtils = require('./utils/route')()

exports.register = function (server, opts, next) {
server.expose('version', require('../package.json').version);

const adapter = opts.adapter;

adapterUtils.checkValidAdapter(adapter);

adapter.connect(() => {
server.expose('adapter', adapter);
next()
});

const get = function (schema) {
routeUtils.createOptionsRoute(server, schema)
adapter.processSchema(schema)
return _.merge(routes.get(schema), {
handler: (req, reply) => {
routeUtils.parseComparators(req)
reply(adapter.find(schema.type, req))
}
})
}

const getById = function (schema) {
routeUtils.createOptionsRoute(server, schema)
adapter.processSchema(schema)
return _.merge(routes.getById(schema), {
handler: (req, reply) => {
reply(adapter.findById(schema.type, req))
}
})
}

const post = function (schema) {
routeUtils.createOptionsRoute(server, schema)
adapter.processSchema(schema)
return _.merge(routes.post(schema), {
handler: (req, reply) => {
reply(adapter.create(schema.type, req)).code(201)
}
})
}

const patch = function (schema) {
routeUtils.createOptionsRoute(server, schema)
adapter.processSchema(schema)
return _.merge(routes.patch(schema), {
handler: (req, reply) => {
reply(adapter.update(schema.type, req))
}
})
}

const del = function (schema) {
routeUtils.createOptionsRoute(server, schema)
adapter.processSchema(schema)
return _.merge(routes.delete(schema), {
handler: (req, reply) => {
reply(adapter.delete(schema.type, req)).code(204)
}
})
}

server.expose('routes', {
get: get,
getById: getById,
post: post,
patch: patch,
delete: del
})

server.ext('onPostStop', (server, next) => {
adapter.disconnect(next)
})
}

exports.register.attributes = {
pkg: require('../package.json')
}

exports.getAdapter = adapterUtils.getStandardAdapter;
Loading

0 comments on commit b0c5656

Please sign in to comment.