Skip to content

Commit f3da297

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

20 files changed

+4722
-9
lines changed

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

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export default (function PgBackwardRelationPlugin(
3636
extend,
3737
getTypeByName,
3838
pgGetGqlTypeByTypeIdAndModifier,
39+
gql2pg,
3940
pgIntrospectionResultsByKind: introspectionResultsByKind,
4041
pgSql: sql,
4142
getSafeAliasFromResolveInfo,
@@ -131,27 +132,48 @@ export default (function PgBackwardRelationPlugin(
131132
const isUnique = !!table.constraints.find(
132133
c =>
133134
(c.type === "p" || c.type === "u") &&
134-
c.keyAttributeNums.length === keys.length &&
135+
c.keyAttributeNums.length <= keys.length &&
135136
c.keyAttributeNums.every((n, i) => keys[i].num === n)
136137
);
137-
138138
const isDeprecated = isUnique && legacyRelationMode === DEPRECATED;
139139

140+
const primaryKeyConstraint = table.primaryKeyConstraint;
141+
const primaryKeys =
142+
primaryKeyConstraint && primaryKeyConstraint.keyAttributes;
143+
const uncoveredPrimaryKeys =
144+
primaryKeys && keys.every(attr => primaryKeys.includes(attr))
145+
? primaryKeys.filter(attr => !keys.includes(attr))
146+
: [];
147+
const parameterKeys = uncoveredPrimaryKeys.map(key => ({
148+
...key,
149+
sqlIdentifier: sql.identifier(key.name),
150+
paramName: inflection.column(key), // inflection.argument(key.name, i)
151+
}));
152+
140153
const singleRelationFieldName = isUnique
141154
? inflection.singleRelationByKeysBackwards(
142155
keys,
143156
table,
144157
foreignTable,
145158
constraint
146159
)
160+
: uncoveredPrimaryKeys.length
161+
? inflection.rowByRelationBackwardsAndUniqueKeys(
162+
uncoveredPrimaryKeys,
163+
table,
164+
foreignTable,
165+
constraint
166+
)
147167
: null;
148168

149-
const primaryKeyConstraint = table.primaryKeyConstraint;
150-
const primaryKeys =
151-
primaryKeyConstraint && primaryKeyConstraint.keyAttributes;
152-
153169
const shouldAddSingleRelation =
154-
isUnique && legacyRelationMode !== ONLY;
170+
(isUnique && legacyRelationMode !== ONLY) ||
171+
(!isUnique &&
172+
!!uncoveredPrimaryKeys.length &&
173+
primaryKeyConstraint &&
174+
!omit(table, "single") &&
175+
!omit(primaryKeyConstraint, "single") &&
176+
!omit(constraint, "single"));
155177

156178
const shouldAddManyRelation =
157179
!isUnique ||
@@ -171,6 +193,7 @@ export default (function PgBackwardRelationPlugin(
171193
({
172194
getDataFromParsedResolveInfoFragment,
173195
addDataGenerator,
196+
addArgDataGenerator,
174197
}) => {
175198
const sqlFrom = sql.identifier(schema.name, table.name);
176199
addDataGenerator(parsedResolveInfoFragment => {
@@ -222,12 +245,43 @@ export default (function PgBackwardRelationPlugin(
222245
},
223246
};
224247
});
248+
if (!isUnique) {
249+
addArgDataGenerator(function idArgumentsGenerator(args) {
250+
return {
251+
pgQuery(queryBuilder): void {
252+
const sqlTableAlias = queryBuilder.getTableAlias();
253+
for (const key of parameterKeys)
254+
queryBuilder.where(
255+
sql.fragment`${sqlTableAlias}.${
256+
key.sqlIdentifier
257+
} = ${gql2pg(
258+
args[key.paramName],
259+
key.type,
260+
key.typeModifier
261+
)}`
262+
);
263+
},
264+
};
265+
});
266+
}
225267
return {
226268
description:
227269
stringTag(constraint, "backwardDescription") ||
228-
`Reads a single \`${tableTypeName}\` that is related to this \`${foreignTableTypeName}\`.`,
270+
`${
271+
isUnique ? "Reads" : "Select"
272+
} a single \`${tableTypeName}\` that is related to this \`${foreignTableTypeName}\`.`,
229273
type: gqlTableType,
230-
args: {},
274+
args: parameterKeys.reduce((memo, key) => {
275+
const ArgType = pgGetGqlTypeByTypeIdAndModifier(
276+
key.typeId,
277+
key.typeModifier
278+
);
279+
if (ArgType)
280+
memo[key.paramName] = {
281+
type: new GraphQLNonNull(ArgType),
282+
};
283+
return memo;
284+
}, {}),
231285
resolve: (data, _args, resolveContext, resolveInfo) => {
232286
const safeAlias = getSafeAliasFromResolveInfo(
233287
resolveInfo

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,12 @@ declare module "graphile-build" {
202202
table: PgClass,
203203
constraint: PgConstraint
204204
): string;
205+
rowByRelationBackwardsAndUniqueKeys(
206+
detailedKeys: PgAttribute[],
207+
table: PgClass,
208+
_foreignTable: PgClass,
209+
constraint: PgConstraint
210+
): string;
205211
updateByKeys(
206212
detailedKeys: PgAttribute[],
207213
table: PgClass,
@@ -610,6 +616,24 @@ function makePgBaseInflectors(): Partial<Inflection> {
610616
.join("-and-")}`
611617
);
612618
},
619+
rowByRelationBackwardsAndUniqueKeys(
620+
detailedKeys: PgAttribute[],
621+
table: PgClass,
622+
_foreignTable: PgClass,
623+
constraint: PgConstraint
624+
) {
625+
if (constraint.tags.foreignSingleFieldName) {
626+
return constraint.tags.foreignSingleFieldName;
627+
}
628+
if (constraint.tags.foreignFieldName) {
629+
return this.singularize(constraint.tags.foreignFieldName);
630+
}
631+
return this.rowByUniqueKeys(
632+
detailedKeys,
633+
table,
634+
table.primaryKeyConstraint
635+
);
636+
},
613637
updateByKeys(
614638
this: Inflection,
615639
detailedKeys: PgAttribute[],

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)