low_card_tables 1.0.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.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.travis.yml +59 -0
  4. data/Gemfile +17 -0
  5. data/LICENSE +21 -0
  6. data/README.md +75 -0
  7. data/Rakefile +6 -0
  8. data/lib/low_card_tables.rb +72 -0
  9. data/lib/low_card_tables/active_record/base.rb +55 -0
  10. data/lib/low_card_tables/active_record/migrations.rb +223 -0
  11. data/lib/low_card_tables/active_record/relation.rb +35 -0
  12. data/lib/low_card_tables/active_record/scoping.rb +87 -0
  13. data/lib/low_card_tables/errors.rb +74 -0
  14. data/lib/low_card_tables/has_low_card_table/base.rb +114 -0
  15. data/lib/low_card_tables/has_low_card_table/low_card_association.rb +273 -0
  16. data/lib/low_card_tables/has_low_card_table/low_card_associations_manager.rb +143 -0
  17. data/lib/low_card_tables/has_low_card_table/low_card_dynamic_method_manager.rb +224 -0
  18. data/lib/low_card_tables/has_low_card_table/low_card_objects_manager.rb +80 -0
  19. data/lib/low_card_tables/low_card_table/base.rb +184 -0
  20. data/lib/low_card_tables/low_card_table/cache.rb +214 -0
  21. data/lib/low_card_tables/low_card_table/cache_expiration/exponential_cache_expiration_policy.rb +151 -0
  22. data/lib/low_card_tables/low_card_table/cache_expiration/fixed_cache_expiration_policy.rb +23 -0
  23. data/lib/low_card_tables/low_card_table/cache_expiration/has_cache_expiration.rb +100 -0
  24. data/lib/low_card_tables/low_card_table/cache_expiration/no_caching_expiration_policy.rb +13 -0
  25. data/lib/low_card_tables/low_card_table/cache_expiration/unlimited_cache_expiration_policy.rb +13 -0
  26. data/lib/low_card_tables/low_card_table/row_collapser.rb +175 -0
  27. data/lib/low_card_tables/low_card_table/row_manager.rb +681 -0
  28. data/lib/low_card_tables/low_card_table/table_unique_index.rb +134 -0
  29. data/lib/low_card_tables/version.rb +4 -0
  30. data/lib/low_card_tables/version_support.rb +52 -0
  31. data/low_card_tables.gemspec +69 -0
  32. data/spec/low_card_tables/helpers/database_helper.rb +148 -0
  33. data/spec/low_card_tables/helpers/query_spy_helper.rb +47 -0
  34. data/spec/low_card_tables/helpers/system_helpers.rb +63 -0
  35. data/spec/low_card_tables/system/basic_system_spec.rb +254 -0
  36. data/spec/low_card_tables/system/bulk_system_spec.rb +334 -0
  37. data/spec/low_card_tables/system/caching_system_spec.rb +531 -0
  38. data/spec/low_card_tables/system/migrations_system_spec.rb +747 -0
  39. data/spec/low_card_tables/system/options_system_spec.rb +581 -0
  40. data/spec/low_card_tables/system/queries_system_spec.rb +142 -0
  41. data/spec/low_card_tables/system/validations_system_spec.rb +88 -0
  42. data/spec/low_card_tables/unit/active_record/base_spec.rb +53 -0
  43. data/spec/low_card_tables/unit/active_record/migrations_spec.rb +207 -0
  44. data/spec/low_card_tables/unit/active_record/relation_spec.rb +47 -0
  45. data/spec/low_card_tables/unit/active_record/scoping_spec.rb +101 -0
  46. data/spec/low_card_tables/unit/has_low_card_table/base_spec.rb +79 -0
  47. data/spec/low_card_tables/unit/has_low_card_table/low_card_association_spec.rb +287 -0
  48. data/spec/low_card_tables/unit/has_low_card_table/low_card_associations_manager_spec.rb +190 -0
  49. data/spec/low_card_tables/unit/has_low_card_table/low_card_dynamic_method_manager_spec.rb +234 -0
  50. data/spec/low_card_tables/unit/has_low_card_table/low_card_objects_manager_spec.rb +70 -0
  51. data/spec/low_card_tables/unit/low_card_table/base_spec.rb +207 -0
  52. data/spec/low_card_tables/unit/low_card_table/cache_expiration/exponential_cache_expiration_policy_spec.rb +128 -0
  53. data/spec/low_card_tables/unit/low_card_table/cache_expiration/fixed_cache_expiration_policy_spec.rb +25 -0
  54. data/spec/low_card_tables/unit/low_card_table/cache_expiration/has_cache_expiration_policy_spec.rb +100 -0
  55. data/spec/low_card_tables/unit/low_card_table/cache_expiration/no_caching_expiration_policy_spec.rb +14 -0
  56. data/spec/low_card_tables/unit/low_card_table/cache_expiration/unlimited_cache_expiration_policy_spec.rb +14 -0
  57. data/spec/low_card_tables/unit/low_card_table/cache_spec.rb +282 -0
  58. data/spec/low_card_tables/unit/low_card_table/row_collapser_spec.rb +109 -0
  59. data/spec/low_card_tables/unit/low_card_table/row_manager_spec.rb +918 -0
  60. data/spec/low_card_tables/unit/low_card_table/table_unique_index_spec.rb +117 -0
  61. metadata +206 -0
@@ -0,0 +1,117 @@
1
+ require 'low_card_tables'
2
+
3
+ describe LowCardTables::LowCardTable::TableUniqueIndex do
4
+ def klass
5
+ LowCardTables::LowCardTable::TableUniqueIndex
6
+ end
7
+
8
+ it "should require a low-card model for instantiation" do
9
+ low_card_model = double("low_card_model")
10
+ lambda { klass.new(low_card_model) }.should raise_error(ArgumentError)
11
+
12
+ allow(low_card_model).to receive(:is_low_card_table?).and_return(false)
13
+ lambda { klass.new(low_card_model) }.should raise_error(ArgumentError)
14
+ end
15
+
16
+ context "with an instance" do
17
+ before :each do
18
+ @low_card_model = double("low_card_model")
19
+ allow(@low_card_model).to receive(:is_low_card_table?).and_return(true)
20
+ allow(@low_card_model).to receive(:table_name).and_return("foobar")
21
+ allow(@low_card_model).to receive(:low_card_value_column_names).and_return(%w{foo bar baz})
22
+ allow(@low_card_model).to receive(:table_exists?).and_return(true)
23
+
24
+ @connection = double("connection")
25
+ allow(@low_card_model).to receive(:connection).and_return(@connection)
26
+
27
+ @non_unique_index = double("non_unique_index")
28
+ allow(@non_unique_index).to receive(:unique).and_return(false)
29
+ allow(@non_unique_index).to receive(:name).and_return("nui")
30
+
31
+ @unique_index_wrong_columns = double("unique_index_wrong_columns")
32
+ allow(@unique_index_wrong_columns).to receive(:unique).and_return(true)
33
+ allow(@unique_index_wrong_columns).to receive(:columns).and_return(%w{foo bar})
34
+ allow(@unique_index_wrong_columns).to receive(:name).and_return("uiwc")
35
+
36
+ @unique_index_right_columns = double("unique_index_right_columns")
37
+ allow(@unique_index_right_columns).to receive(:unique).and_return(true)
38
+ allow(@unique_index_right_columns).to receive(:columns).and_return(%w{bar foo baz})
39
+ allow(@unique_index_right_columns).to receive(:name).and_return("uirc")
40
+
41
+ @instance = klass.new(@low_card_model)
42
+ end
43
+
44
+ describe "#ensure_present!" do
45
+ it "should do nothing if the table doesn't exist" do
46
+ allow(@low_card_model).to receive(:table_exists?).and_return(false)
47
+
48
+ @instance.ensure_present!(false)
49
+ @instance.ensure_present!(true)
50
+ end
51
+
52
+ it "should do nothing if the index does exist" do
53
+ allow(@connection).to receive(:indexes).with("foobar").and_return([ @non_unique_index, @unique_index_wrong_columns, @unique_index_right_columns ])
54
+ @instance.ensure_present!(false)
55
+ @instance.ensure_present!(true)
56
+ end
57
+
58
+ it "should raise if the index doesn't exist, and not told to create it" do
59
+ allow(@connection).to receive(:indexes).with("foobar").and_return([ @non_unique_index, @unique_index_wrong_columns ])
60
+ lambda { @instance.ensure_present!(false) }.should raise_error(LowCardTables::Errors::LowCardNoUniqueIndexError, /uiwc/i)
61
+ end
62
+
63
+ it "should create the index if it doesn't exist, and told to" do
64
+ index_return_values = [
65
+ [ @non_unique_index, @unique_index_wrong_columns ],
66
+ [ @non_unique_index, @unique_index_wrong_columns ],
67
+ [ @non_unique_index, @unique_index_wrong_columns, @unique_index_right_columns ]
68
+ ]
69
+
70
+ allow(@connection).to receive(:indexes).with("foobar") { index_return_values.shift }
71
+
72
+ our_migration_class = Class.new
73
+ allow(Class).to receive(:new).once.with(::ActiveRecord::Migration).and_return(our_migration_class)
74
+
75
+ expect(our_migration_class).to receive(:migrate).once.with(:up)
76
+
77
+ expect(@low_card_model).to receive(:reset_column_information).once
78
+ expect(::LowCardTables::VersionSupport).to receive(:clear_schema_cache!).once.with(@low_card_model)
79
+
80
+ @instance.ensure_present!(true)
81
+
82
+ expect(our_migration_class).to receive(:remove_index).once.with("foobar", :name => "index_foobar_lc_on_all")
83
+ expect(our_migration_class).to receive(:add_index).once.with("foobar", %w{bar baz foo}, :unique => true, :name => "index_foobar_lc_on_all")
84
+ our_migration_class.up
85
+ end
86
+ end
87
+
88
+ describe "#remove!" do
89
+ it "should do nothing if there is no such index" do
90
+ allow(@connection).to receive(:indexes).with("foobar").and_return([ @non_unique_index, @unique_index_wrong_columns ])
91
+ @instance.remove!
92
+ end
93
+
94
+ it "should remove the index if there is one" do
95
+ index_return_values = [
96
+ [ @non_unique_index, @unique_index_wrong_columns, @unique_index_right_columns ],
97
+ [ @non_unique_index, @unique_index_wrong_columns ]
98
+ ]
99
+
100
+ allow(@connection).to receive(:indexes).with("foobar") { index_return_values.shift }
101
+
102
+ our_migration_class = Class.new
103
+ allow(Class).to receive(:new).once.with(::ActiveRecord::Migration).and_return(our_migration_class)
104
+
105
+ expect(our_migration_class).to receive(:migrate).once.with(:up)
106
+
107
+ expect(@low_card_model).to receive(:reset_column_information).once
108
+ expect(::LowCardTables::VersionSupport).to receive(:clear_schema_cache!).once.with(@low_card_model)
109
+
110
+ @instance.remove!
111
+
112
+ expect(our_migration_class).to receive(:remove_index).once.with("foobar", :name => "uirc")
113
+ our_migration_class.up
114
+ end
115
+ end
116
+ end
117
+ end
metadata ADDED
@@ -0,0 +1,206 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: low_card_tables
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Andrew Geweke
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2013-12-03 00:00:00 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ prerelease: false
17
+ requirement: &id001 !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - &id002
20
+ - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
23
+ type: :development
24
+ version_requirements: *id001
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ prerelease: false
28
+ requirement: &id003 !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - *id002
31
+ type: :development
32
+ version_requirements: *id003
33
+ - !ruby/object:Gem::Dependency
34
+ name: rspec
35
+ prerelease: false
36
+ requirement: &id004 !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: "2.14"
41
+ type: :development
42
+ version_requirements: *id004
43
+ - !ruby/object:Gem::Dependency
44
+ name: activerecord
45
+ prerelease: false
46
+ requirement: &id005 !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: "3.0"
51
+ - - <=
52
+ - !ruby/object:Gem::Version
53
+ version: 4.99.99
54
+ type: :runtime
55
+ version_requirements: *id005
56
+ - !ruby/object:Gem::Dependency
57
+ name: activesupport
58
+ prerelease: false
59
+ requirement: &id006 !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "3.0"
64
+ - - <=
65
+ - !ruby/object:Gem::Version
66
+ version: 4.99.99
67
+ type: :runtime
68
+ version_requirements: *id006
69
+ - !ruby/object:Gem::Dependency
70
+ name: activerecord-import
71
+ prerelease: false
72
+ requirement: &id007 !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - *id002
75
+ type: :runtime
76
+ version_requirements: *id007
77
+ - !ruby/object:Gem::Dependency
78
+ name: mysql2
79
+ prerelease: false
80
+ requirement: &id008 !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - *id002
83
+ type: :development
84
+ version_requirements: *id008
85
+ description: "\"Bitfields for ActiveRecord\": store low-cardinality columns in a separate table for vastly more flexibility and better performance."
86
+ email:
87
+ - andrew@geweke.org
88
+ executables: []
89
+
90
+ extensions: []
91
+
92
+ extra_rdoc_files: []
93
+
94
+ files:
95
+ - .gitignore
96
+ - .travis.yml
97
+ - Gemfile
98
+ - LICENSE
99
+ - README.md
100
+ - Rakefile
101
+ - lib/low_card_tables.rb
102
+ - lib/low_card_tables/active_record/base.rb
103
+ - lib/low_card_tables/active_record/migrations.rb
104
+ - lib/low_card_tables/active_record/relation.rb
105
+ - lib/low_card_tables/active_record/scoping.rb
106
+ - lib/low_card_tables/errors.rb
107
+ - lib/low_card_tables/has_low_card_table/base.rb
108
+ - lib/low_card_tables/has_low_card_table/low_card_association.rb
109
+ - lib/low_card_tables/has_low_card_table/low_card_associations_manager.rb
110
+ - lib/low_card_tables/has_low_card_table/low_card_dynamic_method_manager.rb
111
+ - lib/low_card_tables/has_low_card_table/low_card_objects_manager.rb
112
+ - lib/low_card_tables/low_card_table/base.rb
113
+ - lib/low_card_tables/low_card_table/cache.rb
114
+ - lib/low_card_tables/low_card_table/cache_expiration/exponential_cache_expiration_policy.rb
115
+ - lib/low_card_tables/low_card_table/cache_expiration/fixed_cache_expiration_policy.rb
116
+ - lib/low_card_tables/low_card_table/cache_expiration/has_cache_expiration.rb
117
+ - lib/low_card_tables/low_card_table/cache_expiration/no_caching_expiration_policy.rb
118
+ - lib/low_card_tables/low_card_table/cache_expiration/unlimited_cache_expiration_policy.rb
119
+ - lib/low_card_tables/low_card_table/row_collapser.rb
120
+ - lib/low_card_tables/low_card_table/row_manager.rb
121
+ - lib/low_card_tables/low_card_table/table_unique_index.rb
122
+ - lib/low_card_tables/version.rb
123
+ - lib/low_card_tables/version_support.rb
124
+ - low_card_tables.gemspec
125
+ - spec/low_card_tables/helpers/database_helper.rb
126
+ - spec/low_card_tables/helpers/query_spy_helper.rb
127
+ - spec/low_card_tables/helpers/system_helpers.rb
128
+ - spec/low_card_tables/system/basic_system_spec.rb
129
+ - spec/low_card_tables/system/bulk_system_spec.rb
130
+ - spec/low_card_tables/system/caching_system_spec.rb
131
+ - spec/low_card_tables/system/migrations_system_spec.rb
132
+ - spec/low_card_tables/system/options_system_spec.rb
133
+ - spec/low_card_tables/system/queries_system_spec.rb
134
+ - spec/low_card_tables/system/validations_system_spec.rb
135
+ - spec/low_card_tables/unit/active_record/base_spec.rb
136
+ - spec/low_card_tables/unit/active_record/migrations_spec.rb
137
+ - spec/low_card_tables/unit/active_record/relation_spec.rb
138
+ - spec/low_card_tables/unit/active_record/scoping_spec.rb
139
+ - spec/low_card_tables/unit/has_low_card_table/base_spec.rb
140
+ - spec/low_card_tables/unit/has_low_card_table/low_card_association_spec.rb
141
+ - spec/low_card_tables/unit/has_low_card_table/low_card_associations_manager_spec.rb
142
+ - spec/low_card_tables/unit/has_low_card_table/low_card_dynamic_method_manager_spec.rb
143
+ - spec/low_card_tables/unit/has_low_card_table/low_card_objects_manager_spec.rb
144
+ - spec/low_card_tables/unit/low_card_table/base_spec.rb
145
+ - spec/low_card_tables/unit/low_card_table/cache_expiration/exponential_cache_expiration_policy_spec.rb
146
+ - spec/low_card_tables/unit/low_card_table/cache_expiration/fixed_cache_expiration_policy_spec.rb
147
+ - spec/low_card_tables/unit/low_card_table/cache_expiration/has_cache_expiration_policy_spec.rb
148
+ - spec/low_card_tables/unit/low_card_table/cache_expiration/no_caching_expiration_policy_spec.rb
149
+ - spec/low_card_tables/unit/low_card_table/cache_expiration/unlimited_cache_expiration_policy_spec.rb
150
+ - spec/low_card_tables/unit/low_card_table/cache_spec.rb
151
+ - spec/low_card_tables/unit/low_card_table/row_collapser_spec.rb
152
+ - spec/low_card_tables/unit/low_card_table/row_manager_spec.rb
153
+ - spec/low_card_tables/unit/low_card_table/table_unique_index_spec.rb
154
+ homepage: https://github.com/ageweke/low_card_tables
155
+ licenses:
156
+ - MIT
157
+ metadata: {}
158
+
159
+ post_install_message:
160
+ rdoc_options: []
161
+
162
+ require_paths:
163
+ - lib
164
+ required_ruby_version: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - *id002
167
+ required_rubygems_version: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - *id002
170
+ requirements: []
171
+
172
+ rubyforge_project:
173
+ rubygems_version: 2.0.13
174
+ signing_key:
175
+ specification_version: 4
176
+ summary: "\"Bitfields for ActiveRecord\": instead of storing multiple columns with low cardinality (few distinct values) directly in a table, which results in performance and maintainability problems, break them out into a separate table with almost zero overhead. Trivially add new columns without migrating a main, enormous table. Query on combinations of values very efficiently."
177
+ test_files:
178
+ - spec/low_card_tables/helpers/database_helper.rb
179
+ - spec/low_card_tables/helpers/query_spy_helper.rb
180
+ - spec/low_card_tables/helpers/system_helpers.rb
181
+ - spec/low_card_tables/system/basic_system_spec.rb
182
+ - spec/low_card_tables/system/bulk_system_spec.rb
183
+ - spec/low_card_tables/system/caching_system_spec.rb
184
+ - spec/low_card_tables/system/migrations_system_spec.rb
185
+ - spec/low_card_tables/system/options_system_spec.rb
186
+ - spec/low_card_tables/system/queries_system_spec.rb
187
+ - spec/low_card_tables/system/validations_system_spec.rb
188
+ - spec/low_card_tables/unit/active_record/base_spec.rb
189
+ - spec/low_card_tables/unit/active_record/migrations_spec.rb
190
+ - spec/low_card_tables/unit/active_record/relation_spec.rb
191
+ - spec/low_card_tables/unit/active_record/scoping_spec.rb
192
+ - spec/low_card_tables/unit/has_low_card_table/base_spec.rb
193
+ - spec/low_card_tables/unit/has_low_card_table/low_card_association_spec.rb
194
+ - spec/low_card_tables/unit/has_low_card_table/low_card_associations_manager_spec.rb
195
+ - spec/low_card_tables/unit/has_low_card_table/low_card_dynamic_method_manager_spec.rb
196
+ - spec/low_card_tables/unit/has_low_card_table/low_card_objects_manager_spec.rb
197
+ - spec/low_card_tables/unit/low_card_table/base_spec.rb
198
+ - spec/low_card_tables/unit/low_card_table/cache_expiration/exponential_cache_expiration_policy_spec.rb
199
+ - spec/low_card_tables/unit/low_card_table/cache_expiration/fixed_cache_expiration_policy_spec.rb
200
+ - spec/low_card_tables/unit/low_card_table/cache_expiration/has_cache_expiration_policy_spec.rb
201
+ - spec/low_card_tables/unit/low_card_table/cache_expiration/no_caching_expiration_policy_spec.rb
202
+ - spec/low_card_tables/unit/low_card_table/cache_expiration/unlimited_cache_expiration_policy_spec.rb
203
+ - spec/low_card_tables/unit/low_card_table/cache_spec.rb
204
+ - spec/low_card_tables/unit/low_card_table/row_collapser_spec.rb
205
+ - spec/low_card_tables/unit/low_card_table/row_manager_spec.rb
206
+ - spec/low_card_tables/unit/low_card_table/table_unique_index_spec.rb