There's a number of approaches, a couple of which are documented in PostGraphile's documentation under Relations > Many-to-many relations.
create function foos_bars(f foos) returns setof bars as $$
select bars.*
from bars
inner join foo_bars
on foo_bars.bar_id = bars.id
where foo_bars.foo_id = f.id
$$ language sql stable;
const { makeExtendSchemaPlugin, gql, embed } = require("graphile-utils");
module.exports = makeExtendSchemaPlugin(build => {
const { pgSql: sql } = build;
return {
typeDefs: gql`
extend type Foo {
bars: BarsConnection @pgQuery(
source: ${embed(sql.fragment`bars`)}
withQueryBuilder: ${embed((queryBuilder, args) => {
queryBuilder.where(
sql.fragment`exists(select 1 from foo_bars where foo_bars.bar_id = ${queryBuilder.getTableAlias()}.id and foo_bars.foo_id = ${queryBuilder.parentQueryBuilder.getTableAlias()}.id`
);
})}
)
}
`,
};
});
(This is more performant, but somewhat harder to read - we're hoping to optimise this syntax in future).
yarn add @graphile-contrib/pg-many-to-many
postgraphile --append-plugins @graphile-contrib/pg-many-to-many
You can also optimize the naming
We provide a pg-simplify-inflector
plugin that can be used to simplify names in your schema if you're pretty sure there'll be no conflicts; I highly recommend it's usage if your database schema is well defined:
https://github.com/graphile/pg-simplify-inflector