Skip to content

Commit

Permalink
First Release
Browse files Browse the repository at this point in the history
  • Loading branch information
ardalanamini committed Nov 15, 2018
1 parent bfcbcbb commit 826fd91
Show file tree
Hide file tree
Showing 75 changed files with 9,215 additions and 1 deletion.
24 changes: 24 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
language: node_js

os:
# - windows
- linux
- osx

node_js:
- "8"
- "9"
- "10"
- "11"

script:
- npm run codecov

cache:
directories:
- "node_modules"

notifications:
email:
on_success: never
on_failure: always
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"typescript.tsdk": "node_modules/typescript/lib"
}
191 changes: 190 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,191 @@
# foxify-restify-odin
# foxify-restify-odin <!-- omit in toc -->

Easily restify odin databases

[![Npm Version](https://img.shields.io/npm/v/foxify-restify-odin.svg)](https://www.npmjs.com/package/foxify-restify-odin)
[![Node Version](https://img.shields.io/node/v/foxify-restify-odin.svg)](https://nodejs.org)
[![TypeScript Version](https://img.shields.io/npm/types/foxify-restify-odin.svg)](https://www.typescriptlang.org)
[![Package Quality](https://npm.packagequality.com/shield/foxify-restify-odin.svg)](https://packagequality.com/#?package=foxify-restify-odin)
[![Npm Total Downloads](https://img.shields.io/npm/dt/foxify-restify-odin.svg)](https://www.npmjs.com/package/foxify-restify-odin)
[![Npm Monthly Downloads](https://img.shields.io/npm/dm/foxify-restify-odin.svg)](https://www.npmjs.com/package/foxify-restify-odin)
[![Open Issues](https://img.shields.io/github/issues-raw/foxifyjs/foxify-restify-odin.svg)](https://github.com/foxifyjs/foxify-restify-odin/issues?q=is%3Aopen+is%3Aissue)
[![Closed Issues](https://img.shields.io/github/issues-closed-raw/foxifyjs/foxify-restify-odin.svg)](https://github.com/foxifyjs/foxify-restify-odin/issues?q=is%3Aissue+is%3Aclosed)
[![Known Vulnerabilities](https://snyk.io/test/github/foxifyjs/foxify-restify-odin/badge.svg?targetFile=package.json)](https://snyk.io/test/github/foxifyjs/foxify-restify-odin?targetFile=package.json)
[![Dependencies Status](https://david-dm.org/foxifyjs/foxify-restify-odin.svg)](https://david-dm.org/foxifyjs/foxify-restify-odin)
[![Pull Requests](https://img.shields.io/badge/PRs-Welcome-brightgreen.svg)](https://github.com/foxifyjs/foxify-restify-odin/pulls)
[![License](https://img.shields.io/github/license/foxifyjs/foxify-restify-odin.svg)](https://github.com/foxifyjs/foxify-restify-odin/blob/master/LICENSE)
[![Build Status](https://api.travis-ci.com/foxifyjs/foxify-restify-odin.svg?branch=master)](https://travis-ci.com/foxifyjs/foxify-restify-odin)
[![Coverage Status](https://codecov.io/gh/foxifyjs/foxify-restify-odin/branch/master/graph/badge.svg)](https://codecov.io/gh/foxifyjs/foxify-restify-odin)
[![Github Stars](https://img.shields.io/github/stars/foxifyjs/foxify-restify-odin.svg?style=social&label=Stars)](https://github.com/foxifyjs/foxify-restify-odin)
[![Github Forks](https://img.shields.io/github/forks/foxifyjs/foxify-restify-odin.svg?style=social&label=Fork)](https://github.com/foxifyjs/foxify-restify-odin)

## Table on Contents <!-- omit in toc -->

- [Getting Started](#getting-started)
- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Usage](#usage)
- [Documentation](#documentation)
- [Filters](#filters)
- [include](#include)
- [sort](#sort)
- [skip](#skip)
- [limit](#limit)
- [Versioning](#versioning)
- [Authors](#authors)
- [License](#license)
- [Support](#support)

## Getting Started

### Prerequisites

- [Node.js](https://nodejs.org/en/download) `8.12` or higher is required.
- [foxify](https://github.com/foxifyjs/foxify) `0.10.14` or higher is required.
- [@foxify/odin](https://github.com/foxifyjs/odin) `0.2.2` or higher is required.

### Installation

```bash
npm i -s foxify-restify-odin
```

### Usage

```javascript
const Foxify = require('foxify');
const restify = require('foxify-restify-odin');
const User = require('./models/User');

let app = new Foxify();

app.get('/users', restify(User), async (req, res) => {
res.json({
users: await req.fro.query.get(),
total_users: await req.fro.counter.count(),
});
});

app.start();
```

## Documentation

This middleware parses url query string and executes a query on the given model accordingly and passes the `query` to you (since you might need to do some modifications on the query, too)

It also passes a `counter` which is exactly like `query` but without applying `skip`, `limit`, `sort` just because you might want to send a total count in your response as well

Lastly it passes the a `decoded` key in `req.fro` which is the parsed query string that is used in the middleware

**Stringify all query params using [qs](https://www.npmjs.com/package/qs) default options**

All the possible query modifiers are explained as a single modification but they all can be used together

`/users?sort%5B0%5D=age`

### Filters

```javascript
qs.stringify({
filter: {
field: "username",
operator: "eq",
value: "ardalanamini",
}
})
```

```javascript
qs.stringify({
filter: {
or: [
{
field: "username",
operator: "eq",
value: "ardalanamini",
},
{
and: [
{
field: "age",
operator: "gte",
value: 18,
},
{
field: "email",
operator: "ex",
value: true,
},
],
},
],
},
})
```

filter can be a single filter object or `and`/`or` of Array\<filter object\>

possible operators:

`lt` | `lte` | `eq` | `ne` | `gte` | `gt` | `ex` | `in` | `nin` | `bet` | `nbe`

### include

```javascript
qs.stringify({
include: [
"relation1",
"relation2",
]
})
```

### sort

```javascript
qs.stringify({
sort: [
"field1", // same as "+field1"
"-field2",
"+field3",
]
})
```

### skip

```javascript
qs.stringify({
skip: 100,
})
```

### limit

```javascript
qs.stringify({
limit: 10,
})
```

## Versioning

We use [SemVer](http://semver.org) for versioning. For the versions available, see the [tags on this repository](https://github.com/foxifyjs/foxify/tags).

## Authors

- **Ardalan Amini** - *Owner/Developer* - [@ardalanamini](https://github.com/ardalanamini)

See also the list of [contributors](https://github.com/foxifyjs/foxify/contributors) who participated in this project.

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details

## Support

If my work helps you, please consider

[![Become A Patron](https://c5.patreon.com/external/logo/become_a_patron_button.png)](https://www.patreon.com/ardalanamini)

[![Buy Me A Coffee](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/ardalanamini)
2 changes: 2 additions & 0 deletions dist/builders/filter.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
declare const filter: (model: any, filters: any) => any;
export default filter;
53 changes: 53 additions & 0 deletions dist/builders/filter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const BASIC_OPERATORS = {
eq: "=",
gt: ">",
gte: ">=",
lt: "<",
lte: "<=",
ne: "<>",
};
const operate = (query, field, operator, value) => {
switch (operator) {
case "lt":
case "lte":
case "eq":
case "ne":
case "gte":
case "gt":
return query.where(field, BASIC_OPERATORS[operator], value);
case "ex":
if (value === true)
return query.whereNotNull(field);
return query.whereNull(field);
case "in":
return query.whereIn(field, value);
case "nin":
return query.whereNotIn(field, value);
case "bet":
return query.whereBetween(field, value[0], value[1]);
case "nbe":
return query.whereNotBetween(field, value[0], value[1]);
default:
throw new TypeError("Unknown operator");
}
};
const and = (query, filters) => filters
.reduce((prev, curr) => prev.where((q) => filter(q, curr)), query);
const or = (query, filters) => filters.reduce((prev, curr, index) => {
if (index === 0)
return prev.where((q) => filter(q, curr));
return prev.orWhere((q) => filter(q, curr));
}, query);
const filter = (model, filters) => {
if (filters.and) {
if (filters.or)
throw new TypeError("filter can only have one of [\"and\", \"or\"]");
return and(model, filters.and);
}
if (filters.or)
return or(model, filters.or);
return operate(model, filters.field, filters.operator, filters.value);
};
exports.default = filter;
2 changes: 2 additions & 0 deletions dist/builders/include.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
declare const _default: (model: import("@foxify/odin/dist/utils").ClassInterface & typeof import("@foxify/odin/dist/Model").default & typeof import("@foxify/odin/dist/base/QueryBuilder").default & typeof import("@foxify/odin/dist/base/Relational").default & typeof import("@foxify/odin/dist/GraphQL/Model").default, relations: string[]) => import("@foxify/odin/dist/base/Query").default<{}, any>;
export default _default;
3 changes: 3 additions & 0 deletions dist/builders/include.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = (model, relations) => model.with(...relations);
3 changes: 3 additions & 0 deletions dist/builders/limit.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import * as Odin from "@foxify/odin";
declare const _default: (model: Odin<{}> | (import("@foxify/odin/dist/utils").ClassInterface & typeof import("@foxify/odin/dist/Model").default & typeof import("@foxify/odin/dist/base/QueryBuilder").default & typeof import("@foxify/odin/dist/base/Relational").default & typeof import("@foxify/odin/dist/GraphQL/Model").default), limit: number) => any;
export default _default;
3 changes: 3 additions & 0 deletions dist/builders/limit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = (model, limit) => model.limit(limit);
3 changes: 3 additions & 0 deletions dist/builders/skip.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import * as Odin from "@foxify/odin";
declare const _default: (model: Odin<{}> | (import("@foxify/odin/dist/utils").ClassInterface & typeof import("@foxify/odin/dist/Model").default & typeof import("@foxify/odin/dist/base/QueryBuilder").default & typeof import("@foxify/odin/dist/base/Relational").default & typeof import("@foxify/odin/dist/GraphQL/Model").default), skip: number) => any;
export default _default;
3 changes: 3 additions & 0 deletions dist/builders/skip.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = (model, skip) => model.skip(skip);
2 changes: 2 additions & 0 deletions dist/builders/sort.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
declare const _default: (model: any, sorts: string[]) => any;
export default _default;
3 changes: 3 additions & 0 deletions dist/builders/sort.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = (model, sorts) => sorts.reduce((prev, sort) => prev.orderBy(sort.replace(/^(\+|\-)/, ""), /^\-/.test(sort) ? "desc" : "asc"), model);
6 changes: 6 additions & 0 deletions dist/decoder.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
declare const decoder: (query: {
[key: string]: any;
}) => {
[key: string]: any;
};
export default decoder;
33 changes: 33 additions & 0 deletions dist/decoder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const methods_1 = require("prototyped.js/es6/methods");
const { forEach: objectForEach, isPlainObject: isObject } = methods_1.object;
const isArray = (value) => Array.isArray(value);
const isBoolean = (value) => value === "false" || value === "true";
const isNumber = (value) => !isNaN(parseFloat(value)) && isFinite(value);
const parseArray = (arr) => arr.map(value => parseValue(value));
const parseBoolean = (str) => str === "true";
const parseNumber = (str) => Number(str);
const parseValue = (val) => {
if (typeof val === "undefined" || val === "")
return null;
if (isBoolean(val))
return parseBoolean(val);
if (isArray(val))
return parseArray(val);
if (isObject(val))
return decoder(val);
if (isNumber(val))
return parseNumber(val);
return val;
};
const decoder = (query) => {
const result = {};
objectForEach(query, (value, key) => {
value = parseValue(value);
if (value !== null)
result[key] = value;
});
return result;
};
exports.default = decoder;
Empty file added dist/filter.1.d.ts
Empty file.
1 change: 1 addition & 0 deletions dist/filter.1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"use strict";
2 changes: 2 additions & 0 deletions dist/filter.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
declare const filter: (model: any, filters: any) => any;
export default filter;
Loading

0 comments on commit 826fd91

Please sign in to comment.