@@ -54,6 +54,10 @@ def check_columns!(ns, spec)
5454 end
5555 end
5656
57+ def parent_scope_column ( parent , colname )
58+ ( parent . to_s . singularize + "_" + colname . to_s ) . to_sym
59+ end
60+
5761 def parse_spec ( ns , spec , source = [ ] )
5862 out = spec . dup
5963 out [ :columns ] = to_array ( spec . delete ( :columns ) )
@@ -62,7 +66,7 @@ def parse_spec(ns, spec, source=[])
6266 newsource = source + [ name ]
6367 subspec = parse_spec ( ns , subspec , newsource )
6468 subspec [ :meta ] [ :source ] = newsource
65- subspec [ :meta ] [ :parent_fkey ] = ( meta [ :table ] . to_s . singularize + "_id" ) . to_sym
69+ subspec [ :meta ] [ :parent_fkeys ] = primary_sql_keys_for_schema ( out ) . map { | k | parent_scope_column ( meta [ :table ] , k ) }
6670 subspec
6771 end
6872 check_columns! ( ns , out )
@@ -103,12 +107,11 @@ def qualified_table_name(meta)
103107 end
104108 end
105109
106- def create_table ( db , spec , clobber , parent_table = nil , parent_pk_type = nil )
110+ def create_table ( db , spec , clobber , parent_table = nil , parent_pks = { } )
107111 meta = spec [ :meta ]
108112 table_name = qualified_table_name ( meta )
109113 composite_key = meta [ :composite_key ]
110- keys = [ ]
111- keytypes = [ ]
114+ primary_keys = { }
112115 log . info ( "Creating table #{ db . literal ( table_name ) } ..." )
113116 db . drop_table? ( table_name , :cascade => true ) if clobber
114117 db . create_table ( table_name ) do
@@ -129,11 +132,9 @@ def create_table(db, spec, clobber, parent_table=nil, parent_pk_type = nil)
129132 column col [ :name ] , col [ :type ] , opts
130133
131134 if composite_key and composite_key . include? ( col [ :name ] )
132- keys << col [ :name ] . to_sym
133- keytypes << col [ :type ]
135+ primary_keys [ col [ :name ] . to_sym ] = col [ :type ]
134136 elsif not composite_key and col [ :source ] . to_sym == :_id
135- keys << col [ :name ] . to_sym
136- keytypes << col [ :type ]
137+ primary_keys [ col [ :name ] . to_sym ] = col [ :type ]
137138 end
138139 end
139140
@@ -151,20 +152,20 @@ def create_table(db, spec, clobber, parent_table=nil, parent_pk_type = nil)
151152 end
152153
153154 if !parent_table . nil?
154- foreign_key meta [ :parent_fkey ] , parent_table , {
155- :type => parent_pk_type ,
155+ parent_pks . each do |k , type |
156+ column k , type
157+ end
158+ foreign_key parent_pks . keys , parent_table , {
156159 :on_delete => :cascade ,
157160 :on_update => :cascade
158161 }
159- keys << meta [ :parent_fkey ]
160- keytypes << parent_pk_type
161162 end
162- primary_key keys
163+ primary_key primary_keys . keys + parent_pks . keys
163164 end
164165
166+ parent_pks = Hash [ primary_keys . map { |k , t | [ parent_scope_column ( meta [ :table ] , k ) , t ] } ] . merge ( parent_pks )
165167 spec [ :subtables ] . each do |subspec |
166- raise "Too many keys for sub table in #{ table_name } : #{ keys } " unless keys . length == 1
167- create_table ( db , subspec , clobber , table_name , keytypes . first )
168+ create_table ( db , subspec , clobber , table_name , parent_pks )
168169 end
169170 end
170171
@@ -316,13 +317,13 @@ def transform_one(schema, obj)
316317 raise "Invalid null #{ source . inspect } for #{ pks . inspect } "
317318 elsif v . is_a? Sequel ::SQL ::Blob and type != "bytea"
318319 raise "Failed to convert binary #{ source . inspect } to #{ type . inspect } for #{ pks . inspect } "
319- elsif col [ :array_type ]
320+ elsif col [ :array_type ] and not v . nil?
320321 v . each_with_index do |e , i |
321322 if not sanity_check_type ( e , col [ :array_type ] )
322323 raise "Failed to convert array element #{ i } of #{ source . inspect } to #{ type . inspect } : got #{ e . inspect } for #{ pks . inspect } "
323324 end
324325 end
325- elsif not sanity_check_type ( v , type )
326+ elsif not v . nil? and not sanity_check_type ( v , type )
326327 raise "Failed to convert #{ source . inspect } to #{ type . inspect } : got #{ v . inspect } for #{ pks . inspect } "
327328 end
328329 row [ name ] = v
@@ -417,15 +418,18 @@ def all_transforms_for_obj(schema, obj, parent_pks={}, &block)
417418
418419 yield table_ident , primary_keys , transformed
419420
421+ parent_pks = Hash [ primary_keys . map { |k | [
422+ parent_scope_column ( schema [ :meta ] [ :table ] , k ) ,
423+ transformed [ k ]
424+ ] } ]
425+ parent_pks = parent_pks . to_h
420426 schema [ :subtables ] . each do |subspec |
421427 source = subspec [ :meta ] [ :source ]
422428 subobjs = bson_dig ( obj , *source )
423429 break if subobjs . nil?
424430
425- raise "Too many primary keys" if primary_keys . length > 1
426- pks = { subspec [ :meta ] [ :parent_fkey ] => transformed [ primary_keys [ 0 ] ] }
427431 subobjs . each do |subobj |
428- all_transforms_for_obj ( subspec , subobj , pks , &block )
432+ all_transforms_for_obj ( subspec , subobj , parent_pks , &block )
429433 end
430434 end
431435 end
@@ -452,8 +456,8 @@ def primary_sql_keys_for_schema(schema)
452456 else
453457 keys << schema [ :columns ] . find { |c | c [ :source ] == '_id' } [ :name ]
454458 end
455- if schema [ :meta ] [ :parent_fkey ]
456- keys << schema [ :meta ] [ :parent_fkey ]
459+ if schema [ :meta ] [ :parent_fkeys ]
460+ keys += schema [ :meta ] [ :parent_fkeys ]
457461 end
458462
459463 return keys
0 commit comments