Giter Site home page Giter Site logo

odata-sequelize's Introduction

odata-sequelize

License: MIT npm Build Status npm

NPM

Objective

This library is intended to take an OData query string as a parameter and transform it on a sequelize-compliant query.

Requirements

  • Node.JS
  • NPM
  • Sequelize.JS

Installing

Simply run a npm command to install it in your project:

npm install odata-sequelize

How does it work?

The OData query string is first parsed by node-odata-parser and then the resulting object is recursively iterated to build a new object that is compliant to sequelize's standard.

Roadmap

WIP

  • Query in children tables
  • $expand

Boolean Operators

  • AND
  • OR
  • NOT

Comparison Operators

  • Equal (eq)
  • Not Equal (ne)
  • Greater Than (gt)
  • Greater Than or Equal (ge)
  • Less Than (lt)
  • Less Than or Equal (le)

Functions

  1. String Functions
  • substringof
  • endswith
  • startswith
  • tolower
  • toupper
  • trim
  • concat
  • substring
  • replace
  • indexof
  1. Date Functions
  • day
  • hour
  • minute
  • month
  • second
  • year

Others

  • Test (Jest) - Thanks to @remcohaszing
  • Lint & Prettier - Thanks to @remcohaszing
  • Complex query with precedence
  • top
  • select
  • filter
  • skip
  • expand
  • query children tables

How to Use

You just need to pass an OData query string as parameter with your sequelize object instance, and automagically it is converted to a sequelize query.

Usage Example:

var parseOData = require("odata-sequelize");
var sequelize = require("sequelize");
var query = parseOData(
  "$top=5&$skip=1&$select=Foo,Bar&$filter=Foo eq 'Test' or Bar eq 'Test'&$orderby=Foo desc",
  sequelize
);

// Supposing you have your sequelize model
Model.findAll(query);

See the examples below to checkout what's created under the hood:

1) Simple Query with Top, Skip, Select, Filter and OrderBy

var parseOData = require("odata-sequelize");
var sequelize = require("sequelize");
var query = parseOData(
  "$top=5&$skip=1&$select=Foo,Bar&$filter=Foo eq 'Test' or Bar eq 'Test'&$orderby=Foo desc",
  sequelize
);

query becomes...

{
    attributes: ['Foo', 'Bar'],
    limit: 5,
    offset: 1,
    order: [
        ['Foo', 'DESC']
    ],
    where: {
        [Op.or]: [
            {
                Foo: {
                    [Op.eq]: "Test"
                }
            },
            {
                Bar: {
                    [Op.eq]: "Test"
                }
            }
        ]
    }
}

2) Complex Query with Precedence

var parseOData = require("odata-sequelize");
var sequelize = require("sequelize");
var query = parseOData(
  "$filter=(Foo eq 'Test' or Bar eq 'Test') and ((Foo ne 'Lorem' or Bar ne 'Ipsum') and (Year gt 2017))",
  sequelize
);

query becomes...

{
    where: {
        [Op.and]: [
            {
                [Op.or]: [
                    {
                        Foo: {
                            [Op.eq]: "Test"
                        }
                    },
                    {
                        Bar: {
                            [Op.eq]: "Test"
                        }
                    }
                ]
            },
            {
                [Op.and]: [
                    {
                        [Op.or]: [
                            {
                                Foo: {
                                    [Op.ne]: "Lorem"
                                },
                            },
                            {
                                Bar: {
                                    [Op.ne]: "Ipsum"
                                }
                            }
                        ]
                    },
                    {
                        Year: {
                            [Op.gt]: 2017
                        }
                    }
                ]
            }
        ]
    }
}

3) Using Date

var parseOData = require("odata-sequelize");
var sequelize = require("sequelize");
var query = parseOData(
  "$filter=Foo eq 'Test' and Date gt datetime'2012-09-27T21:12:59'",
  sequelize
);

query becomes...

{
    where: {
        [Op.and]: [
            {
                Foo: {
                    [Op.eq]: "Test"
                }
            },
            {
                Date: {
                    [Op.gt]: new Date("2012-09-27T21:12:59")
                }
            }
        ]
    }
}

4) startswith function

var parseOData = require("odata-sequelize");
var sequelize = require("sequelize");
var query = parseOData("$filter=startswith('lorem', Foo) and Bar eq 'Test'", sequelize);

query becomes...

{
    where: {
        [Op.and]: [
            {
                Foo: {
                    [Op.like]: "lorem%"
                }
            },
            {
                Bar: {
                    [Op.eq]: "Test"
                }
            }
        ]
    }
}

5) substringof function

var parseOData = require("odata-sequelize");
var sequelize = require("sequelize");
var query = parseOData("$filter=substringof('lorem', Foo) and Bar eq 'Test'", sequelize);

query becomes...

{
    where: {
        [Op.and]: [
            {
                Foo: {
                    [Op.like]: "%lorem%"
                }
            },
            {
                Bar: {
                    [Op.eq]: "Test"
                }
            }
        ]
    }
}

6) startswith function

var parseOData = require("odata-sequelize");
var sequelize = require("sequelize");
var query = parseOData("$filter=startswith('Foo', Name) and Bar eq 'Test'", sequelize);

query becomes...

{
    where: {
        [Op.and]: [
            {
                Name: {
                    [Op.like]: "Foo%"
                }
            },
            {
                Bar: {
                    [Op.eq]: "Test"
                }
            }
        ]
    }
}

7) trim function

var parseOData = require("odata-sequelize");
var sequelize = require("sequelize");
var query = parseOData("$filter=trim(Name) eq 'Foo' and Bar eq 'Test'", sequelize);

query becomes...

{
    where: {
        [Op.and]: [
            {
                Name: {
                    comparator: [Op.eq],
                    logic: "Foo",
                    attribute: {
                        fn: "trim",
                        args: [
                            {
                                col: "Name"
                            }
                        ]
                    }
                }
            },
            {
                Bar: {
                    [Op.eq]: "Test"
                }
            }
        ]
    }
}

8) tolower function

var parseOData = require("odata-sequelize");
var sequelize = require("sequelize");
var query = parseOData("$filter=tolower(Name) eq 'foobaz' and Name eq 'bar'", sequelize);

query becomes...

{
    where: {
        [Op.and]: [
            {
                Name: {
                    comparator: [Op.eq],
                    logic: "foobaz",
                    attribute: {
                        fn: "lower",
                        args: [
                            {
                                col: "Name"
                            }
                        ]
                    }
                }
            },
            {
                Bar: {
                    [Op.eq]: "Test"
                }
            }
        ]
    }
}

9) toupper function

var parseOData = require("odata-sequelize");
var sequelize = require("sequelize");
var query = parseOData("$filter=toupper(Name) eq 'FOOBAZ' and Name eq 'bar'", sequelize);

query becomes...

{
    where: {
        [Op.and]: [
            {
                Name: {
                    comparator: [Op.eq],
                    logic: "FOOBAZ",
                    attribute: {
                        fn: "upper",
                        args: [
                            {
                                col: "Name"
                            }
                        ]
                    }
                }
            },
            {
                Bar: {
                    [Op.eq]: "Test"
                }
            }
        ]
    }
}

10) year, month, day, hour, minute, second function

  • The same logic applies to all 6 date functions. The only difference resides in attribute object, whose "fn" property reflects the called function.
var parseOData = require("odata-sequelize");
var sequelize = require("sequelize");
var query = parseOData("$filter=year(StartDate) gt 2017", sequelize);

becomes...

{
    where: {
        {
            StartDate: {
                comparator: [Op.gt],
                logic: 2017,
                attribute: {
                    fn: "year",
                    args: [
                        {
                            col: "StartDate"
                        }
                    ]
                }
            }
        }
    }
}

odata-sequelize's People

Contributors

dependabot[bot] avatar remcohaszing avatar ubreddy avatar vicnovais avatar wesselkuipers avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

odata-sequelize's Issues

Filter child collection based on count

We've run into a scenario lately where we're trying to filter a collection based on the count of a child collection.

For example, we want to filter users who are assigned to groups. Based on the OData specification, the $count query option or length operator are available to get counts on collections.

For reference how to use these, refer to:

Does anyone have thoughts on how something like this might be implemented to a Sequelize query?

Thanks!

substringof does not work when used with and or or

  [Op.and]: [ 
          { [Op.and]: {Foo: '%lorem%'} }, 
          { Bar: { [Op.eq]: 'Test'} }
    ]


The above is obtained instead of

[Op.and]: [
            {
                Foo: {
                    [Op.like]: "%lorem%"
                }
            },
            {
                Bar: {
                    [Op.eq]: "Test"
                }
            }
        ]

var query = parseOData("$filter=substringof('lorem', Foo) and Bar eq 'Test'", sequelize);

filtering with nested functions not working

Using a query string of: ?$filter=substringof('a',tolower(column))

I get the following exception:

TypeError: Cannot read property 'name' of undefined
        at parseFunction (.../node_modules/odata-sequelize/index.js:141:83)
        at parseFunctionCall (.../node_modules/odata-sequelize/index.js:209:7)
        at preOrderTraversal (.../node_modules/odata-sequelize/index.js:222:5)
        at parseFilter (.../node_modules/odata-sequelize/index.js:335:16)
        at module.exports (.../node_modules/odata-sequelize/index.js:380:18)

It looks like the function parser doesn't support nested functions:

const key = args.filter(t => Object.prototype.hasOwnProperty.call(t, "name"))[0].name;

Import using typescript

When try to use typescript to import typescript generate this error.

"This module can only be referenced with ECMAScript imports/exports by turning on the 'esModuleInterop' flag and referencing its default export."

Thanks

filter wrong and or paramters

.......?$top=100&$filter=(foo eq '2019-02-12' and bar eq 'TK0001') or (foo eq '2019-02-12' and bar eq 'TK0003')

sequelize generated MSSQL sentece in WHERE

WHERE ((([foo] = N'2019-02-12') OR ([bar] = N'TK0001')) OR  (([foo] = N'2019-02-12') OR ([bar] = N'TK0003'))) ORDER BY [foo] OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY

my expected

WHERE ((([foo] = N'2019-02-12')  AND  ([bar] = N'TK0001')) OR  (([foo] = N'2019-02-12') AND ([bar] = N'TK0003'))) ORDER BY [foo] OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY

another one odata

$top=100&$filter=foo eq '2019-02-12' and (bar eq 'TK0001' or bar eq 'TK0003')

generated

WHERE (([foo] = N'2019-02-12') AND (([bar] = N'TK0001') AND ([bar] = N'TK0003'))) ORDER BY [foo] OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY;

my excepted

WHERE (([foo] = N'2019-02-12') AND (([bar] = N'TK0001') OR ([bar] = N'TK0003'))) ORDER BY [foo] OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY;

what wrong? Is bug?

Functions Error

  1. Function Comparison not working
    oData
    odata : ...?$filter=year(OrderDate) gt '2016'

sequelize generated MSSQL sentece in WHERE:
year([OrderDate]) = N'2016'

my expected:
year([OrderDate]) > N'2016'

always run eq..

2)Error : Function fieldName not working:
"Invalid column name 'OrderDate'.",

Model:

OrderDate: {
			type: Sequelize.DataTypes.DATEONLY,
			allowNull:false,
			unique:true,
			primaryKey:true,
			field:'Order Date' //my defination
		}

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.