Skip to content

Commit

Permalink
Add support for Map data types in the schema
Browse files Browse the repository at this point in the history
  • Loading branch information
cbisnett committed Apr 10, 2024
1 parent ff5f522 commit 0d9db1d
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 1 deletion.
33 changes: 33 additions & 0 deletions lib/active_record/connection_adapters/clickhouse/oid/map.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true

module ActiveRecord
module ConnectionAdapters
module Clickhouse
module OID # :nodoc:
class Map < Type::Value # :nodoc:
def initialize(sql_type)
match_data = /map\(([^,]+),\s([^\)]+)\)/i.match(sql_type)
@key_type = ClickhouseAdapter::TYPE_MAP.lookup(match_data[1])
@value_type = ClickhouseAdapter::TYPE_MAP.lookup(match_data[2])
end

def type
@value_type.type
end

def key_type
@key_type.type
end

def serialize(value)
if value.is_a?(Hash)
value.each_with_object({}) { |(k, v), h| h[@key_type.serialize(k)] = @value_type.serialize(v) }
else
super
end
end
end
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ def add_column_options!(sql, options)
if options[:array]
sql.gsub!(/\s+(.*)/, ' Array(\1)')
end
if options[:map]
key_type = ClickhouseAdapter::NATIVE_DATABASE_TYPES.dig(options[:map],:name)
sql.gsub!(/\s+(.*)/, " Map(#{key_type}, \\1)")
end
sql.gsub!(/(\sString)\(\d+\)/, '\1')
sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
sql
Expand Down
11 changes: 10 additions & 1 deletion lib/active_record/connection_adapters/clickhouse_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
require 'active_record/connection_adapters/clickhouse/oid/array'
require 'active_record/connection_adapters/clickhouse/oid/date'
require 'active_record/connection_adapters/clickhouse/oid/date_time'
require 'active_record/connection_adapters/clickhouse/oid/map'
require 'active_record/connection_adapters/clickhouse/oid/uuid'
require 'active_record/connection_adapters/clickhouse/oid/big_integer'
require 'active_record/connection_adapters/clickhouse/schema_definitions'
Expand Down Expand Up @@ -235,18 +236,26 @@ def initialize_type_map(m) # :nodoc:
m.register_type(%r(Array)) do |sql_type|
Clickhouse::OID::Array.new(sql_type)
end

m.register_type(%r(Map)) do |sql_type|
Clickhouse::OID::Map.new(sql_type)
end
end
end

TYPE_MAP = Type::TypeMap.new.tap { |m| ClickhouseAdapter.initialize_type_map(m) }

# In Rails 7 used constant TYPE_MAP, we need redefine method
def type_map
@type_map ||= Type::TypeMap.new.tap { |m| ClickhouseAdapter.initialize_type_map(m) }
TYPE_MAP
end

def quote(value)
case value
when Array
'[' + value.map { |v| quote(v) }.join(', ') + ']'
when Hash
'{' + value.map { |k, v| "#{quote(k)}: #{quote(v)}" }.join(', ') + '}'
else
super
end
Expand Down
6 changes: 6 additions & 0 deletions lib/clickhouse-activerecord/schema_dumper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,16 @@ def schema_array(column)
(column.sql_type =~ /Array?\(/).nil? ? nil : true
end

def schema_map(column)
match_data = /Map\(([^,]+)/.match(column.sql_type)
match_data.nil? ? nil : ":" + match_data[1].downcase
end

def prepare_column_options(column)
spec = {}
spec[:unsigned] = schema_unsigned(column)
spec[:array] = schema_array(column)
spec[:map] = schema_map(column)
spec.merge(super).compact
end
end
Expand Down

0 comments on commit 0d9db1d

Please sign in to comment.