I have problem to understand the line: this.callQueue = [ [ 'pre', [ 'save', beforeSave ] ] ];
Here is the line where it locates at:
var util = require('util');
var Schema = require('mongoose').Schema;
var counter = require('./counter');
var utils = require('./utils');
/**
* Base Schema constructor.
*
* ####Example:
*
* var user = new BaseSchema({ name: String });
* var post = new BaseSchema({ content: String });
*
* // setting schema options
* new BaseSchema({ name: String }, { _id: false, autoIndex: false })
*
* ####Options:
*
* - [autoIndex](/docs/guide.html#autoIndex): bool - defaults to true
* - [bufferCommands](/docs/guide.html#bufferCommands): bool - defaults to true
* - [capped](/docs/guide.html#capped): bool - defaults to false
* - [collection](/docs/guide.html#collection): string - no default
* - [id](/docs/guide.html#id): bool - defaults to true
* - [_id](/docs/guide.html#_id): bool - defaults to true
* - `minimize`: bool - controls [document#toObject](#document_Document-toObject) behavior when called manually - defaults to true
* - [read](/docs/guide.html#read): string
* - [safe](/docs/guide.html#safe): bool - defaults to true.
* - [shardKey](/docs/guide.html#shardKey): bool - defaults to `null`
* - [strict](/docs/guide.html#strict): bool - defaults to true
* - [toJSON](/docs/guide.html#toJSON) - object - no default
* - [toObject](/docs/guide.html#toObject) - object - no default
* - [versionKey](/docs/guide.html#versionKey): bool - defaults to "__v"
*
*
* #param {Object} definition
* #inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter
* #event `init`: Emitted after the schema is compiled into a `Model`.
* #api public
*/
function BaseSchema() {
Schema.apply(this, arguments);
this.callQueue = [ [ 'pre', [ 'save', beforeSave ] ] ];
this.add({
_id: Number,
createTime: Number,
modifyTime: Number
});
}
/**
* set default value before save to db
*
*
* #param {Function} next
*/
function beforeSave(next) {
var model = this;
if(model.isNew) {
model.modifyTime = model.createTime = Date.now();
counter.getNextId(model.collection.name + '_id', function(err, id) {
model._id = id;
next();
});
}
else {
model.modifyTime = Date.now();
next();
}
}
util.inherits(BaseSchema, Schema);
module.exports = BaseSchema;
Also I think the usage is like this
var Post = new BaseSchema({
title: String,
tags: Array,
content: String,
creator: String,
avatar: String,
comments: [Comment],
pv: Array,
reprint: { type: Object, default: {} },
lastUpdateTime: String
}, options);
Post.pre('save', function(next) {
if(this.isNew) {
this.lastUpdateTime = utils.formatDate(Date.now());
}
next();
})
Also here is the project github link: [https://github.com/smadey/node-mongoose-blog]. The code is in models file
this.callQueue = [ [ 'pre', [ 'save', beforeSave ] ] ] is internally adding a pre save middleware for all the schemas that are inherited from it. For example is the Post schema will have now two pre save hooks attached to it:
First one is the beforeSave hook attached with BaseSchema
Second one is the hook that is attached with Post schema
Internally all hooks are stored in callQueue array. If you log that variable, you'll see two callbacks for those two hooks:
> console.log(Post.callQueue)
[ [ 'pre', [ 'save', [Function: beforeSave] ] ],
[ 'pre', { '0': 'save', '1': [Function] } ] ]
Related
I am using Express and Node. I am following the below link to get my swagger documentation for the APIs: http://mherman.org/blog/2016/05/26/swagger-and-nodejs/#.We8gq2iCzDc. I have the same project structure. I am sure there is something missing yet I am unable to find the mistake. Any help is appreciated.
This is my app.js:
import express from 'express';
import path from 'path';
var routes = require('./routes/routes');
var swaggerJSDoc = require('swagger-jsdoc');
var bodyParser = require('body-parser');
var swaggerDefinition = {
info: {
title: 'Node Swagger API',
version: '1.0.0',
description: 'Demonstrating how to describe a RESTful API with Swagger',
},
host: 'localhost:3000',
basePath: '/',
};
var options = {
swaggerDefinition: swaggerDefinition,
apis: ['./routes/routes.js']
};
var swaggerSpec = swaggerJSDoc(options);
class Server {
constructor() {
this.app = express();
}
configureApp() {
this.app.set('port', (process.env.PORT || 3000));
this.app.use(bodyParser.json());
this.app.use(bodyParser.urlencoded({ extended: true }));
this.app.use(bodyParser());
this.app.use(express.static(path.join(__dirname, 'public')));
this.app.use('/', routes);
}
configureCORS() {
this.app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'POST, PUT, DELETE, GET');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With');
res.setHeader('Cache-Control', 'no-cache');
next();
});
}
configureRoutes() {
this.app.post('/api/doctorPost', doctor.post);
this.app.put('/api/doctorEdit/:id', doctor.put);
this.app.delete('/api/doctorDelete/:id', doctor.delete);*/
this.app.get('/swagger.json', function(req, res) {
res.setHeader('Content-Type', 'application/json');
res.send(swaggerSpec);
});
}
listen(port) {
this.app.listen(port, () => {
console.log(`Server started: http://localhost:${port}/`);
});
}
run() {
this.configureApp();
this.configureCORS()
this.configureRoutes();
this.listen(this.app.get('port'));
}
}
export default Server;
This is my routes.js:
var express = require('express');
var router = express.Router();
var api = require('../doctor.api');
/**
* #swagger
* definition:
* doctor:
* type: object
* properties:
* id:
* type: integer
* name:
* type: string
* picUrl:
* type: string
* briefDescription:
* type: string
* speciality:
* type: string
* exprience:
* type: string
* description:
* type: string
* contact:
* type: string
* email:
* type: string
* phoneno:
* type: integer
* status:
* type: string
* description: doctor Status
* enum:
* - available
* - pending
* - not exists
* waitingTime:
* type: integer
* format: int64
* rating:
* type: integer
* format: int64
* videoUrl:
* type: string
* appearUrl:
* type: string
* collapseId:
* type: string
* thumbnailUrl:
* type: string
* lastUpdateTime:
* type: integer
* format: int64
*/
/**
* #swagger
* /api/doctorGet:
* get:
* tags:
* - doctor
* description: Returns all doctor
* produces:
* - application/json
* responses:
* 200:
* description: An array of doctor
* schema:
* $ref: '#/definitions/doctor'
*/
router.get('/api/doctorGet', api.getDoctors);
/**
* #swagger
* /api/doctorPost:
* post:
* tags:
* - doctor
* summary: Add a new doctor to the list
* description: New doctor added
* operationId: addDoctor
* consumes:
* - application/json
* - application/xml
* produces:
* - application/xml
* - application/json
* parameters:
* - in: body
* name: body
* description: Doctor object that needs to be added to the list
* required: true
* schema:
* $ref: '#/definitions/doctor'
* responses:
* '405':
* description: Invalid input
* security:
* - doctor_auth:
* - 'write:doctor'
* - 'read:doctor'
*/
router.post('/api/doctorPost', api.createDoctor);
/**
* #swagger
* /api/doctorEdit/{id}:
* put:
* tags:
* - doctor
* description: Updates a single doctor
* produces:
* - application/json
* parameters:
* - name: id
* description: doctor's id
* in: path
* required: true
* type: integer
* - name: puppy
* description: doctor object
* in: body
* required: true
* schema:
* $ref: '#/definitions/doctor'
* responses:
* 200:
* description: Successfully updated
*/
router.put('/api/doctorEdit/:id', api.updateDoctor);
/**
* #swagger
* /api/doctorDelete/{id}:
* delete:
* tags:
* - doctor
* description: Deletes a single doctor
* produces:
* - application/json
* parameters:
* - name: id
* description: doctor's id
* in: path
* required: true
* type: integer
* responses:
* 200:
* description: Successfully deleted
*/
router.delete('/api/doctorDelete/:id', api.deleteDoctor);
module.exports = router;
My output is:
{"info":{"title":"Node Swagger
API","version":"1.0.0","description":"Demonstrating how to describe a
RESTful API with Swagger"},"host":"localhost:3000","basePath":"/","swagger":"2.0","paths":
{},"definitions":{},"responses":{},"parameters":{},"securityDefinitions":{}}
Expected output would be something like this:
{"info":{"title":"Node Swagger
API","version":"1.0.0","description":"Demonstrating how to desribe a RESTful API with Swagger"},"host":"localhost:3000","basePath":"/","swagger":"2.0","paths":{"/api/puppies":{"get":{"tags":["Puppies"],"description":"Returns all puppies","produces":["application/json"],"responses":{"200":{"description":"An array of puppies","schema":{"$ref":"#/definitions/Puppy"}}}},"post":{"tags":["Puppies"],"description":"Creates a new puppy","produces":["application/json"],"parameters":[{"name":"puppy","description":"Puppy object","in":"body","required":true,"schema":{"$ref":"#/definitions/Puppy"}}],"responses":{"200":{"description":"Successfully created"}}}},"/api/puppies/{id}":{"get":{"tags":["Puppies"],"description":"Returns a single puppy","produces":["application/json"],"parameters":[{"name":"id","description":"Puppy's id","in":"path","required":true,"type":"integer"}],"responses":{"200":{"description":"A single puppy","schema":{"$ref":"#/definitions/Puppy"}}}},"put":{"tags":["Puppies"],"description":"Updates a single puppy","produces":["application/json"],"parameters":[{"name":"id","description":"Puppy's id","in":"path","required":true,"type":"integer"},{"name":"puppy","description":"Puppy object","in":"body","required":true,"schema":{"$ref":"#/definitions/Puppy"}}],"responses":{"200":{"description":"Successfully updated"}}},"delete":{"tags":["Puppies"],"description":"Deletes a single puppy","produces":["application/json"],"parameters":[{"name":"id","description":"Puppy's id","in":"path","required":true,"type":"integer"}],"responses":{"200":{"description":"Successfully deleted"}}}}},"definitions":{"Puppy":{"properties":{"name":{"type":"string"},"breed":{"type":"string"},"age":{"type":"integer"},"sex":{"type":"string"}}}},"responses":{},"parameters":{},"securityDefinitions":{},"tags":[]}
I need to import the data from a CSV file (around 20K rows) to my database. Some of the rows may already exist in the database, thus they only need to be updated, but the new rows must be inserted. If any of the operations fail, the transaction must be cancelled.
How can I do this? This is the code I was using:
var vehicle = {
id: row.id,
lastUpdate: moment(row.lastUpdate, 'DD/MM/YYYY - HH:mm').toDate(),
version: row.version,
color: row.color,
location: row.location,
status: row.status
};
Vehicle.forge({
id: row.id
})
.save(vehicle, { transacting: t, patch: true })
.then(model => {
console.log('*************' + vehicle.id);
})
.catch(Vehicle.NoRowsUpdatedError, err => {
// There are no rows for this chassis, so let's insert it
Vehicle.forge(vehicle)
.save(null, { transacting: t, method: 'insert' })
.then(model => {
console.log('++++++++++++++' + vehicle.id);
})
.catch(err => {
console.log(`INSERT ERROR: ${err.message}`);
t.rollback();
return res.json({ status: false, count: 0, error: err.message });
});
})
.catch(err => {
console.log(`UPDATE ERROR: ${err.message}`);
t.rollback();
return res.json({ status: false, count: 0, error: err.message });
});
This code is in a for loop, but it fails in the second iteration, probably because of concurrency between the promises.
I also tried to add a custom function to my model file, but it says that the function does not exist.
let bookshelf = require('./base');
var Vehicle,
Vehicles;
Vehicle = bookshelf.Model.extend({
tableName: 'vehicles',
/**
* Insert a model based on data
* #param {Object} data
* #param {Object} [options] Options for model.save
* #return {Promise(bookshelf.Model)}
*/
create: function (data, options) {
return this.forge(data).save(null, options);
},
/**
* Select a model based on a query
* #param {Object} [query]
* #param {Object} [options] Options for model.fetch
* #param {Boolean} [options.require=false]
* #return {Promise(bookshelf.Model)}
*/
findOne: function (query, options) {
options = extend({ require: true }, options);
return this.forge(query).fetch(options);
},
/**
* Select a model based on data and update if found, insert if not found
* #param {Object} selectData Data for select
* #param {Object} updateData Data for update
* #param {Object} [options] Options for model.save
*/
upsert: function (selectData, updateData, options) {
return this.findOne(selectData, extend(options, { require: false }))
.bind(this)
.then(function (model) {
return model
? model.save(
updateData,
extend({ patch: true, method: 'update' }, options)
)
: this.create(
extend(selectData, updateData),
extend(options, { method: 'insert' })
)
});
}
});
Vehicles = bookshelf.Collection.extend({
model: Vehicle
});
module.exports = {
Vehicle: bookshelf.model('Vehicle', Vehicle),
Vehicles: bookshelf.collection('Vehicles', Vehicles)
};
Instead of using bookshelf, you could utilize knex directly to do this. Just grab the instance of knex you pass to bookshelf, and you can use it like this:
knex.transaction((trx) => {
return Bluebird.map(vehicles, vehicle => {
const insert = knex('vehicles').insert(vehicle).toString();
delete vehicle.id;
const update = knex('vehicles').update(vehicle).toString();
const set = update.substring(18);
return trx.raw(`${insert} ON CONFLICT (id) DO UPDATE ${set}`);
});
});
We can utilize Knex's handy toString method to generate most of our raw query for us; in this way, we can do an upsert even though it's not directly supported by Knex. Bluebird's map function is perfect for cleanly handling an array of data like this and would let you await having to loop through it altogether.
I'm trying to set up a node.js server with a Relay-compatible GraphQL schema.
When trying to validate or load the schema I get the following error:
EventEdge.node field type must be Output Type but got: undefined.
This is caused by having a connection type for for the Event type in one of the other type definitions.
I won't post the whole schema because it's quite verbose but when the connection field is commented out the schema is loaded correctly and no errors are thrown.
I've included an example of a simplified schema that causes the same issue:
const graphql = require('graphql')
const relay = require('graphql-relay')
const GraphQLID = graphql.GraphQLID,
GraphQLInt = graphql.GraphQLInt,
GraphQLString = graphql.GraphQLString,
GraphQLList = graphql.GraphQLList,
GraphQLObjectType = graphql.GraphQLObjectType,
GraphQLSchema = graphql.GraphQLSchema,
GraphQLNonNull = graphql.GraphQLNonNull
const connectionArgs = relay.connectionArgs,
connectionDefinitions = relay.connectionDefinitions,
connectionFromArray = relay.connectionFromArray,
cursorForObjectInConnection = relay.cursorForObjectInConnection,
fromGlobalId = relay.fromGlobalId,
globalIdField = relay.globalIdField,
mutationWithClientMutationId = relay.mutationWithClientMutationId,
nodeDefinitions = relay.nodeDefinitions,
toGlobalId = relay.toGlobalId
// Models (ORM Mappings)
const models = require('../models')
// Model handlers
const handlers = require('../models/handlers')
/*
* Relay Node Definition:
* {nodeInterface, nodeField} = nodeDefinitions
*/
var nodeDefinition = nodeDefinitions(
(globalId) => {
// {type, id} = fromGlobalId(globalId)
const gid = fromGlobalId(globalId);
switch (gid.type) {
case 'User':
return handlers.getUser(id)
// case 'Event':
// return handlers.getEvent(id)
//
// case 'Club':
// return handlers.getClub(id)
default:
return null
}
},
(obj) => {
switch (true) {
case (obj instanceof models.User):
return UserType
// case (obj instanceof models.Club):
// return ClubType
//
// case (obj instanceof models.Event):
// return EventType
default:
return null
}
}
)
/**************************
**************************
* Relay Connections
*
* { connectionType, edgeType } = connectionDefinitions({nodeType: LoremType})
**************************
**************************/
// User Connection
// const usersConnection = connectionDefinitions({name: 'User', nodeType: UserType})
// Event Connection
const eventsConnection = connectionDefinitions({name: 'Event', nodeType: EventType})
// Club Connection
// const clubsConnection = connectionDefinitions({name: 'Club', nodeType: ClubType})
/**************************
**************************
* GraphQL Type Definitions
**************************
**************************/
/*
* User Type
*
* type User : Object {
* id: String!
* first_name: String
* last_name: String
* friends: [User]
* }
*/
var UserType = new GraphQLObjectType({
name: 'User',
description: 'A user of the app.',
fields: () => ({
id: globalIdField('User'),
events: {
type: eventsConnection.connectionType,
description: 'User\'s events.',
args: connectionArgs,
resolve: (user, args) => connectionFromArray(getEvents(), args)
}
}),
interfaces: [nodeDefinition.nodeInterface]
})
/*
** Event Type
*
* type Event : Object {
* id: String!
* title: String
* description: String
* datetime: Int
* location: [Int]
* managers: [User]
* club: Club
* members: [User]
* }
*/
var EventType = new GraphQLObjectType({
name: 'Event',
description: 'An event in the app.',
fields: () => ({
id: globalIdField('Event'),
name: {
type: GraphQLString,
description: 'Event\'s name.',
resolve: event => event.get('name')
}
}),
interfaces: [nodeDefinition.nodeInterface]
})
/****************************
****************************
* Relay Mutation Definitions
****************************
****************************/
/**************************
**************************
* Root Schema Definitions
**************************
**************************/
/*
** Root Query
*
* type Query {
* user(id: String!): User
* club(id: String!): Club
* event(id: String!): Event
* }
*/
var QueryType = new GraphQLObjectType({
name: 'Query',
fields: () => ({
node: nodeDefinition.nodeField,
user: {
type: UserType,
resolve: () => handlers.getUser()
}
})
})
/*
** Root Schema
*
* type Schema {
* query: Query
* mutation: Mutation
* }
*/
var Schema = new GraphQLSchema({
query: QueryType
})
module.exports = Schema
You've made a reference to EventType before assigning to it. First define the type, then make use of it in the connection:
/**
* Event Type
*
* type Event : Object {
* id: String!
* title: String
* description: String
* datetime: Int
* location: [Int]
* managers: [User]
* club: Club
* members: [User]
* }
*/
var EventType = new GraphQLObjectType({
name: 'Event',
description: 'An event in the app.',
fields: () => ({
id: globalIdField('Event'),
name: {
type: GraphQLString,
description: 'Event\'s name.',
resolve: event => event.get('name')
},
}),
interfaces: [nodeDefinition.nodeInterface],
});
// Event Connection
const eventsConnection = connectionDefinitions({
name: 'Event',
nodeType: EventType,
});
I have a schema defined as below:
var UserSchema = [{
id: { // unique id for users, store as int
type: Number, index: true, unique: true },
login: { // login name
type: String, index: true, unique: true },
mail: { // mail address
type: String, index: true, unique: true }
}, {
id: false // disable mongoose's automatic id mapping
}];
and a method to create those new documents
/**
* Generate user Id, range 1-16777215 (1-FFFFFF, in Hex)
* #private
* #return {number} - random generated user id
*/
UserManager.prototype._generateUserId = function () {
return Math.floor(Math.random() * 16777215) + 1;
};
/**
* Create a user with desired "login" and "mail"
* #access public
* #param {string} login - user login name
* #param {string} mail - user mail address
*/
UserManager.prototype.createUser = function (login, mail) {
var d = Q.defer();
var rec = new this.umodel({ login: login, mail: mail });
var try_create = (function () {
rec.id = this._generateUserId();
rec.save((function (error) {
if (error)
if (error.code == 11000) {
// E11000: duplicate key error
// genre
try_create();
} else
d.reject();
d.resolve(rec.id);
}).bind(this));
}).bind(this);
try_create();
};
I managed to make the user's id, username and email address unique by setting it to a unique key, and now I failed to figure out which key is duplicated when I'm getting a duplicated key error.
I have a User model and a Follower model which has HasManyThrough relation with User for the follower and followee.
How can I change the default __get__followers method parameters?
I figured out that I can juse add a new remote method the normal way.
loopback.remoteMethod(
UserModel.prototype.getFollows,
{
description: 'Get the users who are followed by the user',
accepts: [
{arg: 'page', type: 'Number', http: {source: 'query'}, required: true}
],
returns: {arg: 'data', type: 'object'},
http: {verb: 'get', path: '/follows'},
isStatic: false,
}
);
Yet another way. Tree hasMany Leaves and we want to override the __get__leaves relation handler of a Tree.
/**
* Before Remote handler
*
* #param {Object} ctx - Context
* #param {Function} next - Callback function
*/
Tree.beforeRemote('**', function (ctx, unused, next) {
if (ctx.method.name === '__get__leaves') {
return Tree.getLeaves(ctx)
}
next()
})
/**
* Override Relation handler
*
* #param {Object} ctx - Context
*/
Tree.getLeaves = (ctx) => {
ctx.res.sendStatus(200)
}