16
16
ChoiceType = JSONType = ScalarListType = TSVectorType = object
17
17
18
18
19
+ def _get_attr_resolver (attr_name ):
20
+ return lambda root , _info : getattr (root , attr_name , None )
21
+
22
+
19
23
def get_column_doc (column ):
20
24
return getattr (column , "doc" , None )
21
25
@@ -24,43 +28,61 @@ def is_column_nullable(column):
24
28
return bool (getattr (column , "nullable" , True ))
25
29
26
30
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
30
34
31
35
def dynamic_type ():
32
36
_type = registry .get_type_for_model (model )
37
+
33
38
if not _type :
34
39
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
+ )
37
46
elif direction in (interfaces .ONETOMANY , interfaces .MANYTOMANY ):
38
47
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
+ )
41
54
42
55
return Dynamic (dynamic_type )
43
56
44
57
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
+ )
47
67
48
68
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 )
51
71
if not converter :
52
72
try :
53
73
raise Exception (
54
74
"Don't know how to convert the composite field %s (%s)"
55
- % (composite , composite .composite_class )
75
+ % (composite_prop , composite_prop .composite_class )
56
76
)
57
77
except AttributeError :
58
78
# handle fields that are not attached to a class yet (don't have a parent)
59
79
raise Exception (
60
80
"Don't know how to convert the composite field %r (%s)"
61
- % (composite , composite .composite_class )
81
+ % (composite_prop , composite_prop .composite_class )
62
82
)
63
- return converter (composite , registry )
83
+
84
+ # TODO Add a way to override composite fields default parameters
85
+ return converter (composite_prop , registry )
64
86
65
87
66
88
def _register_composite_class (cls , registry = None ):
@@ -78,8 +100,16 @@ def inner(fn):
78
100
convert_sqlalchemy_composite .register = _register_composite_class
79
101
80
102
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
+ )
83
113
84
114
85
115
@singledispatch
@@ -101,93 +131,63 @@ def convert_sqlalchemy_type(type, column, registry=None):
101
131
@convert_sqlalchemy_type .register (postgresql .CIDR )
102
132
@convert_sqlalchemy_type .register (TSVectorType )
103
133
def 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
107
135
108
136
109
137
@convert_sqlalchemy_type .register (types .DateTime )
110
138
def convert_column_to_datetime (type , column , registry = None ):
111
139
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
116
141
117
142
118
143
@convert_sqlalchemy_type .register (types .SmallInteger )
119
144
@convert_sqlalchemy_type .register (types .Integer )
120
145
def 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
131
147
132
148
133
149
@convert_sqlalchemy_type .register (types .Boolean )
134
150
def 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
138
152
139
153
140
154
@convert_sqlalchemy_type .register (types .Float )
141
155
@convert_sqlalchemy_type .register (types .Numeric )
142
156
@convert_sqlalchemy_type .register (types .BigInteger )
143
157
def 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
147
159
148
160
149
161
@convert_sqlalchemy_type .register (types .Enum )
150
162
def 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 ())
156
164
157
165
166
+ # TODO Make ChoiceType conversion consistent with other enums
158
167
@convert_sqlalchemy_type .register (ChoiceType )
159
168
def convert_choice_to_enum (type , column , registry = None ):
160
169
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 )
162
171
163
172
164
173
@convert_sqlalchemy_type .register (ScalarListType )
165
174
def convert_scalar_list_to_list (type , column , registry = None ):
166
- return List (String , description = get_column_doc ( column ) )
175
+ return List (String )
167
176
168
177
169
178
@convert_sqlalchemy_type .register (postgresql .ARRAY )
170
179
def 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 )
178
182
179
183
180
184
@convert_sqlalchemy_type .register (postgresql .HSTORE )
181
185
@convert_sqlalchemy_type .register (postgresql .JSON )
182
186
@convert_sqlalchemy_type .register (postgresql .JSONB )
183
187
def 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
187
189
188
190
189
191
@convert_sqlalchemy_type .register (JSONType )
190
192
def 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