hstore_test.rb 5.5 KB
Newer Older
1 2
# encoding: utf-8

3
require "cases/helper"
4 5
require 'active_record/base'
require 'active_record/connection_adapters/postgresql_adapter'
6 7 8 9

class PostgresqlHstoreTest < ActiveRecord::TestCase
  class Hstore < ActiveRecord::Base
    self.table_name = 'hstores'
10 11

    store_accessor :settings, :language, :timezone
12 13 14 15
  end

  def setup
    @connection = ActiveRecord::Base.connection
16 17 18 19 20

    unless @connection.supports_extensions?
      return skip "do not test on PG without hstore"
    end

21 22
    unless @connection.extension_enabled?('hstore')
      @connection.enable_extension 'hstore'
23
      @connection.commit_db_transaction
24
    end
25

26 27
    @connection.reconnect!

28 29 30
    @connection.transaction do
      @connection.create_table('hstores') do |t|
        t.hstore 'tags', :default => ''
31
        t.hstore 'settings'
32 33
      end
    end
34
    @column = Hstore.columns.find { |c| c.name == 'tags' }
35 36 37 38 39 40
  end

  def teardown
    @connection.execute 'drop table if exists hstores'
  end

41
  def test_hstore_included_in_extensions
42
    assert @connection.respond_to?(:extensions), "connection should have a list of extensions"
43 44 45
    assert @connection.extensions.include?('hstore'), "extension list should include hstore"
  end

46
  def test_disable_enable_hstore
47
    assert @connection.extension_enabled?('hstore')
48
    @connection.disable_extension 'hstore'
49 50 51
    assert_not @connection.extension_enabled?('hstore')
    @connection.enable_extension 'hstore'
    assert @connection.extension_enabled?('hstore')
52 53 54
  ensure
    # Restore column(s) dropped by `drop extension hstore cascade;`
    load_schema
55 56
  end

57
  def test_column
58
    assert_equal :hstore, @column.type
59
  end
60

61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
  def test_change_table_supports_hstore
    @connection.transaction do
      @connection.change_table('hstores') do |t|
        t.hstore 'users', default: ''
      end
      Hstore.reset_column_information
      column = Hstore.columns.find { |c| c.name == 'users' }
      assert_equal :hstore, column.type

      raise ActiveRecord::Rollback # reset the schema change
    end
  ensure
    Hstore.reset_column_information
  end

76 77 78 79 80 81 82
  def test_cast_value_on_write
    x = Hstore.new tags: {"bool" => true, "number" => 5}
    assert_equal({"bool" => "true", "number" => "5"}, x.tags)
    x.save
    assert_equal({"bool" => "true", "number" => "5"}, x.reload.tags)
  end

83
  def test_type_cast_hstore
84
    assert @column
85 86

    data = "\"1\"=>\"2\""
87
    hash = @column.class.string_to_hstore data
88
    assert_equal({'1' => '2'}, hash)
89 90 91 92 93 94 95
    assert_equal({'1' => '2'}, @column.type_cast(data))

    assert_equal({}, @column.type_cast(""))
    assert_equal({'key'=>nil}, @column.type_cast('key => NULL'))
    assert_equal({'c'=>'}','"a"'=>'b "a b'}, @column.type_cast(%q(c=>"}", "\"a\""=>"b \"a b")))
  end

96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
  def test_with_store_accessors
    x = Hstore.new(language: "fr", timezone: "GMT")
    assert_equal "fr", x.language
    assert_equal "GMT", x.timezone

    x.save!
    x = Hstore.first
    assert_equal "fr", x.language
    assert_equal "GMT", x.timezone

    x.language = "de"
    x.save!

    x = Hstore.first
    assert_equal "de", x.language
    assert_equal "GMT", x.timezone
  end

114
  def test_gen1
115
    assert_equal(%q(" "=>""), @column.class.hstore_to_string({' '=>''}))
116 117 118
  end

  def test_gen2
119
    assert_equal(%q(","=>""), @column.class.hstore_to_string({','=>''}))
120 121 122
  end

  def test_gen3
123
    assert_equal(%q("="=>""), @column.class.hstore_to_string({'='=>''}))
124 125 126
  end

  def test_gen4
127
    assert_equal(%q(">"=>""), @column.class.hstore_to_string({'>'=>''}))
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
  end

  def test_parse1
    assert_equal({'a'=>nil,'b'=>nil,'c'=>'NuLl','null'=>'c'}, @column.type_cast('a=>null,b=>NuLl,c=>"NuLl",null=>c'))
  end

  def test_parse2
    assert_equal({" " => " "},  @column.type_cast("\\ =>\\ "))
  end

  def test_parse3
    assert_equal({"=" => ">"},  @column.type_cast("==>>"))
  end

  def test_parse4
    assert_equal({"=a"=>"q=w"},   @column.type_cast('\=a=>q=w'))
  end

  def test_parse5
    assert_equal({"=a"=>"q=w"},   @column.type_cast('"=a"=>q\=w'))
  end

  def test_parse6
    assert_equal({"\"a"=>"q>w"},  @column.type_cast('"\"a"=>q>w'))
  end

  def test_parse7
    assert_equal({"\"a"=>"q\"w"}, @column.type_cast('\"a=>q"w'))
156 157
  end

158 159
  def test_rewrite
    @connection.execute "insert into hstores (tags) VALUES ('1=>2')"
160
    x = Hstore.first
161 162 163 164 165
    x.tags = { '"a\'' => 'b' }
    assert x.save!
  end


166 167
  def test_select
    @connection.execute "insert into hstores (tags) VALUES ('1=>2')"
168
    x = Hstore.first
169 170
    assert_equal({'1' => '2'}, x.tags)
  end
A
Aaron Patterson 已提交
171 172 173

  def test_select_multikey
    @connection.execute "insert into hstores (tags) VALUES ('1=>2,2=>3')"
174
    x = Hstore.first
A
Aaron Patterson 已提交
175 176
    assert_equal({'1' => '2', '2' => '3'}, x.tags)
  end
177 178

  def test_create
A
Aaron Patterson 已提交
179
    assert_cycle('a' => 'b', '1' => '2')
A
Aaron Patterson 已提交
180 181
  end

182 183 184 185
  def test_nil
    assert_cycle('a' => nil)
  end

A
Aaron Patterson 已提交
186
  def test_quotes
A
Aaron Patterson 已提交
187
    assert_cycle('a' => 'b"ar', '1"foo' => '2')
A
Aaron Patterson 已提交
188 189 190
  end

  def test_whitespace
A
Aaron Patterson 已提交
191
    assert_cycle('a b' => 'b ar', '1"foo' => '2')
A
Aaron Patterson 已提交
192 193 194
  end

  def test_backslash
A
Aaron Patterson 已提交
195
    assert_cycle('a\\b' => 'b\\ar', '1"foo' => '2')
A
Aaron Patterson 已提交
196 197 198
  end

  def test_comma
A
Aaron Patterson 已提交
199
    assert_cycle('a, b' => 'bar', '1"foo' => '2')
A
Aaron Patterson 已提交
200 201 202
  end

  def test_arrow
A
Aaron Patterson 已提交
203
    assert_cycle('a=>b' => 'bar', '1"foo' => '2')
A
Aaron Patterson 已提交
204 205
  end

206 207 208 209
  def test_quoting_special_characters
    assert_cycle('ca' => 'cà', 'ac' => 'àc')
  end

210 211 212 213
  def test_multiline
    assert_cycle("a\nb" => "c\nd")
  end

A
Aaron Patterson 已提交
214
  private
A
Aaron Patterson 已提交
215
  def assert_cycle hash
216
    # test creation
217 218
    x = Hstore.create!(:tags => hash)
    x.reload
A
Aaron Patterson 已提交
219
    assert_equal(hash, x.tags)
A
Aaron Patterson 已提交
220

221 222
    # test updating
    x = Hstore.create!(:tags => {})
A
Aaron Patterson 已提交
223 224 225 226
    x.tags = hash
    x.save!
    x.reload
    assert_equal(hash, x.tags)
227
  end
228
end