How do I apply filters to custom routes?

Hello all, I was following this article (Field representing related object not populating) on how to get fields representing related objects populated. I was able to get it working, however, I noticed the custom filters no longer work.

My question how can I extend the base behavior so that I can add my model includes? I view the documentation here https://docs.forestadmin.com/documentation/v/v6/reference-guide/routes/default-routes#get-a-list-of-records, but it doesn’t show how to add includes/joins.

My imports

const express = require('express');
const { PermissionMiddlewareCreator, RecordsGetter, RecordGetter } = require('forest-express-sequelize');
const { collections, orderItems, orders, buyers, brands } = require('../models');
const routr = express.Router();
const permissionMiddlewareCreator = new PermissionMiddlewareCreator('orders');

List override

router.get('/orders', permissionMiddlewareCreator.list(), (request, response, next) => {
  // Learn what this route does here: https://docs.forestadmin.com/documentation/v/v6/reference-guide/routes/default-routes#get-a-list-of-records
  
  const limit = parseInt(request.query.page.size, 10) || 15
  const offset = (parseInt(request.query.page.number, 10) - 1) * limit
  const recordsGetter = new RecordsGetter(orders)

  const include = [
    { model: collections, include: [{ model: brands}] },
    { model: orderItems },
    { model: buyers }
  ]

  var findAll = orders.findAndCountAll({ include: include, offset, limit })

  Promise.all([findAll]).then(([allOrders]) => {
    return recordsGetter.serialize(allOrders.rows, { count: allOrders.count })
  })
  .then((recordsSerialized) => {
    return response.send(recordsSerialized);
  })
  .catch(next)
});

Expected behavior

  1. The user goes to the list page
  2. User clicks on the filter button and applies custom filters (where the selected field is not = x)
  3. The admin displays filters orders by the custom filters

Actual behavior

What is the current behavior?

  1. Filters are not being displayed

Context

  • Package Version:
  • Express Version: 4.16.3
  • Sequelize Version: 5.15.1
  • Database Dialect: MySQL
  • Database Version: 1.7.0

Hi @james-janetech,

Welcome to our community! :raised_hands:

I have one silly question to begin: why do you need to override your route? Are you sure you need to?
I was wondering because the features you talked about (having related data displayed, custom filters taken into account) are working with the default code if your DB is well defined.

If you actually need to override your route, then your filters will be taken into account if you use (as shown in the doc) recordsGetter.getAll(request.query).

Let me know!
Cheers.

Hi @adriguy,
I’m running into the same issue mentioned in this article where Field representing related object not populating

Order model association:

Orders.associate = (models) => {
 Orders.belongsTo(models.buyers);
 Orders.belongsTo(models.collections);
 Orders.hasMany(models.orderItems);
};

My order smart view

const { collection } = require('forest-express-sequelize');
const models = require('../models');

// This file allows you to add to your Forest UI:
// - Smart actions: https://docs.forestadmin.com/documentation/reference-guide/actions/create-and-manage-smart-actions
// - Smart fields: https://docs.forestadmin.com/documentation/reference-guide/fields/create-and-manage-smart-fields
// - Smart relationships: https://docs.forestadmin.com/documentation/reference-guide/relationships/create-a-smart-relationship
// - Smart segments: https://docs.forestadmin.com/documentation/reference-guide/segments/smart-segments
collection('orders', {
  actions: [],
  fields: [
    {
      field: 'order number',
      type: 'Integer',
      get: (order) => {
        return order.id
      }
    },
    {
      field: 'units',
      type: 'Number',
      get: function(order) {
        return order.orderItems.reduce((a, b) => {
          return a + (b['quantity'] || 0)
        }, 0);
      }
    },
    {
      field: 'Collection Name',
      type: "String", 
      get: (order) => {
        return `${order.collection.brand.name} ${order.collection.season}`; 
      }
    },
    { // used to override totalPrice until moved  to the database
      field: 'total_price',
      type: 'String',
      get: (order) => {
        let totalPrice = (order.status == 'draft') ? (order.orderItems||[]).reduce((a, b) => { return a + (parseFloat(b['totalPrice']) || 0) }, 0) : parseFloat(order.totalPrice);
        let currency = (order.orderItems.length > 0) ? order.orderItems[0].currency : order.collection.currency[0]
        return `${totalPrice.toFixed(2)} ${currency.toUpperCase()}`
      }
    },

    { // used to override subtotalPrice // used to override totalPrice until moved  to the database
      field: 'sub_total_price',
      type: 'String',
      get: (order) => {
        let subtotalPrice = (order.status == 'draft') ? (order.orderItems||[]).reduce((a, b) => { return a + (parseFloat(b['subtotalPrice']) || 0) }, 0) : parseFloat(order.subtotalPrice);
        let currency = (order.orderItems.length > 0) ? order.orderItems[0].currency : order.collection.currency[0]
        return `${subtotalPrice.toFixed(2)} ${currency.toUpperCase()}`
      }
    }
  ],
  segments: [],
});

I’m only able to view the see the smart fields if I click on the data.


This tells me my orders list isn’t including the joins when querying. I even tried it using the snipet here
https://docs.forestadmin.com/documentation/reference-guide/relationships/create-a-smart-relationship

@james-janetech,

Yes the problem is probably coming from the route you’ve overridden.
I am still not sure why you needed to though. If you explain me it might give me more useful information to help you out :ok_hand:

And as I said in my previous message:

if you actually need to override your route, then your filters will be taken into account if you use (as shown in the doc) recordsGetter.getAll(request.query).

Did you check this documentation and did you try this syntax?

Thanks.

@adriguy ,
I’m trying to get my smart view fields to be populated. I reverted my changes overriding the routes using the code from the documentation only.

orders admin page

orders.js (route)

orders.js (forest)

Okay I resolved the issue. When debugging I don’t think forest add the includes on the list page, that’s why I’m not seeing the smart view.

My solution feels like a hack if there’s a better way feel free to chime in.

First, I let forest do all of the work with the filtering, then I take the ids and pass it to my orders model so it can return all of the includes
records => orders.findAll({include: associations, where:{ id: records.map(r => r.id )}}))

code block

const recordsGetter = new RecordsGetter(orders);
  recordsGetter.getAll(request.query).then(records => orders.findAll({include: associations, where:{ id: records.map(r => r.id )}}))
    .then(records => recordsGetter.serialize(records))
    .then(recordsSerialized => response.send(recordsSerialized))
    .catch(next);

Thanks