Skip to content

Commit a59294e

Browse files
Add Array support to Map (#158)
1 parent de39940 commit a59294e

File tree

9 files changed

+58
-14
lines changed

9 files changed

+58
-14
lines changed

lib/active_record/connection_adapters/clickhouse/oid/map.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ def type
2626
def deserialize(value)
2727
if value.is_a?(::Hash)
2828
value.map { |k, item| [k.to_s, deserialize(item)] }.to_h
29+
elsif value.is_a?(::Array)
30+
value.map { |item| deserialize(item) }
2931
else
3032
return value if value.nil?
3133
case @subtype
@@ -44,6 +46,8 @@ def deserialize(value)
4446
def serialize(value)
4547
if value.is_a?(::Hash)
4648
value.map { |k, item| [k.to_s, serialize(item)] }.to_h
49+
elsif value.is_a?(::Array)
50+
value.map { |item| serialize(item) }
4751
else
4852
return value if value.nil?
4953
case @subtype

lib/active_record/connection_adapters/clickhouse/schema_creation.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ def add_column_options!(sql, options)
3333
if options[:array]
3434
sql.gsub!(/\s+(.*)/, ' Array(\1)')
3535
end
36-
if options[:map]
36+
if options[:map] == :array
37+
sql.gsub!(/\s+(.*)/, ' Map(String, Array(\1))')
38+
end
39+
if options[:map] == true
3740
sql.gsub!(/\s+(.*)/, ' Map(String, \1)')
3841
end
3942
sql.gsub!(/(\sString)\(\d+\)/, '\1')

lib/clickhouse-activerecord/schema_dumper.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,10 @@ def schema_array(column)
149149
end
150150

151151
def schema_map(column)
152+
if column.sql_type =~ /Map\(([^,]+),\s*(Array)\)/
153+
return :array
154+
end
155+
152156
(column.sql_type =~ /Map?\(/).nil? ? nil : true
153157
end
154158

@@ -161,6 +165,9 @@ def prepare_column_options(column)
161165
spec[:unsigned] = schema_unsigned(column)
162166
spec[:array] = schema_array(column)
163167
spec[:map] = schema_map(column)
168+
if spec[:map] == :array
169+
spec[:array] = nil
170+
end
164171
spec[:low_cardinality] = schema_low_cardinality(column)
165172
spec.merge(super).compact
166173
end

spec/fixtures/migrations/add_array_datetime/1_create_actions_table.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,3 @@ def up
1010
end
1111
end
1212
end
13-

spec/fixtures/migrations/add_map_datetime/1_create_verbs_table.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@ def up
44
t.datetime :map_datetime, null: false, map: true
55
t.string :map_string, null: false, map: true
66
t.integer :map_int, null: false, map: true
7+
8+
t.datetime :map_array_datetime, null: false, map: :array
9+
t.string :map_array_string, null: false, map: :array
10+
t.integer :map_array_int, null: false, map: :array
11+
712
t.date :date, null: false
813
end
914
end
1015
end
11-

spec/fixtures/migrations/dsl_table_with_fixed_string_creation/1_create_some_table.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ def up
66
t.string :fixed_string1, fixed_string: 1, null: false
77
t.string :fixed_string16_array, fixed_string: 16, array: true, null: true
88
t.string :fixed_string16_map, fixed_string: 16, map: true, null: true
9+
t.string :fixed_string16_map_array, fixed_string: 16, map: :array, null: true
910
end
1011
end
1112
end

spec/fixtures/migrations/dsl_table_with_low_cardinality_creation/1_create_some_table.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ def up
77
t.string :col2, low_cardinality: true, null: true
88
t.string :col3, low_cardinality: true, array: true, null: true
99
t.string :col4, low_cardinality: true, map: true, null: true
10+
t.string :col5, low_cardinality: true, map: :array, null: true
1011
end
1112
end
1213
end

spec/single/migration_spec.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,16 +156,18 @@
156156

157157
current_schema = schema(model)
158158

159-
expect(current_schema.keys.count).to eq(4)
159+
expect(current_schema.keys.count).to eq(5)
160160
expect(current_schema).to have_key('col1')
161161
expect(current_schema).to have_key('col2')
162162
expect(current_schema).to have_key('col3')
163163
expect(current_schema).to have_key('col4')
164+
expect(current_schema).to have_key('col5')
164165
expect(current_schema['col1'].sql_type).to eq('LowCardinality(String)')
165166
expect(current_schema['col1'].default).to eq('col')
166167
expect(current_schema['col2'].sql_type).to eq('LowCardinality(Nullable(String))')
167168
expect(current_schema['col3'].sql_type).to eq('Array(LowCardinality(Nullable(String)))')
168169
expect(current_schema['col4'].sql_type).to eq('Map(String, LowCardinality(Nullable(String)))')
170+
expect(current_schema['col5'].sql_type).to eq('Map(String, Array(LowCardinality(Nullable(String))))')
169171
end
170172
end
171173

@@ -176,13 +178,16 @@
176178

177179
current_schema = schema(model)
178180

179-
expect(current_schema.keys.count).to eq(3)
181+
expect(current_schema.keys.count).to eq(4)
180182
expect(current_schema).to have_key('fixed_string1')
181183
expect(current_schema).to have_key('fixed_string16_array')
182184
expect(current_schema).to have_key('fixed_string16_map')
185+
expect(current_schema).to have_key('fixed_string16_map_array')
183186
expect(current_schema['fixed_string1'].sql_type).to eq('FixedString(1)')
184187
expect(current_schema['fixed_string16_array'].sql_type).to eq('Array(Nullable(FixedString(16)))')
185188
expect(current_schema['fixed_string16_map'].sql_type).to eq('Map(String, Nullable(FixedString(16)))')
189+
expect(current_schema['fixed_string16_map_array'].sql_type).to eq('Map(String, Array(Nullable(FixedString(16))))')
190+
186191
end
187192
end
188193

spec/single/model_spec.rb

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -444,16 +444,29 @@ class ModelWithoutPrimaryKey < ActiveRecord::Base
444444
map_datetime: {a: 1.day.ago, b: Time.now, c: '2022-12-06 15:22:49'},
445445
map_string: {a: 'asdf', b: 'jkl' },
446446
map_int: {a: 1, b: 2},
447+
map_array_datetime: {a: [1.day.ago], b: [Time.now, '2022-12-06 15:22:49']},
448+
map_array_string: {a: ['str'], b: ['str1', 'str2']},
449+
map_array_int: {a: [1], b: [1, 2, 3]},
447450
date: date
448451
)
449-
}.to change { model.count }
452+
}.to change { model.count }.by(1)
453+
450454
record = model.first
451-
expect(record.map_datetime.is_a?(Hash)).to be_truthy
452-
expect(record.map_datetime['a'].is_a?(DateTime)).to be_truthy
453-
expect(record.map_string['a'].is_a?(String)).to be_truthy
455+
expect(record.map_datetime).to be_a Hash
456+
expect(record.map_string).to be_a Hash
457+
expect(record.map_int).to be_a Hash
458+
expect(record.map_array_datetime).to be_a Hash
459+
expect(record.map_array_string).to be_a Hash
460+
expect(record.map_array_int).to be_a Hash
461+
462+
expect(record.map_datetime['a']).to be_a DateTime
463+
expect(record.map_string['a']).to be_a String
454464
expect(record.map_string).to eq({'a' => 'asdf', 'b' => 'jkl'})
455-
expect(record.map_int.is_a?(Hash)).to be_truthy
456465
expect(record.map_int).to eq({'a' => 1, 'b' => 2})
466+
467+
expect(record.map_array_datetime['b']).to be_a Array
468+
expect(record.map_array_string['b']).to be_a Array
469+
expect(record.map_array_int['b']).to be_a Array
457470
end
458471

459472
it 'create with insert all' do
@@ -462,21 +475,28 @@ class ModelWithoutPrimaryKey < ActiveRecord::Base
462475
map_datetime: {a: 1.day.ago, b: Time.now, c: '2022-12-06 15:22:49'},
463476
map_string: {a: 'asdf', b: 'jkl' },
464477
map_int: {a: 1, b: 2},
478+
map_array_datetime: {a: [1.day.ago], b: [Time.now, '2022-12-06 15:22:49']},
479+
map_array_string: {a: ['str'], b: ['str1', 'str2']},
480+
map_array_int: {a: [1], b: [1, 2, 3]},
465481
date: date
466482
}])
467-
}.to change { model.count }
483+
}.to change { model.count }.by(1)
468484
end
469485

470486
it 'get record' do
471-
model.connection.insert("INSERT INTO #{model.table_name} (id, map_datetime, date) VALUES (1, {'a': '2022-12-05 15:22:49', 'b': '2022-12-06 15:22:49'}, '2022-12-06')")
487+
model.connection.insert("INSERT INTO #{model.table_name} (id, map_datetime, map_array_datetime, date) VALUES (1, {'a': '2022-12-05 15:22:49', 'b': '2024-01-01 12:00:08'}, {'c': ['2022-12-05 15:22:49','2024-01-01 12:00:08']}, '2022-12-06')")
472488
expect(model.count).to eq(1)
473489
record = model.first
474490
expect(record.date.is_a?(Date)).to be_truthy
475491
expect(record.date).to eq(Date.parse('2022-12-06'))
476-
expect(record.map_datetime.is_a?(Hash)).to be_truthy
492+
expect(record.map_datetime).to be_a Hash
477493
expect(record.map_datetime['a'].is_a?(DateTime)).to be_truthy
478494
expect(record.map_datetime['a']).to eq(DateTime.parse('2022-12-05 15:22:49'))
479-
expect(record.map_datetime['b']).to eq(DateTime.parse('2022-12-06 15:22:49'))
495+
expect(record.map_datetime['b']).to eq(DateTime.parse('2024-01-01 12:00:08'))
496+
expect(record.map_array_datetime).to be_a Hash
497+
expect(record.map_array_datetime['c']).to be_a Array
498+
expect(record.map_array_datetime['c'][0]).to eq(DateTime.parse('2022-12-05 15:22:49'))
499+
expect(record.map_array_datetime['c'][1]).to eq(DateTime.parse('2024-01-01 12:00:08'))
480500
end
481501
end
482502
end

0 commit comments

Comments
 (0)