@@ -991,6 +991,19 @@ pub struct NodeBuilder {
991991 pub selections : Vec < NodeSelection > ,
992992}
993993
994+ #[ derive( Clone , Debug ) ]
995+ pub struct NodeByPkBuilder {
996+ // args - map of column name to value
997+ pub pk_values : HashMap < String , serde_json:: Value > ,
998+
999+ pub _alias : String ,
1000+
1001+ // metadata
1002+ pub table : Arc < Table > ,
1003+
1004+ pub selections : Vec < NodeSelection > ,
1005+ }
1006+
9941007#[ derive( Clone , Debug ) ]
9951008pub enum NodeSelection {
9961009 Connection ( ConnectionBuilder ) ,
@@ -2028,6 +2041,188 @@ where
20282041 } )
20292042}
20302043
2044+ pub fn to_node_by_pk_builder < ' a , T > (
2045+ field : & __Field ,
2046+ query_field : & graphql_parser:: query:: Field < ' a , T > ,
2047+ fragment_definitions : & Vec < FragmentDefinition < ' a , T > > ,
2048+ variables : & serde_json:: Value ,
2049+ variable_definitions : & Vec < VariableDefinition < ' a , T > > ,
2050+ ) -> Result < NodeByPkBuilder , String >
2051+ where
2052+ T : Text < ' a > + Eq + AsRef < str > + Clone ,
2053+ T :: Value : Hash ,
2054+ {
2055+ let type_ = field. type_ ( ) . unmodified_type ( ) ;
2056+ let alias = alias_or_name ( query_field) ;
2057+
2058+ match type_ {
2059+ __Type:: Node ( xtype) => {
2060+ let type_name = xtype
2061+ . name ( )
2062+ . ok_or ( "Encountered type without name in node_by_pk builder" ) ?;
2063+
2064+ let field_map = field_map ( & __Type:: Node ( xtype. clone ( ) ) ) ;
2065+
2066+ // Get primary key columns from the table
2067+ let pkey = xtype
2068+ . table
2069+ . primary_key ( )
2070+ . ok_or ( "Table has no primary key" . to_string ( ) ) ?;
2071+
2072+ // Create a map of expected field arguments based on the field's arg definitions
2073+ let mut pk_arg_map = HashMap :: new ( ) ;
2074+ for arg in field. args ( ) {
2075+ if let Some ( NodeSQLType :: Column ( col) ) = & arg. sql_type {
2076+ pk_arg_map. insert ( arg. name ( ) . to_string ( ) , col. name . clone ( ) ) ;
2077+ }
2078+ }
2079+
2080+ let mut pk_values = HashMap :: new ( ) ;
2081+
2082+ // Process each argument in the query
2083+ for arg in & query_field. arguments {
2084+ let arg_name = arg. 0 . as_ref ( ) ;
2085+
2086+ // Find the corresponding column name from our argument map
2087+ if let Some ( col_name) = pk_arg_map. get ( arg_name) {
2088+ let value = to_gson ( & arg. 1 , variables, variable_definitions) ?;
2089+ let json_value = gson:: gson_to_json ( & value) ?;
2090+ pk_values. insert ( col_name. clone ( ) , json_value) ;
2091+ }
2092+ }
2093+
2094+ // Need values for all primary key columns
2095+ if pk_values. len ( ) != pkey. column_names . len ( ) {
2096+ return Err ( "All primary key columns must be provided" . to_string ( ) ) ;
2097+ }
2098+
2099+ let mut builder_fields = vec ! [ ] ;
2100+ let selection_fields = normalize_selection_set (
2101+ & query_field. selection_set ,
2102+ fragment_definitions,
2103+ & type_name,
2104+ variables,
2105+ ) ?;
2106+
2107+ for selection_field in selection_fields {
2108+ match field_map. get ( selection_field. name . as_ref ( ) ) {
2109+ None => {
2110+ return Err ( format ! (
2111+ "Unknown field '{}' on type '{}'" ,
2112+ selection_field. name. as_ref( ) ,
2113+ & type_name
2114+ ) )
2115+ }
2116+ Some ( f) => {
2117+ let alias = alias_or_name ( & selection_field) ;
2118+
2119+ let node_selection = match & f. sql_type {
2120+ Some ( node_sql_type) => match node_sql_type {
2121+ NodeSQLType :: Column ( col) => NodeSelection :: Column ( ColumnBuilder {
2122+ alias,
2123+ column : Arc :: clone ( col) ,
2124+ } ) ,
2125+ NodeSQLType :: Function ( func) => {
2126+ let function_selection = match & f. type_ ( ) {
2127+ __Type:: Scalar ( _) => FunctionSelection :: ScalarSelf ,
2128+ __Type:: List ( _) => FunctionSelection :: Array ,
2129+ __Type:: Node ( _) => {
2130+ let node_builder = to_node_builder (
2131+ f,
2132+ & selection_field,
2133+ fragment_definitions,
2134+ variables,
2135+ & [ ] ,
2136+ variable_definitions,
2137+ ) ?;
2138+ FunctionSelection :: Node ( node_builder)
2139+ }
2140+ __Type:: Connection ( _) => {
2141+ let connection_builder = to_connection_builder (
2142+ f,
2143+ & selection_field,
2144+ fragment_definitions,
2145+ variables,
2146+ & [ ] ,
2147+ variable_definitions,
2148+ ) ?;
2149+ FunctionSelection :: Connection ( connection_builder)
2150+ }
2151+ _ => {
2152+ return Err (
2153+ "invalid return type from function" . to_string ( )
2154+ )
2155+ }
2156+ } ;
2157+ NodeSelection :: Function ( FunctionBuilder {
2158+ alias,
2159+ function : Arc :: clone ( func) ,
2160+ table : Arc :: clone ( & xtype. table ) ,
2161+ selection : function_selection,
2162+ } )
2163+ }
2164+ NodeSQLType :: NodeId ( pkey_columns) => {
2165+ NodeSelection :: NodeId ( NodeIdBuilder {
2166+ alias,
2167+ columns : pkey_columns. clone ( ) ,
2168+ table_name : xtype. table . name . clone ( ) ,
2169+ schema_name : xtype. table . schema . clone ( ) ,
2170+ } )
2171+ }
2172+ } ,
2173+ _ => match f. name ( ) . as_ref ( ) {
2174+ "__typename" => NodeSelection :: Typename {
2175+ alias : alias_or_name ( & selection_field) ,
2176+ typename : xtype. name ( ) . expect ( "node type should have a name" ) ,
2177+ } ,
2178+ _ => match f. type_ ( ) . unmodified_type ( ) {
2179+ __Type:: Connection ( _) => {
2180+ let con_builder = to_connection_builder (
2181+ f,
2182+ & selection_field,
2183+ fragment_definitions,
2184+ variables,
2185+ & [ ] ,
2186+ variable_definitions,
2187+ ) ;
2188+ NodeSelection :: Connection ( con_builder?)
2189+ }
2190+ __Type:: Node ( _) => {
2191+ let node_builder = to_node_builder (
2192+ f,
2193+ & selection_field,
2194+ fragment_definitions,
2195+ variables,
2196+ & [ ] ,
2197+ variable_definitions,
2198+ ) ;
2199+ NodeSelection :: Node ( node_builder?)
2200+ }
2201+ _ => {
2202+ return Err ( format ! (
2203+ "unexpected field type on node {}" ,
2204+ f. name( )
2205+ ) ) ;
2206+ }
2207+ } ,
2208+ } ,
2209+ } ;
2210+ builder_fields. push ( node_selection) ;
2211+ }
2212+ }
2213+ }
2214+
2215+ Ok ( NodeByPkBuilder {
2216+ pk_values,
2217+ _alias : alias,
2218+ table : Arc :: clone ( & xtype. table ) ,
2219+ selections : builder_fields,
2220+ } )
2221+ }
2222+ _ => Err ( "cannot build query for non-node type" . to_string ( ) ) ,
2223+ }
2224+ }
2225+
20312226// Introspection
20322227
20332228#[ allow( clippy:: large_enum_variant) ]
0 commit comments