low_card_tables 1.0.3 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +69 -45
- data/CHANGES.md +8 -0
- data/Gemfile +5 -0
- data/lib/low_card_tables/has_low_card_table/base.rb +100 -0
- data/lib/low_card_tables/has_low_card_table/low_card_associations_manager.rb +28 -1
- data/lib/low_card_tables/has_low_card_table/low_card_dynamic_method_manager.rb +32 -2
- data/lib/low_card_tables/low_card_table/base.rb +21 -2
- data/lib/low_card_tables/low_card_table/row_manager.rb +19 -2
- data/lib/low_card_tables/version.rb +1 -1
- data/lib/low_card_tables/version_support.rb +8 -0
- data/low_card_tables.gemspec +10 -7
- data/spec/low_card_tables/helpers/database_helper.rb +23 -1
- data/spec/low_card_tables/helpers/system_helpers.rb +5 -4
- data/spec/low_card_tables/system/basic_system_spec.rb +14 -0
- data/spec/low_card_tables/system/options_system_spec.rb +3 -2
- data/spec/low_card_tables/system/queries_system_spec.rb +31 -18
- data/spec/low_card_tables/system/sti_system_spec.rb +178 -0
- data/spec/low_card_tables/unit/active_record/base_spec.rb +1 -0
- data/spec/low_card_tables/unit/has_low_card_table/low_card_dynamic_method_manager_spec.rb +1 -1
- data/spec/low_card_tables/unit/low_card_table/base_spec.rb +3 -0
- data/spec/low_card_tables/unit/low_card_table/row_manager_spec.rb +1 -7
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 930fa1a9dafbd8e32e72961f024beb1754c13254
|
4
|
+
data.tar.gz: 034fc44ed55f2ede181f09edaf7e7d27b494fe5d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5013b79fe4902ec65b05914c92b33c6330873144bfff2bf73eb0710fc0efde02f41d16d15afa2bd81bf9cf22053ca66de28d6a38e38cc17606ec9b83ef7b59c6
|
7
|
+
data.tar.gz: 38ae46cc876311d8e15b6a6616439955d2d696b7e1e72b9f23790e8eb79fcce3b1f3a0f31e15b604d7824b58365da71c6efc5341bc7a0d438a6e5784232ec3b1
|
data/.travis.yml
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
rvm:
|
2
2
|
- "1.8.7"
|
3
|
-
- "1.9.3"
|
4
|
-
- "2.0.0"
|
5
|
-
- "2.1.
|
6
|
-
- "
|
3
|
+
- "1.9.3-p551"
|
4
|
+
- "2.0.0-p598"
|
5
|
+
- "2.1.5"
|
6
|
+
- "2.2.0"
|
7
|
+
- "jruby-1.7.19"
|
7
8
|
env:
|
8
9
|
# Sadly, Travis seems to have a version of SQLite < 3.7.11 installed on many of its workers;
|
9
10
|
# this prevents activerecord-import from working, since those versions of the SQLite engine
|
@@ -15,65 +16,88 @@ env:
|
|
15
16
|
- LOW_CARD_TABLES_AR_TEST_VERSION=3.1.12 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=mysql
|
16
17
|
- LOW_CARD_TABLES_AR_TEST_VERSION=3.1.12 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=postgres
|
17
18
|
# - LOW_CARD_TABLES_AR_TEST_VERSION=3.1.12 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=sqlite
|
18
|
-
- LOW_CARD_TABLES_AR_TEST_VERSION=3.2.
|
19
|
-
- LOW_CARD_TABLES_AR_TEST_VERSION=3.2.
|
20
|
-
# - LOW_CARD_TABLES_AR_TEST_VERSION=3.2.
|
21
|
-
- LOW_CARD_TABLES_AR_TEST_VERSION=4.0.
|
22
|
-
- LOW_CARD_TABLES_AR_TEST_VERSION=4.0.
|
23
|
-
# - LOW_CARD_TABLES_AR_TEST_VERSION=4.0.
|
24
|
-
- LOW_CARD_TABLES_AR_TEST_VERSION=4.1.
|
25
|
-
- LOW_CARD_TABLES_AR_TEST_VERSION=4.1.
|
26
|
-
# - LOW_CARD_TABLES_AR_TEST_VERSION=4.1.
|
19
|
+
- LOW_CARD_TABLES_AR_TEST_VERSION=3.2.21 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=mysql
|
20
|
+
- LOW_CARD_TABLES_AR_TEST_VERSION=3.2.21 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=postgres
|
21
|
+
# - LOW_CARD_TABLES_AR_TEST_VERSION=3.2.21 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=sqlite
|
22
|
+
- LOW_CARD_TABLES_AR_TEST_VERSION=4.0.13 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=mysql
|
23
|
+
- LOW_CARD_TABLES_AR_TEST_VERSION=4.0.13 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=postgres
|
24
|
+
# - LOW_CARD_TABLES_AR_TEST_VERSION=4.0.13 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=sqlite
|
25
|
+
- LOW_CARD_TABLES_AR_TEST_VERSION=4.1.9 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=mysql
|
26
|
+
- LOW_CARD_TABLES_AR_TEST_VERSION=4.1.9 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=postgres
|
27
|
+
# - LOW_CARD_TABLES_AR_TEST_VERSION=4.1.9 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=sqlite
|
28
|
+
- LOW_CARD_TABLES_AR_TEST_VERSION=4.2.0 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=mysql
|
29
|
+
- LOW_CARD_TABLES_AR_TEST_VERSION=4.2.0 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=postgres
|
30
|
+
# - LOW_CARD_TABLES_AR_TEST_VERSION=4.2.0 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=sqlite
|
27
31
|
before_script:
|
28
|
-
- export JRUBY_OPTS="-J-
|
32
|
+
- export JRUBY_OPTS="-J-Xmx512m -J-Xms512m $JRUBY_OPTS"
|
29
33
|
- mysql -e 'create database myapp_test;'
|
30
34
|
- psql -c 'create database myapp_test;' -U postgres
|
31
35
|
matrix:
|
32
36
|
exclude:
|
33
37
|
# ActiveRecord 4.x doesn't support Ruby 1.8.7
|
34
38
|
- rvm: 1.8.7
|
35
|
-
env: LOW_CARD_TABLES_AR_TEST_VERSION=4.0.
|
39
|
+
env: LOW_CARD_TABLES_AR_TEST_VERSION=4.0.13 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=mysql
|
36
40
|
- rvm: 1.8.7
|
37
|
-
env: LOW_CARD_TABLES_AR_TEST_VERSION=4.0.
|
41
|
+
env: LOW_CARD_TABLES_AR_TEST_VERSION=4.0.13 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=postgres
|
38
42
|
- rvm: 1.8.7
|
39
|
-
env: LOW_CARD_TABLES_AR_TEST_VERSION=4.0.
|
43
|
+
env: LOW_CARD_TABLES_AR_TEST_VERSION=4.0.13 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=sqlite
|
40
44
|
- rvm: 1.8.7
|
41
|
-
env: LOW_CARD_TABLES_AR_TEST_VERSION=4.1.
|
45
|
+
env: LOW_CARD_TABLES_AR_TEST_VERSION=4.1.9 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=mysql
|
42
46
|
- rvm: 1.8.7
|
43
|
-
env: LOW_CARD_TABLES_AR_TEST_VERSION=4.1.
|
47
|
+
env: LOW_CARD_TABLES_AR_TEST_VERSION=4.1.9 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=postgres
|
44
48
|
- rvm: 1.8.7
|
45
|
-
env: LOW_CARD_TABLES_AR_TEST_VERSION=4.1.
|
49
|
+
env: LOW_CARD_TABLES_AR_TEST_VERSION=4.1.9 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=sqlite
|
50
|
+
- rvm: 1.8.7
|
51
|
+
env: LOW_CARD_TABLES_AR_TEST_VERSION=4.2.0 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=mysql
|
52
|
+
- rvm: 1.8.7
|
53
|
+
env: LOW_CARD_TABLES_AR_TEST_VERSION=4.2.0 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=postgres
|
54
|
+
- rvm: 1.8.7
|
55
|
+
env: LOW_CARD_TABLES_AR_TEST_VERSION=4.2.0 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=sqlite
|
46
56
|
# There's a bug in ActiveRecord 3.1.x that makes it incompatible with Ruby 2.x
|
47
|
-
- rvm: 2.0.0
|
57
|
+
- rvm: 2.0.0-p598
|
48
58
|
env: LOW_CARD_TABLES_AR_TEST_VERSION=3.1.12 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=mysql
|
49
|
-
- rvm: 2.0.0
|
59
|
+
- rvm: 2.0.0-p598
|
50
60
|
env: LOW_CARD_TABLES_AR_TEST_VERSION=3.1.12 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=postgres
|
51
|
-
- rvm: 2.0.0
|
61
|
+
- rvm: 2.0.0-p598
|
52
62
|
env: LOW_CARD_TABLES_AR_TEST_VERSION=3.1.12 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=sqlite
|
53
|
-
- rvm: 2.1.
|
63
|
+
- rvm: 2.1.5
|
54
64
|
env: LOW_CARD_TABLES_AR_TEST_VERSION=3.1.12 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=mysql
|
55
|
-
- rvm: 2.1.
|
65
|
+
- rvm: 2.1.5
|
56
66
|
env: LOW_CARD_TABLES_AR_TEST_VERSION=3.1.12 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=postgres
|
57
|
-
- rvm: 2.1.
|
67
|
+
- rvm: 2.1.5
|
58
68
|
env: LOW_CARD_TABLES_AR_TEST_VERSION=3.1.12 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=sqlite
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
- rvm: jruby-1.7.15
|
69
|
+
- rvm: 2.2.0
|
70
|
+
env: LOW_CARD_TABLES_AR_TEST_VERSION=3.1.12 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=mysql
|
71
|
+
- rvm: 2.2.0
|
63
72
|
env: LOW_CARD_TABLES_AR_TEST_VERSION=3.1.12 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=postgres
|
64
|
-
- rvm:
|
65
|
-
env: LOW_CARD_TABLES_AR_TEST_VERSION=3.2.19 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=postgres
|
66
|
-
- rvm: jruby-1.7.15
|
67
|
-
env: LOW_CARD_TABLES_AR_TEST_VERSION=4.0.10 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=postgres
|
68
|
-
- rvm: jruby-1.7.15
|
69
|
-
env: LOW_CARD_TABLES_AR_TEST_VERSION=4.1.6 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=postgres
|
70
|
-
- rvm: jruby-1.7.15
|
71
|
-
env: LOW_CARD_TABLES_AR_TEST_VERSION=3.0.20 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=sqlite
|
72
|
-
- rvm: jruby-1.7.15
|
73
|
+
- rvm: 2.2.0
|
73
74
|
env: LOW_CARD_TABLES_AR_TEST_VERSION=3.1.12 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=sqlite
|
74
|
-
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
75
|
+
# The activerecord-import gem currently doesn't support JRuby JDBC adapters with anything but MySQL
|
76
|
+
# - rvm: jruby-1.7.15
|
77
|
+
# env: LOW_CARD_TABLES_AR_TEST_VERSION=3.0.20 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=postgres
|
78
|
+
# - rvm: jruby-1.7.15
|
79
|
+
# env: LOW_CARD_TABLES_AR_TEST_VERSION=3.1.12 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=postgres
|
80
|
+
# - rvm: jruby-1.7.15
|
81
|
+
# env: LOW_CARD_TABLES_AR_TEST_VERSION=3.2.21 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=postgres
|
82
|
+
# - rvm: jruby-1.7.15
|
83
|
+
# env: LOW_CARD_TABLES_AR_TEST_VERSION=4.0.13 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=postgres
|
84
|
+
# - rvm: jruby-1.7.15
|
85
|
+
# env: LOW_CARD_TABLES_AR_TEST_VERSION=4.1.9 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=postgres
|
86
|
+
# - rvm: jruby-1.7.15
|
87
|
+
# env: LOW_CARD_TABLES_AR_TEST_VERSION=3.0.20 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=sqlite
|
88
|
+
# - rvm: jruby-1.7.15
|
89
|
+
# env: LOW_CARD_TABLES_AR_TEST_VERSION=3.1.12 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=sqlite
|
90
|
+
# - rvm: jruby-1.7.15
|
91
|
+
# env: LOW_CARD_TABLES_AR_TEST_VERSION=3.2.21 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=sqlite
|
92
|
+
# - rvm: jruby-1.7.15
|
93
|
+
# env: LOW_CARD_TABLES_AR_TEST_VERSION=4.0.13 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=sqlite
|
94
|
+
# - rvm: jruby-1.7.15
|
95
|
+
# env: LOW_CARD_TABLES_AR_TEST_VERSION=4.1.9 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=sqlite
|
96
|
+
|
97
|
+
allow_failures:
|
98
|
+
# As of this writing (2015-02-18), activerecord-jdbc doesn't support ActiveRecord 4.2.x
|
99
|
+
# completely.
|
100
|
+
- rvm: jruby-1.7.19
|
101
|
+
env: LOW_CARD_TABLES_AR_TEST_VERSION=4.2.0 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=mysql
|
102
|
+
- rvm: jruby-1.7.19
|
103
|
+
env: LOW_CARD_TABLES_AR_TEST_VERSION=4.2.0 LOW_CARD_TABLES_TRAVIS_CI_DATABASE_TYPE=postgres
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# `low_card_tables` Changelog
|
2
2
|
|
3
|
+
## 1.1.0, 2015-02-18
|
4
|
+
|
5
|
+
* The [single-table inheritance](http://api.rubyonrails.org/classes/ActiveRecord/Base.html#label-Single+table+inheritance) type-discrimination column — by default called `type` — can now be part of a low-cardinality table itself. This elegantly allows you to use STI without consuming the very large amounts of space required by Rails' default implementation, where it stores the name of the class in every single row.
|
6
|
+
* Fixed issues where you couldn't use `low_card_tables` with an ActiveRecord class that was at anything but the leaf of a [single-table inheritance](http://api.rubyonrails.org/classes/ActiveRecord/Base.html#label-Single+table+inheritance) hierarchy.
|
7
|
+
* Ensured that you can query a column containing a string or symbol with a query that's a string or a symbol, and it all works fine.
|
8
|
+
* Added support for `WHERE` clauses on a low-card table containing an array (`.where(:my_low_card_column => [ :foo, :bar ])`).
|
9
|
+
* Added support for ActiveRecord 4.2.x, and bumped versions on the CI configuration.
|
10
|
+
|
3
11
|
## 1.0.3, 2014-09-22
|
4
12
|
|
5
13
|
* Fixed an issue where, if a table that owned a low-card table was declared a namespace (_e.g._, `module Foo; class Bar < ActiveRecord::Base; has_low_card_table :status; end; end`), the call to `has_low_card_table` would fail with an error (trying to call `+` on `nil`).
|
data/Gemfile
CHANGED
@@ -60,6 +60,18 @@ module LowCardTables
|
|
60
60
|
extend ActiveSupport::Concern
|
61
61
|
|
62
62
|
|
63
|
+
def ensure_proper_type
|
64
|
+
if (assn = self.class.association_for_inheritance_column)
|
65
|
+
superclass = self.class.superclass
|
66
|
+
unless (superclass == ::ActiveRecord::Base) || (superclass.abstract_class?)
|
67
|
+
lco = send(assn.association_name)
|
68
|
+
lco.send(:write_attribute, self.class.inheritance_column, self.class.sti_name)
|
69
|
+
end
|
70
|
+
else
|
71
|
+
super
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
63
75
|
module ClassMethods
|
64
76
|
# Several methods go straight to the LowCardAssociationsManager.
|
65
77
|
delegate :has_low_card_table, :_low_card_association, :_low_card_update_collapsed_rows, :low_card_value_collapsing_update_scheme, :to => :_low_card_associations_manager
|
@@ -70,6 +82,94 @@ module LowCardTables
|
|
70
82
|
true
|
71
83
|
end
|
72
84
|
|
85
|
+
def association_for_inheritance_column
|
86
|
+
_low_card_associations_manager.association_containing_method_named(inheritance_column)
|
87
|
+
end
|
88
|
+
|
89
|
+
def descends_from_active_record?
|
90
|
+
out = super
|
91
|
+
|
92
|
+
if out && (self != ::ActiveRecord::Base) && (! superclass.abstract_class?) && (superclass != ::ActiveRecord::Base)
|
93
|
+
out = false if association_for_inheritance_column
|
94
|
+
end
|
95
|
+
|
96
|
+
out
|
97
|
+
end
|
98
|
+
|
99
|
+
def type_condition(table = arel_table)
|
100
|
+
if (association = association_for_inheritance_column)
|
101
|
+
sti_names = ([self] + descendants).map { |model| model.sti_name }
|
102
|
+
|
103
|
+
ids = association.low_card_class.low_card_ids_matching(inheritance_column => sti_names).to_a
|
104
|
+
table[association.foreign_key_column_name].in(ids)
|
105
|
+
else
|
106
|
+
if ::ActiveRecord::Base.method(:type_condition).arity.abs >= 1
|
107
|
+
super
|
108
|
+
else
|
109
|
+
super()
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def discriminate_class_for_record(record, call_super = true)
|
115
|
+
if (! record[inheritance_column])
|
116
|
+
if (association = association_for_inheritance_column)
|
117
|
+
foreign_key = record[association.foreign_key_column_name]
|
118
|
+
|
119
|
+
foreign_key = association.low_card_class.low_card_type_cast_id(foreign_key)
|
120
|
+
low_card_row = association.low_card_class.low_card_row_for_id(foreign_key)
|
121
|
+
type = low_card_row.send(inheritance_column)
|
122
|
+
|
123
|
+
return _low_card_find_sti_class(type) if type
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
super(record) if call_super
|
128
|
+
end
|
129
|
+
|
130
|
+
if ::LowCardTables::VersionSupport.sti_uses_discriminate_class_for_record?
|
131
|
+
def _low_card_find_sti_class(type)
|
132
|
+
find_sti_class(type)
|
133
|
+
end
|
134
|
+
else
|
135
|
+
def _low_card_find_sti_class(type_name)
|
136
|
+
return self if type_name.blank?
|
137
|
+
|
138
|
+
begin
|
139
|
+
if store_full_sti_class
|
140
|
+
ActiveSupport::Dependencies.constantize(type_name)
|
141
|
+
else
|
142
|
+
compute_type(type_name)
|
143
|
+
end
|
144
|
+
rescue NameError
|
145
|
+
raise ::ActiveRecord::SubclassNotFound,
|
146
|
+
"The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " +
|
147
|
+
"This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " +
|
148
|
+
"Please rename this column if you didn't intend it to be used for storing the inheritance class " +
|
149
|
+
"or overwrite #{name}.inheritance_column to use another column for that information."
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def instantiate(record)
|
154
|
+
sti_class = discriminate_class_for_record(record, false)
|
155
|
+
if sti_class
|
156
|
+
record_id = sti_class.primary_key && record[sti_class.primary_key]
|
157
|
+
|
158
|
+
if defined?(::ActiveRecord::IdentityMap) && ::ActiveRecord::IdentityMap.enabled? && record_id
|
159
|
+
instance = use_identity_map(sti_class, record_id, record)
|
160
|
+
else
|
161
|
+
instance = sti_class.allocate
|
162
|
+
instance.init_with('attributes' => record)
|
163
|
+
instance
|
164
|
+
end
|
165
|
+
|
166
|
+
instance
|
167
|
+
else
|
168
|
+
super
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
73
173
|
# The LowCardAssociationsManager keeps track of which low-card tables this table refers to; see its
|
74
174
|
# documentation for more information.
|
75
175
|
def _low_card_associations_manager
|
@@ -45,6 +45,13 @@ module LowCardTables
|
|
45
45
|
@model_class._low_card_dynamic_method_manager.sync_methods!
|
46
46
|
end
|
47
47
|
|
48
|
+
def association_containing_method_named(method_name)
|
49
|
+
out = @associations.detect do |low_card_association|
|
50
|
+
low_card_association.class_method_name_to_low_card_method_name_map[method_name]
|
51
|
+
end
|
52
|
+
out || superclass_low_card_associations_manager.try(:association_containing_method_named, method_name)
|
53
|
+
end
|
54
|
+
|
48
55
|
# Called when someone has called ::ActiveRecord::Base#reset_column_information on the low-card model in question.
|
49
56
|
# This simply tells the LowCardDynamicMethodManager to sync the methods on this model class, thus updating the
|
50
57
|
# set of delegated methods to match the new columns.
|
@@ -60,7 +67,9 @@ module LowCardTables
|
|
60
67
|
|
61
68
|
# Just like _low_card_association, but returns nil when an association is not found, rather than raising an error.
|
62
69
|
def maybe_low_card_association(name)
|
63
|
-
@associations.detect { |a| a.association_name.to_s.strip.downcase == name.to_s.strip.downcase }
|
70
|
+
out = @associations.detect { |a| a.association_name.to_s.strip.downcase == name.to_s.strip.downcase }
|
71
|
+
out ||= superclass_low_card_associations_manager.maybe_low_card_association(name) if superclass_low_card_associations_manager
|
72
|
+
out
|
64
73
|
end
|
65
74
|
|
66
75
|
# Updates all foreign keys that the given model_instance has to their correct values, given the set of attributes
|
@@ -71,6 +80,10 @@ module LowCardTables
|
|
71
80
|
@associations.each do |association|
|
72
81
|
association.update_foreign_key!(model_instance)
|
73
82
|
end
|
83
|
+
|
84
|
+
if superclass_low_card_associations_manager
|
85
|
+
superclass_low_card_associations_manager.low_card_update_foreign_keys!(model_instance)
|
86
|
+
end
|
74
87
|
end
|
75
88
|
|
76
89
|
DEFAULT_COLLAPSING_UPDATE_VALUE = 10_000
|
@@ -113,6 +126,20 @@ module LowCardTables
|
|
113
126
|
end
|
114
127
|
end
|
115
128
|
|
129
|
+
# Returns the LowCardAssociationsManager for the model class's superclass, if there is one. This is used for
|
130
|
+
# supporting STI.
|
131
|
+
def superclass_low_card_associations_manager
|
132
|
+
@superclass_low_card_associations_manager ||= begin
|
133
|
+
model_superclass = @model_class.superclass
|
134
|
+
if model_superclass.respond_to?(:_low_card_associations_manager)
|
135
|
+
model_superclass._low_card_associations_manager
|
136
|
+
else
|
137
|
+
:none
|
138
|
+
end
|
139
|
+
end
|
140
|
+
@superclass_low_card_associations_manager unless @superclass_low_card_associations_manager == :none
|
141
|
+
end
|
142
|
+
|
116
143
|
private
|
117
144
|
# Makes sure that +model_instance+ is an instance of the model class this LowCardAssociationsManager is for.
|
118
145
|
def ensure_correct_class!(model_instance)
|
@@ -32,7 +32,11 @@ module LowCardTables
|
|
32
32
|
|
33
33
|
method_data = @method_delegation_map[method_name.to_s]
|
34
34
|
unless method_data
|
35
|
-
|
35
|
+
if superclass_low_card_dynamic_method_manager
|
36
|
+
return superclass_low_card_dynamic_method_manager.run_low_card_method(object, method_name, args)
|
37
|
+
else
|
38
|
+
raise NameError, "Whoa -- we're trying to call a delegated low-card method #{method_name.inspect} on #{object}, of class #{object.class}, but somehow the LowCardDynamicMethodManager has no knowledge of that method?!? We know about: #{@method_delegation_map.keys.sort.inspect}"
|
39
|
+
end
|
36
40
|
end
|
37
41
|
|
38
42
|
(association, association_method_name) = method_data
|
@@ -53,6 +57,18 @@ module LowCardTables
|
|
53
57
|
end
|
54
58
|
end
|
55
59
|
|
60
|
+
# Returns the effective association and method that we delegate the given method to. This is very close to
|
61
|
+
# identical to @method_delegation_map; the only difference is that it delegates to the +model_class+'s superclass
|
62
|
+
# as appropriate, too.
|
63
|
+
def effective_method_delegation_for(method_name)
|
64
|
+
method_name = method_name.to_s
|
65
|
+
out = @method_delegation_map[method_name]
|
66
|
+
if (! out) && superclass_low_card_dynamic_method_manager
|
67
|
+
out = superclass_low_card_dynamic_method_manager.effective_method_delegation_for(method_name)
|
68
|
+
end
|
69
|
+
out
|
70
|
+
end
|
71
|
+
|
56
72
|
# Given a base ::ActiveRecord::Relation scope (which can of course just be a model class itself), and a set of
|
57
73
|
# query constraints as passed into ::ActiveRecord::Relation#where (which must be a Hash -- for the other forms
|
58
74
|
# of #where, our override of ::ActiveRecord::Relation#where doesn't call this method but just passes through to
|
@@ -83,7 +99,7 @@ module LowCardTables
|
|
83
99
|
# to that association; the constraints in the Hash use key names that are the actual low-card column names
|
84
100
|
# (i.e., we translate them from whatever delegated method names were present in the referring class)
|
85
101
|
query_hash.each do |query_key, query_value|
|
86
|
-
low_card_delegation =
|
102
|
+
low_card_delegation = effective_method_delegation_for(query_key)
|
87
103
|
|
88
104
|
# Does this constraint even mention a low-card column or association name?
|
89
105
|
if low_card_delegation
|
@@ -192,6 +208,20 @@ yourself, using #{association.low_card_class.name}#ids_matching.}
|
|
192
208
|
@model_class._low_card_associations_manager.associations
|
193
209
|
end
|
194
210
|
|
211
|
+
# Returns the LowCardDynamicMethodManager for the model class's superclass, if there is one. This is used for
|
212
|
+
# supporting STI.
|
213
|
+
def superclass_low_card_dynamic_method_manager
|
214
|
+
@superclass_low_card_dynamic_method_manager ||= begin
|
215
|
+
model_superclass = @model_class.superclass
|
216
|
+
if model_superclass.respond_to?(:_low_card_dynamic_method_manager)
|
217
|
+
model_superclass._low_card_dynamic_method_manager
|
218
|
+
else
|
219
|
+
:none
|
220
|
+
end
|
221
|
+
end
|
222
|
+
@superclass_low_card_dynamic_method_manager unless @superclass_low_card_dynamic_method_manager == :none
|
223
|
+
end
|
224
|
+
|
195
225
|
# Makes sure the given object is an instance of the class we're handling dynamic methods for.
|
196
226
|
def ensure_correct_class!(object)
|
197
227
|
unless object.kind_of?(@model_class)
|
@@ -19,6 +19,7 @@ module LowCardTables
|
|
19
19
|
# Set up cache-policy inheritance -- see HasCacheExpiration for more details.
|
20
20
|
included do
|
21
21
|
low_card_cache_policy_inherits_from ::LowCardTables
|
22
|
+
self.inheritance_column = '_sti_on_low_card_tables_should_never_be_used'
|
22
23
|
end
|
23
24
|
|
24
25
|
# This method is a critical entry point from the rest of the low-card system. For example, given our usual
|
@@ -57,7 +58,25 @@ module LowCardTables
|
|
57
58
|
# instead of #_low_card_row_matches_any_hash? or #_low_card_row_matches_hash?, if its semantics work better for
|
58
59
|
# your purposes, since its behavior will affect those methods as well.
|
59
60
|
def _low_card_column_matches?(key, value)
|
60
|
-
self[key.to_s]
|
61
|
+
my_value = self[key.to_s]
|
62
|
+
|
63
|
+
if value.kind_of?(Array)
|
64
|
+
if my_value && my_value.kind_of?(Symbol)
|
65
|
+
my_value = my_value.to_s
|
66
|
+
end
|
67
|
+
|
68
|
+
value = value.map { |m| if m.kind_of?(Symbol) then m.to_s else m end }
|
69
|
+
value.include?(my_value)
|
70
|
+
else
|
71
|
+
value_sym = value.kind_of?(Symbol)
|
72
|
+
my_value_sym = my_value.kind_of?(Symbol)
|
73
|
+
|
74
|
+
if (value_sym != my_value_sym) && value && my_value
|
75
|
+
my_value.to_s.eql?(value.to_s)
|
76
|
+
else
|
77
|
+
my_value.eql?(value)
|
78
|
+
end
|
79
|
+
end
|
61
80
|
end
|
62
81
|
|
63
82
|
# This method is called from methods like #low_card_rows_matching, when passed a block -- its job is simply to
|
@@ -173,7 +192,7 @@ on this object, and it will save, but make sure you understand ALL the implicati
|
|
173
192
|
# Gems or by client code, since many of the names are pretty generic (e.g., +all_rows+).
|
174
193
|
[ :all_rows, :row_for_id, :rows_for_ids, :rows_matching, :ids_matching, :find_ids_for, :find_or_create_ids_for,
|
175
194
|
:find_rows_for, :find_or_create_rows_for, :flush_cache!, :referring_models, :value_column_names, :referred_to_by,
|
176
|
-
:collapse_rows_and_update_referrers!, :ensure_has_unique_index!, :remove_unique_index
|
195
|
+
:collapse_rows_and_update_referrers!, :ensure_has_unique_index!, :remove_unique_index!, :type_cast_id ].each do |delegated_method_name|
|
177
196
|
define_method("low_card_#{delegated_method_name}") do |*args|
|
178
197
|
_low_card_row_manager.send(delegated_method_name, *args)
|
179
198
|
end
|
@@ -115,6 +115,15 @@ module LowCardTables
|
|
115
115
|
rows_for_ids(id)
|
116
116
|
end
|
117
117
|
|
118
|
+
def type_cast_id(id)
|
119
|
+
column = @low_card_model.columns_hash[@low_card_model.primary_key]
|
120
|
+
if column.respond_to?(:type_cast_from_database)
|
121
|
+
column.type_cast_from_database(id)
|
122
|
+
else
|
123
|
+
column.type_cast(id)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
118
127
|
# Given a single Hash specifying zero or more constraints for low-card rows (i.e., mapping zero or more columns
|
119
128
|
# of the low-card table to specific values for those columns), returns a (possibly empty) Array of IDs of
|
120
129
|
# low-card rows that match those constraints.
|
@@ -327,7 +336,6 @@ but we got back these rows:
|
|
327
336
|
column_name = column.name.to_s.strip.downcase
|
328
337
|
|
329
338
|
use = true
|
330
|
-
use = false if column.primary
|
331
339
|
use = false if column_names_to_skip.include?(column_name)
|
332
340
|
use
|
333
341
|
end
|
@@ -531,6 +539,13 @@ equivalent of 'LOCK TABLE'(s) in your database.}
|
|
531
539
|
# metadata and shouldn't play a direct role in the low-card system).
|
532
540
|
def column_names_to_skip
|
533
541
|
@column_names_to_skip ||= begin
|
542
|
+
primary_keys = if @low_card_model.respond_to?(:primary_keys)
|
543
|
+
Array(@low_card_model.primary_keys)
|
544
|
+
else
|
545
|
+
Array(@low_card_model.primary_key)
|
546
|
+
end
|
547
|
+
|
548
|
+
primary_keys +
|
534
549
|
COLUMN_NAMES_TO_ALWAYS_SKIP +
|
535
550
|
Array(@low_card_model.low_card_options[:exclude_column_names] || [ ]).map { |n| n.to_s.strip.downcase }
|
536
551
|
end
|
@@ -587,7 +602,9 @@ equivalent of 'LOCK TABLE'(s) in your database.}
|
|
587
602
|
missing = missing.select do |missing_column_name|
|
588
603
|
column = @low_card_model.columns.detect { |c| c.name.to_s.strip.downcase == missing_column_name.to_s.strip.downcase }
|
589
604
|
if column && column.default
|
590
|
-
|
605
|
+
the_default = column.default
|
606
|
+
the_default = column.type_cast_from_database(the_default) if column.respond_to?(:type_cast_from_database)
|
607
|
+
hash[column.name] = the_default
|
591
608
|
false
|
592
609
|
else
|
593
610
|
true
|
@@ -23,6 +23,14 @@ module LowCardTables
|
|
23
23
|
(::ActiveRecord::VERSION::MAJOR <= 3 && ::ActiveRecord::VERSION::MINOR == 0)
|
24
24
|
end
|
25
25
|
|
26
|
+
def sti_uses_discriminate_class_for_record?
|
27
|
+
::ActiveRecord::VERSION::MAJOR >= 4
|
28
|
+
end
|
29
|
+
|
30
|
+
def allows_static_scopes?
|
31
|
+
(::ActiveRecord::VERSION::MAJOR < 4) || (::ActiveRecord::VERSION::MINOR < 2)
|
32
|
+
end
|
33
|
+
|
26
34
|
# Define a default scope on the class in question. This is only actually used from our specs.
|
27
35
|
def define_default_scope(klass, conditions)
|
28
36
|
if default_scopes_accept_a_block?
|
data/low_card_tables.gemspec
CHANGED
@@ -21,12 +21,6 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.add_development_dependency "rake"
|
22
22
|
s.add_development_dependency "rspec", "~> 2.14"
|
23
23
|
|
24
|
-
if (RUBY_VERSION =~ /^1\.9\./ || RUBY_VERSION =~ /^2\.0\./) && ((! defined?(RUBY_ENGINE)) || (RUBY_ENGINE != 'jruby'))
|
25
|
-
s.add_development_dependency "pry"
|
26
|
-
s.add_development_dependency "pry-debugger"
|
27
|
-
s.add_development_dependency "pry-stack_explorer"
|
28
|
-
end
|
29
|
-
|
30
24
|
ar_version = ENV['LOW_CARD_TABLES_AR_TEST_VERSION']
|
31
25
|
ar_version = ar_version.strip if ar_version
|
32
26
|
|
@@ -44,6 +38,7 @@ Gem::Specification.new do |s|
|
|
44
38
|
|
45
39
|
ar_import_version = case ar_version
|
46
40
|
when nil then nil
|
41
|
+
when /^4\.2\./ then '~> 0.7.0'
|
47
42
|
when 'master', /^4\.0\./, /^4\.1\./ then '~> 0.4.1'
|
48
43
|
when /^3\.0\./ then '~> 0.2.11'
|
49
44
|
when /^3\.1\./, /^3\.2\./ then '~> 0.3.1'
|
@@ -56,13 +51,21 @@ Gem::Specification.new do |s|
|
|
56
51
|
s.add_dependency("activerecord-import")
|
57
52
|
end
|
58
53
|
|
54
|
+
# i18n released an 0.7.0 that's incompatible with Ruby 1.8.
|
55
|
+
if RUBY_VERSION =~ /^1\.8\./
|
56
|
+
s.add_development_dependency 'i18n', '< 0.7.0'
|
57
|
+
end
|
58
|
+
|
59
59
|
require File.expand_path(File.join(File.dirname(__FILE__), 'spec', 'low_card_tables', 'helpers', 'database_helper'))
|
60
60
|
database_gem_name = LowCardTables::Helpers::DatabaseHelper.maybe_database_gem_name
|
61
61
|
|
62
62
|
# Ugh. Later versions of the 'mysql2' gem are incompatible with AR 3.0.x; so, here, we explicitly trap that case
|
63
63
|
# and use an earlier version of that Gem.
|
64
64
|
if database_gem_name && database_gem_name == 'mysql2' && ar_version && ar_version =~ /^3\.0\./
|
65
|
-
s.add_development_dependency(
|
65
|
+
s.add_development_dependency(database_gem_name, '~> 0.2.0')
|
66
|
+
# The 'pg' gem removed Ruby 1.8 compatibility as of 0.18.
|
67
|
+
elsif database_gem_name && database_gem_name == 'pg' && RUBY_VERSION =~ /^1\.8\./
|
68
|
+
s.add_development_dependency(database_gem_name, '< 0.18.0')
|
66
69
|
else
|
67
70
|
s.add_development_dependency(database_gem_name)
|
68
71
|
end
|
@@ -79,6 +79,28 @@ module LowCardTables
|
|
79
79
|
:encoding => 'utf8'
|
80
80
|
}
|
81
81
|
}
|
82
|
+
when 'postgres', 'postgresql'
|
83
|
+
{
|
84
|
+
:require => 'activerecord-jdbcpostgresql-adapter',
|
85
|
+
:database_gem_name => 'activerecord-jdbcpostgresql-adapter',
|
86
|
+
:config => {
|
87
|
+
:adapter => 'postgresql',
|
88
|
+
:database => 'myapp_test',
|
89
|
+
:username => 'travis',
|
90
|
+
:encoding => 'utf8'
|
91
|
+
}
|
92
|
+
}
|
93
|
+
when 'sqlite'
|
94
|
+
{
|
95
|
+
:require => 'activerecord-jdbcsqlite3-adapter',
|
96
|
+
:database_gem_name => 'activerecord-jdbcsqlite3-adapter',
|
97
|
+
:config => {
|
98
|
+
:adapter => 'jdbcsqlite3',
|
99
|
+
:database => 'myapp_test',
|
100
|
+
:username => 'travis',
|
101
|
+
:encoding => 'utf8'
|
102
|
+
}
|
103
|
+
}
|
82
104
|
when '', nil then nil
|
83
105
|
else
|
84
106
|
raise "Unknown Travis CI database type: #{dbtype.inspect}"
|
@@ -129,7 +151,7 @@ module LowCardTables
|
|
129
151
|
end
|
130
152
|
|
131
153
|
def invalid_config_file!
|
132
|
-
raise
|
154
|
+
raise InvalidDatabaseConfigurationError, %{In order to run specs for LowCardTables, you need to create a file at:
|
133
155
|
|
134
156
|
#{config_file_path}
|
135
157
|
|
@@ -16,12 +16,13 @@ module LowCardTables
|
|
16
16
|
LowCardTables::VersionSupport.clear_schema_cache!(::ActiveRecord::Base)
|
17
17
|
end
|
18
18
|
|
19
|
-
def define_model_class(name, table_name, &block)
|
20
|
-
|
19
|
+
def define_model_class(name, table_name, options = { }, &block)
|
20
|
+
superclass = options[:superclass] || ::ActiveRecord::Base
|
21
|
+
model_class = Class.new(superclass)
|
21
22
|
::Object.send(:remove_const, name) if ::Object.const_defined?(name)
|
22
23
|
::Object.const_set(name, model_class)
|
23
|
-
model_class.table_name = table_name
|
24
|
-
model_class.class_eval(&block)
|
24
|
+
model_class.table_name = table_name if table_name
|
25
|
+
model_class.class_eval(&block) if block
|
25
26
|
end
|
26
27
|
|
27
28
|
def create_standard_system_spec_tables!
|
@@ -64,6 +64,20 @@ describe "LowCardTables basic operations" do
|
|
64
64
|
user1_v2.donation_level.should == 3
|
65
65
|
end
|
66
66
|
|
67
|
+
it "should let you set options via a scope, and create those correctly in #new" do
|
68
|
+
pending "This does not work yet, and it will require a major refactor of low_card_tables"
|
69
|
+
scope = User.where(:deleted => false, :deceased => true, :gender => 'male', :donation_level => 7)
|
70
|
+
user2 = scope.new
|
71
|
+
user2.name = 'User2'
|
72
|
+
user2.save!
|
73
|
+
|
74
|
+
user2_again = User.where(:name => 'User2').first
|
75
|
+
expect(user2_again.deleted).to be_false
|
76
|
+
expect(user2_again.deceased).to be_true
|
77
|
+
expect(user2_again.gender).to eq('male')
|
78
|
+
expect(user2_again.donation_level).to eq(7)
|
79
|
+
end
|
80
|
+
|
67
81
|
it "should expose a low-card row, but not with an ID, when read in from the DB" do
|
68
82
|
@user1.status.should be
|
69
83
|
@user1.status.id.should_not be
|
@@ -101,9 +101,9 @@ describe "LowCardTables association options" do
|
|
101
101
|
user1.deceased = false
|
102
102
|
user1.gender = 'female'
|
103
103
|
|
104
|
-
start_time = Time.now.
|
104
|
+
start_time = Time.now.to_f.floor
|
105
105
|
user1.save!
|
106
|
-
end_time = Time.now.
|
106
|
+
end_time = Time.now.to_f.ceil
|
107
107
|
|
108
108
|
::UserStatusExcludeCreatedUpdated.count.should == 1
|
109
109
|
::UserStatusExcludeCreatedUpdated.first.created_at.to_i.should >= start_time
|
@@ -126,6 +126,7 @@ describe "LowCardTables association options" do
|
|
126
126
|
::UserStatusExcludeCreatedUpdated.first.updated_at.to_i.should >= start_time
|
127
127
|
::UserStatusExcludeCreatedUpdated.first.updated_at.to_i.should <= end_time
|
128
128
|
end
|
129
|
+
|
129
130
|
context "with standard setup" do
|
130
131
|
before :each do
|
131
132
|
create_standard_system_spec_tables!
|
@@ -55,6 +55,17 @@ describe "LowCardTables query support" do
|
|
55
55
|
check_user_ids(::User.where(:deleted => false, :name => 'User2'), [ ])
|
56
56
|
end
|
57
57
|
|
58
|
+
it "should allow 'where' clauses that use an array" do
|
59
|
+
check_user_ids(::User.where(:donation_level => [ 8, 10 ]), [ @user1, @user2, @user3, @user4, @user5 ])
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should allow 'where' clauses to use a symbol or a string, and work fine either way" do
|
63
|
+
check_user_ids(::User.where(:gender => :male), [ @user4 ])
|
64
|
+
check_user_ids(::User.where(:gender => 'male'), [ @user4 ])
|
65
|
+
check_user_ids(::User.where(:gender => [ :male, :female ]), [ @user1, @user2, @user3, @user4, @user5 ])
|
66
|
+
check_user_ids(::User.where(:gender => [ 'male', 'female' ]), [ @user1, @user2, @user3, @user4, @user5 ])
|
67
|
+
end
|
68
|
+
|
58
69
|
it "should allow 'where' clauses that use delegated properties with differently-prefixed names directly" do
|
59
70
|
define_model_class(:User2, :lctables_spec_users) { has_low_card_table :status, :prefix => :foo, :class => ::UserStatus, :foreign_key => :user_status_id }
|
60
71
|
|
@@ -114,29 +125,31 @@ describe "LowCardTables query support" do
|
|
114
125
|
check_user_ids(::User.bar, [ @user1, @user2, @user3, @user5, @user6 ])
|
115
126
|
end
|
116
127
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
128
|
+
if ::LowCardTables::VersionSupport.allows_static_scopes?
|
129
|
+
it "should blow up if you constrain on low-card foreign keys in a static scope" do
|
130
|
+
lambda do
|
131
|
+
LowCardTables::VersionSupport.define_default_scope(::User, nil)
|
132
|
+
class ::User < ::ActiveRecord::Base
|
133
|
+
scope :foo, where(:deleted => false)
|
134
|
+
end
|
135
|
+
end.should raise_error(LowCardTables::Errors::LowCardStaticScopeError, /user_status_id/mi)
|
136
|
+
|
137
|
+
lambda do
|
138
|
+
LowCardTables::VersionSupport.define_default_scope(::User, nil)
|
139
|
+
class ::User < ::ActiveRecord::Base
|
140
|
+
scope :foo, where(:user_status_id => ::UserStatus.low_card_ids_matching(:deleted => false))
|
141
|
+
end
|
142
|
+
end.should raise_error(LowCardTables::Errors::LowCardStaticScopeError, /user_status_id/mi)
|
143
|
+
end
|
144
|
+
|
124
145
|
|
125
|
-
|
146
|
+
it "should not blow up if you constrain on other things in a static scope" do
|
126
147
|
LowCardTables::VersionSupport.define_default_scope(::User, nil)
|
127
148
|
class ::User < ::ActiveRecord::Base
|
128
|
-
scope :foo, where(:
|
149
|
+
scope :foo, where(:name => %w{foo bar})
|
129
150
|
end
|
130
|
-
end.should raise_error(LowCardTables::Errors::LowCardStaticScopeError, /user_status_id/mi)
|
131
|
-
end
|
132
|
-
|
133
151
|
|
134
|
-
|
135
|
-
LowCardTables::VersionSupport.define_default_scope(::User, nil)
|
136
|
-
class ::User < ::ActiveRecord::Base
|
137
|
-
scope :foo, where(:name => %w{foo bar})
|
152
|
+
::User.first.should be
|
138
153
|
end
|
139
|
-
|
140
|
-
::User.first.should be
|
141
154
|
end
|
142
155
|
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'low_card_tables'
|
2
|
+
require 'low_card_tables/helpers/database_helper'
|
3
|
+
require 'low_card_tables/helpers/system_helpers'
|
4
|
+
|
5
|
+
describe "LowCardTables STI support" do
|
6
|
+
include LowCardTables::Helpers::SystemHelpers
|
7
|
+
|
8
|
+
before :each do
|
9
|
+
@dh = LowCardTables::Helpers::DatabaseHelper.new
|
10
|
+
@dh.setup_activerecord!
|
11
|
+
end
|
12
|
+
|
13
|
+
context "with the 'type' column defined in a low-card table" do
|
14
|
+
before :each do
|
15
|
+
migrate do
|
16
|
+
drop_table :lctables_spec_account_statuses rescue nil
|
17
|
+
create_table :lctables_spec_account_statuses, :low_card => true do |t|
|
18
|
+
t.boolean :deleted, :null => false
|
19
|
+
t.string :type
|
20
|
+
t.integer :account_level
|
21
|
+
end
|
22
|
+
|
23
|
+
drop_table :lctables_spec_accounts rescue nil
|
24
|
+
create_table :lctables_spec_accounts do |t|
|
25
|
+
t.string :name, :null => false
|
26
|
+
t.integer :account_status_id, :null => false, :limit => 2
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
define_model_class(:AccountStatus, 'lctables_spec_account_statuses') { is_low_card_table }
|
31
|
+
define_model_class(:Account, 'lctables_spec_accounts') { has_low_card_table :status; self.inheritance_column = :type }
|
32
|
+
define_model_class(:AdminAccount, nil, :superclass => ::Account)
|
33
|
+
define_model_class(:AccountStatusBackdoor, 'lctables_spec_account_statuses') { self.inheritance_column = :_disabled_ }
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should work normally" do
|
37
|
+
account1 = ::Account.new
|
38
|
+
account1.name = "account 1"
|
39
|
+
account1.deleted = false
|
40
|
+
account1.account_level = 10
|
41
|
+
account1.save!
|
42
|
+
|
43
|
+
account2 = ::AdminAccount.new
|
44
|
+
account2.name = "account 2"
|
45
|
+
account2.deleted = true
|
46
|
+
account2.account_level = 20
|
47
|
+
account2.save!
|
48
|
+
|
49
|
+
account1_again = ::Account.find(account1.id)
|
50
|
+
expect(account1_again.class).to eq(::Account)
|
51
|
+
expect(account1_again.name).to eq('account 1')
|
52
|
+
expect(account1_again.deleted).to eq(false)
|
53
|
+
expect(account1_again.account_level).to eq(10)
|
54
|
+
|
55
|
+
account2_again = ::Account.find(account2.id)
|
56
|
+
expect(account2_again.class).to eq(::AdminAccount)
|
57
|
+
expect(account2_again.name).to eq('account 2')
|
58
|
+
expect(account2_again.deleted).to eq(true)
|
59
|
+
expect(account2_again.account_level).to eq(20)
|
60
|
+
|
61
|
+
all_accounts = ::Account.all.to_a
|
62
|
+
expect(all_accounts.length).to eq(2)
|
63
|
+
account1 = all_accounts.detect { |a| a.id == account1.id }
|
64
|
+
account2 = all_accounts.detect { |a| a.id == account2.id }
|
65
|
+
|
66
|
+
admin_accounts = ::AdminAccount.all.to_a
|
67
|
+
expect(admin_accounts.length).to eq(1)
|
68
|
+
expect(admin_accounts.first.id).to eq(account2.id)
|
69
|
+
|
70
|
+
expect(account1.class.name).to eq('Account')
|
71
|
+
expect(account2.class.name).to eq('AdminAccount')
|
72
|
+
|
73
|
+
expect(::AccountStatusBackdoor.count).to eq(2)
|
74
|
+
asid = account1.account_status_id
|
75
|
+
status1 = ::AccountStatusBackdoor.find(asid)
|
76
|
+
expect(status1.deleted).to eq(false)
|
77
|
+
expect(status1.type).to eq(nil)
|
78
|
+
expect(status1.account_level).to eq(10)
|
79
|
+
status2 = ::AccountStatusBackdoor.find(account2.account_status_id)
|
80
|
+
expect(status2.deleted).to eq(true)
|
81
|
+
expect(status2.type).to eq('AdminAccount')
|
82
|
+
expect(status2.account_level).to eq(20)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "with a normal table that uses STI, and has a low-card table" do
|
87
|
+
before :each do
|
88
|
+
migrate do
|
89
|
+
drop_table :lctables_spec_account_statuses rescue nil
|
90
|
+
create_table :lctables_spec_account_statuses, :low_card => true do |t|
|
91
|
+
t.boolean :deleted, :null => false
|
92
|
+
t.integer :account_level
|
93
|
+
end
|
94
|
+
|
95
|
+
drop_table :lctables_spec_accounts rescue nil
|
96
|
+
create_table :lctables_spec_accounts do |t|
|
97
|
+
t.string :name, :null => false
|
98
|
+
t.string :type
|
99
|
+
t.integer :account_status_id, :null => false, :limit => 2
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
define_model_class(:AccountStatus, 'lctables_spec_account_statuses') { is_low_card_table }
|
104
|
+
define_model_class(:Account, 'lctables_spec_accounts') { has_low_card_table :status; self.inheritance_column = :type }
|
105
|
+
define_model_class(:AccountStatusBackdoor, 'lctables_spec_account_statuses') { }
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should work normally with the base table" do
|
109
|
+
account1 = ::Account.new
|
110
|
+
account1.name = "account 1"
|
111
|
+
account1.deleted = false
|
112
|
+
account1.account_level = 10
|
113
|
+
account1.save!
|
114
|
+
|
115
|
+
account2 = ::Account.new
|
116
|
+
account2.name = "account 2"
|
117
|
+
account2.deleted = true
|
118
|
+
account2.account_level = 20
|
119
|
+
account2.save!
|
120
|
+
|
121
|
+
account1_again = ::Account.find(account1.id)
|
122
|
+
expect(account1_again.name).to eq('account 1')
|
123
|
+
expect(account1_again.deleted).to eq(false)
|
124
|
+
expect(account1_again.account_level).to eq(10)
|
125
|
+
|
126
|
+
account2_again = ::Account.find(account2.id)
|
127
|
+
expect(account2_again.name).to eq('account 2')
|
128
|
+
expect(account2_again.deleted).to eq(true)
|
129
|
+
expect(account2_again.account_level).to eq(20)
|
130
|
+
|
131
|
+
expect(::AccountStatusBackdoor.count).to eq(2)
|
132
|
+
status1 = ::AccountStatusBackdoor.find(account1.account_status_id)
|
133
|
+
expect(status1.deleted).to eq(false)
|
134
|
+
expect(status1.account_level).to eq(10)
|
135
|
+
status2 = ::AccountStatusBackdoor.find(account2.account_status_id)
|
136
|
+
expect(status2.deleted).to eq(true)
|
137
|
+
expect(status2.account_level).to eq(20)
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should work normally with the base table and a derived table" do
|
141
|
+
define_model_class(:AdminAccount, nil, :superclass => ::Account)
|
142
|
+
|
143
|
+
account1 = ::Account.new
|
144
|
+
account1.name = "account 1"
|
145
|
+
account1.deleted = false
|
146
|
+
account1.account_level = 10
|
147
|
+
account1.save!
|
148
|
+
|
149
|
+
account2 = ::AdminAccount.new
|
150
|
+
account2.name = "account 2"
|
151
|
+
account2.deleted = true
|
152
|
+
account2.account_level = 20
|
153
|
+
account2.save!
|
154
|
+
|
155
|
+
account1_again = ::Account.find(account1.id)
|
156
|
+
expect(account1_again.class).to eq(::Account)
|
157
|
+
expect(account1_again.name).to eq('account 1')
|
158
|
+
expect(account1_again.deleted).to eq(false)
|
159
|
+
expect(account1_again.account_level).to eq(10)
|
160
|
+
|
161
|
+
account2_again = ::Account.find(account2.id)
|
162
|
+
expect(account2_again.class.name).to eq('AdminAccount')
|
163
|
+
expect(account2_again.name).to eq('account 2')
|
164
|
+
expect(account2_again.deleted).to eq(true)
|
165
|
+
expect(account2_again.account_level).to eq(20)
|
166
|
+
|
167
|
+
expect(::AccountStatusBackdoor.count).to eq(2)
|
168
|
+
status1 = ::AccountStatusBackdoor.find(account1.account_status_id)
|
169
|
+
expect(status1.deleted).to eq(false)
|
170
|
+
expect(status1.account_level).to eq(10)
|
171
|
+
status2 = ::AccountStatusBackdoor.find(account2.account_status_id)
|
172
|
+
expect(status2.deleted).to eq(true)
|
173
|
+
expect(status2.account_level).to eq(20)
|
174
|
+
|
175
|
+
expect(::AdminAccount.where(:deleted => true).first.id).to eq(account2.id)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -4,6 +4,7 @@ describe LowCardTables::ActiveRecord::Base do
|
|
4
4
|
before :each do
|
5
5
|
@klass = Class.new
|
6
6
|
@klass.send(:include, LowCardTables::ActiveRecord::Base)
|
7
|
+
allow(@klass).to receive(:inheritance_column=).with('_sti_on_low_card_tables_should_never_be_used')
|
7
8
|
end
|
8
9
|
|
9
10
|
it "should include LowCardTables::LowCardTable::Base appropriately and respond to #is_low_card_table? appropriately" do
|
@@ -2,7 +2,7 @@ require 'low_card_tables'
|
|
2
2
|
|
3
3
|
describe LowCardTables::HasLowCardTable::LowCardDynamicMethodManager do
|
4
4
|
before :each do
|
5
|
-
@model_class = double("model_class")
|
5
|
+
@model_class = double("model_class", :superclass => ::Object)
|
6
6
|
@lcam = double("low_card_associations_manager")
|
7
7
|
allow(@model_class).to receive(:_low_card_associations_manager).and_return(@lcam)
|
8
8
|
|
@@ -3,6 +3,7 @@ require 'low_card_tables'
|
|
3
3
|
describe LowCardTables::LowCardTable::Base do
|
4
4
|
before :each do
|
5
5
|
@test_class = Class.new
|
6
|
+
allow(@test_class).to receive(:inheritance_column=).with('_sti_on_low_card_tables_should_never_be_used')
|
6
7
|
@test_class.send(:include, LowCardTables::LowCardTable::Base)
|
7
8
|
end
|
8
9
|
|
@@ -112,6 +113,7 @@ describe LowCardTables::LowCardTable::Base do
|
|
112
113
|
end
|
113
114
|
|
114
115
|
test_class = Class.new
|
116
|
+
allow(test_class).to receive(:inheritance_column=).with('_sti_on_low_card_tables_should_never_be_used')
|
115
117
|
test_class.send(:extend, mod)
|
116
118
|
test_class.send(:include, LowCardTables::LowCardTable::Base)
|
117
119
|
|
@@ -163,6 +165,7 @@ ensure_has_unique_index! remove_unique_index!}.each do |method_name|
|
|
163
165
|
|
164
166
|
# We need a new class -- because we need to make sure our module gets in there first
|
165
167
|
@test_class = Class.new
|
168
|
+
allow(@test_class).to receive(:inheritance_column=).with('_sti_on_low_card_tables_should_never_be_used')
|
166
169
|
@test_class.send(:include, @save_mod)
|
167
170
|
@test_class.send(:include, LowCardTables::LowCardTable::Base)
|
168
171
|
|
@@ -88,20 +88,18 @@ describe LowCardTables::LowCardTable::RowManager do
|
|
88
88
|
allow(@low_card_model).to receive(:reset_column_information)
|
89
89
|
allow(@low_card_model).to receive(:table_exists?).and_return(true)
|
90
90
|
allow(@low_card_model).to receive(:table_name).and_return("thetablename")
|
91
|
+
allow(@low_card_model).to receive(:primary_key).and_return('id')
|
91
92
|
|
92
93
|
@table_unique_index = double("table_unique_index")
|
93
94
|
allow(LowCardTables::LowCardTable::TableUniqueIndex).to receive(:new).with(@low_card_model).and_return(@table_unique_index)
|
94
95
|
|
95
96
|
@column_id = double("column_id")
|
96
97
|
allow(@column_id).to receive(:name).and_return("id")
|
97
|
-
allow(@column_id).to receive(:primary).and_return(true)
|
98
98
|
@column_foo = double("column_foo")
|
99
99
|
allow(@column_foo).to receive(:name).and_return("foo")
|
100
|
-
allow(@column_foo).to receive(:primary).and_return(false)
|
101
100
|
allow(@column_foo).to receive(:default).and_return(nil)
|
102
101
|
@column_bar = double("column_bar")
|
103
102
|
allow(@column_bar).to receive(:name).and_return("bar")
|
104
|
-
allow(@column_bar).to receive(:primary).and_return(false)
|
105
103
|
allow(@column_bar).to receive(:default).and_return('yohoho')
|
106
104
|
allow(@low_card_model).to receive(:columns).and_return([ @column_id, @column_foo, @column_bar ])
|
107
105
|
|
@@ -332,7 +330,6 @@ describe LowCardTables::LowCardTable::RowManager do
|
|
332
330
|
it "should accept hashes containing valid data, if it isn't found the first time through" do
|
333
331
|
column_baz = double("column_bar")
|
334
332
|
allow(column_baz).to receive(:name).and_return("baz")
|
335
|
-
allow(column_baz).to receive(:primary).and_return(false)
|
336
333
|
|
337
334
|
columns_to_return = [
|
338
335
|
[ @column_id, @column_foo, @column_bar ],
|
@@ -865,15 +862,12 @@ describe LowCardTables::LowCardTable::RowManager do
|
|
865
862
|
|
866
863
|
it "should exclude primary keys, created/updated_at, and options-specified column names" do
|
867
864
|
column_created_at = double("column_created_at")
|
868
|
-
allow(column_created_at).to receive(:primary).and_return(false)
|
869
865
|
allow(column_created_at).to receive(:name).and_return("created_at")
|
870
866
|
|
871
867
|
column_updated_at = double("column_updated_at")
|
872
|
-
allow(column_updated_at).to receive(:primary).and_return(false)
|
873
868
|
allow(column_updated_at).to receive(:name).and_return("updated_at")
|
874
869
|
|
875
870
|
column_skipped = double("column_skipped")
|
876
|
-
allow(column_skipped).to receive(:primary).and_return(false)
|
877
871
|
allow(column_skipped).to receive(:name).and_return("FooFle")
|
878
872
|
|
879
873
|
columns = [ @column_id, @column_foo, @column_bar, @column_created_at, @column_updated_at, @column_skipped ]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: low_card_tables
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Geweke
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-02-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -169,6 +169,7 @@ files:
|
|
169
169
|
- spec/low_card_tables/system/namespaced_models_system_spec.rb
|
170
170
|
- spec/low_card_tables/system/options_system_spec.rb
|
171
171
|
- spec/low_card_tables/system/queries_system_spec.rb
|
172
|
+
- spec/low_card_tables/system/sti_system_spec.rb
|
172
173
|
- spec/low_card_tables/system/validations_system_spec.rb
|
173
174
|
- spec/low_card_tables/unit/active_record/base_spec.rb
|
174
175
|
- spec/low_card_tables/unit/active_record/migrations_spec.rb
|
@@ -209,7 +210,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
209
210
|
version: '0'
|
210
211
|
requirements: []
|
211
212
|
rubyforge_project:
|
212
|
-
rubygems_version: 2.
|
213
|
+
rubygems_version: 2.4.5
|
213
214
|
signing_key:
|
214
215
|
specification_version: 4
|
215
216
|
summary: '"Bitfields for ActiveRecord": instead of storing multiple columns with low
|
@@ -228,6 +229,7 @@ test_files:
|
|
228
229
|
- spec/low_card_tables/system/namespaced_models_system_spec.rb
|
229
230
|
- spec/low_card_tables/system/options_system_spec.rb
|
230
231
|
- spec/low_card_tables/system/queries_system_spec.rb
|
232
|
+
- spec/low_card_tables/system/sti_system_spec.rb
|
231
233
|
- spec/low_card_tables/system/validations_system_spec.rb
|
232
234
|
- spec/low_card_tables/unit/active_record/base_spec.rb
|
233
235
|
- spec/low_card_tables/unit/active_record/migrations_spec.rb
|