1616 ChoiceType = JSONType = ScalarListType = TSVectorType = object
1717
1818
19+ def _get_attr_resolver (attr_name ):
20+ return lambda root , _info : getattr (root , attr_name , None )
21+
22+
1923def get_column_doc (column ):
2024 return getattr (column , "doc" , None )
2125
@@ -24,43 +28,61 @@ def is_column_nullable(column):
2428 return bool (getattr (column , "nullable" , True ))
2529
2630
27- def convert_sqlalchemy_relationship (relationship , registry , connection_field_factory ):
28- direction = relationship .direction
29- model = relationship .mapper .entity
31+ def convert_sqlalchemy_relationship (relationship_prop , registry , connection_field_factory , ** field_kwargs ):
32+ direction = relationship_prop .direction
33+ model = relationship_prop .mapper .entity
3034
3135 def dynamic_type ():
3236 _type = registry .get_type_for_model (model )
37+
3338 if not _type :
3439 return None
35- if direction == interfaces .MANYTOONE or not relationship .uselist :
36- return Field (_type )
40+ if direction == interfaces .MANYTOONE or not relationship_prop .uselist :
41+ return Field (
42+ _type ,
43+ resolver = _get_attr_resolver (relationship_prop .key ),
44+ ** field_kwargs
45+ )
3746 elif direction in (interfaces .ONETOMANY , interfaces .MANYTOMANY ):
3847 if _type ._meta .connection :
39- return connection_field_factory (relationship , registry )
40- return Field (List (_type ))
48+ # TODO Add a way to override connection_field_factory
49+ return connection_field_factory (relationship_prop , registry , ** field_kwargs )
50+ return Field (
51+ List (_type ),
52+ ** field_kwargs
53+ )
4154
4255 return Dynamic (dynamic_type )
4356
4457
45- def convert_sqlalchemy_hybrid_method (hybrid_item ):
46- return String (description = getattr (hybrid_item , "__doc__" , None ), required = False )
58+ def convert_sqlalchemy_hybrid_method (hybrid_prop , prop_name , ** field_kwargs ):
59+ if 'type' not in field_kwargs :
60+ # TODO The default type should be dependent on the type of the property propety.
61+ field_kwargs ['type' ] = String
62+
63+ return Field (
64+ resolver = _get_attr_resolver (prop_name ),
65+ ** field_kwargs
66+ )
4767
4868
49- def convert_sqlalchemy_composite (composite , registry ):
50- converter = registry .get_converter_for_composite (composite .composite_class )
69+ def convert_sqlalchemy_composite (composite_prop , registry ):
70+ converter = registry .get_converter_for_composite (composite_prop .composite_class )
5171 if not converter :
5272 try :
5373 raise Exception (
5474 "Don't know how to convert the composite field %s (%s)"
55- % (composite , composite .composite_class )
75+ % (composite_prop , composite_prop .composite_class )
5676 )
5777 except AttributeError :
5878 # handle fields that are not attached to a class yet (don't have a parent)
5979 raise Exception (
6080 "Don't know how to convert the composite field %r (%s)"
61- % (composite , composite .composite_class )
81+ % (composite_prop , composite_prop .composite_class )
6282 )
63- return converter (composite , registry )
83+
84+ # TODO Add a way to override composite fields default parameters
85+ return converter (composite_prop , registry )
6486
6587
6688def _register_composite_class (cls , registry = None ):
@@ -78,8 +100,16 @@ def inner(fn):
78100convert_sqlalchemy_composite .register = _register_composite_class
79101
80102
81- def convert_sqlalchemy_column (column , registry = None ):
82- return convert_sqlalchemy_type (getattr (column , "type" , None ), column , registry )
103+ def convert_sqlalchemy_column (column_prop , registry , ** field_kwargs ):
104+ column = column_prop .columns [0 ]
105+ field_kwargs .setdefault ('type' , convert_sqlalchemy_type (getattr (column , "type" , None ), column , registry ))
106+ field_kwargs .setdefault ('required' , not is_column_nullable (column ))
107+ field_kwargs .setdefault ('description' , get_column_doc (column ))
108+
109+ return Field (
110+ resolver = _get_attr_resolver (column_prop .key ),
111+ ** field_kwargs
112+ )
83113
84114
85115@singledispatch
@@ -101,93 +131,63 @@ def convert_sqlalchemy_type(type, column, registry=None):
101131@convert_sqlalchemy_type .register (postgresql .CIDR )
102132@convert_sqlalchemy_type .register (TSVectorType )
103133def convert_column_to_string (type , column , registry = None ):
104- return String (
105- description = get_column_doc (column ), required = not (is_column_nullable (column ))
106- )
134+ return String
107135
108136
109137@convert_sqlalchemy_type .register (types .DateTime )
110138def convert_column_to_datetime (type , column , registry = None ):
111139 from graphene .types .datetime import DateTime
112-
113- return DateTime (
114- description = get_column_doc (column ), required = not (is_column_nullable (column ))
115- )
140+ return DateTime
116141
117142
118143@convert_sqlalchemy_type .register (types .SmallInteger )
119144@convert_sqlalchemy_type .register (types .Integer )
120145def convert_column_to_int_or_id (type , column , registry = None ):
121- if column .primary_key :
122- return ID (
123- description = get_column_doc (column ),
124- required = not (is_column_nullable (column )),
125- )
126- else :
127- return Int (
128- description = get_column_doc (column ),
129- required = not (is_column_nullable (column )),
130- )
146+ return ID if column .primary_key else Int
131147
132148
133149@convert_sqlalchemy_type .register (types .Boolean )
134150def convert_column_to_boolean (type , column , registry = None ):
135- return Boolean (
136- description = get_column_doc (column ), required = not (is_column_nullable (column ))
137- )
151+ return Boolean
138152
139153
140154@convert_sqlalchemy_type .register (types .Float )
141155@convert_sqlalchemy_type .register (types .Numeric )
142156@convert_sqlalchemy_type .register (types .BigInteger )
143157def convert_column_to_float (type , column , registry = None ):
144- return Float (
145- description = get_column_doc (column ), required = not (is_column_nullable (column ))
146- )
158+ return Float
147159
148160
149161@convert_sqlalchemy_type .register (types .Enum )
150162def convert_enum_to_enum (type , column , registry = None ):
151- return Field (
152- lambda : enum_for_sa_enum (type , registry or get_global_registry ()),
153- description = get_column_doc (column ),
154- required = not (is_column_nullable (column )),
155- )
163+ return lambda : enum_for_sa_enum (type , registry or get_global_registry ())
156164
157165
166+ # TODO Make ChoiceType conversion consistent with other enums
158167@convert_sqlalchemy_type .register (ChoiceType )
159168def convert_choice_to_enum (type , column , registry = None ):
160169 name = "{}_{}" .format (column .table .name , column .name ).upper ()
161- return Enum (name , type .choices , description = get_column_doc ( column ) )
170+ return Enum (name , type .choices )
162171
163172
164173@convert_sqlalchemy_type .register (ScalarListType )
165174def convert_scalar_list_to_list (type , column , registry = None ):
166- return List (String , description = get_column_doc ( column ) )
175+ return List (String )
167176
168177
169178@convert_sqlalchemy_type .register (postgresql .ARRAY )
170179def convert_postgres_array_to_list (_type , column , registry = None ):
171- graphene_type = convert_sqlalchemy_type (column .type .item_type , column )
172- inner_type = type (graphene_type )
173- return List (
174- inner_type ,
175- description = get_column_doc (column ),
176- required = not (is_column_nullable (column )),
177- )
180+ inner_type = convert_sqlalchemy_type (column .type .item_type , column )
181+ return List (inner_type )
178182
179183
180184@convert_sqlalchemy_type .register (postgresql .HSTORE )
181185@convert_sqlalchemy_type .register (postgresql .JSON )
182186@convert_sqlalchemy_type .register (postgresql .JSONB )
183187def convert_json_to_string (type , column , registry = None ):
184- return JSONString (
185- description = get_column_doc (column ), required = not (is_column_nullable (column ))
186- )
188+ return JSONString
187189
188190
189191@convert_sqlalchemy_type .register (JSONType )
190192def convert_json_type_to_string (type , column , registry = None ):
191- return JSONString (
192- description = get_column_doc (column ), required = not (is_column_nullable (column ))
193- )
193+ return JSONString
0 commit comments