graphile-contrib / pg-many-to-many Goto Github PK
View Code? Open in Web Editor NEWAdd connection fields for many-to-many relations
License: MIT License
Add connection fields for many-to-many relations
License: MIT License
We began using this plugin with the intention to allow querying for linker tables (no primary key, purely two or more FK constraints). As we have grown our data model, we are seeing a lot of generated ManyToMany relationships that come from multiple constraints on the same table, which we'd prefer to ignore.
It is a bit of a hassle to try and track them all down, now and in the future, to ensure we add @omit manyToMany
and the names can tend to be 50+ characters long. Is there any option to only enable this plugin for tables that do not have a primary key? I believe that would reduce the majority of the relationships that we would omit anyway, and allow us to still handle the case where the table can only be acted on as a manyToMany.
Thanks for the advice!
Just asking....
I'm using 4.4.0-beta.3 of postgraphile:
Error: Plugin @graphile-contrib/[email protected] requires graphile-build-pg@^4.1.0 (current version: 4.4.0-beta.3)
at depends (/Users/sdavis2/Documents/git/omicidx-graphql/node_modules/@graphile-contrib/pg-many-to-many/index.js:17:15)
at PgManyToManyPlugin.builder.hook.build (/Users/sdavis2/Documents/git/omicidx-graphql/node_modules/@graphile-contrib/pg-many-to-many/index.js:26:5)
Hello!
I'm having a hard time querying many to many when simply-inflector plugin is active. When it's inactive, things work as expected. Here's my query without:
{
allProjects {
nodes {
host
locationsByProjectId {
nodes {
zip
keywordsByKeywordsLocationLocationIdAndKeywordId {
nodes {
keyword
}
}
}
}
}
}
}
With simplify inflector active, I've tried
{
projects {
nodes {
host
locations {
nodes {
zip
keywordsLocations {
nodes {
keyword
}
}
}
}
}
}
}
But that doesn't work. It requires that I select fields on the keyword table. Also tried the full relation name, ie keywordsByKeywordsLocationLocationIdAndKeywordId
on the above, but I get "message": "Cannot query field "keywordsByKeywordsLocationLocationIdAndKeywordId\" on type \"Location\".",
Is there a conflict going on between these two plugins or do I need to modify my queries?
Console isn't showing any conflict when PGraphile is loading up.
Got error message
Error: Cannot find module './src/PgManyToManyRelationPlugin.js'
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:581:15)
at Function.Module._load (internal/modules/cjs/loader.js:507:25)
at Module.require (internal/modules/cjs/loader.js:637:17)
at require (internal/modules/cjs/helpers.js:22:18)
at PgManyToManyPlugin (~/repo/node_modules/@graphile-contrib/pg-many-to-many/index.js:35:3)
at Object.exports.getBuilder (~/repo/node_modules/graphile-build/node8plus/index.js:83:11)
at process._tickCallback (internal/process/next_tick.js:68:7)
error Command failed with exit code 1.
Package.json here
{
"scripts": {
"start": "node index.js"
},
"dependencies": {
"@graphile-contrib/pg-many-to-many": "^1.0.0-beta.1",
"@graphile-contrib/pg-simplify-inflector": "^3.0.0",
"express": "^4.16.4",
"postgraphile": "^4.2.0"
}
}
Index.js here
const express = require("express")
const { postgraphile } = require("postgraphile")
const PgManyToManyPlugin = require("@graphile-contrib/pg-many-to-many")
const PgSimplifyInflectorPlugin = require("@graphile-contrib/pg-simplify-inflector")
const app = express()
app.use(
postgraphile(process.env.DATABASE_URL || 'postgres:///whatever_development', 'public', {
appendPlugins: [PgManyToManyPlugin],
graphiql: true,
watchPg: true,
dynamicJson: true,
classicIds: false,
disableDefaultMutations: true,
enhanceGraphiql: true,
})
)
app.listen(5000)
And from node modules, I can see the /src
folder is missing.
Hopefully I'm not just misunderstanding something about how the new plugin/behavior system works, but it seems like in the v5
branch, we've lost the ability to filter out relations with the @omit
smart tag. I was trying this on a project today and couldn't get it to work, and on inspection, I don't see any of the if (omit(..., "manyToMany"))
checks in manyToManyRelationships.ts
on the v5
branch that exist in manyToManyRelationships.js
on master
.
Apologies if this is already on your radar!
A naming conflict has occurred - two entities have tried to define the same key 'images'.
The first entity was:
Many-to-many relation (connection) for constraint "articles_author_id_fkey" on table "public"."articles" and constraint "articles_poster_id_fkey" on table "public"."articles".
The second entity was:
Many-to-many relation (connection) for constraint "articles_updater_id_fkey" on table "public"."articles" and constraint "articles_poster_id_fkey" on table "public"."articles".
I'm getting this error without clearly understanding the reason. Here is an the sql. Why 'articles_poster_id_fkey' is trying to define name images
? Also when I remove one of the references on users
table seems it's working correctly.
Also my plugins list and order:
export default makePluginByCombiningPlugins(
PgManyToManyPlugin,
PgSimplifyInflectorPlugin,
PgManyToManyInflector
)
Hi,
thanks for this very useful plugin! While testing, I realised that while adding a comment on a foreign key constraint works great with PostGraphile's default setting--simple-collections omit
, the comment is ignored when PostGraphile is invoked with --simple-collections only
.
when i use typescript i get this error:
Could not find a declaration file for module '@graphile-contrib/pg-many-to-many'. '/home/sasa/Public/testProject/blogproject/server/node_modules/@graphile-contrib/pg-many-to-many/index.js' implicitly has an 'any' type.
Try npm i --save-dev @types/graphile-contrib__pg-many-to-many
if it exists or add a new declaration (.d.ts) file containing `declare module '@graphile-contrib/pg-many-to-many';
I'd love to be able to hide the join table for my relations, to make it feel more... graphy.
comment on table p.persons_things is E'@omit manyToMany';
hides the relation itself.
Hello, first of all, thank you for making this package available.
I am having difficulty getting this up and running and am wondering if there are a common list of troubleshooting tips available?
When following the documented instructions I am greeted with a app crashed - waiting for file changes before starting...
upon bootup.
This problem seems isolated to my aws production server, but not on my local one. No errors found.
"pg": "^7.6.1",
"postgraphile": "^4.5.0",
Thank you for your time
I'm exposing a schema to Postgraphile using a set of views and I'm wondering if it's possible to use smart comments to influence the field naming somehow.
Taking this toy schema
create schema data;
create table data.author (
id serial primary key,
name text
);
create table data.post (
id serial primary key,
title text unique not null,
summary text,
body text not null,
created timestamptz not null default now()
);
create table data.post_author (
id serial primary key,
post_id int not null references data.post (id),
author_id int not null references data.author (id),
unique (post_id, author_id)
);
create view public.author as (
select * from data.author
);
create view public.post as (
select * from data.post
);
create view public.post_author as (
select
post_id,
author_id
from data.post_author
);
comment on view public.post_author is E'@foreignKey (post_id) references public.post (id)\n@foreignKey (author_id) references public.author (id)';
Is there a way I can add a smart comment so that Author.posts
is a relationship rather than Author.postsByPostAuthorPostIdAndAuthorId
? Given the smart comments are on the constraints only, I guess the only way I can make this work is via a custom inflector plugin?
Hello, I see this error when using postgraphile as a library and including pg-many-to-many
I have "@graphile-contrib/pg-many-to-many": "^1.0.0-beta.4",
and
"postgraphile": "^4.4.0-beta.13",
Error: Cannot find module 'debug'
at Function.Module._resolveFilename (module.js:547:15)
at Function.Module._load (module.js:474:25)
at Module.require (module.js:596:17)
at require (internal/module.js:11:18)
at Object.<anonymous> (/var/task/node_modules/@graphile-contrib/pg-many-to-many/src/PgManyToManyRelationPlugin.js:1:84)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
When starting the server with this plugin added, this error occurs:
Error: Option 'appendPlugins' should be an array of functions, found 'undefined' at index 0
The other plugin (SimplifyInflector) loads without issues.
postgraphile 4.12.4 as an express middleware
instal the plugin with yarn, import it in the project and add to appendPlugins
array.
Could this be related to to tsconfig settings?
minimal server repro:
import { config } from 'dotenv'
import express = require('express')
import { postgraphile } from 'postgraphile'
import SimplifyInflector from '@graphile-contrib/pg-simplify-inflector'
import PgManyToManyPlugin from '@graphile-contrib/pg-many-to-many'
const app = express()
app.use(
postgraphile(process.env.POSTGRES_DATABASE_URL, {
watchPg: true,
dynamicJson: true,
setofFunctionsContainNulls: false,
ignoreRBAC: false,
ignoreIndexes: false,
showErrorStack: 'json',
extendedErrors: ['hint', 'detail', 'errcode'],
appendPlugins: [PgManyToManyPlugin, SimplifyInflector],
exportGqlSchemaPath: 'generated/graphql/schema.gql',
graphiql: true,
enhanceGraphiql: true,
enableQueryBatching: true,
legacyRelations: 'omit',
allowExplain: () => true,
})
)
const port = process.env.API_PORT
const server = app.listen(port, () => {
console.log(`Listening at http://localhost:${port}/graphiql`)
})
server.on('error', console.error)
This is a continuation of #19 - I'd love a way to expose edge properties when I'm using Simple Collections. I'm not 100% sure there's a way to do this cleanly in GraphQL, but I was thinking of exposing it as something like an "incoming_edge" connection or something similar.
Today in our application we are exposing both the m2m generated edges, and the built in FK support, since that allows selecting join table columns, but having two ways to do that is confusing to users.
Hi,
In my database there are some accidental many-to-many connections that I'd rather not expose. As far as I see this is currently not possible, all I can do is
comment on constraint team_member_team_id_fkey on p.team_member is E'@manyToManyFieldName IGNORE_ME';
It would be good if the @omit
smart comment worked there, too. And while we're at it, probably also @deprecate
makes sense.
Without this plugin, queries on many-to-many relations look like this:
{
allPeople {
nodes {
teamMembersByPersonId {
nodes {
teamByTeamId {
teamName
}
}
}
}
}
}
and generate the following SQL fragment:
-- ... snip
select to_json(
(
json_build_object(
'@teamByTeamId'::text,
(
select json_build_object(
'teamName'::text,
(__local_2__."team_name")
) as object
from "public"."team" as __local_2__
where (__local_3__."team_id" = __local_2__."id") and (TRUE) and (TRUE)
)
)
)
) as "@nodes"
from "public"."team_member" as __local_3__
where (__local_3__."person_id" = __local_4__."id") and (TRUE) and (TRUE)
order by __local_3__."person_id" ASC,
__local_3__."team_id" ASC
-- ... snip
With this plugin, queries look like this:
{
allPeople {
nodes {
teamsByTeamMemberPersonIdAndTeamId {
nodes {
teamName
}
}
}
}
}
and generate the following SQL fragment:
-- ...
select to_json(
(
json_build_object(
'teamName'::text,
(__local_2__."team_name")
)
)
) as "@nodes"
from "public"."team" as __local_2__
where (
__local_2__."id" in (
select "team_id"
from "public"."team_member"
where "person_id" = __local_3__."id"
)
) and (TRUE) and (TRUE)
order by __local_2__."id" ASC
-- ...
@benjie - Can we / should we try to do better? I tried adding team_member
as a second table after from "public"."team" as __local_2__
, but kept getting an error that from
was locked. Obviously we don't have join
support yet either. Thoughts?
Like the builtin PgForwardRelation
and PgBackwardRelation
plugins, the many-to-many relation plugin should consider omit
smart tags on the tables themselves. I have a problem with this as I wanted to completely @omit
a table of my database, but pg-many-to-many still created a field referencing the type.
To be more specific, I think there should be a omit(junctionTable, "read")
check in line 32 and a omit(rightTable, "read")
check around line 65.
Say I have tables a
, b
and c
.
b
is the junction table link between a
and c
.
b
itself has status is_active: boolean
.
I need to get all the c
associated with a
through active-only b
.
Currently, the plugin only accepts argument condition on table c
.
Is it possible to achieve what I want? I am also happy to help create PR if you can walk me through some high-level implementation plan.
Cheers
Given the following schema:
CREATE TABLE users (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY
);
CREATE TABLE posts (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
title text NOT NULL,
content text,
created_at timestamp with time zone DEFAULT now() NOT NULL
);
CREATE TABLE post_authors (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
post_id uuid NOT NULL REFERENCES posts(id),
user_id uuid NOT NULL REFERENCES users(id),
created_at timestamp with time zone DEFAULT now() NOT NULL
);
CREATE INDEX ON post_authors (post_id);
CREATE INDEX ON post_authors (user_id);
COMMENT ON TABLE post_authors IS E'@omit many';
COMMENT ON CONSTRAINT post_authors_user_id_fkey ON post_authors IS E'@manyToManyFieldName authors';
Results in the error:
Error: A type naming conflict has occurred - two entities have tried to define the same type 'PostAuthorsEdge'.
The first entity was:
Adding table edge type for table "public"."post_authors". You can rename the table's GraphQL type via:
COMMENT ON TABLE "public"."post_authors" IS E'@name newNameHere\n@omit many';
The second entity was:
'newWithHooks' call during hook 'PgManyToManyPlugin/GraphQLObjectType:fields/unnamed'
...
I believe this is because Postgraphile still generates it's own PostAuthorsEdge
even though I have disabled it with @omit many
. Then renaming my many to many field name to be authors causes pg-many-to-many to generate a type of the same name.
Currently the only solution I have found is to rename the table to something different as Postgraphile suggests, but that defeats the point of renaming the many to many field in the first place!
Hi,
I need many to many relations in PostGraphile, and found this plugin but multi column key relations are not generated. I see // TODO: handle multi-column
comment.
pg-structure (I'm developer of it) library provides the functions you need.
Below is a sample code for this use case:
const pgStructure = require( "pg-structure").default;
async function demo() {
const db = await pgStructure({ database: "teknik", user: "user", password: "password" }, { includeSchemas: ["public", "Region"] });
const accountTable = db.get("public.Account"); // TypeScript: db.get("public.Account") as Entity
console.log(accountTable.belongsToManyTables.map(t => t.name))
console.log(accountTable.m2mRelations.map(r => r.name))
}
demo();
You can access all many to many tables including multi column keys using belongsToManyTables
and m2mRelations
. I suggest to use m2mRelations object, which provides more info and possibilities. You can use your inflection methods easily.
I would be happy to if you have questions or need assistance how to use.
When importing this plugin library with:
import PgManyToManyPlugin from '@graphile-contrib/pg-many-to-many';
using the plugin in createPostGraphileSchema
throws a runtime error:
[Error: Option 'appendPlugins' should be an array of functions, found 'undefined' at index 1]
The library's index.d.ts
exports PgManyToManyPlugin
as a default export, but the library's index.js
doesn't set modules.exports.default
to the function. As a result, there seems to be a conflict between the types (expecting a default import) and the runtime behavior (expecting an import * as
-style import).
Contrast this with https://github.com/graphile/pg-simplify-inflector, where both the types and the library set the default export as expected.
Using patch-package:
diff --git a/node_modules/@graphile-contrib/pg-many-to-many/index.js b/node_modules/@graphile-contrib/pg-many-to-many/index.js
index 6c28f70..3ab1736 100644
--- a/node_modules/@graphile-contrib/pg-many-to-many/index.js
+++ b/node_modules/@graphile-contrib/pg-many-to-many/index.js
@@ -4,7 +4,7 @@ const PgManyToManyRelationPlugin = require("./src/PgManyToManyRelationPlugin.js"
const PgManyToManyRelationEdgeColumnsPlugin = require("./src/PgManyToManyRelationEdgeColumnsPlugin.js");
const PgManyToManyRelationEdgeTablePlugin = require("./src/PgManyToManyRelationEdgeTablePlugin.js");
-module.exports = function PgManyToManyPlugin(builder, options) {
+function PgManyToManyPlugin(builder, options) {
builder.hook("build", (build) => {
// Check dependencies
if (!build.versions) {
@@ -36,3 +36,7 @@ module.exports = function PgManyToManyPlugin(builder, options) {
PgManyToManyRelationEdgeColumnsPlugin(builder, options);
PgManyToManyRelationEdgeTablePlugin(builder, options);
};
+
+module.exports = PgManyToManyPlugin;
+module.exports.default = PgManyToManyPlugin;
+Object.defineProperty(module.exports, "__esModule", { value: true });
This is a similar change to the one in pg-simplify-inflector
. Confirmed this fixes the issue in my environment.
Happy to make a pull request if desired!
allowSyntheticDefaultImports: true
Currently, only the global --simple-collections flag is supported. As you are already checking the tags on the foreign key (for @manyToManyFieldName and @manyToManySimpleFieldName), you could also probably check @simpleCollections to override the global flag on a case by case basis.
Support for many to many relationships of the same type? The plugin doesn't seem to handle this currently unless I'm missing something?
Good afternoon, this is my problem. I have a table called talents within this table, there are two columns that relate to the city table, but it generates this error.
I already made the respective intelligent comments to the foreign keys but the error still appears.
The relationship between the tables are these
What solution can you give me to this problem thanks.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.