New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@graphile-contrib/pg-many-to-many

Package Overview
Dependencies
Maintainers
4
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@graphile-contrib/pg-many-to-many - npm Package Compare versions

Comparing version 1.0.0-beta.10 to 1.0.0-beta.11

src/createManyToManyConnectionType.js

11

index.js

@@ -8,7 +8,3 @@ module.exports = function PgManyToManyPlugin(builder, options) {

throw new Error(
`Plugin ${pkg.name}@${
pkg.version
} requires graphile-build@^4.1.0 in order to check dependencies (current version: ${
build.graphileBuildVersion
})`
`Plugin ${pkg.name}@${pkg.version} requires graphile-build@^4.1.0 in order to check dependencies (current version: ${build.graphileBuildVersion})`
);

@@ -27,3 +23,3 @@ }

};
depends("graphile-build-pg", "^4.3.1");
depends("graphile-build-pg", "^4.4.0");

@@ -36,3 +32,6 @@ // Register this plugin

require("./src/PgManyToManyRelationInflectionPlugin.js")(builder, options);
require("./src/PgManyToManyRelationPlugin.js")(builder, options);
require("./src/PgManyToManyRelationEdgeColumnsPlugin.js")(builder, options);
require("./src/PgManyToManyRelationEdgeTablePlugin.js")(builder, options);
};
{
"name": "@graphile-contrib/pg-many-to-many",
"version": "1.0.0-beta.10",
"version": "1.0.0-beta.11",
"description": "Add connection fields for many-to-many relations",

@@ -20,11 +20,11 @@ "main": "index.js",

"devDependencies": {
"eslint": "^5.16.0",
"eslint-config-prettier": "^4.0.0",
"eslint-plugin-jest": "^22.2.2",
"eslint-plugin-prettier": "^3.0.1",
"graphql": "^14.0.2",
"jest": "^24.8.0",
"pg": "^7.8.0",
"postgraphile-core": "4.3.1",
"prettier": "1.16.4"
"eslint": "^6.4.0",
"eslint-config-prettier": "^6.3.0",
"eslint-plugin-jest": "^22.17.0",
"eslint-plugin-prettier": "^3.1.1",
"graphql": "^14.5.7",
"jest": "^24.9.0",
"pg": "^7.12.1",
"postgraphile-core": "4.4.0",
"prettier": "1.18.2"
},

@@ -31,0 +31,0 @@ "jest": {

@@ -7,3 +7,3 @@ # @graphile-contrib/pg-many-to-many

> Requires `postgraphile@^4.3.1` or `graphile-build-pg@^4.3.1`
> Requires `postgraphile@^4.4.0` or `graphile-build-pg@^4.4.0`

@@ -10,0 +10,0 @@ Example:

@@ -1,64 +0,10 @@

module.exports = function PgManyToManyRelationPlugin(
builder,
{ pgSimpleCollections }
) {
builder.hook("inflection", inflection => {
return Object.assign(inflection, {
manyToManyRelationByKeys(
_leftKeyAttributes,
junctionLeftKeyAttributes,
junctionRightKeyAttributes,
_rightKeyAttributes,
junctionTable,
rightTable,
_junctionLeftConstraint,
junctionRightConstraint
) {
if (junctionRightConstraint.tags.manyToManyFieldName) {
return junctionRightConstraint.tags.manyToManyFieldName;
}
return this.camelCase(
`${this.pluralize(
this._singularizedTableName(rightTable)
)}-by-${this._singularizedTableName(junctionTable)}-${[
...junctionLeftKeyAttributes,
...junctionRightKeyAttributes,
]
.map(attr => this.column(attr))
.join("-and-")}`
);
},
manyToManyRelationByKeysSimple(
_leftKeyAttributes,
junctionLeftKeyAttributes,
junctionRightKeyAttributes,
_rightKeyAttributes,
junctionTable,
rightTable,
_junctionLeftConstraint,
junctionRightConstraint
) {
if (junctionRightConstraint.tags.manyToManySimpleFieldName) {
return junctionRightConstraint.tags.manyToManySimpleFieldName;
}
return this.camelCase(
`${this.pluralize(
this._singularizedTableName(rightTable)
)}-by-${this._singularizedTableName(junctionTable)}-${[
...junctionLeftKeyAttributes,
...junctionRightKeyAttributes,
]
.map(attr => this.column(attr))
.join("-and-")}-list`
);
},
});
});
const createManyToManyConnectionType = require("./createManyToManyConnectionType");
const manyToManyRelationships = require("./manyToManyRelationships");
module.exports = function PgManyToManyRelationPlugin(builder, options) {
const { pgSimpleCollections } = options;
builder.hook("GraphQLObjectType:fields", (fields, build, context) => {
const {
extend,
getTypeByName,
pgGetGqlTypeByTypeIdAndModifier,
pgIntrospectionResultsByKind: introspectionResultsByKind,
pgSql: sql,

@@ -71,3 +17,2 @@ getSafeAliasFromResolveInfo,

pgAddStartEndCursor: addStartEndCursor,
pgOmit: omit,
describePgEntity,

@@ -84,299 +29,200 @@ } = build;

const relationships = manyToManyRelationships(leftTable, build);
return extend(
fields,
leftTable.foreignConstraints
.filter(con => con.type === "f")
.reduce((memoLeft, junctionLeftConstraint) => {
if (
omit(junctionLeftConstraint, "read") ||
omit(junctionLeftConstraint, "manyToMany")
) {
return memoLeft;
}
const junctionTable =
introspectionResultsByKind.classById[
junctionLeftConstraint.classId
];
if (!junctionTable) {
throw new Error(
`Could not find the table that referenced us (constraint: ${
junctionLeftConstraint.name
})`
);
}
if (omit(junctionTable, "manyToMany")) {
return memoLeft;
}
memoLeft = extend(
memoLeft,
junctionTable.constraints
.filter(
con =>
con.id !== junctionLeftConstraint.id && // Don't follow the same constraint back to the left table
con.type === "f" &&
!omit(con, "read") &&
!omit(con, "manyToMany")
)
.reduce((memoRight, junctionRightConstraint) => {
const rightTable = junctionRightConstraint.foreignClass;
const rightTableTypeName = inflection.tableType(rightTable);
const RightTableType = pgGetGqlTypeByTypeIdAndModifier(
rightTable.type.id,
null
);
if (!RightTableType) {
throw new Error(
`Could not determine type for table with id ${
junctionRightConstraint.classId
}`
);
}
const RightTableConnectionType = getTypeByName(
inflection.connection(RightTableType.name)
);
relationships.reduce((memo, relationship) => {
const {
leftKeyAttributes,
junctionLeftKeyAttributes,
junctionRightKeyAttributes,
rightKeyAttributes,
junctionTable,
rightTable,
junctionLeftConstraint,
junctionRightConstraint,
} = relationship;
const RightTableType = pgGetGqlTypeByTypeIdAndModifier(
rightTable.type.id,
null
);
if (!RightTableType) {
throw new Error(
`Could not determine type for table with id ${rightTable.type.id}`
);
}
const RightTableConnectionType = createManyToManyConnectionType(
relationship,
build,
options,
leftTable
);
const leftKeyAttributes =
junctionLeftConstraint.foreignKeyAttributes;
const junctionLeftKeyAttributes =
junctionLeftConstraint.keyAttributes;
const junctionRightKeyAttributes =
junctionRightConstraint.keyAttributes;
const rightKeyAttributes =
junctionRightConstraint.foreignKeyAttributes;
// Since we're ignoring multi-column keys, we can simplify here
const leftKeyAttribute = leftKeyAttributes[0];
const junctionLeftKeyAttribute = junctionLeftKeyAttributes[0];
const junctionRightKeyAttribute = junctionRightKeyAttributes[0];
const rightKeyAttribute = rightKeyAttributes[0];
// Ensure keys were found
if (
!leftKeyAttributes.every(_ => _) ||
!junctionLeftKeyAttributes.every(_ => _) ||
!junctionRightKeyAttributes.every(_ => _) ||
!rightKeyAttributes.every(_ => _)
) {
throw new Error("Could not find key columns!");
}
function makeFields(isConnection) {
const manyRelationFieldName = isConnection
? inflection.manyToManyRelationByKeys(
leftKeyAttributes,
junctionLeftKeyAttributes,
junctionRightKeyAttributes,
rightKeyAttributes,
junctionTable,
rightTable,
junctionLeftConstraint,
junctionRightConstraint
)
: inflection.manyToManyRelationByKeysSimple(
leftKeyAttributes,
junctionLeftKeyAttributes,
junctionRightKeyAttributes,
rightKeyAttributes,
junctionTable,
rightTable,
junctionLeftConstraint,
junctionRightConstraint
);
// Ensure keys can be read
if (
leftKeyAttributes.some(attr => omit(attr, "read")) ||
junctionLeftKeyAttributes.some(attr => omit(attr, "read")) ||
junctionRightKeyAttributes.some(attr => omit(attr, "read")) ||
rightKeyAttributes.some(attr => omit(attr, "read"))
) {
return memoRight;
}
// Ensure both constraints are single-column
// TODO: handle multi-column
if (
leftKeyAttributes.length > 1 ||
rightKeyAttributes.length > 1
) {
return memoRight;
}
// Since we're ignoring multi-column keys, we can simplify here
const leftKeyAttribute = leftKeyAttributes[0];
const junctionLeftKeyAttribute = junctionLeftKeyAttributes[0];
const junctionRightKeyAttribute = junctionRightKeyAttributes[0];
const rightKeyAttribute = rightKeyAttributes[0];
// Ensure junction constraint keys are not unique (which would result in a one-to-one relation)
const junctionLeftConstraintIsUnique = !!junctionTable.constraints.find(
c =>
(c.type === "p" || c.type === "u") &&
c.keyAttributeNums.length ===
junctionLeftKeyAttributes.length &&
c.keyAttributeNums.every(
(n, i) => junctionLeftKeyAttributes[i].num === n
)
);
const junctionRightConstraintIsUnique = !!junctionTable.constraints.find(
c =>
(c.type === "p" || c.type === "u") &&
c.keyAttributeNums.length ===
junctionRightKeyAttributes.length &&
c.keyAttributeNums.every(
(n, i) => junctionRightKeyAttributes[i].num === n
)
);
if (
junctionLeftConstraintIsUnique ||
junctionRightConstraintIsUnique
) {
return memoRight;
}
function makeFields(isConnection) {
const manyRelationFieldName = isConnection
? inflection.manyToManyRelationByKeys(
leftKeyAttributes,
junctionLeftKeyAttributes,
junctionRightKeyAttributes,
rightKeyAttributes,
junctionTable,
rightTable,
junctionLeftConstraint,
junctionRightConstraint
)
: inflection.manyToManyRelationByKeysSimple(
leftKeyAttributes,
junctionLeftKeyAttributes,
junctionRightKeyAttributes,
rightKeyAttributes,
junctionTable,
rightTable,
junctionLeftConstraint,
junctionRightConstraint
);
memoRight = extend(
memoRight,
{
[manyRelationFieldName]: fieldWithHooks(
manyRelationFieldName,
({
getDataFromParsedResolveInfoFragment,
addDataGenerator,
}) => {
addDataGenerator(parsedResolveInfoFragment => {
return {
pgQuery: queryBuilder => {
queryBuilder.select(() => {
const resolveData = getDataFromParsedResolveInfoFragment(
parsedResolveInfoFragment,
isConnection
? RightTableConnectionType
: RightTableType
);
const rightTableAlias = sql.identifier(
Symbol()
);
const leftTableAlias = queryBuilder.getTableAlias();
const query = queryFromResolveData(
sql.identifier(
rightTable.namespace.name,
rightTable.name
),
rightTableAlias,
resolveData,
{
withPagination: isConnection,
withPaginationAsFields: false,
asJsonAggregate: !isConnection,
},
innerQueryBuilder => {
innerQueryBuilder.parentQueryBuilder = queryBuilder;
const rightPrimaryKeyConstraint =
rightTable.primaryKeyConstraint;
const rightPrimaryKeyAttributes =
rightPrimaryKeyConstraint &&
rightPrimaryKeyConstraint.keyAttributes;
if (rightPrimaryKeyAttributes) {
innerQueryBuilder.beforeLock(
"orderBy",
() => {
// append order by primary key to the list of orders
if (
!innerQueryBuilder.isOrderUnique(
false
)
) {
innerQueryBuilder.data.cursorPrefix = [
"primary_key_asc",
];
rightPrimaryKeyAttributes.forEach(
attr => {
innerQueryBuilder.orderBy(
sql.fragment`${innerQueryBuilder.getTableAlias()}.${sql.identifier(
attr.name
)}`,
true
);
}
);
innerQueryBuilder.setOrderIsUnique();
}
}
);
}
innerQueryBuilder.where(
sql.fragment`${rightTableAlias}.${sql.identifier(
rightKeyAttribute.name
)} in (select ${sql.identifier(
junctionRightKeyAttribute.name
)} from ${sql.identifier(
junctionTable.namespace.name,
junctionTable.name
)} where ${sql.identifier(
junctionLeftKeyAttribute.name
)} = ${leftTableAlias}.${sql.identifier(
leftKeyAttribute.name
)})`
memo = extend(
memo,
{
[manyRelationFieldName]: fieldWithHooks(
manyRelationFieldName,
({
getDataFromParsedResolveInfoFragment,
addDataGenerator,
}) => {
const sqlFrom = sql.identifier(
rightTable.namespace.name,
rightTable.name
);
const queryOptions = {
useAsterisk: rightTable.canUseAsterisk,
withPagination: isConnection,
withPaginationAsFields: false,
asJsonAggregate: !isConnection,
};
addDataGenerator(parsedResolveInfoFragment => {
return {
pgQuery: queryBuilder => {
queryBuilder.select(() => {
const resolveData = getDataFromParsedResolveInfoFragment(
parsedResolveInfoFragment,
isConnection
? RightTableConnectionType
: RightTableType
);
const rightTableAlias = sql.identifier(Symbol());
const leftTableAlias = queryBuilder.getTableAlias();
const query = queryFromResolveData(
sqlFrom,
rightTableAlias,
resolveData,
queryOptions,
innerQueryBuilder => {
innerQueryBuilder.parentQueryBuilder = queryBuilder;
const rightPrimaryKeyConstraint =
rightTable.primaryKeyConstraint;
const rightPrimaryKeyAttributes =
rightPrimaryKeyConstraint &&
rightPrimaryKeyConstraint.keyAttributes;
if (rightPrimaryKeyAttributes) {
innerQueryBuilder.beforeLock("orderBy", () => {
// append order by primary key to the list of orders
if (!innerQueryBuilder.isOrderUnique(false)) {
innerQueryBuilder.data.cursorPrefix = [
"primary_key_asc",
];
rightPrimaryKeyAttributes.forEach(attr => {
innerQueryBuilder.orderBy(
sql.fragment`${innerQueryBuilder.getTableAlias()}.${sql.identifier(
attr.name
)}`,
true
);
},
queryBuilder.context,
queryBuilder.rootValue
);
return sql.fragment`(${query})`;
}, getSafeAliasFromAlias(parsedResolveInfoFragment.alias));
},
};
});
});
innerQueryBuilder.setOrderIsUnique();
}
});
}
return {
description: `Reads and enables pagination through a set of \`${rightTableTypeName}\`.`,
type: isConnection
? new GraphQLNonNull(RightTableConnectionType)
: new GraphQLNonNull(
new GraphQLList(
new GraphQLNonNull(RightTableType)
)
),
args: {},
resolve: (data, _args, _context, resolveInfo) => {
const safeAlias = getSafeAliasFromResolveInfo(
resolveInfo
innerQueryBuilder.where(
sql.fragment`${rightTableAlias}.${sql.identifier(
rightKeyAttribute.name
)} in (select ${sql.identifier(
junctionRightKeyAttribute.name
)} from ${sql.identifier(
junctionTable.namespace.name,
junctionTable.name
)} where ${sql.identifier(
junctionLeftKeyAttribute.name
)} = ${leftTableAlias}.${sql.identifier(
leftKeyAttribute.name
)})`
);
if (isConnection) {
return addStartEndCursor(data[safeAlias]);
} else {
return data[safeAlias];
}
},
};
},
{
isPgFieldConnection: isConnection,
isPgFieldSimpleCollection: !isConnection,
isPgManyToManyRelationField: true,
pgFieldIntrospection: rightTable,
}
),
queryBuilder.context,
queryBuilder.rootValue
);
return sql.fragment`(${query})`;
}, getSafeAliasFromAlias(parsedResolveInfoFragment.alias));
},
};
});
return {
description: `Reads and enables pagination through a set of \`${RightTableType.name}\`.`,
type: isConnection
? new GraphQLNonNull(RightTableConnectionType)
: new GraphQLNonNull(
new GraphQLList(new GraphQLNonNull(RightTableType))
),
args: {},
resolve: (data, _args, _context, resolveInfo) => {
const safeAlias = getSafeAliasFromResolveInfo(
resolveInfo
);
if (isConnection) {
return addStartEndCursor(data[safeAlias]);
} else {
return data[safeAlias];
}
},
};
},
{
isPgFieldConnection: isConnection,
isPgFieldSimpleCollection: !isConnection,
isPgManyToManyRelationField: true,
pgFieldIntrospection: rightTable,
}
),
},
`Many-to-many relation field (${
isConnection ? "connection" : "simple collection"
}) on ${Self.name} type for ${describePgEntity(
junctionLeftConstraint
)} and ${describePgEntity(junctionRightConstraint)}.`
);
}
const simpleCollections =
junctionRightConstraint.tags.simpleCollections ||
rightTable.tags.simpleCollections ||
pgSimpleCollections;
const hasConnections = simpleCollections !== "only";
const hasSimpleCollections =
simpleCollections === "only" || simpleCollections === "both";
if (hasConnections) {
makeFields(true);
}
if (hasSimpleCollections) {
makeFields(false);
}
return memoRight;
}, {})
`Many-to-many relation field (${
isConnection ? "connection" : "simple collection"
}) on ${Self.name} type for ${describePgEntity(
junctionLeftConstraint
)} and ${describePgEntity(junctionRightConstraint)}.`
);
return memoLeft;
}, {}),
}
const simpleCollections =
junctionRightConstraint.tags.simpleCollections ||
rightTable.tags.simpleCollections ||
pgSimpleCollections;
const hasConnections = simpleCollections !== "only";
const hasSimpleCollections =
simpleCollections === "only" || simpleCollections === "both";
if (hasConnections) {
makeFields(true);
}
if (hasSimpleCollections) {
makeFields(false);
}
return memo;
}, {}),
`Adding many-to-many relations for ${Self.name}`

@@ -383,0 +229,0 @@ );

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc