Hi! Hope you’re having a good day.
There are two parts to my topic: General understanding of the Forest records API and a specific code example.
General understanding
- Why do we use
RecordsGetter
and others instead of the ORM (Sequelize in our case)? Is it for authentication, a simpler API, possibly other purposes? We think we get the general idea but want to make sure =) - Following on the first question, are there instances when it would be more appropriate to use the ORM directly? Our use of FA is mostly editorial, any heavy lifting / business critical logic is handled by our backend via jobs.
- There is a fairly old GitHub issue about whether you are interested in any commits / improvements over the TypeScript definitions. This is something which would greatly enhance the developer experience, as we regularly have to dive into code examples or the internals to even understand which parameters to pass to an API method. Are you willing to work on this topic or take contributions? If so, in which form?
- What care do issues and PR receive on
forest-express-sequelize
and other repos? Some PRs have been opened and inactive for years.
Code
Now let’s take the following simplified example, in which a user can participate in events. There is a one-to-many relationship between users and participants. We’ve built a smart relationship to get participants based on the user email.
This is a trivial example to demonstrate our use of the API.
Note that some of the questions below may be based on wrong premises or a poor understanding on our part, comments and criticisms are very welcome.
router.get('/users/:user_id/relationships/participants', async (request, response, next) => {
try {
const userId = request.params.user_id
const usersGetter = new RecordGetter(Users, request.user, request.query)
const { email } = await usersGetter.get(userId)
const participantsGetter = new RecordsGetter(Participants, request.user, request.query)
const query = {
filters: JSON.stringify({ // (1)
aggregator: 'and',
conditions: [{
field: 'email',
operator: 'equal',
value: email
}, {
field: 'accountId',
operator: 'equal',
value: '0'
}]
}),
page: {
number: request.query.page.number,
size: request.query.page.size
}
}
const participants = await participantsGetter.getAll(query)
const participantsCounter = new RecordsCounter(Participants, request.user, {
...request.query,
filters: query.filters,
searchExtended: '0'
})
response.send(await participantsGetter.serialize(participants, { // (2)
count: await participantsCounter.count(), // (3)
page: {
number: request.query.page.number,
size: request.query.page.size
}
}))
} catch (e) {
next(e)
}
})
We have several questions about the above code:
- As you can see in the code at
(1)
, we have to pass a string of filters instead of the actual object. This has to be done this way because the parameter isJSON.parse
d if it exists, inbase-filters-parser.js
. It feels very strange to pass filters this way, particularly considering this bonks all type information.
a. Speaking of types, they specify an object and not a string (filters?: Filter|AggregatedFilters;
). Is the behaviour of the filters parser a bug? - At
(2)
, we pass a second object to our serializer to carry page and count information. This is done both against the documentation and the types specified by forest-express-sequelize.
It is the only way to show page and count information on the front-end, otherwise we see no count below the table and a1 of NAN
display at the bottom. - At
(3)
, we were somewhat expecting to usecount
likecounter.count(myFilters)
instead of having to rebuild aquery
object, but this may be a wrong expectation on our part.
Context
- Package Version: 8.0.9
- Express Version: 4.17.1
- Sequelize Version: 6.6.5
- Database Dialect: MSSQL
- Database Version: -
- Project Name: -
Thanks for your help =)