Skip to content
This repository was archived by the owner on Dec 22, 2020. It is now read-only.

Commit 2abd0eb

Browse files
committed
allow subtables of composite key tables
1 parent 2d7950d commit 2abd0eb

File tree

1 file changed

+26
-22
lines changed

1 file changed

+26
-22
lines changed

lib/mosql/schema.rb

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)