Objection.js: Define named filters on model

Created on 3 May 2017  路  6Comments  路  Source: Vincit/objection.js

Currently you can supply named filters when doing eager stuff, e.g

      .query()
      .eager('users(active)', {
        active: (builder) => builder.where('active', true)
      })      

It would be cool if you could define these named filters at the model level on the related model itself.
That is to say,

class UserModel {
    static tableName = 'users';
    static namedFilters = {
        active: (builder) => builder.where('active', true)
    };
}

Thinking here is that the filter implementation is a concern of the model being filtered, not some related consumer of the model.
Probably the named filters passed immediately to the query should override any defined on the model.

Most helpful comment

After giving this some thought, I think I'll implement this. There are some fun things you can do with this. For example graphql-like selects:

class Person extends Model {
  static get namedFilters() {
    return _.mapValues(this.jsonSchema.properties, (value, key) => {
      return (builder) => builder.select(key);
    });
  }
}

Movie
  .query()
  .eager('actors(firstName, lastName, age)')

All 6 comments

You can do this:

teams
      .query()
      .eager('players(active)', UserModel.namedFilters)   

or this:

class BaseQueryBuilder extends Model.QueryBuilder {
  eager(expr, filters) {
    return super.eager(expr, Object.assign({}, this.modelClass().namedFilters, filters);
  }
}

class BaseModel extends Model {
  static get QueryBuilder() {
    return BaseQueryBuilder;
  }
}

// UserModel.js

class UserModel extends BaseModel {
    static tableName = 'users';
    static namedFilters = {
        active: (builder) => builder.where('active', true)
    };
}

I think this is pretty easy to implement on the application side and maybe shouldn't be added to objection.

Thanks @koskimas
I came up with the same kind of implementation as your first example and have also used functions to create parameterised filters.
When working with multiple relations I was looking at merging named filters from multiple models but you run into trouble where filters from different models could overwrite one another - 'active' could mean different filters to different models.

I resorted to dedupe them by mapping:

.eager('[users(activeUser) widgets(activeWidget)]', { activeUser: UserModel.namedFilters.active, activeWidget: WidgetModel.namedFilters.active })

or just giving them unique names in the first place.

Being able to use dot notation to refer to named queries may ease this... maybe this is already possible?

An objection implementation would avoid this problem as it would resolve named filter via the model the filter applies to i.e [users(active) widgets(active)] would use UserModel.namedFilters.active and WidgetModel.namedFilters.active respectively.
But you then lose the ability to parameterise anything unless that is somehow built into the DSL which seems way over the top.
The more I think about this the more it says 'too complicated' ... but you surprised me before with the join algo so maybe you have some good idea ;)

Second example is interesting also but I think this.modelClass() would be a TeamModel when querying teams and so wouldn't find your UserModel.namedFilters?

My second example would probably work (to some extent) how you want if you are using the default WHERE IN based eager algorithm since it calls eager recursively.

Forgive me I don't follow... can you expand?

It was poorly written and incorrect. Never mind 馃槃

After giving this some thought, I think I'll implement this. There are some fun things you can do with this. For example graphql-like selects:

class Person extends Model {
  static get namedFilters() {
    return _.mapValues(this.jsonSchema.properties, (value, key) => {
      return (builder) => builder.select(key);
    });
  }
}

Movie
  .query()
  .eager('actors(firstName, lastName, age)')
Was this page helpful?
0 / 5 - 0 ratings

Related issues

Gustav0ar picture Gustav0ar  路  4Comments

nazar picture nazar  路  3Comments

louis-etne picture louis-etne  路  4Comments

AhmadRaza786 picture AhmadRaza786  路  3Comments

purepear picture purepear  路  3Comments