schema_plus_indexes 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe "with multiple schemas" do
4
+ def connection
5
+ ActiveRecord::Base.connection
6
+ end
7
+
8
+ before(:all) do
9
+ newdb = case connection.adapter_name
10
+ when /^mysql/i then "CREATE SCHEMA IF NOT EXISTS schema_plus_indexes_test2"
11
+ when /^postgresql/i then "CREATE SCHEMA schema_plus_indexes_test2"
12
+ when /^sqlite/i then "ATTACH ':memory:' AS schema_plus_indexes_test2"
13
+ end
14
+ begin
15
+ ActiveRecord::Base.connection.execute newdb
16
+ rescue ActiveRecord::StatementInvalid => e
17
+ raise unless e.message =~ /already exists/
18
+ end
19
+
20
+ class User < ::ActiveRecord::Base ; end
21
+ end
22
+
23
+ before(:each) do
24
+ define_schema do
25
+ create_table :users, :force => true do |t|
26
+ t.string :login
27
+ end
28
+ end
29
+
30
+ connection.execute 'DROP TABLE IF EXISTS schema_plus_indexes_test2.users'
31
+ connection.execute 'CREATE TABLE schema_plus_indexes_test2.users (id ' + case connection.adapter_name
32
+ when /^mysql/i then "integer primary key auto_increment"
33
+ when /^postgresql/i then "serial primary key"
34
+ when /^sqlite/i then "integer primary key autoincrement"
35
+ end + ", login varchar(255))"
36
+ end
37
+
38
+ context "with indexes in each schema" do
39
+ before(:each) do
40
+ connection.execute 'CREATE INDEX ' + case connection.adapter_name
41
+ when /^mysql/i then "index_users_on_login ON schema_plus_indexes_test2.users"
42
+ when /^postgresql/i then "index_users_on_login ON schema_plus_indexes_test2.users"
43
+ when /^sqlite/i then "schema_plus_indexes_test2.index_users_on_login ON users"
44
+ end + " (login)"
45
+ end
46
+
47
+ it "should not find indexes in other schema" do
48
+ User.reset_column_information
49
+ expect(User.indexes).to be_empty
50
+ end
51
+
52
+ it "should find index in current schema" do
53
+ connection.execute 'CREATE INDEX index_users_on_login ON users (login)'
54
+ User.reset_column_information
55
+ expect(User.indexes.map(&:name)).to eq(['index_users_on_login'])
56
+ end
57
+ end
58
+
59
+ end
60
+
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ # A basic sanity check to have as a spec when first starting. Feel free to delete this
5
+ # once you've got real content.
6
+
7
+ describe "Sanity Check" do
8
+
9
+ it "database is connected" do
10
+ expect(ActiveRecord::Base).to be_connected
11
+ end
12
+
13
+ end
@@ -0,0 +1,118 @@
1
+ require 'spec_helper'
2
+ require 'stringio'
3
+
4
+ describe "Schema dump" do
5
+
6
+ before(:all) do
7
+ ActiveRecord::Migration.suppress_messages do
8
+ ActiveRecord::Schema.define do
9
+ connection.tables.each do |table| drop_table table, :cascade => true end
10
+
11
+ create_table :users, :force => true do |t|
12
+ t.string :login
13
+ t.datetime :deleted_at
14
+ t.integer :first_post_id
15
+ end
16
+
17
+ create_table :posts, :force => true do |t|
18
+ t.text :body
19
+ t.integer :user_id
20
+ t.integer :first_comment_id
21
+ t.string :string_no_default
22
+ t.integer :short_id
23
+ t.string :str_short
24
+ t.integer :integer_col
25
+ t.float :float_col
26
+ t.decimal :decimal_col
27
+ t.datetime :datetime_col
28
+ t.timestamp :timestamp_col
29
+ t.time :time_col
30
+ t.date :date_col
31
+ t.binary :binary_col
32
+ t.boolean :boolean_col
33
+ end
34
+
35
+ create_table :comments, :force => true do |t|
36
+ t.text :body
37
+ t.integer :post_id
38
+ t.integer :commenter_id
39
+ end
40
+ end
41
+ end
42
+ class ::User < ActiveRecord::Base ; end
43
+ class ::Post < ActiveRecord::Base ; end
44
+ class ::Comment < ActiveRecord::Base ; end
45
+ end
46
+
47
+ it "should include in-table index definition" do
48
+ with_index Post, :user_id do
49
+ expect(dump_posts).to match(/"user_id",.*index:/)
50
+ end
51
+ end
52
+
53
+ it "should not include add_index statement" do
54
+ with_index Post, :user_id do
55
+ expect(dump_posts).not_to match(%r{add_index.*user_id})
56
+ end
57
+ end
58
+
59
+ it "should include index name" do
60
+ with_index Post, :user_id, :name => "custom_name" do
61
+ expect(dump_posts).to match(/"user_id",.*index:.*name: "custom_name"/)
62
+ end
63
+ end
64
+
65
+ it "should define unique index" do
66
+ with_index Post, :user_id, :name => "posts_user_id_index", :unique => true do
67
+ expect(dump_posts).to match(/"user_id",.*index:.*name: "posts_user_id_index", unique: true/)
68
+ end
69
+ end
70
+
71
+ it "should include index order", :mysql => :skip do
72
+ with_index Post, [:user_id, :first_comment_id, :short_id], :order => { :user_id => :asc, :first_comment_id => :desc } do
73
+ expect(dump_posts).to match(/"user_id".*index: {.*with: \["first_comment_id", "short_id"\],.*order: {"user_id"=>:asc, "first_comment_id"=>:desc, "short_id"=>:asc}/)
74
+ end
75
+ end
76
+
77
+ protected
78
+
79
+ def to_regexp(string)
80
+ Regexp.new(Regexp.escape(string))
81
+ end
82
+
83
+ def with_index(*args)
84
+ options = args.extract_options!
85
+ model, columns = args
86
+ ActiveRecord::Migration.suppress_messages do
87
+ ActiveRecord::Migration.add_index(model.table_name, columns, options)
88
+ end
89
+ model.reset_column_information
90
+ begin
91
+ yield
92
+ ensure
93
+ ActiveRecord::Migration.suppress_messages do
94
+ ActiveRecord::Migration.remove_index(model.table_name, :name => determine_index_name(model, columns, options))
95
+ end
96
+ end
97
+ end
98
+
99
+ def determine_index_name(model, columns, options)
100
+ name = columns[:name] if columns.is_a?(Hash)
101
+ name ||= options[:name]
102
+ name ||= model.indexes.detect { |index| index.table == model.table_name.to_s && index.columns.sort == Array(columns).collect(&:to_s).sort }.name
103
+ name
104
+ end
105
+
106
+ def dump_schema(opts={})
107
+ stream = StringIO.new
108
+ ActiveRecord::SchemaDumper.ignore_tables = Array.wrap(opts[:ignore]) || []
109
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
110
+ stream.string
111
+ end
112
+
113
+ def dump_posts
114
+ dump_schema(:ignore => %w[users comments])
115
+ end
116
+
117
+ end
118
+
@@ -0,0 +1,34 @@
1
+ require 'simplecov'
2
+ require 'simplecov-gem-profile'
3
+ SimpleCov.start "gem"
4
+
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+
8
+ require 'rspec'
9
+ require 'active_record'
10
+ require 'schema_plus_indexes'
11
+ require 'schema_dev/rspec'
12
+
13
+ SchemaDev::Rspec.setup
14
+
15
+ Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f}
16
+
17
+ RSpec.configure do |config|
18
+ config.include(SchemaPlusIndexesMatchers)
19
+ config.warnings = true
20
+ end
21
+
22
+ def define_schema(config={}, &block)
23
+ ActiveRecord::Migration.suppress_messages do
24
+ ActiveRecord::Schema.define do
25
+ connection.tables.each do |table|
26
+ drop_table table, :cascade => true
27
+ end
28
+ instance_eval &block
29
+ end
30
+ end
31
+ end
32
+
33
+ SimpleCov.command_name "[ruby #{RUBY_VERSION} - ActiveRecord #{::ActiveRecord::VERSION::STRING} - #{ActiveRecord::Base.connection.adapter_name}]"
34
+
@@ -0,0 +1,60 @@
1
+ module SchemaPlusIndexesMatchers
2
+
3
+ class HaveIndex
4
+
5
+ def initialize(expectation, options = {})
6
+ set_required_columns(expectation)
7
+ @unique = options.delete(:unique)
8
+ @name = options.delete(:name)
9
+ end
10
+
11
+ def matches?(model)
12
+ @too_many = nil
13
+ @model = model
14
+ indexes = @model.indexes.select { |index| index.columns.to_set == @required_columns }
15
+ if indexes.length > 1
16
+ @too_many = indexes.length
17
+ return false
18
+ end
19
+ index = indexes.first
20
+ return index && (@unique ? index.unique : true) && (@name ? index.name == @name.to_s : true)
21
+ end
22
+
23
+ def failure_message(should_not = false)
24
+ invert = should_not ? "not to" : "to"
25
+ what = ""
26
+ what += "unique " if @unique
27
+ what += "named '{@name}'" if @name
28
+ msg = "Expected #{@model.table_name} #{invert} contain one #{what}index on #{@required_columns.entries.inspect}"
29
+ msg += "; found #{@too_many} indexes" if @too_many
30
+ msg
31
+ end
32
+
33
+ def failure_message_when_negated
34
+ failure_message(true)
35
+ end
36
+
37
+ def on(expectation)
38
+ set_required_columns(expectation)
39
+ self
40
+ end
41
+
42
+ private
43
+ def set_required_columns(expectation)
44
+ @required_columns = Array(expectation).collect(&:to_s).to_set
45
+ end
46
+
47
+ end
48
+
49
+ def have_index(*expectation)
50
+ options = expectation.extract_options!
51
+ HaveIndex.new(expectation, options)
52
+ end
53
+
54
+ def have_unique_index(*expectation)
55
+ options = expectation.extract_options!
56
+ options[:unique] = true
57
+ HaveIndex.new(expectation, options)
58
+ end
59
+
60
+ end
metadata ADDED
@@ -0,0 +1,194 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: schema_plus_indexes
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - ronen barzel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: schema_monkey
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.7'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.7'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 3.0.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 3.0.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: schema_dev
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov-gem-profile
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description:
126
+ email:
127
+ - ronen@barzel.org
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".gitignore"
133
+ - ".travis.yml"
134
+ - Gemfile
135
+ - LICENSE.txt
136
+ - README.md
137
+ - Rakefile
138
+ - gemfiles/Gemfile.base
139
+ - gemfiles/rails-4.2/Gemfile.base
140
+ - gemfiles/rails-4.2/Gemfile.mysql2
141
+ - gemfiles/rails-4.2/Gemfile.postgresql
142
+ - gemfiles/rails-4.2/Gemfile.sqlite3
143
+ - lib/schema_plus_indexes.rb
144
+ - lib/schema_plus_indexes/active_record/base.rb
145
+ - lib/schema_plus_indexes/active_record/connection_adapters/abstract_adapter.rb
146
+ - lib/schema_plus_indexes/active_record/connection_adapters/index_definition.rb
147
+ - lib/schema_plus_indexes/middleware/dumper.rb
148
+ - lib/schema_plus_indexes/middleware/migration.rb
149
+ - lib/schema_plus_indexes/middleware/model.rb
150
+ - lib/schema_plus_indexes/middleware/sqlite3.rb
151
+ - lib/schema_plus_indexes/version.rb
152
+ - schema_dev.yml
153
+ - schema_plus_indexes.gemspec
154
+ - spec/index_definition_spec.rb
155
+ - spec/index_spec.rb
156
+ - spec/migration_spec.rb
157
+ - spec/named_schema_spec.rb
158
+ - spec/sanity_spec.rb
159
+ - spec/schema_dumper_spec.rb
160
+ - spec/spec_helper.rb
161
+ - spec/support/matchers/have_index.rb
162
+ homepage: https://github.com/SchemaPlus/schema_plus_indexes
163
+ licenses:
164
+ - MIT
165
+ metadata: {}
166
+ post_install_message:
167
+ rdoc_options: []
168
+ require_paths:
169
+ - lib
170
+ required_ruby_version: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
175
+ required_rubygems_version: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ requirements: []
181
+ rubyforge_project:
182
+ rubygems_version: 2.2.2
183
+ signing_key:
184
+ specification_version: 4
185
+ summary: Adds shorthands and conveniences to ActiveRecord's handling of indexes
186
+ test_files:
187
+ - spec/index_definition_spec.rb
188
+ - spec/index_spec.rb
189
+ - spec/migration_spec.rb
190
+ - spec/named_schema_spec.rb
191
+ - spec/sanity_spec.rb
192
+ - spec/schema_dumper_spec.rb
193
+ - spec/spec_helper.rb
194
+ - spec/support/matchers/have_index.rb