Skip to content

Commit d35e5dc

Browse files
committed
refactor: use consistent relationSpec objects
1 parent af26c67 commit d35e5dc

File tree

2 files changed

+151
-169
lines changed

2 files changed

+151
-169
lines changed

src/PgConnectionArgFilterBackwardRelationsPlugin.js

Lines changed: 117 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -21,201 +21,181 @@ module.exports = function PgConnectionArgFilterBackwardRelationsPlugin(
2121
} = build;
2222
const {
2323
fieldWithHooks,
24-
scope: { pgIntrospection: foreignTable, isPgConnectionFilter },
24+
scope: { pgIntrospection: table, isPgConnectionFilter },
2525
Self,
2626
} = context;
2727

2828
if (!isPgConnectionFilter) return fields;
2929

3030
connectionFilterTypesByTypeName[Self.name] = Self;
3131

32-
const foreignKeyConstraints = introspectionResultsByKind.constraint
32+
const backwardRelationSpecs = introspectionResultsByKind.constraint
3333
.filter(con => con.type === "f")
34-
.filter(con => con.foreignClassId === foreignTable.id);
35-
const foreignAttributes = introspectionResultsByKind.attribute
36-
.filter(attr => attr.classId === foreignTable.id)
37-
.sort((a, b) => a.num - b.num);
38-
39-
const backwardRelationInfoByFieldName = foreignKeyConstraints.reduce(
40-
(memo, constraint) => {
41-
if (omit(constraint, "read")) {
34+
.filter(con => con.foreignClassId === table.id)
35+
.reduce((memo, foreignConstraint) => {
36+
if (omit(foreignConstraint, "read")) {
4237
return memo;
4338
}
44-
45-
const table = introspectionResultsByKind.classById[constraint.classId];
46-
if (!table) {
39+
const foreignTable =
40+
introspectionResultsByKind.classById[foreignConstraint.classId];
41+
if (!foreignTable) {
4742
throw new Error(
48-
`Could not find the table that referenced us (constraint: ${
49-
constraint.name
43+
`Could not find the foreign table (constraint: ${
44+
foreignConstraint.name
5045
})`
5146
);
5247
}
53-
54-
const attributes = introspectionResultsByKind.attribute.filter(
55-
attr => attr.classId === table.id
56-
);
57-
58-
const keys = constraint.keyAttributeNums.map(
48+
if (omit(foreignTable, "read")) {
49+
return memo;
50+
}
51+
const attributes = introspectionResultsByKind.attribute
52+
.filter(attr => attr.classId === table.id)
53+
.sort((a, b) => a.num - b.num);
54+
const foreignAttributes = introspectionResultsByKind.attribute
55+
.filter(attr => attr.classId === foreignTable.id)
56+
.sort((a, b) => a.num - b.num);
57+
const keyAttributes = foreignConstraint.foreignKeyAttributeNums.map(
5958
num => attributes.filter(attr => attr.num === num)[0]
6059
);
61-
const foreignKeys = constraint.foreignKeyAttributeNums.map(
60+
const foreignKeyAttributes = foreignConstraint.keyAttributeNums.map(
6261
num => foreignAttributes.filter(attr => attr.num === num)[0]
6362
);
64-
if (!keys.every(_ => _) || !foreignKeys.every(_ => _)) {
65-
throw new Error("Could not find key columns!");
66-
}
67-
if (keys.some(key => omit(key, "read"))) {
63+
if (keyAttributes.some(attr => omit(attr, "read"))) {
6864
return memo;
6965
}
70-
if (foreignKeys.some(key => omit(key, "read"))) {
66+
if (foreignKeyAttributes.some(attr => omit(attr, "read"))) {
7167
return memo;
7268
}
73-
const isUnique = !!introspectionResultsByKind.constraint.find(
69+
const isForeignKeyUnique = !!introspectionResultsByKind.constraint.find(
7470
c =>
75-
c.classId === table.id &&
71+
c.classId === foreignTable.id &&
7672
(c.type === "p" || c.type === "u") &&
77-
c.keyAttributeNums.length === keys.length &&
78-
c.keyAttributeNums.every((n, i) => keys[i].num === n)
79-
);
80-
81-
const singleRelationFieldName = isUnique
82-
? inflection.singleRelationByKeysBackwards(
83-
keys,
84-
table,
85-
foreignTable,
86-
constraint
73+
c.keyAttributeNums.length === foreignKeyAttributes.length &&
74+
c.keyAttributeNums.every(
75+
(n, i) => foreignKeyAttributes[i].num === n
8776
)
88-
: null;
89-
90-
const shouldAddSingleRelation = isUnique;
91-
92-
// Intentionally disabled for now.
93-
// Need to expose `any` and `all` options instead of simply checking for `any`.
94-
const shouldAddManyRelation = false; // !isUnique;
95-
96-
if (
97-
shouldAddSingleRelation &&
98-
!omit(table, "read") &&
99-
singleRelationFieldName
100-
) {
77+
);
78+
memo.push({
79+
table,
80+
keyAttributes,
81+
foreignTable,
82+
foreignKeyAttributes,
83+
foreignConstraint,
84+
isOneToMany: !isForeignKeyUnique,
85+
});
86+
return memo;
87+
}, []);
88+
89+
const backwardRelationSpecByFieldName = backwardRelationSpecs.reduce(
90+
(memo, spec) => {
91+
const {
92+
foreignTable,
93+
foreignKeyAttributes,
94+
foreignConstraint,
95+
isOneToMany,
96+
} = spec;
97+
if (isOneToMany) {
98+
// Not yet implemented
99+
} else {
100+
const fieldName = inflection.singleRelationByKeysBackwards(
101+
foreignKeyAttributes,
102+
foreignTable,
103+
table,
104+
foreignConstraint
105+
);
101106
memo = extend(memo, {
102-
[singleRelationFieldName]: {
103-
table,
104-
foreignKeys,
105-
keys,
106-
},
107+
[fieldName]: spec,
107108
});
108109
}
109-
function makeFields(isConnection) {
110-
if (isUnique && !isConnection) {
111-
// Don't need this, use the singular instead
112-
return;
113-
}
114-
if (shouldAddManyRelation && !omit(table, "many")) {
115-
const manyRelationFieldName = isConnection
116-
? inflection.manyRelationByKeys(
117-
keys,
118-
table,
119-
foreignTable,
120-
constraint
121-
)
122-
: inflection.manyRelationByKeysSimple(
123-
keys,
124-
table,
125-
foreignTable,
126-
constraint
127-
);
128-
129-
memo = extend(memo, {
130-
[manyRelationFieldName]: {
131-
table,
132-
foreignKeys,
133-
keys,
134-
},
135-
});
136-
}
137-
}
138-
if (hasConnections) {
139-
makeFields(true);
140-
}
141-
if (hasSimpleCollections) {
142-
makeFields(false);
143-
}
144-
145110
return memo;
146111
},
147112
{}
148113
);
149114

150115
const backwardRelationFields = Object.entries(
151-
backwardRelationInfoByFieldName
116+
backwardRelationSpecByFieldName
152117
).reduce((memo, curr) => {
153-
const [fieldName, { table }] = curr;
154-
const tableTypeName = inflection.tableType(table);
155-
const tableFilterTypeName = inflection.filterType(tableTypeName);
118+
const [fieldName, { foreignTable, isOneToMany }] = curr;
119+
const foreignTableTypeName = inflection.tableType(foreignTable);
120+
const foreignTableFilterTypeName = inflection.filterType(
121+
foreignTableTypeName
122+
);
156123
const FilterType = connectionFilterType(
157124
newWithHooks,
158-
tableFilterTypeName,
159-
table,
160-
tableTypeName
125+
foreignTableFilterTypeName,
126+
foreignTable,
127+
foreignTableTypeName
161128
);
162129
if (FilterType != null) {
163-
memo[fieldName] = fieldWithHooks(
164-
fieldName,
165-
{
166-
description: `Filter by the object’s \`${fieldName}\` field.`,
167-
type: FilterType,
168-
},
169-
{
170-
isPgConnectionFilterField: true,
171-
}
172-
);
130+
if (isOneToMany) {
131+
// Not yet implemented
132+
} else {
133+
memo[fieldName] = fieldWithHooks(
134+
fieldName,
135+
{
136+
description: `Filter by the object’s \`${fieldName}\` field.`,
137+
type: FilterType,
138+
},
139+
{
140+
isPgConnectionFilterField: true,
141+
}
142+
);
143+
}
173144
}
174145
return memo;
175146
}, {});
176147

177148
const resolve = ({ sourceAlias, fieldName, fieldValue, queryBuilder }) => {
178149
if (fieldValue == null) return null;
179150

180-
const { table, foreignKeys, keys } = backwardRelationInfoByFieldName[
181-
fieldName
182-
];
151+
const {
152+
foreignTable,
153+
foreignKeyAttributes,
154+
keyAttributes,
155+
isOneToMany,
156+
} = backwardRelationSpecByFieldName[fieldName];
183157

184-
const tableAlias = sql.identifier(Symbol());
185-
if (table == null) return null;
158+
const foreignTableAlias = sql.identifier(Symbol());
159+
if (foreignTable == null) return null;
186160

187-
const sqlIdentifier = sql.identifier(table.namespace.name, table.name);
161+
const sqlIdentifier = sql.identifier(
162+
foreignTable.namespace.name,
163+
foreignTable.name
164+
);
188165

189166
const sqlKeysMatch = sql.query`(${sql.join(
190-
keys.map((key, i) => {
191-
return sql.fragment`${tableAlias}.${sql.identifier(
192-
key.name
193-
)} = ${sourceAlias}.${sql.identifier(foreignKeys[i].name)}`;
167+
foreignKeyAttributes.map((attr, i) => {
168+
return sql.fragment`${foreignTableAlias}.${sql.identifier(
169+
attr.name
170+
)} = ${sourceAlias}.${sql.identifier(keyAttributes[i].name)}`;
194171
}),
195172
") and ("
196173
)})`;
197174

198-
const tableTypeName = inflection.tableType(table);
199-
const tableFilterTypeName = inflection.filterType(tableTypeName);
200-
201-
const sqlFragment = connectionFilterResolve(
202-
fieldValue,
203-
tableAlias,
204-
tableFilterTypeName,
205-
queryBuilder
175+
const foreignTableTypeName = inflection.tableType(foreignTable);
176+
const foreignTableFilterTypeName = inflection.filterType(
177+
foreignTableTypeName
206178
);
207179

208-
return sqlFragment == null
209-
? null
210-
: sql.query`\
211-
exists(
212-
select 1 from ${sqlIdentifier} as ${tableAlias}
213-
where ${sqlKeysMatch} and
214-
(${sqlFragment})
215-
)`;
180+
if (isOneToMany) {
181+
// Not yet implemented
182+
} else {
183+
const sqlFragment = connectionFilterResolve(
184+
fieldValue,
185+
foreignTableAlias,
186+
foreignTableFilterTypeName,
187+
queryBuilder
188+
);
189+
190+
const sqlSelectWhereKeysMatch = sql.query`select 1 from ${sqlIdentifier} as ${foreignTableAlias} where ${sqlKeysMatch}`;
191+
192+
return sqlFragment == null
193+
? null
194+
: sql.query`exists(${sqlSelectWhereKeysMatch} and (${sqlFragment}))`;
195+
}
216196
};
217197

218-
for (const fieldName of Object.keys(backwardRelationInfoByFieldName)) {
198+
for (const fieldName of Object.keys(backwardRelationSpecByFieldName)) {
219199
connectionFilterFieldResolversByTypeNameAndFieldName[Self.name][
220200
fieldName
221201
] = resolve;

0 commit comments

Comments
 (0)