Giter VIP home page Giter VIP logo

querymen's Introduction

Querymen

JS Standard Style NPM version Build Status Coveralls Status Dependency Status Downloads

Querystring parser middleware for MongoDB, Express and Nodejs

Install

npm install --save querymen

Examples

Pagination

Querymen has a default schema to handle pagination. This is the most simple and common usage.

import { middleware as query } from 'querymen';

app.get('/posts', query(), ({ querymen: { query, select, cursor } }, res) => {

  Post.find(query, select, cursor).then(posts => {
    // posts are proper paginated here
  });
});

User requests /posts?page=2&limit=20&sort=-createdAt querymen will be:

querymen = {
  query: {},
  select: {},
  cursor: {
    limit: 20, 
    skip: 20, 
    sort: { createdAt: -1 }
  }
}

User requests /posts?q=term&fields=title,desc querymen will be:

When user requests /posts?q=term, querymen parses it to {keywords: /term/i}. It was designed to work with mongoose-keywords plugin, which adds a keywords field to schemas (check that out).

querymen = {
  query: {
    keywords: /term/i
  },
  select: {
    title: 1,
    desc: 1
  },
  cursor: {
    // defaults
    limit: 30, 
    skip: 0, 
    sort: { createdAt: -1 }
  }
}

User requests /posts?fields=-title&sort=name,-createdAt querymen will be:

querymen = {
  query: {},
  select: {
    title: 0
  },
  cursor: {
    limit: 30, 
    skip: 0, 
    sort: {
      name: 1,
      createdAt: -1
    }
  }
}

Custom schema

You can define a custom schema, which will be merged into querymen default schema (explained above).

import { middleware as query } from 'querymen';

app.get('/posts', query({
  after: {
    type: Date,
    paths: ['createdAt'],
    operator: '$gte'
  }
}), ({ querymen }, res) => {
  Post.find(querymen.query).then(posts => {
    // ...
  });
});

User requests /posts?after=2016-04-23 querymen will be:

querymen = {
  query: {
    createdAt: { $gte: 1461369600000 }
  },
  select: {},
  cursor: {
    // defaults
    limit: 30, 
    skip: 0, 
    sort: { createdAt: -1 }
  }
}

Reusable schemas

You can create reusable schemas as well. Just instantiate a Schema object.

import { middleware as query, Schema } from 'querymen';

const schema = new Schema({
  tags: {
    type: [String],
  }
});

// user requests /posts?tags=world,travel
// querymen.query is { tags: { $in: ['world', 'travel'] }}
app.get('/posts', query(schema));
app.get('/articles', query(schema));

Advanced schema

import { middleware as query, Schema } from 'querymen';

const schema = new Schema({
  active: Boolean, // shorthand to { type: Boolean }
  sort: '-createdAt', // shorthand to { type: String, default: '-createdAt' }
  term: {
    type: RegExp,
    paths: ['title', 'description'],
    bindTo: 'search' // default was 'query'
  },
  with_picture: {
    type: Boolean,
    paths: ['picture'],
    operator: '$exists'
  }
}, {
  page: false, // disable default parameter `page`
  limit: 'max_items' // change name of default parameter `limit` to `max_items`
});

app.get('/posts', query(schema), ({ querymen }, res) => {
  // user requests /posts?term=awesome&with_picture=true&active=true&max_items=100
  // querymen.query is { picture: { $exists: true }, active: true }
  // querymen.cursor is { limit: 100, sort: { createdAt: -1 } }
  // querymen.search is { $or: [{ title: /awesome/i }, { description: /awesome/i }]}
});

Dynamic advanced schema

import { middleware as query, Schema } from 'querymen';
const schema = new Schema();

schema.formatter('scream', (scream, value, param) => {
  if (scream) {
    value = value.toUpperCase() + '!!!!!!!';
  }
  return value;
});

schema.param('text', null, { type: String }); // { type: String }
schema.param('text').option('scream', true); // { type: String, scream: true }
schema.param('text').value('help');
console.log(schema.param('text').value()); // HELP!!!!!!!

schema.validator('isPlural', (isPlural, value, param) => {
  return {
    valid: !isPlural || value.substr(-1) === 's',
    message: param.name + ' must be in plural form.'
  };
});

schema.param('text').option('isPlural', true); // { type: String, scream: true, isPlural: true }
console.log(schema.validate()); // false
schema.param('text', 'helps');
console.log(schema.validate()); // true
console.log(schema.param('text').value()); // HELPS!!!!!!!

schema.parser('elemMatch', (elemMatch, value, path, operator) => {
  if (elemMatch) {
    value = { [path]: { $elemMatch: {[elemMatch]: {[operator]: value } }}};
  }
  return value;
});

schema.param('text', 'ivegotcontrols');
console.log(schema.param('text').parse()); // { text: 'IVEGOTCONTROLS!!!!!!!' }

schema.param('text').option('elemMatch', 'prop');
console.log(schema.param('text').parse()); // { text: { $elemMatch: { prop: { $eq: 'IVEGOTCONTROLS!!!!!!!'} }}}

Geo queries

Querymen also support geo queries, but it's disabled by default. To enable geo queries you just need to set near option to true in schema options.

import { middleware as query } from 'querymen';

app.get('/places', query({}, { near: true }), (req, res) => {
  
});

Its paths option is set to ['location'] by default, but you can change this as well:

import { middleware as query } from 'querymen';

app.get('/places', 
  query({
    near: { paths: ['loc'] }
  }, {
    near: true
  }), 
  (req, res) => {
  
  });

User requests /places?near=-22.332113,-44.312311 (latitude, longitude), req.querymen.query will be:

req.querymen.query = {
  loc: {
    $near: {
      $geometry: {
        type: 'Point',
        coordinates: [-44.312311, -22.332113]
      }
    }
  }
}

User requests /places?near=-22.332113,-44.312311&min_distance=200&max_distance=2000 (min_distance and max_distance in meters), req.querymen.query will be:

req.querymen.query = {
  loc: {
    $near: {
      $geometry: {
        type: 'Point',
        coordinates: [-44.312311, -22.332113]
      },
      $minDistace: 200,
      $maxDistance: 2000
    }
  }
}

You can also use legacy geo queries as well. Just set geojson option in param:

import { middleware as query } from 'querymen';

app.get('/places', 
  query({
    near: {
      paths: ['loc'],
      geojson: false
    }
  }, {
    near: true
  }), 
  (req, res) => {
  
  });

User requests /places?near=-22.332113,-44.312311&min_distance=200&max_distance=2000, req.querymen.query will be:

req.querymen.query = {
  loc: {
    $near: [-44.312311, -22.332113],
    // convert meters to radians automatically
    $minDistace: 0.000031,
    $maxDistance: 0.00031
  }
}

Error handling

// user requests /posts?category=world
import { middleware as query, querymen, Schema } from 'querymen';

const schema = new Schema({
  category: {
    type: String,
    enum: ['culture', 'general', 'travel']
  }
});

app.get('/posts', query(schema));

// create your own handler
app.use((err, req, res, next) => {
  res.status(400).json(err);
});

// or use querymen error handler
app.use(querymen.errorHandler());

Response body will look like:

{
  "valid": false,
  "name": "enum",
  "enum": ["culture", "general", "travel"],
  "value": "world",
  "message": "category must be one of: culture, general, travel"
}

Contributing

This package was created with generator-rise. Please refer to there to understand the codestyle and workflow. Issues and PRs are welcome!

License

MIT © Diego Haz

querymen's People

Contributors

chemitaxis avatar diegohaz avatar greenkeeper[bot] avatar jorgeluisrezende avatar talesdsp avatar tguelcan avatar

Stargazers

 avatar

Forkers

felipegs31

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.