@@ -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