active_record-mti 0.3.2 → 0.4.0.pre.1

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -6
  3. data/{LICENSE.txt → LICENSE} +0 -0
  4. data/README.md +47 -10
  5. data/lib/active_record/mti.rb +56 -56
  6. data/lib/active_record/mti/config.rb +26 -0
  7. data/lib/active_record/mti/connection_adapters/postgresql/adapter.rb +0 -8
  8. data/lib/active_record/mti/connection_adapters/postgresql/schema_statements.rb +30 -11
  9. data/lib/active_record/mti/core_extension.rb +170 -0
  10. data/lib/active_record/mti/railtie.rb +9 -4
  11. data/lib/active_record/mti/relation.rb +95 -0
  12. data/lib/active_record/mti/schema_dumper.rb +4 -4
  13. data/lib/active_record/mti/table.rb +19 -0
  14. data/lib/active_record/mti/table_oid.rb +6 -0
  15. data/lib/active_record/mti/version.rb +1 -1
  16. data/lib/core_ext/array.rb +14 -0
  17. data/lib/core_ext/hash.rb +1 -3
  18. data/lib/core_ext/thread.rb +14 -0
  19. metadata +94 -95
  20. data/.gitignore +0 -78
  21. data/.rspec +0 -2
  22. data/.travis.yml +0 -38
  23. data/Gemfile +0 -21
  24. data/Rakefile +0 -6
  25. data/active_record-mti.gemspec +0 -42
  26. data/gemfiles/activerecord-4.0.Gemfile +0 -3
  27. data/gemfiles/activerecord-4.1.Gemfile +0 -3
  28. data/gemfiles/activerecord-4.2.Gemfile +0 -3
  29. data/gemfiles/activerecord-5.0.Gemfile +0 -3
  30. data/gemfiles/activerecord-5.1.Gemfile +0 -3
  31. data/lib/active_record/mti/calculations.rb +0 -23
  32. data/lib/active_record/mti/inheritance.rb +0 -127
  33. data/lib/active_record/mti/model_schema.rb +0 -55
  34. data/lib/active_record/mti/query_methods.rb +0 -40
  35. data/lib/active_record/mti/querying.rb +0 -7
  36. data/lib/active_record/mti/registry.rb +0 -23
  37. data/spec/active_record/mti/calculations_spec.rb +0 -56
  38. data/spec/active_record/mti/inheritance_spec.rb +0 -184
  39. data/spec/active_record/mti/model_schema_spec.rb +0 -11
  40. data/spec/active_record/mti/query_methods_spec.rb +0 -12
  41. data/spec/active_record/mti/schema_dumper_spec.rb +0 -22
  42. data/spec/active_record/mti_spec.rb +0 -24
  43. data/spec/active_record/sti/inheritance_spec.rb +0 -24
  44. data/spec/spec_helper.rb +0 -28
  45. data/spec/support/rails/app/models/admin.rb +0 -3
  46. data/spec/support/rails/app/models/comment.rb +0 -4
  47. data/spec/support/rails/app/models/post.rb +0 -4
  48. data/spec/support/rails/app/models/transportation/military/vehicle.rb +0 -7
  49. data/spec/support/rails/app/models/transportation/truck.rb +0 -5
  50. data/spec/support/rails/app/models/transportation/vehicle.rb +0 -4
  51. data/spec/support/rails/app/models/user.rb +0 -6
  52. data/spec/support/rails/config/database.yml +0 -4
  53. data/spec/support/rails/config/routes.rb +0 -3
  54. data/spec/support/rails/db/schema.rb +0 -51
  55. data/spec/support/rails/log/.gitignore +0 -1
  56. data/spec/support/rails/public/favicon.ico +0 -0
data/.gitignore DELETED
@@ -1,78 +0,0 @@
1
- # See http://help.github.com/ignore-files/ for more about ignoring files.
2
- #
3
- # If you find yourself ignoring temporary files generated by your text editor
4
- # or operating system, you probably want to add a global ignore instead:
5
- # git config --global core.excludesfile ~/.gitignore_global
6
-
7
- # Database config and secrets
8
- /config/database.yml
9
- /config/secrets.yml
10
-
11
- # Ignore bundler config
12
- /.bundle
13
-
14
- # Ignore client credentials
15
- /config/client_api_credentials.yml
16
-
17
- # Ignore the default SQLite database.
18
- /db/*.sqlite3
19
-
20
- # Ignore all logfiles and tempfiles.
21
- /log/*.log
22
- /tmp
23
- /db/structure.sql
24
- /doc/app/*
25
- /vendor/cldr/*
26
- /public/uploads/*
27
- /public/photo/*
28
- /public/test/*
29
- /test/assets/*
30
- /spec/assets/*
31
- /public/assets/**
32
- .powenv
33
- .rvmrc
34
- .env
35
- .ruby-version
36
-
37
- # Compiled source #
38
- ###################
39
- /pkg/
40
- *.com
41
- *.class
42
- *.dll
43
- *.exe
44
- *.o
45
- *.so
46
-
47
- # Packages #
48
- ############
49
- # it's better to unpack these files and commit the raw source
50
- # git has its own built in compression methods
51
- *.7z
52
- *.dmg
53
- *.gz
54
- *.iso
55
- *.jar
56
- *.rar
57
- *.tar
58
- *.zip
59
-
60
- # Logs and databases #
61
- ######################
62
- *.log
63
- *.sql
64
- *.sqlite
65
-
66
- # OS generated files #
67
- ######################
68
- .DS_Store
69
- .DS_Store?
70
- ._*
71
- .Spotlight-V100
72
- .Trashes
73
- Icon?
74
- ehthumbs.db
75
- Thumbs.db
76
- /Gemfile.lock
77
- /coverage
78
- /.editorconfig
data/.rspec DELETED
@@ -1,2 +0,0 @@
1
- --format documentation
2
- --color
data/.travis.yml DELETED
@@ -1,38 +0,0 @@
1
- language: ruby
2
- sudo: false
3
-
4
- cache: bundler
5
- script:
6
- - bundle exec rspec
7
-
8
- after_success:
9
- - bundle exec codeclimate-test-reporter
10
-
11
- addons:
12
- postgresql: "9.3"
13
-
14
- rvm:
15
- - 2.4
16
- - 2.3
17
- - 2.2
18
- - 2.1
19
-
20
- gemfile:
21
- - gemfiles/activerecord-5.1.Gemfile
22
- - gemfiles/activerecord-5.0.Gemfile
23
- - gemfiles/activerecord-4.2.Gemfile
24
- - gemfiles/activerecord-4.1.Gemfile
25
- - gemfiles/activerecord-4.0.Gemfile
26
-
27
- matrix:
28
- exclude:
29
-
30
- - rvm: 2.1
31
- gemfile: gemfiles/activerecord-5.0.Gemfile
32
- - rvm: 2.1
33
- gemfile: gemfiles/activerecord-5.1.Gemfile
34
-
35
- - rvm: 2.4
36
- gemfile: gemfiles/activerecord-4.0.Gemfile
37
- - rvm: 2.4
38
- gemfile: gemfiles/activerecord-4.1.Gemfile
data/Gemfile DELETED
@@ -1,21 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gemspec
4
-
5
- group :test do
6
-
7
- gem 'pry'
8
-
9
- # Generates coverage stats of specs
10
- gem 'simplecov'
11
-
12
- # Publishes coverage to codeclimate
13
- gem 'codeclimate-test-reporter'
14
-
15
- gem 'rspec'
16
-
17
- gem 'database_cleaner'
18
-
19
- gem 'combustion'
20
-
21
- end
data/Rakefile DELETED
@@ -1,6 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require 'rspec/core/rake_task'
3
-
4
- RSpec::Core::RakeTask.new
5
-
6
- task default: :spec
@@ -1,42 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'active_record/mti/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "active_record-mti"
8
- spec.version = ActiveRecord::MTI::VERSION
9
- spec.authors = ["Dale Stevens"]
10
- spec.email = ["dale@twilightcoders.net"]
11
-
12
- spec.summary = %q{Multi Table Inheritance for PostgreSQL in Rails}
13
- spec.description = %q{Gives ActiveRecord support for PostgreSQL's native inherited tables}
14
- spec.homepage = "https://github.com/twilightcoders/active_record-mti"
15
- spec.license = "MIT"
16
-
17
- # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
- # to allow pushing to a single host or delete this section to allow pushing to any host.
19
- if spec.respond_to?(:metadata)
20
- spec.metadata['allowed_push_host'] = 'https://rubygems.org'
21
- else
22
- raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
23
- end
24
-
25
- spec.files = `git ls-files -z`.split("\x0")
26
- spec.bindir = 'bin'
27
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
28
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
29
- spec.require_paths = ['lib', 'spec']
30
-
31
- rails_versions = ['>= 4', '< 6']
32
- spec.required_ruby_version = '>= 2.1'
33
-
34
- spec.add_runtime_dependency 'pg', '~> 0'
35
- spec.add_runtime_dependency 'activerecord', rails_versions
36
-
37
- spec.add_development_dependency 'pry-byebug', '~> 3'
38
- spec.add_development_dependency 'bundler', '~> 1.3'
39
- spec.add_development_dependency 'rake', '~> 12.0'
40
- spec.add_development_dependency 'combustion', '~> 0.7'
41
-
42
- end
@@ -1,3 +0,0 @@
1
- eval_gemfile File.join(File.dirname(__FILE__), "../Gemfile")
2
-
3
- gem 'activerecord', '~> 4.0.0'
@@ -1,3 +0,0 @@
1
- eval_gemfile File.join(File.dirname(__FILE__), "../Gemfile")
2
-
3
- gem 'activerecord', '~> 4.1.0'
@@ -1,3 +0,0 @@
1
- eval_gemfile File.join(File.dirname(__FILE__), "../Gemfile")
2
-
3
- gem 'activerecord', '~> 4.2.0'
@@ -1,3 +0,0 @@
1
- eval_gemfile File.join(File.dirname(__FILE__), "../Gemfile")
2
-
3
- gem 'activerecord', '~> 5.0.0'
@@ -1,3 +0,0 @@
1
- eval_gemfile File.join(File.dirname(__FILE__), "../Gemfile")
2
-
3
- gem 'activerecord', '~> 5.1.0'
@@ -1,23 +0,0 @@
1
- module ActiveRecord
2
- module MTI
3
- module Calculations
4
-
5
- private
6
-
7
- def perform_calculation(*args)
8
- swap_and_restore_tableoid_cast(true) do
9
- super
10
- end
11
- end
12
-
13
- def swap_and_restore_tableoid_cast(value)
14
- orignal_value = Thread.current['skip_tableoid_cast']
15
- Thread.current['skip_tableoid_cast'] = value
16
- return_value = yield if block_given?
17
- ensure
18
- Thread.current['skip_tableoid_cast'] = orignal_value
19
- end
20
-
21
- end
22
- end
23
- end
@@ -1,127 +0,0 @@
1
- module ActiveRecord
2
- # == Multi-Table Inheritance
3
- module MTI
4
- module Inheritance
5
-
6
- def self.prepended(subclass)
7
- subclass.extend(ClassMethods)
8
- class << subclass
9
- attr_reader :mti_type_column
10
- attr_reader :tableoid_column
11
- end
12
- end
13
-
14
- module ClassMethods
15
- def has_tableoid_column?
16
- tableoid_column != false
17
- end
18
-
19
- def inherited(subclass)
20
- super
21
- subclass.using_multi_table_inheritance?
22
- end
23
-
24
- def uses_mti(*args)
25
- warn "DEPRECATED - `uses_mti` is no longer needed (nor has any effect)"
26
- end
27
-
28
- def using_multi_table_inheritance?
29
- mti = ActiveRecord::MTI::Registry.tableoid?(self)
30
- return (mti != false) unless mti == nil
31
-
32
- if (mti = check_inheritance_of(@table_name))
33
- if (self != base_class && self.table_name == base_class.table_name)
34
- mti = false
35
- else
36
- mti = detect_tableoid(table_name)
37
- end
38
- end
39
-
40
- ActiveRecord::MTI::Registry[self] = mti
41
-
42
- descendants.each do |d|
43
- d.using_multi_table_inheritance?
44
- end
45
-
46
- return mti && mti != false
47
- end
48
-
49
- private
50
-
51
- def check_inheritance_of(table_name, table_schema = 'public')
52
- ActiveRecord::MTI.logger.debug("Trying to check inheritance of table with no table name (#{self})") and return nil unless table_name
53
- ActiveRecord::MTI.logger.debug "Checking inheritance for #{table_schema}.#{table_name}"
54
-
55
- result = connection.execute <<-SQL
56
- SELECT EXISTS (
57
- SELECT 1
58
- FROM pg_catalog.pg_inherits AS i
59
- JOIN information_schema.tables AS t ON t.table_schema = '#{table_schema}' AND t.table_name = '#{table_name}'
60
- LEFT JOIN pg_catalog.pg_rewrite AS r ON r.ev_class = t.table_name::regclass::oid
61
- LEFT JOIN pg_catalog.pg_depend AS d ON d.objid = r.oid
62
- LEFT JOIN pg_catalog.pg_class AS c ON c.oid = d.refobjid
63
- WHERE i.inhrelid = COALESCE(c.relname, t.table_name)::regclass::oid
64
- OR i.inhparent = COALESCE(c.relname, t.table_name)::regclass::oid
65
- ) AS uses_inheritance;
66
- SQL
67
-
68
- return ActiveRecord::MTI.testify(result.try(:first)['uses_inheritance']) == true
69
- end
70
-
71
- def detect_tableoid(table_name, table_schema = 'public')
72
-
73
- tableoid_query = connection.execute(<<-SQL
74
- SELECT 1 AS has_tableoid_column, t.table_name::regclass::oid as tableoid
75
- FROM pg_catalog.pg_attribute
76
- JOIN information_schema.tables t ON t.table_schema = '#{table_schema}' AND t.table_name = '#{table_name}'
77
- WHERE attrelid = t.table_name::regclass
78
- AND attname = 'tableoid'
79
- AND NOT attisdropped;
80
- SQL
81
- ).first
82
-
83
- tableoid = tableoid_query.try(:[], 'tableoid') || false
84
- @tableoid_column = ActiveRecord::MTI.testify(tableoid_query.try(:[], 'has_tableoid_column'))
85
-
86
- if (has_tableoid_column?)
87
- ActiveRecord::MTI.logger.debug "#{table_schema}.#{table_name} has tableoid column! (#{tableoid})"
88
- add_tableoid_column
89
- @mti_type_column = arel_table[:tableoid]
90
- else
91
- @mti_type_column = nil
92
- end
93
-
94
- tableoid
95
- end
96
-
97
- # Called by +instantiate+ to decide which class to use for a new
98
- # record instance. For single-table inheritance, we check the record
99
- # for a +type+ column and return the corresponding class.
100
- def discriminate_class_for_record(record)
101
- if using_multi_table_inheritance?
102
- ActiveRecord::MTI::Registry.find_mti_class(record['tableoid']) || self
103
- else
104
- super
105
- end
106
- end
107
-
108
- # Type condition only applies if it's STI, otherwise it's
109
- # done for free by querying the inherited table in MTI
110
- def type_condition(table = arel_table)
111
- return nil if using_multi_table_inheritance?
112
- super
113
- end
114
-
115
- def add_tableoid_column
116
- if self.respond_to? :attribute
117
- self.attribute :tableoid, ActiveRecord::MTI.oid_class.new
118
- else
119
- new_column = ActiveRecord::ConnectionAdapters::PostgreSQLColumn.new('tableoid', nil, ActiveRecord::MTI.oid_class.new, "oid", false)
120
- columns.unshift new_column
121
- columns_hash['tableoid'] = new_column
122
- end
123
- end
124
- end
125
- end
126
- end
127
- end
@@ -1,55 +0,0 @@
1
- module ActiveRecord
2
- module MTI
3
- module ModelSchema
4
-
5
- def self.prepended(base)
6
- base.extend(ClassMethods)
7
- end
8
-
9
- module ClassMethods
10
- # Computes and returns a table name according to default conventions.
11
- def compute_table_name
12
- if self != base_class
13
- # Nested classes are prefixed with singular parent table name.
14
- if superclass < Base && !superclass.abstract_class?
15
- contained = superclass.table_name
16
- contained = contained.singularize if superclass.pluralize_table_names
17
- contained += '/'
18
- end
19
-
20
- potential_table_name = "#{full_table_name_prefix}#{contained}#{decorated_table_name(name)}#{full_table_name_suffix}"
21
-
22
- if check_inheritance_of(potential_table_name)
23
- potential_table_name
24
- else
25
- superclass.table_name
26
- end
27
- else
28
- super
29
- end
30
- end
31
-
32
- def full_table_name_suffix #:nodoc:
33
- super
34
- rescue NoMethodError
35
- full_table_name_rescue(:table_name_suffix)
36
- end
37
-
38
- private
39
-
40
- def full_table_name_rescue(which)
41
- (parents.detect{ |p| p.respond_to?(which) } || self).send(which)
42
- end
43
-
44
- # Guesses the table name, but does not decorate it with prefix and suffix information.
45
- def decorated_table_name(class_name = base_class.name)
46
- super
47
- rescue NoMethodError
48
- table_name = class_name.to_s.underscore
49
- pluralize_table_names ? table_name.pluralize : table_name
50
- end
51
- end
52
-
53
- end
54
- end
55
- end
@@ -1,40 +0,0 @@
1
- module ActiveRecord
2
- module MTI
3
- module QueryMethods
4
-
5
- def build_arel
6
- @select_by_tableoid = [select_values.delete(:tableoid), tableoid?(klass)].compact.first
7
- @group_by_tableoid = group_values.delete(:tableoid)
8
-
9
- super.tap do |arel|
10
- if @group_by_tableoid || (@select_by_tableoid && group_values.any?)
11
- arel.group(tableoid_group(@klass))
12
- end
13
- end
14
- end
15
-
16
- def build_select(*args)
17
- super.tap do |arel|
18
- arel.project(tableoid_project(@klass)) if (@group_by_tableoid || @select_by_tableoid)
19
- end
20
- end
21
-
22
- private
23
-
24
- def tableoid?(klass)
25
- !Thread.current['skip_tableoid_cast'] &&
26
- klass.using_multi_table_inheritance? &&
27
- klass.mti_type_column
28
- end
29
-
30
- def tableoid_project(klass)
31
- klass.mti_type_column.as('tableoid')
32
- end
33
-
34
- def tableoid_group(klass)
35
- klass.mti_type_column
36
- end
37
-
38
- end
39
- end
40
- end