active_record-mti 0.3.2 → 0.4.0.pre.1

Sign up to get free protection for your applications and to get access to all the features.
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