@@ -153,14 +153,19 @@ def read_type(self, column_type: str) -> str:
153
153
# Write
154
154
155
155
def write_schema ( # type: ignore
156
- self , schema : Schema , * , table_name : str , with_metadata : bool = False
156
+ self ,
157
+ schema : Schema ,
158
+ * ,
159
+ table_name : str ,
160
+ with_metadata : bool = False ,
161
+ ignore_constraints : bool = False ,
157
162
) -> Table :
158
163
"""Convert frictionless schema to sqlalchemy table"""
159
164
sa = platform .sqlalchemy
160
165
columns : List [Column ] = [] # type: ignore
161
166
constraints : List [Constraint ] = []
162
167
163
- # Fields
168
+ # Metadata
164
169
if with_metadata :
165
170
columns .append ( # type: ignore
166
171
sa .Column (
@@ -171,16 +176,19 @@ def write_schema( # type: ignore
171
176
)
172
177
)
173
178
columns .append (sa .Column (settings .ROW_VALID_IDENTIFIER , sa .Boolean )) # type: ignore
179
+
180
+ # Fields
174
181
for field in schema .fields :
175
- column = self .write_field (field , table_name = table_name ) # type: ignore
182
+ column = self .write_field ( # type: ignore
183
+ field , table_name = table_name , ignore_constraints = ignore_constraints
184
+ )
176
185
columns .append (column ) # type: ignore
177
186
178
187
# Primary key
179
188
if schema .primary_key :
180
189
Class = sa .UniqueConstraint if with_metadata else sa .PrimaryKeyConstraint
181
- if not with_metadata :
182
- constraint = Class (* schema .primary_key )
183
- constraints .append (constraint )
190
+ constraint = Class (* schema .primary_key )
191
+ constraints .append (constraint )
184
192
185
193
# Foreign keys
186
194
for fk in schema .foreign_keys :
@@ -192,11 +200,18 @@ def write_schema( # type: ignore
192
200
constraint = sa .ForeignKeyConstraint (fields , foreign_fields )
193
201
constraints .append (constraint )
194
202
195
- # Table
196
- table = sa .Table (table_name , sa .MetaData (), * (columns + constraints ))
203
+ # Prepare table
204
+ table_args = [table_name , sa .MetaData (), * columns ] # type: ignore
205
+ if not ignore_constraints :
206
+ table_args += constraints # type: ignore
207
+
208
+ # Create table
209
+ table = sa .Table (* table_args )
197
210
return table
198
211
199
- def write_field (self , field : Field , * , table_name : str ) -> Column : # type: ignore
212
+ def write_field ( # type: ignore
213
+ self , field : Field , * , table_name : str , ignore_constraints : bool = False
214
+ ) -> Column : # type: ignore
200
215
"""Convert frictionless Field to sqlalchemy Column"""
201
216
sa = platform .sqlalchemy
202
217
quote = self .dialect .identifier_preparer .quote # type: ignore
@@ -206,8 +221,17 @@ def write_field(self, field: Field, *, table_name: str) -> Column: # type: igno
206
221
# General properties
207
222
quoted_name = quote (field .name )
208
223
column_type = self .write_type (field .type ) # type: ignore
224
+
225
+ # Required constraint
209
226
nullable = not field .required
210
227
228
+ # Unique constraint
229
+ unique = field .constraints .get ("unique" , False )
230
+ if self .dialect .name == "mysql" :
231
+ # MySQL requires keys to have an explicit maximum length
232
+ # https://stackoverflow.com/questions/1827063/mysql-error-key-specification-without-a-key-length
233
+ unique = unique and column_type is not sa .Text
234
+
211
235
# Length constraints
212
236
if field .type == "string" :
213
237
min_length = field .constraints .get ("minLength" , None )
@@ -227,13 +251,6 @@ def write_field(self, field: Field, *, table_name: str) -> Column: # type: igno
227
251
if not isinstance (column_type , sa .CHAR ) or self .dialect .name == "sqlite" :
228
252
checks .append (Check ("LENGTH(%s) >= %s" % (quoted_name , min_length )))
229
253
230
- # Unique constraint
231
- unique = field .constraints .get ("unique" , False )
232
- if self .dialect .name == "mysql" :
233
- # MySQL requires keys to have an explicit maximum length
234
- # https://stackoverflow.com/questions/1827063/mysql-error-key-specification-without-a-key-length
235
- unique = unique and column_type is not sa .Text
236
-
237
254
# Others constraints
238
255
for const , value in field .constraints .items ():
239
256
if const == "minimum" :
@@ -252,15 +269,20 @@ def write_field(self, field: Field, *, table_name: str) -> Column: # type: igno
252
269
enum_name = "%s_%s_enum" % (table_name , field .name )
253
270
column_type = sa .Enum (* value , name = enum_name )
254
271
255
- # Create column
256
- column_args = [field .name , column_type ] + checks # type: ignore
272
+ # Prepare column
257
273
# TODO: shall it use "autoincrement=False"
258
274
# https://github.com/Mause/duckdb_engine/issues/595#issuecomment-1495408566
259
- column_kwargs = {"nullable" : nullable , "unique" : unique }
275
+ column_args = [field .name , column_type ] # type: ignore
276
+ column_kwargs = {}
260
277
if field .description :
261
278
column_kwargs ["comment" ] = field .description
262
- column = sa .Column (* column_args , ** column_kwargs )
279
+ if not ignore_constraints :
280
+ column_args += checks # type: ignore
281
+ column_kwargs ["nullable" ] = nullable
282
+ column_kwargs ["unique" ] = unique
263
283
284
+ # Create column
285
+ column = sa .Column (* column_args , ** column_kwargs )
264
286
return column
265
287
266
288
def write_type (self , field_type : str ) -> Type [TypeEngine ]: # type: ignore
0 commit comments