Skip to content

Commit 50fabfa

Browse files
committed
feat(pg) single backward relations with arguments if primary key covered partially
1 parent eff7bbb commit 50fabfa

20 files changed

+4715
-9
lines changed

packages/graphile-build-pg/src/plugins/PgBackwardRelationPlugin.js

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export default (function PgBackwardRelationPlugin(
2525
extend,
2626
getTypeByName,
2727
pgGetGqlTypeByTypeIdAndModifier,
28+
gql2pg,
2829
pgIntrospectionResultsByKind: introspectionResultsByKind,
2930
pgSql: sql,
3031
getSafeAliasFromResolveInfo,
@@ -105,27 +106,47 @@ export default (function PgBackwardRelationPlugin(
105106
const isUnique = !!table.constraints.find(
106107
c =>
107108
(c.type === "p" || c.type === "u") &&
108-
c.keyAttributeNums.length === keys.length &&
109+
c.keyAttributeNums.length <= keys.length &&
109110
c.keyAttributeNums.every((n, i) => keys[i].num === n)
110111
);
111-
112112
const isDeprecated = isUnique && legacyRelationMode === DEPRECATED;
113113

114+
const primaryKeyConstraint = table.primaryKeyConstraint;
115+
const primaryKeys =
116+
primaryKeyConstraint && primaryKeyConstraint.keyAttributes;
117+
const uncoveredPrimaryKeys =
118+
primaryKeys && keys.every(attr => primaryKeys.includes(attr))
119+
? primaryKeys.filter(attr => !keys.includes(attr))
120+
: [];
121+
const parameterKeys = uncoveredPrimaryKeys.map(key => ({
122+
...key,
123+
sqlIdentifier: sql.identifier(key.name),
124+
paramName: inflection.column(key), // inflection.argument(key.name, i)
125+
}));
126+
114127
const singleRelationFieldName = isUnique
115128
? inflection.singleRelationByKeysBackwards(
116129
keys,
117130
table,
118131
foreignTable,
119132
constraint
120133
)
134+
: uncoveredPrimaryKeys.length
135+
? inflection.rowByRelationBackwardsAndUniqueKeys(
136+
uncoveredPrimaryKeys,
137+
table,
138+
foreignTable,
139+
constraint
140+
)
121141
: null;
122142

123-
const primaryKeyConstraint = table.primaryKeyConstraint;
124-
const primaryKeys =
125-
primaryKeyConstraint && primaryKeyConstraint.keyAttributes;
126-
127143
const shouldAddSingleRelation =
128-
isUnique && legacyRelationMode !== ONLY;
144+
(isUnique && legacyRelationMode !== ONLY) ||
145+
(!isUnique &&
146+
!!uncoveredPrimaryKeys.length &&
147+
!omit(table, "single") &&
148+
!omit(primaryKeyConstraint, "single") &&
149+
!omit(constraint, "single"));
129150

130151
const shouldAddManyRelation =
131152
!isUnique ||
@@ -145,6 +166,7 @@ export default (function PgBackwardRelationPlugin(
145166
({
146167
getDataFromParsedResolveInfoFragment,
147168
addDataGenerator,
169+
addArgDataGenerator,
148170
}) => {
149171
const sqlFrom = sql.identifier(schema.name, table.name);
150172
addDataGenerator(parsedResolveInfoFragment => {
@@ -193,12 +215,43 @@ export default (function PgBackwardRelationPlugin(
193215
},
194216
};
195217
});
218+
if (!isUnique) {
219+
addArgDataGenerator(function idArgumentsGenerator(args) {
220+
return {
221+
pgQuery(queryBuilder: QueryBuilder) {
222+
const sqlTableAlias = queryBuilder.getTableAlias();
223+
for (const key of parameterKeys)
224+
queryBuilder.where(
225+
sql.fragment`${sqlTableAlias}.${
226+
key.sqlIdentifier
227+
} = ${gql2pg(
228+
args[key.paramName],
229+
key.type,
230+
key.typeModifier
231+
)}`
232+
);
233+
},
234+
};
235+
});
236+
}
196237
return {
197238
description:
198239
constraint.tags.backwardDescription ||
199-
`Reads a single \`${tableTypeName}\` that is related to this \`${foreignTableTypeName}\`.`,
240+
`${
241+
isUnique ? "Reads" : "Select"
242+
} a single \`${tableTypeName}\` that is related to this \`${foreignTableTypeName}\`.`,
200243
type: gqlTableType,
201-
args: {},
244+
args: parameterKeys.reduce((memo, key) => {
245+
memo[key.paramName] = {
246+
type: new GraphQLNonNull(
247+
pgGetGqlTypeByTypeIdAndModifier(
248+
key.typeId,
249+
key.typeModifier
250+
)
251+
),
252+
};
253+
return memo;
254+
}, {}),
202255
resolve: (data, _args, resolveContext, resolveInfo) => {
203256
const safeAlias = getSafeAliasFromResolveInfo(
204257
resolveInfo

packages/graphile-build-pg/src/plugins/PgBasicsPlugin.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,24 @@ export default (function PgBasicsPlugin(
724724
.join("-and-")}`
725725
);
726726
},
727+
rowByRelationBackwardsAndUniqueKeys(
728+
detailedKeys: PgAttribute[],
729+
table: PgClass,
730+
_foreignTable: PgClass,
731+
constraint: PgConstraint
732+
) {
733+
if (constraint.tags.foreignSingleFieldName) {
734+
return constraint.tags.foreignSingleFieldName;
735+
}
736+
if (constraint.tags.foreignFieldName) {
737+
return this.singularize(constraint.tags.foreignFieldName);
738+
}
739+
return this.rowByUniqueKeys(
740+
detailedKeys,
741+
table,
742+
table.primaryKeyConstraint
743+
);
744+
},
727745
updateByKeys(
728746
detailedKeys: Keys,
729747
table: PgClass,

packages/postgraphile-core/__tests__/fixtures/queries/relation-head-tail.graphql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@ query {
1515
authorId
1616
}
1717
}
18+
compoundKeyByPersonId1(personId1: 2) {
19+
personId1
20+
personId2
21+
extra
22+
}
23+
compoundKeyByPersonId2(personId2: 3) {
24+
personId1
25+
personId2
26+
extra
27+
}
1828
compoundKeysByPersonId1 {
1929
nodes {
2030
personId1

packages/postgraphile-core/__tests__/integration/__snapshots__/queries.test.js.snap

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5972,6 +5972,12 @@ Object {
59725972
"allPeople": Object {
59735973
"nodes": Array [
59745974
Object {
5975+
"compoundKeyByPersonId1": Object {
5976+
"extra": false,
5977+
"personId1": 2,
5978+
"personId2": 1,
5979+
},
5980+
"compoundKeyByPersonId2": null,
59755981
"compoundKeysByPersonId1": Object {
59765982
"nodes": Array [
59775983
Object {
@@ -6012,6 +6018,12 @@ Object {
60126018
},
60136019
},
60146020
Object {
6021+
"compoundKeyByPersonId1": null,
6022+
"compoundKeyByPersonId2": Object {
6023+
"extra": null,
6024+
"personId1": 2,
6025+
"personId2": 3,
6026+
},
60156027
"compoundKeysByPersonId1": Object {
60166028
"nodes": Array [
60176029
Object {
@@ -6055,6 +6067,12 @@ Object {
60556067
},
60566068
},
60576069
Object {
6070+
"compoundKeyByPersonId1": Object {
6071+
"extra": null,
6072+
"personId1": 2,
6073+
"personId2": 3,
6074+
},
6075+
"compoundKeyByPersonId2": null,
60586076
"compoundKeysByPersonId1": Object {
60596077
"nodes": Array [],
60606078
},
@@ -6089,6 +6107,12 @@ Object {
60896107
},
60906108
},
60916109
Object {
6110+
"compoundKeyByPersonId1": null,
6111+
"compoundKeyByPersonId2": Object {
6112+
"extra": true,
6113+
"personId1": 4,
6114+
"personId2": 3,
6115+
},
60926116
"compoundKeysByPersonId1": Object {
60936117
"nodes": Array [
60946118
Object {
@@ -6119,6 +6143,12 @@ Object {
61196143
},
61206144
},
61216145
Object {
6146+
"compoundKeyByPersonId1": Object {
6147+
"extra": true,
6148+
"personId1": 2,
6149+
"personId2": 5,
6150+
},
6151+
"compoundKeyByPersonId2": null,
61226152
"compoundKeysByPersonId1": Object {
61236153
"nodes": Array [],
61246154
},
@@ -6145,6 +6175,8 @@ Object {
61456175
},
61466176
},
61476177
Object {
6178+
"compoundKeyByPersonId1": null,
6179+
"compoundKeyByPersonId2": null,
61486180
"compoundKeysByPersonId1": Object {
61496181
"nodes": Array [],
61506182
},

packages/postgraphile-core/__tests__/integration/schema/__snapshots__/defaultOptions.test.js.snap

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5773,6 +5773,12 @@ type Person implements Node {
57735773
about: String
57745774
aliases: [String]!
57755775

5776+
"""Select a single \`CompoundKey\` that is related to this \`Person\`."""
5777+
compoundKeyByPersonId1(personId1: Int!): CompoundKey
5778+
5779+
"""Select a single \`CompoundKey\` that is related to this \`Person\`."""
5780+
compoundKeyByPersonId2(personId2: Int!): CompoundKey
5781+
57765782
"""Reads and enables pagination through a set of \`CompoundKey\`."""
57775783
compoundKeysByPersonId1(
57785784
"""Read all values in the set after (below) this cursor."""
@@ -15853,6 +15859,12 @@ type Person implements Node {
1585315859
about: String
1585415860
aliases: [String]!
1585515861

15862+
"""Select a single \`CompoundKey\` that is related to this \`Person\`."""
15863+
compoundKeyByPersonId1(personId1: Int!): CompoundKey
15864+
15865+
"""Select a single \`CompoundKey\` that is related to this \`Person\`."""
15866+
compoundKeyByPersonId2(personId2: Int!): CompoundKey
15867+
1585615868
"""Reads and enables pagination through a set of \`CompoundKey\`."""
1585715869
compoundKeysByPersonId1(
1585815870
"""Read all values in the set after (below) this cursor."""

packages/postgraphile-core/__tests__/integration/schema/__snapshots__/disabledTagsNoLegacyRelations.test.js.snap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2863,6 +2863,12 @@ type Person implements Node {
28632863
about: String
28642864
aliases: [String]!
28652865
2866+
"""Select a single \`CompoundKey\` that is related to this \`Person\`."""
2867+
compoundKeyByPersonId1(personId1: Int!): CompoundKey
2868+
2869+
"""Select a single \`CompoundKey\` that is related to this \`Person\`."""
2870+
compoundKeyByPersonId2(personId2: Int!): CompoundKey
2871+
28662872
"""Reads and enables pagination through a set of \`CompoundKey\`."""
28672873
compoundKeysByPersonId1(
28682874
"""Read all values in the set after (below) this cursor."""

packages/postgraphile-core/__tests__/integration/schema/__snapshots__/function-clash.test.js.snap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5773,6 +5773,12 @@ type Person implements Node {
57735773
about: String
57745774
aliases: [String]!
57755775
5776+
"""Select a single \`CompoundKey\` that is related to this \`Person\`."""
5777+
compoundKeyByPersonId1(personId1: Int!): CompoundKey
5778+
5779+
"""Select a single \`CompoundKey\` that is related to this \`Person\`."""
5780+
compoundKeyByPersonId2(personId2: Int!): CompoundKey
5781+
57765782
"""Reads and enables pagination through a set of \`CompoundKey\`."""
57775783
compoundKeysByPersonId1(
57785784
"""Read all values in the set after (below) this cursor."""

packages/postgraphile-core/__tests__/integration/schema/__snapshots__/indexes.test.js.snap

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6098,6 +6098,9 @@ type Person implements Node {
60986098
about: String
60996099
aliases: [String]!
61006100
6101+
"""Select a single \`CompoundKey\` that is related to this \`Person\`."""
6102+
compoundKeyByPersonId2(personId2: Int!): CompoundKey
6103+
61016104
"""Reads and enables pagination through a set of \`CompoundKey\`."""
61026105
compoundKeysByPersonId1(
61036106
"""Read all values in the set after (below) this cursor."""

packages/postgraphile-core/__tests__/integration/schema/__snapshots__/inflect-core.test.js.snap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5768,6 +5768,12 @@ type Person implements N {
57685768
about: String
57695769
aliases: [String]!
57705770
5771+
"""Select a single \`CompoundKey\` that is related to this \`Person\`."""
5772+
compoundKeyByPersonId1(personId1: Int!): CompoundKey
5773+
5774+
"""Select a single \`CompoundKey\` that is related to this \`Person\`."""
5775+
compoundKeyByPersonId2(personId2: Int!): CompoundKey
5776+
57715777
"""Reads and enables pagination through a set of \`CompoundKey\`."""
57725778
compoundKeysByPersonId1(
57735779
"""Read all values in the set after (below) this cursor."""

packages/postgraphile-core/__tests__/integration/schema/__snapshots__/legacyFunctionsOnly.test.js.snap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2145,6 +2145,12 @@ type Person implements Node {
21452145
about: String
21462146
aliases: [String]!
21472147
2148+
"""Select a single \`CompoundKey\` that is related to this \`Person\`."""
2149+
compoundKeyByPersonId1(personId1: Int!): CompoundKey
2150+
2151+
"""Select a single \`CompoundKey\` that is related to this \`Person\`."""
2152+
compoundKeyByPersonId2(personId2: Int!): CompoundKey
2153+
21482154
"""Reads and enables pagination through a set of \`CompoundKey\`."""
21492155
compoundKeysByPersonId1(
21502156
"""Read all values in the set after (below) this cursor."""

0 commit comments

Comments
 (0)