lib/mosql/schema.rb in mosql-0.3.1 vs lib/mosql/schema.rb in mosql-0.3.2

- old
+ new

@@ -3,31 +3,35 @@ class Schema include MoSQL::Logging def to_array(lst) - array = [] - lst.each do |ent| + lst.map do |ent| + col = nil if ent.is_a?(Hash) && ent[:source].is_a?(String) && ent[:type].is_a?(String) # new configuration format - array << { + col = { :source => ent.fetch(:source), :type => ent.fetch(:type), :name => (ent.keys - [:source, :type]).first, } elsif ent.is_a?(Hash) && ent.keys.length == 1 && ent.values.first.is_a?(String) - array << { + col = { :source => ent.first.first, :name => ent.first.first, :type => ent.first.last } else raise SchemaError.new("Invalid ordered hash entry #{ent.inspect}") end + if !col.key?(:array_type) && /\A(.+)\s+array\z/i.match(col[:type]) + col[:array_type] = $1 + end + + col end - array end def check_columns!(ns, spec) seen = Set.new spec[:columns].each do |col| @@ -85,11 +89,17 @@ if col[:source].to_sym == :_id primary_key [col[:name].to_sym] end end if meta[:extra_props] - column '_extra_props', 'TEXT' + type = + if meta[:extra_props] == "JSON" + "JSON" + else + "TEXT" + end + column '_extra_props', type end end end end end @@ -102,11 +112,11 @@ end @map[db] end def find_ns(ns) - db, collection = ns.split(".") + db, collection = ns.split(".", 2) unless spec = find_db(db) return nil end unless schema = spec[collection] log.debug("No mapping for ns: #{ns}") @@ -164,36 +174,52 @@ else v = fetch_and_delete_dotted(obj, source) case v when BSON::Binary, BSON::ObjectId, Symbol v = v.to_s - when Hash, Array + when BSON::DBRef + v = v.object_id.to_s + when Hash v = JSON.dump(v) + when Array + if col[:array_type] + v = Sequel.pg_array(v, col[:array_type]) + else + v = JSON.dump(v) + end end end row << v end if schema[:meta][:extra_props] - # Kludgily delete binary blobs from _extra_props -- they may - # contain invalid UTF-8, which to_json will not properly encode. - extra = {} - obj.each do |k,v| - case v - when BSON::Binary - next - when Float - # NaN is illegal in JSON. Translate into null. - v = nil if v.nan? - end - extra[k] = v - end + extra = sanitize(obj) row << JSON.dump(extra) end log.debug { "Transformed: #{row.inspect}" } row + end + + def sanitize(value) + # Base64-encode binary blobs from _extra_props -- they may + # contain invalid UTF-8, which to_json will not properly encode. + case value + when Hash + ret = {} + value.each {|k, v| ret[k] = sanitize(v)} + ret + when Array + value.map {|v| sanitize(v)} + when BSON::Binary + Base64.encode64(value.to_s) + when Float + # NaN is illegal in JSON. Translate into null. + value.nan? ? nil : value + else + value + end end def copy_column?(col) col[:source] != '$timestamp' end