Giter VIP home page Giter VIP logo

objection-find's Introduction

Build Status Coverage Status

Topics

Introduction

Note: since Objection.js (which this library is based on) now requires Node 6.0.0 as the minimum, objection-find will not work on node < 6.0.0 either.

Objection-find is a module for building search queries for objection.js models using HTTP query parameters. You can easily filter, order and page the result based on model's properties and relations using simple expressions. Relations can be eagerly fetched for the results using objection.js relation expressions.

Using objection-find in an express route is as easy as this:

const findQuery = require('objection-find');
// Our objection.js model.
const Person = require('../models/Person');

expressApp.get('/api/persons', function (req, res, next) {
  findQuery(Person)
    .allow(['firstName', 'movies.name', 'children.age', 'parent.lastName'])
    .allowEager('[children.movies, movies, parent.movies]')
    .build(req.query)
    .then(function (persons) {
      res.send(persons);
    })
    .catch(next);
});

Objection-find can be used with any node.js framework. Express is not a requirement. The route we just created can be used like this:

$http({
  method: 'GET',
  url: '/api/persons',

  // HTTP Query parameters.
  params: {
    // Select all persons whose first name starts with 'j' or 'J'
    'firstName:likeLower': 'J%',

    // And who have acted in the movie 'Silver Linings Playbook'.
    // This checks if the relation `movies` contains at least
    // one movie whose name equals 'Silver Linings Playbook'.
    'movies.name:eq': 'Silver Linings Playbook',

    // And who have at least one child younger than 10.
    // This checks if the relation `children` contains at least
    // one person whose age is less than 10.
    'children.age:lt': 10,

    // Order the result by person's parent's last name.
    // `parent` is a one-to-one relation.
    'orderBy': 'parent.lastName',

    // Fetch relations for the results. This is an objection.js
    // relation expression. Check out objection.js for more info.
    'eager': '[children, movies, parent.movies]',

    // Fetch only count of entries that satisfy given criteria. Value can include optional alias parameter, e. g. 'id as countId'. '*' is a valid value.
    'count': 'id',

    // Group fetched entries by specified properties. Primarily intended to be used together with 'count' parameter'.
    'groupBy': 'firstName,lastName',

    // Select a range starting from index 0
    'rangeStart': 0,

    // Select a range ending to index 4
    'rangeEnd': 4
  }
}).then(function (res) {
  const persons = res.data.results;

  console.log(persons.length); // --> 5
  console.log(persons[0].children);
  console.log(persons[0].movie);
  console.log(persons[0].parent.movies);

  // Total size of the result if the range wasn't given.
  console.log(res.data.total);
});

In our example Person model had a one-to-one relation parent, a many-to-many relation movies and one-to-many relation children. This example used the $http module of AngularJS but you can use objection-find with anything that can send an HTTP request.

Documentation on the supported query parameters can be found here and API documentation here.

It is recommended to use query builder for constructing query parameters on the client side.

Installation

npm install objection objection-find

Getting started

Easiest way to get started is to use the objection.js example project and copy paste this to the api.js file:

const findQuery = require('objection-find');

app.get('/persons/search', function (req, res, next) {
  findQuery(Person).build(req.query).then(function (persons) {
    res.send(persons);
  }).catch(next);
});

You also need to run this in the root of the example project to install objection-find:

npm install --save objection-find

Now you can start bombing the /persons/search route. Documentation on the supported query parameters can be found here.

Query parameters

Objection-find understands two kinds of query parameters: filters and special parameters.

Filters

A filter parameter has the following format:

<propertyReference>|<propertyReference>|...:<filter>=<value>

A propertyReference is either simply a property name like firstName or a reference to a relation's property like children.age (children is the name of the relation).

filter is one of the built-in filters eq, neq, lt, lte, gt, gte, like, likeLower in, notNull or isNull. Filter can also be a custom filter registered using the registerFilter method.

The following examples explain how filter parameters work. For the examples, assume we have an objection.js model Person that has a one-to-one relation parent, a many-to-many relation movies and one-to-many relation children.

Filter query parameter Explanation
firstName=Jennifer Returns all Persons whose first name is 'Jennifer'.
firstName:eq=Jennifer Returns all Persons whose first name is 'Jennifer'.
children.firstName:like=%rad% Returns all Persons who have at least one child whose first name contains 'rad'.
lastName|movies.name:like=%Gump% Returns all Persons whose last name contains 'Gump' or who acted in a movie whose name contains 'Gump'.
parent.age:lt=60 Returns all persons whose parent's age is less than 60.
parent.age:in=20,22,24 Returns all persons whose parent's age is 20, 22 or 24.

Filters are joined with AND operator so for example the query string:

firstName:eq=Jennifer&parent.age:lt=60&children.firstName:like=%rad%

would return the Persons whose firstName is 'Jennifer' and whose parent's age is less than 60 and who have at least one child whose name contains 'rad'.

Special parameters

In addition to the filter parameters, there is a set of query parameters that have a special meaning:

Special parameter Explanation
eager=[children, parent.movies] Which relations to fetch eagerly for the result models. An objection.js relation expression. That pass to withGraphFetched.
join=[parent, parent.movies] Which relations to join and fetch eagerly for the result models. An objection.js relation expression. That pass to withGraphJoined.
orderBy=firstName Sort the result by certain property.
orderByDesc=firstName Sort the result by certain property in descending order.
rangeStart=10 The start of the result range (inclusive). The result will be {total: 12343, results: [ ... ]}.
rangeEnd=50 The end of the result range (inclusive). The result will be {total: 12343, results: [ ... ]}.

Additional parameters

Any query parameters, that are not listed in Special parameters, such as page, can be passed as query in second parameter.

const findQuery = require('objection-find');

app.get('/persons', function (req, res, next) {
  const { page, ...query } = req.query;
  
  findQuery(Person)
    .build(query, Person.query().page(page, 12))
    .then(function (persons) {
      res.send(persons);
    })
    .catch(next);
});

objection-find's People

Contributors

afm-sayem avatar alexkvak avatar chasewagoner avatar davidpayne-woodscamp avatar dependabot[bot] avatar igor-savin-ht avatar kapouer avatar kibertoad avatar koskimas avatar leearaneta avatar nojimage avatar parrker avatar thisiskalnins avatar vigzmv 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  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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

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

objection-find's Issues

Filtering does not work on HasMany relations

How to Reproduce

  1. Take the two models Component and ComponentVersion, where Component HasMany ComponentVersions:

Component

class Component extends Model {
  public static tableName = 'components';
  public static idColumn = 'component_id';
  public static modelPaths = [ __dirname ];

  // Fields
  public component_id!: number;

  // Relational Fields
  public versions!: ComponentVersion[] | null;
  
  // Relational Mappings
  public static relationMappings() {
    return {
      versions: {
        relation: Model.HasManyRelation,
        modelClass: ComponentVersion,
        join: {
          from: 'components.component_id',
          to: 'component_versions.component_id'
        }
      }
    };
  }
}

ComponentVersion

class ComponentVersion extends Model {
  public static tableName = 'component_versions';
  public static idColumn = 'component_version_id';
  public static modelPaths = [ __dirname ];

  // Fields
  public component_version_id!: number;
  public component_id!: number;
  public component_version_is_active!: boolean;
}
  1. Attempt to retrieve all Components and filter on one of ComponentVersion's fields:
  public async getAllComponents(): Promise<Component[]> {
    const request = Component.query().withGraphFetched('versions');
    const filter = { 'versions.component_version_is_active:eq': '1' };

    return await findQuery(Component).build(filter, request);
  }
  1. The following SQL is produced:
select `components`.* from `components` 
where exists (
  select 1 from `component_versions` as `ComponentVersion` 
  where `ComponentVersion`.`component_id` = `components`.`component_id` 
  and `component_versions`.`component_version_is_active` like '1'
)

Notice that an alias is given to the relational table's name (in this example, the component_versions table is aliased as ComponentVersion), but this alias is not used on the last line where the query performs the filter operation. Instead, ComponentVersion's table_name is used, causing the query to fail with error:

ER_BAD_FIELD_ERROR: Unknown column 'component_versions.component_version_is_active' in 'where clause'.

When the alias is used, the SQL statement works as intended:

select `components`.* from `components` 
where exists (
  select 1 from `component_versions` as `ComponentVersion` 
  where `ComponentVersion`.`component_id` = `components`.`component_id` 
  and `ComponentVersion`.`component_version_is_active` like '1'
)

Proposed Solution

This issue exists because PropertyRef.buildFilter() aliases XToMany relations, but PropertyRef.fullColumnName() does not. I propose adding this aliasing to PropertyRef.fullColumnName() as well.
Resolved in #81

Only one level of relations is supported

How do you do a query that filters from few level of relations?

Specifically, I wrote this:

      const legs = await findQuery(Leg)
          .build({
            'eager': `[
              passengers, 
              flight.[airline, aircraft, via_airport,
                route.[outbound_origin, outbound_destination]
              ],
            ]`,
            'flight.route.organization_id': org.id,
            'flight.route.outbound_destination.iata_code': 'CDG'
          })     

Thanks!

filtering through a HasMany relationship -> "owner.buildFindQuery is not a function"

hi,

i'm trying to do something very similar to an example in the docs:

// This checks if the relation `children` contains at least
// one person whose age is less than 10.
'children.age:lt': 10,
...

i'm getting an error that looks like this:

TypeError: owner.buildFindQuery is not a function
    at HasManyRelation.findQuery (/app/backend/node_modules/objection/lib/relations/Relation.js:118:11)
    at PropertyRef.buildFilter (/app/backend/node_modules/objection-find/lib/PropertyRef.js:145:28)
...

i dug into the code for both objection-find and objection and one of the function signatures doesn't seem to be consistent.

here's where the error is in objection-find:

const subQuery = rel.findQuery(rel.relatedModelClass.query(), {
  ownerIds: rel.ownerProp.refs(builder)
});

and here's the findQuery function as defined in objection:

findQuery(builder, owner) {
  const relatedRefs = this.relatedProp.refs(builder);
  owner.buildFindQuery(builder, this, relatedRefs);

  return this.applyModify(builder);
}

it looks like findQuery should take in a RelationOwner as its second argument, but we're passing in the relatedRefs instead. i'm not sure how to retrieve the owner - any help would be appreciated!

here are my query parameters for context:

{
    eager: '[account,assignments,users]',
    'assignments.userId:eq': 1,
}

can we search by timestamp ?

Hi,

i have a user that has createdAt value 2018-12-22 16:29:02.987406+00

I can't get any results with this query:
createdAt:like = 2018-12-22

raised error:
"message": "select \"users\".* from \"users\" where \"users\".\"created_at\" like $1 limit $2 - operator does not exist: timestamp with time zone ~~ unknown"

any idea?
thanks.

any suggestions to sort by nested eager ?

hi,

currently it is not supported to sort by nested eager.
Can only order by model's own properties and by BelongsToOneRelation relations' properties/
OR
PropertyRef: only one level of relations is supported

i tried to make the relationships eager-able in one level but apparently it is not supported by objection js.
Vincit/objection.js#1250

any suggestions to achieve that ?

thanks in advance!

Support for boolean "OR" operator

Hey,

first of all thanks for this library! I couldn't figure out whether it's possible to combine certain fields in an "OR" manner? Is this something that should work? If not, are there any plans if and when this might be added here?

Transaction support?

Are transactions supported? What if I want to search through the models in a transaction?

Join param filtering by eager relations

Hey,

Is there a way to query nested relations like you can using native withGraphJoined()? I'd like to be able to filter columns like so:

where(children:pets.name, 'John');

Fix #46 broke searching with relation's field

Hi
Excuse my english, I'm french. I'll do my best to explain

The fix for fullColumName is not working like before the depracated relatedTableAlias. Searching for a field from a relation table is not working.

I have submitted a pull request many weeks ago but you change the fix in your correction for columnName function.

The fullColumnName return from your function didn't match with the real related table name in the database.

the query contain a criteria format like : maintable__rel__relation.myfield
But the good one should be formatted as : real_related_table_name.field

My relation is defined in the model of main table with
{
...
relation: Model.HasOneRelation,
...
}

Originally posted by @marcpearson in #46 (comment)

FieldExpression support

If i understand things correctly, propertyRef actually only allow column names and relation names.
Adding FieldExpression support would be awesome for custom filters

Include a way to specify disallowed columns/relations

The Problem

Currently, it is possible to limit columns/relations that can be filtered/ordered via the allow method

findQuery(User).allow(['firstName', 'lastName', 'email']).build(query)

However, it is inconvenient when you want to restrict only a handful of columns/relations in a model with lots of columns. For instance, if we have a model with 20 columns and only want to restrict one column, currently, we have to list all 19 columns we want to allow

findQuery(SomeBigModel).allow(['column1', 'column2', 'column3', ...., 'column19']).build(query)

It would be more convenient if we could specify only the column we want to restrict instead

findQuery(User).disallow(['password']).build(query)

In certain cases, this might make more sense and can lead to concise code that is easier to follow and reason about.

Possible Solutions

There are a couple of ways this can be implemented

1. Add optional parameter in the allowAll method
An optional parameter can be added to specify exceptions

findQuery(User).allowAll(['password']).buid(query) // Allow all columns except password

2. Add disallow() method
A new method can be added to complement the allow method. This would be mutually exclusive and the opposite of the allow method

findQuery(User).disallow(['password']).build(query)

I am keen to know if this has been considered before

Isolate non-filtering data from filter parameter?

Hi, great work on the library! I just found it while browsing your repo, I have looked at https://github.com/TryGhost/GQL earlier today for translating my find queries to knex runnable queries, but since I'm already using objectionjs this is the library I'm going to use. The library lacks discoverability a bit, so if you mentioned this in the official docs I think people like me would find it useful.

A few suggestions:

  • eager should not be part of the filter object, it should be a separate parameter. Since it's not technically being used to filter data.
  • orderBy and orderByDesc should not be part of the filter object as well, candidate for a separate parameter. Also, I think orderByDesc could be implemented by including a negation character precede the value.
  • range should be a separate parameter. Objection supports paging already, doesn't page[size] and page[limit] qualify as a better candidate?

I'm basing my suggestions off of JSON API

Proposal: Remove special parameters

Objection find is used as a 'WHERE' replacement in query parameters. But it also does pagination, sorting and eager loading. Implementing pagination, sorting and eager loading is trivial if someone is already using objection.js.

I propose we get rid of special parameters altogether.

How to import objection-find with typescript

  1. import * as findQuery from 'objection-find
  2. import findQuery from 'objection-find'

I got this error : TypeError: objection_find_1.default is not a function

The only it works:
const findQuery = require('objection-find')

Do i need to set something in my tsconfig.json

Could you write and example in the readme, thanks

Get rid of deprecated model.formatter() call

According to koskimas, here is the example of how change is supposed to look:

'lower(' + formatter.wrap(propertyRef.fullColumnName()) + ')'

-->

raw('lower(??)', propertyRef.fullColumnName())

Is this project still under development?

It looks like this project could be a very good addition to objection.js, and I am willing to try it and use it.

However, I am wondering whether it still is under development.

Is it still alive?

Support for RelationThrough joins?

Hi, having trouble filtering our db with a through join relationship, I'm fairly new to objection so I could be missing something but can't seem to see anything if I am.
I have two models with a many to many relationship which is managed with a through relation on our Users model with a UserCompany model.

Users

class User extends Model implements IUser {
  static tableName = "users";
  id!: number;
  firstName!: string;

  companies?: Company[];

  static relationMappings = {
    companies: {
      relation: Model.ManyToManyRelation,
      modelClass: Company,
      join: {
        from: "users.id",
        through: {
          from: "user_companies.user_id",
          to: "user_companies.company_id",
        },
        to: "companies.id",
      },
    },
  };
}

Companies

class Company extends Model implements ICompany {
  static tableName = "companies";
  id!: number;
  name!: string;
}

UserCompany

class UserCompany extends Model {
  static tableName = "user_companies";
  id!: number;
  userId!: number;
  companyId!: number;
}

Performing a simple get users by company id lookup:

findQuery(User)
  .allow("id", "firstName", "companies.id")
  .allowEager("companies")
  .build({
    "companies.id:eq": "1",
  });

Expected result:
Should return list of users who belong to company with id of 1.

Results in following error message:

DBError: select `users`.* from `users` where exists (select 1 from `companies` as `Company` inner join `user_companies` on `Company`.`id` = `user_companies`.`company_id` where `user_companies`.`user_id` = `users`.`id` and `companies`.`id` = '1') limit 50 - SQLITE_ERROR: no such column: companies.id

The above sql script is invalid, it sets up the alias of Companies but on the final where clause it doesn't use the alias and instead uses the table name incorrectly. Correcting this error and running the script in my db works as expected.
Is there a way to remove this alias that it's creating or a way for it to actually apply the alias in the final where clause.

package.json

"objection": "^2.2.3",
"objection-find": "^3.0.1",

TypeScript types declaration file

This npm package needs a TypeScript types declaration file so that developers who enjoy writing with TS can use it with this package and have a better development experience. Would you like me to write one?

Encounter findQuery(...).allowAll(...).allowGraph is not a function

Hi there, I am new to here and just encountered an issue when building a findQuery.
I was using allowGraph()to pass relations to withGraphFetched by following README.md
It returns "message": "findQuery(...).allowAll(...).allowGraph is not a function"
But after I moved .build() between .allow() and .allowGraph(), it works fine.
Is it my problem of understanding or there is something need to fix?

After changes

    const JobsQuery = findQuery(Jobs)
      .allowAll()
      .build(req.query)
      .allowGraph(
        "[tags, job_category]"
      )

Before Change

router.get("/jobs/search/", checkAuth, async (req, res, next) => {
  try {
    const user = req.user;
    const JobsQuery = findQuery(Jobs)
      .allowAll()
      .build(req.query)
      .allowGraph(
        "[tags, job_category]"
      );
    const result = await paginateQuery(JobsQuery, req, res, next);
    result.results = result.results.map(encapsulateJobFields);
    return res.status(200).json(result);
  } catch (error) {
    next(error);
  }
});

Issue with filters: TypeError: this.relation.relatedTableAlias

Issue with filters

Only happens on usage with objectionjs > 1.2.2

module.exports = function(propertyRef, value, modelClass) {
   const fullColumnName = propertyRef.fullColumnName(),
  
  ...
}

on calling propertyRef.fullColumnName()
Error TypeError: this.relation.relatedTableAlias is not a function is thrown.

Any recommended solutions will be appreciated.
Thanks!


Update:
Looks like the relatedTableAlias was removed in Vincit/objection.js@1.2.2...1.2.3#diff-1b101aaae4f893ec44a231f0578d57d7

Running Objection-find together with pagination?

Hi there,
is there a method to use objection.js native page function together with objection-find to create pagination?

I tried to send a page and limit parameter in a req.query but since I tried to pass the full req.query object into the build function it tries to search for the page and limit properties.
One way I could do this is extract every property of the req.query and build a object for the build function but is there a better way?

Filters don't work when using columnNameMappers

I have the following mapper:

static columnNameMappers = {
    parse(obj) {
      // database --> code
      return {
        id: obj.MktTypeID,
        desc: obj.MktTypeDesc,
        entryDesc: obj.MktTypeEntryDesc,
        active: obj.Active
      };
    },

    format(obj) {
      // code --> database
      return {
        MktTypeID: obj.id,
        MktTypeDesc: obj.desc,
        MktTypeEntryDesc: obj.entryDesc,
        Active: obj.active
      };
    }
  };

When I do a query as such: /api/v1/LinkMktType?desc=Other, I get the error:

Error: PropertyRef: unknown property desc
    at Object.throwError (c:\git\DCST\api\node_modules\objection-find\lib\utils.js:3:19)
    at PropertyRef._parse (c:\git\DCST\api\node_modules\objection-find\lib\PropertyRef.js:95:13)
    at new PropertyRef (c:\git\DCST\api\node_modules\objection-find\lib\PropertyRef.js:68:10)
    at FindQueryBuilder._parsePropertyRef (c:\git\DCST\api\node_modules\objection-find\lib\FindQueryBuilder.js:498:37)
    at _.reduce (c:\git\DCST\api\node_modules\objection-find\lib\FindQueryBuilder.js:489:28)
    at arrayReduce (c:\git\DCST\api\node_modules\lodash\lodash.js:704:21)
    at Function.reduce (c:\git\DCST\api\node_modules\lodash\lodash.js:9698:14)
    at FindQueryBuilder._parsePropertyRefs (c:\git\DCST\api\node_modules\objection-find\lib\FindQueryBuilder.js:486:14)
    at QueryParameter._parseFilter (c:\git\DCST\api\node_modules\objection-find\lib\QueryParameter.js:89:33)
    at QueryParameter._parse (c:\git\DCST\api\node_modules\objection-find\lib\QueryParameter.js:58:12)
    at new QueryParameter (c:\git\DCST\api\node_modules\objection-find\lib\QueryParameter.js:51:10)
    at _.each (c:\git\DCST\api\node_modules\objection-find\lib\FindQueryBuilder.js:352:21)
    at c:\git\DCST\api\node_modules\lodash\lodash.js:4944:15
    at baseForOwn (c:\git\DCST\api\node_modules\lodash\lodash.js:3001:24)
    at c:\git\DCST\api\node_modules\lodash\lodash.js:4913:18
    at Function.forEach (c:\git\DCST\api\node_modules\lodash\lodash.js:9359:14)

I'm using 1.0.0-rc.5.

No way to search in postgres arrays ( array column not json or jsonb)

I have one region array in column. When i am trying to findquery and applying query into it. Searching inside array column doesn't work when array have more than one entry.

Case 1. array column(i.e. region) is [NA-US] and search query is region={NA-US}. It works

Case 2. array column(i.e. region) is [NA-US, AS-US] and search query is region={NA-US}. It doesn't works.

I tried with ANY operator in where clause by removing region from query. It gives error operator any is not permitted.

Feature request: Throw BadRequest when query parameter contains invalid data

Unhandled rejection error: invalid input syntax for integer: "aou"
    at Connection.parseE (/home/kishan/projects/api-server-seed/node_modules/pg/lib/connection.js:539:11)
    at Connection.parseMessage (/home/kishan/projects/api-server-seed/node_modules/pg/lib/connection.js:366:17)
    at Socket.<anonymous> (/home/kishan/projects/api-server-seed/node_modules/pg/lib/connection.js:105:22)
    at emitOne (events.js:96:13)
    at Socket.emit (events.js:188:7)
    at readableAddChunk (_stream_readable.js:172:18)
    at Socket.Readable.push (_stream_readable.js:130:10)
    at TCP.onread (net.js:542:20)
From previous event:
    at Client._query (/home/kishan/projects/api-server-seed/node_modules/knex/lib/dialects/postgres/index.js:179:12)
    at Client.query (/home/kishan/projects/api-server-seed/node_modules/knex/lib/client.js:187:24)
    at Runner.<anonymous> (/home/kishan/projects/api-server-seed/node_modules/knex/lib/runner.js:129:36)
From previous event:
    at /home/kishan/projects/api-server-seed/node_modules/knex/lib/runner.js:55:21
From previous event:
    at Runner.run (/home/kishan/projects/api-server-seed/node_modules/knex/lib/runner.js:41:33)
    at QueryBuilder.Target.then (/home/kishan/projects/api-server-seed/node_modules/knex/lib/interface.js:32:43)
    at QueryBuilder.resultSize (/home/kishan/projects/api-server-seed/node_modules/objection/lib/queryBuilder/QueryBuilder.js:611:23)
    at QueryBuilder.<anonymous> (/home/kishan/projects/api-server-seed/node_modules/objection/lib/queryBuilder/QueryBuilder.js:642:34)
    at RunBeforeOperation.onBefore (/home/kishan/projects/api-server-seed/node_modules/objection/lib/queryBuilder/operations/RunBeforeOperation.js:44:22)
    at /home/kishan/projects/api-server-seed/node_modules/objection/lib/queryBuilder/QueryBuilder.js:1279:19
    at /home/kishan/projects/api-server-seed/node_modules/objection/lib/queryBuilder/QueryBuilder.js:1324:14
    at tryOnImmediate (timers.js:543:15)
    at processImmediate [as _immediateCallback] (timers.js:523:5)
From previous event:
    at /home/kishan/projects/api-server-seed/node_modules/objection/lib/queryBuilder/QueryBuilder.js:1323:23
    at arrayEach (/home/kishan/projects/api-server-seed/node_modules/lodash/lodash.js:451:11)
    at Function.forEach (/home/kishan/projects/api-server-seed/node_modules/lodash/lodash.js:8634:14)
    at promiseChain (/home/kishan/projects/api-server-seed/node_modules/objection/lib/queryBuilder/QueryBuilder.js:1318:20)
    at chainBeforeOperations (/home/kishan/projects/api-server-seed/node_modules/objection/lib/queryBuilder/QueryBuilder.js:1278:10)
    at QueryBuilder.execute (/home/kishan/projects/api-server-seed/node_modules/objection/lib/queryBuilder/QueryBuilder.js:704:15)
    at QueryBuilder.then (/home/kishan/projects/api-server-seed/node_modules/objection/lib/queryBuilder/QueryBuilder.js:527:24)
    at index (movie.controller.js:40:6)
    at Layer.handle [as handle_request] (/home/kishan/projects/api-server-seed/node_modules/express/lib/router/layer.js:95:5)
    at next (/home/kishan/projects/api-server-seed/node_modules/express/lib/router/route.js:131:13)
    at processQuery (utilities.js:64:3)
    at Layer.handle [as handle_request] (/home/kishan/projects/api-server-seed/node_modules/express/lib/router/layer.js:95:5)
    at next (/home/kishan/projects/api-server-seed/node_modules/express/lib/router/route.js:131:13)
    at Route.dispatch (/home/kishan/projects/api-server-seed/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/home/kishan/projects/api-server-seed/node_modules/express/lib/router/layer.js:95:5)
    at /home/kishan/projects/api-server-seed/node_modules/express/lib/router/index.js:277:22
    at Function.process_params (/home/kishan/projects/api-server-seed/node_modules/express/lib/router/index.js:330:12)
    at next (/home/kishan/projects/api-server-seed/node_modules/express/lib/router/index.js:271:10)
    at Function.handle (/home/kishan/projects/api-server-seed/node_modules/express/lib/router/index.js:176:3)

When sending an arbitrary string for an integer field for a find query, objection-find constructs the query anyway which results in unhandled exception in server.

Since a models' JSON schema is available to the library, a validation should be run before constructing the query and throw a BadRequest error if it fails the check.

Error thrown when trying to select 2 or more fields with 'likeLower'

Objection 0.8.9
Objection-find 0.5.0

When trying to use filter name|surname:likeLower got error:

Unhandled rejection TypeError: Cannot read property 'apply' of undefined
at PropertyRef.buildFilter (/home/watson/WebstormProjects/pfa-meetups/node_modules/objection-find/lib/PropertyRef.js:148:25)
at /home/watson/WebstormProjects/pfa-meetups/node_modules/objection-find/lib/FindQueryBuilder.js:447:13
at /home/watson/WebstormProjects/pfa-meetups/node_modules/lodash/lodash.js:4944:15
at baseForOwn (/home/watson/WebstormProjects/pfa-meetups/node_modules/lodash/lodash.js:3001:24)
at /home/watson/WebstormProjects/pfa-meetups/node_modules/lodash/lodash.js:4913:18
at Function.forEach (/home/watson/WebstormProjects/pfa-meetups/node_modules/lodash/lodash.js:9359:14)
at QueryBuilderBase. (/home/watson/WebstormProjects/pfa-meetups/node_modules/objection-find/lib/FindQueryBuilder.js:446:9)
at convertQueryBuilderFunction (/home/watson/WebstormProjects/pfa-meetups/node_modules/objection/lib/queryBuilder/operations/ObjectionToKnexConvertingOperation.js:144:8)
at Builder.convertedKnexArgumentFunction (/home/watson/WebstormProjects/pfa-meetups/node_modules/objection/lib/queryBuilder/operations/ObjectionToKnexConvertingOperation.js:131:7)
at Formatter.compileCallback (/home/watson/WebstormProjects/pfa-meetups/node_modules/knex/lib/formatter.js:161:14)
at Formatter.rawOrFn (/home/watson/WebstormProjects/pfa-meetups/node_modules/knex/lib/formatter.js:104:36)
at QueryCompiler_PG.whereWrapped (/home/watson/WebstormProjects/pfa-meetups/node_modules/knex/lib/query/compiler.js:531:30)
at QueryCompiler_PG.where (/home/watson/WebstormProjects/pfa-meetups/node_modules/knex/lib/query/compiler.js:314:32)
at /home/watson/WebstormProjects/pfa-meetups/node_modules/knex/lib/query/compiler.js:147:30
at Array.map ()
at QueryCompiler_PG.select (/home/watson/WebstormProjects/pfa-meetups/node_modules/knex/lib/query/compiler.js:146:33)

getMany method code:

async getMany(criteria: SpeakerGetManyCriteria): Promise<{items: Speaker[], total: number}> {
    const { filters: criteriaFilters = {} } = criteria;
    const getFilters = (filters: Object) => {
      const { query, isDeleted } = filters;
      const resultFilters = criteriaFilters;

      if (isString(query)) {
        resultFilters['name|surname:likeLower'] = `%${query}%`;
      }

      if (isDeleted) {
        resultFilters['deletedAt:notNull'] = true;
      }

      return omitBy(flatten(resultFilters), (value: any, key: string) => ['query', 'isDeleted'].includes(key) || value === '');
    };

    return SpeakerModel.getMany({
      ...criteria,
      filters: {
        ...getFilters(criteriaFilters),
      },
    });
  },

name|surname:like works well

please stop asking for my approvals :)

Though i'm usually pretty interested in what's happening here (and in objection.js which i'm watching thoroughly) please please directly commit now to the repository. If you do something wrong, users of the module will open issues.
Thank you !

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.