torque-postgresql 0.1.7 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/README.rdoc +74 -0
  3. data/lib/torque/postgresql/adapter/database_statements.rb +44 -2
  4. data/lib/torque/postgresql/adapter/schema_creation.rb +55 -0
  5. data/lib/torque/postgresql/adapter/schema_definitions.rb +26 -1
  6. data/lib/torque/postgresql/adapter/schema_statements.rb +20 -0
  7. data/lib/torque/postgresql/adapter.rb +1 -1
  8. data/lib/torque/postgresql/arel/join_source.rb +15 -0
  9. data/lib/torque/postgresql/arel/select_manager.rb +21 -0
  10. data/lib/torque/postgresql/arel/using.rb +10 -0
  11. data/lib/torque/postgresql/arel/visitors.rb +18 -1
  12. data/lib/torque/postgresql/arel.rb +4 -0
  13. data/lib/torque/postgresql/attributes/enum.rb +7 -1
  14. data/lib/torque/postgresql/attributes.rb +9 -1
  15. data/lib/torque/postgresql/auxiliary_statement/settings.rb +7 -0
  16. data/lib/torque/postgresql/auxiliary_statement.rb +19 -10
  17. data/lib/torque/postgresql/base.rb +76 -7
  18. data/lib/torque/postgresql/coder.rb +132 -0
  19. data/lib/torque/postgresql/collector.rb +2 -0
  20. data/lib/torque/postgresql/config.rb +35 -1
  21. data/lib/torque/postgresql/inheritance.rb +133 -0
  22. data/lib/torque/postgresql/railtie.rb +16 -0
  23. data/lib/torque/postgresql/relation/auxiliary_statement.rb +26 -19
  24. data/lib/torque/postgresql/relation/distinct_on.rb +9 -7
  25. data/lib/torque/postgresql/relation/inheritance.rb +112 -0
  26. data/lib/torque/postgresql/relation/merger.rb +48 -0
  27. data/lib/torque/postgresql/relation.rb +67 -2
  28. data/lib/torque/postgresql/schema_cache.rb +192 -0
  29. data/lib/torque/postgresql/schema_dumper.rb +49 -1
  30. data/lib/torque/postgresql/version.rb +1 -1
  31. data/lib/torque/postgresql.rb +6 -4
  32. metadata +14 -8
@@ -1,13 +1,21 @@
1
-
2
1
  require_relative 'relation/distinct_on'
3
2
  require_relative 'relation/auxiliary_statement'
3
+ require_relative 'relation/inheritance'
4
+
5
+ require_relative 'relation/merger'
4
6
 
5
7
  module Torque
6
8
  module PostgreSQL
7
9
  module Relation
10
+ extend ActiveSupport::Concern
8
11
 
9
12
  include DistinctOn
10
13
  include AuxiliaryStatement
14
+ include Inheritance
15
+
16
+ SINGLE_VALUE_METHODS = [:itself_only]
17
+ MULTI_VALUE_METHODS = [:distinct_on, :auxiliary_statements, :cast_records]
18
+ VALUE_METHODS = SINGLE_VALUE_METHODS + MULTI_VALUE_METHODS
11
19
 
12
20
  # Resolve column definition up to second value.
13
21
  # For example, based on Post model:
@@ -23,7 +31,7 @@ module Torque
23
31
  def resolve_column(list, base = false)
24
32
  base = resolve_base_table(base)
25
33
 
26
- list.map do |item|
34
+ Array.wrap(list).map do |item|
27
35
  case item
28
36
  when String
29
37
  ::Arel::Nodes::SqlLiteral.new(klass.send(:sanitize_sql, item.to_s))
@@ -55,8 +63,65 @@ module Torque
55
63
  end
56
64
  end
57
65
 
66
+ private
67
+
68
+ # Compatibility method with 5.0
69
+ unless ActiveRecord::Relation.method_defined?(:get_value)
70
+ def get_value(name)
71
+ @values[name] || ActiveRecord::QueryMethods::FROZEN_EMPTY_ARRAY
72
+ end
73
+ end
74
+
75
+ # Compatibility method with 5.0
76
+ unless ActiveRecord::Relation.method_defined?(:set_value)
77
+ def set_value(name, value)
78
+ assert_mutability!
79
+ @values[name] = value
80
+ end
81
+ end
82
+
83
+ module ClassMethods
84
+ # Easy and storable way to access the name used to get the record table
85
+ # name when using inheritance tables
86
+ def _record_class_attribute
87
+ @@record_class ||= Torque::PostgreSQL.config
88
+ .inheritance.record_class_column_name.to_sym
89
+ end
90
+
91
+ # Easy and storable way to access the name used to get the indicater of
92
+ # auto casting inherited records
93
+ def _auto_cast_attribute
94
+ @@auto_cast ||= Torque::PostgreSQL.config
95
+ .inheritance.auto_cast_column_name.to_sym
96
+ end
97
+ end
58
98
  end
59
99
 
100
+ # Include the methos here provided and then change the constants to ensure
101
+ # the operation of ActiveRecord Relation
60
102
  ActiveRecord::Relation.include Relation
103
+
104
+ warn_level = $VERBOSE
105
+ $VERBOSE = nil
106
+
107
+ ActiveRecord::Relation::SINGLE_VALUE_METHODS += Relation::SINGLE_VALUE_METHODS
108
+ ActiveRecord::Relation::MULTI_VALUE_METHODS += Relation::MULTI_VALUE_METHODS
109
+ ActiveRecord::Relation::VALUE_METHODS += Relation::VALUE_METHODS
110
+ ActiveRecord::QueryMethods::VALID_UNSCOPING_VALUES += [:cast_records, :itself_only,
111
+ :distinct_on, :auxiliary_statements]
112
+
113
+ if ActiveRecord::QueryMethods.const_defined?('DEFAULT_VALUES')
114
+ Relation::SINGLE_VALUE_METHODS.each do |value|
115
+ ActiveRecord::QueryMethods::DEFAULT_VALUES[value] = nil \
116
+ if ActiveRecord::QueryMethods::DEFAULT_VALUES[value].nil?
117
+ end
118
+
119
+ Relation::MULTI_VALUE_METHODS.each do |value|
120
+ ActiveRecord::QueryMethods::DEFAULT_VALUES[value] ||= \
121
+ ActiveRecord::QueryMethods::FROZEN_EMPTY_ARRAY
122
+ end
123
+ end
124
+
125
+ $VERBOSE = warn_level
61
126
  end
62
127
  end
@@ -0,0 +1,192 @@
1
+ module Torque
2
+ module PostgreSQL
3
+ # :TODO: Create the +add+ to load inheritance info
4
+ module SchemaCache
5
+
6
+ def initialize(*) # :nodoc:
7
+ super
8
+
9
+ @data_sources_model_names = {}
10
+ @inheritance_dependencies = {}
11
+ @inheritance_associations = {}
12
+ @cached_data_sources_size = 0
13
+ end
14
+
15
+ def initialize_dup(*) # :nodoc:
16
+ super
17
+ @data_sources_model_names = @data_sources_model_names.dup
18
+ @inheritance_dependencies = @inheritance_dependencies.dup
19
+ @inheritance_associations = @inheritance_associations.dup
20
+ @cached_data_sources_size = @cached_data_sources_size.dup
21
+ end
22
+
23
+ def clear! # :nodoc:
24
+ super
25
+ @data_sources_model_names.clear
26
+ @inheritance_dependencies.clear
27
+ @inheritance_associations.clear
28
+ @cached_data_sources_size = nil
29
+ end
30
+
31
+ def size # :nodoc:
32
+ super + [
33
+ @data_sources_model_names,
34
+ @inheritance_dependencies,
35
+ @inheritance_associations,
36
+ ].map(&:size).inject(:+)
37
+ end
38
+
39
+ def clear_data_source_cache!(name) # :nodoc:
40
+ super
41
+ @data_sources_model_names.delete name
42
+ @inheritance_dependencies.delete name
43
+ @inheritance_associations.delete name
44
+ @inheritance_cache -= 1
45
+ end
46
+
47
+ def marshal_dump # :nodoc:
48
+ super + [
49
+ @inheritance_cache,
50
+ @inheritance_dependencies,
51
+ @inheritance_associations,
52
+ @data_sources_model_names,
53
+ ]
54
+ end
55
+
56
+ def marshal_load(array) # :nodoc:
57
+ @data_sources_model_names = array.pop
58
+ @inheritance_associations = array.pop
59
+ @inheritance_dependencies = array.pop
60
+ @inheritance_cache = array.pop
61
+ super
62
+ end
63
+
64
+ # A way to manually add models name so it doesn't need the lookup method
65
+ def add_model_name(table_name, model)
66
+ return unless data_source_exists?(table_name) && model.is_a?(Class)
67
+ @data_sources_model_names[table_name] = model
68
+ end
69
+
70
+ # Get all the tables that the given one inherits from
71
+ def dependencies(table_name)
72
+ reload_inheritance_data!
73
+ @inheritance_dependencies[table_name]
74
+ end
75
+
76
+ # Get the list of all tables that are associated (direct or indirect
77
+ # inheritance) with the provided one
78
+ def associations(table_name)
79
+ reload_inheritance_data!
80
+ @inheritance_associations[table_name]
81
+ end
82
+
83
+ # Try to find a model based on a given table
84
+ def lookup_model(table_name, scopred_class = '')
85
+ scopred_class = scopred_class.name if scopred_class.is_a?(Class)
86
+ return @data_sources_model_names[table_name] \
87
+ if @data_sources_model_names.key?(table_name)
88
+
89
+ # Get all the possible scopes
90
+ scopes = scopred_class.scan(/(?:::)?[A-Z][a-z]+/)
91
+ scopes.unshift('Object::')
92
+
93
+ # Consider the maximum namespaced possible model name
94
+ max_name = table_name.tr('_', '/').camelize.split(/(::)/)
95
+ max_name[-1] = max_name[-1].singularize
96
+
97
+ # Test all the possible names against all the possible scopes
98
+ until scopes.size == 0
99
+ scope = scopes.join.safe_constantize
100
+ model = find_model(max_name, table_name, scope) unless scope.nil?
101
+ return @data_sources_model_names[table_name] = model unless model.nil?
102
+ scopes.pop
103
+ end
104
+
105
+ nil
106
+ end
107
+
108
+ private
109
+
110
+ # Find a model by a given max namespaced class name thath matches the
111
+ # given table name
112
+ def find_model(max_name, table_name, scope = Object)
113
+ pieces = max_name.is_a?(Array) ? max_name : max_name.split(/(::)/)
114
+ ns_places = (1..(max_name.size - 1)).step(2).to_a
115
+
116
+ # Generate all possible combinarions
117
+ conditions = []
118
+ range = Torque::PostgreSQL.config.inheritance.inverse_lookup \
119
+ ? 0.upto(ns_places.size) \
120
+ : ns_places.size.downto(0)
121
+ range.each do |size|
122
+ conditions.concat(ns_places.combination(size).to_a)
123
+ end
124
+
125
+ # Now iterate over
126
+ while (condition = conditions.shift)
127
+ ns_places.each{ |i| pieces[i] = condition.include?(i) ? '::' : '' }
128
+ next unless scope.const_defined?(pieces.join)
129
+
130
+ # Check if the class match the table name
131
+ klass = scope.const_get(pieces.join)
132
+ return klass if klass < ::ActiveRecord::Base && klass.table_name == table_name
133
+ end
134
+ end
135
+
136
+ # Generates the cache key for inheitance information
137
+ def inheritance_cache_key
138
+ @data_sources.keys.sort.join(',')
139
+ end
140
+
141
+ # Reload information about tables inheritance and dependencies, uses a
142
+ # cache to not perform additional checkes
143
+ def reload_inheritance_data!
144
+ cache_key = inheritance_cache_key
145
+
146
+ return unless @inheritance_cache != cache_key
147
+ @inheritance_cache = cache_key
148
+
149
+ @inheritance_dependencies = connection.inherited_tables.freeze
150
+ @inheritance_associations = generate_associations.freeze
151
+ end
152
+
153
+ # Calculates the inverted dependency (association), where even indirect
154
+ # inheritance comes up in the list
155
+ def generate_associations
156
+ result = Hash.new{ |h, k| h[k] = [] }
157
+ masters = @inheritance_dependencies.values.flatten.uniq
158
+
159
+ # Add direct associations
160
+ masters.map do |master|
161
+ @inheritance_dependencies.each do |(dependent, associations)|
162
+ result[master] << dependent if associations.include?(master)
163
+ end
164
+ end
165
+
166
+ # Add indirect associations
167
+ result.each do |master, children|
168
+ children.each do |child|
169
+ children.concat(result[child]).uniq! if result.key?(child)
170
+ end
171
+ end
172
+
173
+ # Remove the default proc that would create new entries
174
+ result.default_proc = nil
175
+ result
176
+ end
177
+
178
+ # Use this method to also load any irregular model name. This is smart
179
+ # enought to only load the sources present on this instance
180
+ def prepare_data_sources
181
+ super
182
+ @data_sources_model_names = Torque::PostgreSQL.config
183
+ .irregular_models.slice(*@data_sources.keys).map do |table_name, model_name|
184
+ [table_name, model_name.constantize]
185
+ end.to_h
186
+ end
187
+
188
+ end
189
+
190
+ ActiveRecord::ConnectionAdapters::SchemaCache.prepend SchemaCache
191
+ end
192
+ end
@@ -2,13 +2,60 @@ module Torque
2
2
  module PostgreSQL
3
3
  module SchemaDumper
4
4
 
5
- def extensions(stream)
5
+ def dump(stream) # :nodoc:
6
+ @connection.dump_mode!
7
+ super
8
+
9
+ @connection.dump_mode!
10
+ stream
11
+ end
12
+
13
+ def extensions(stream) # :nodoc:
6
14
  super
7
15
  user_defined_types(stream)
8
16
  end
9
17
 
10
18
  private
11
19
 
20
+ def tables(stream) # :nodoc:
21
+ inherited_tables = @connection.inherited_tables
22
+ sorted_tables = @connection.data_sources.sort - @connection.views
23
+
24
+ stream.puts " # These are the common tables managed"
25
+ (sorted_tables - inherited_tables.keys).each do |table_name|
26
+ table(table_name, stream) unless ignored?(table_name)
27
+ end
28
+
29
+ if inherited_tables.present?
30
+ stream.puts " # These are tables that has inheritance"
31
+ inherited_tables.each do |table_name, inherits|
32
+ unless ignored?(table_name)
33
+ sub_stream = StringIO.new
34
+ table(table_name, sub_stream)
35
+
36
+ # Add the inherits setting
37
+ sub_stream.rewind
38
+ inherits.map!(&:to_sym)
39
+ inherits = inherits.first if inherits.size === 1
40
+ inherits = ", inherits: #{inherits.inspect} do |t|"
41
+ table_dump = sub_stream.read.gsub(/ do \|t\|$/, inherits)
42
+
43
+ # Ensure bodyless definitions
44
+ table_dump.gsub!(/do \|t\|\n end/, '')
45
+ stream.print table_dump
46
+ end
47
+ end
48
+ end
49
+
50
+ # dump foreign keys at the end to make sure all dependent tables exist.
51
+ if @connection.supports_foreign_keys?
52
+ sorted_tables.each do |tbl|
53
+ foreign_keys(tbl, stream) unless ignored?(tbl)
54
+ end
55
+ end
56
+ end
57
+
58
+ # Dump user defined types like enum
12
59
  def user_defined_types(stream)
13
60
  types = @connection.user_defined_types
14
61
  return unless types.any?
@@ -25,6 +72,7 @@ module Torque
25
72
  stream.puts
26
73
  end
27
74
 
75
+ # Dump enum custom type
28
76
  def enum(name, stream)
29
77
  values = @connection.enum_values(name).map { |v| "\"#{v}\"" }
30
78
  stream.puts " create_enum \"#{name}\", [#{values.join(', ')}], force: :cascade"
@@ -1,5 +1,5 @@
1
1
  module Torque
2
2
  module PostgreSQL
3
- VERSION = '0.1.7'
3
+ VERSION = '0.2.1'
4
4
  end
5
5
  end
@@ -1,4 +1,5 @@
1
1
  require 'i18n'
2
+ require 'ostruct'
2
3
  require 'active_model'
3
4
  require 'active_record'
4
5
  require 'active_support'
@@ -11,15 +12,16 @@ require 'torque/postgresql/version'
11
12
  require 'torque/postgresql/collector'
12
13
 
13
14
  require 'torque/postgresql/i18n'
15
+ require 'torque/postgresql/arel'
14
16
  require 'torque/postgresql/adapter'
15
17
  require 'torque/postgresql/attributes'
16
18
  require 'torque/postgresql/auxiliary_statement'
17
19
  require 'torque/postgresql/base'
20
+ require 'torque/postgresql/inheritance'
21
+ require 'torque/postgresql/coder'
18
22
  require 'torque/postgresql/migration'
19
23
  require 'torque/postgresql/relation'
24
+ require 'torque/postgresql/schema_cache'
20
25
  require 'torque/postgresql/schema_dumper'
21
26
 
22
- gdep = Gem::Dependency.new('arel', '~> 9.0.0')
23
- unless gdep.matching_specs.sort_by(&:version).last
24
- require 'torque/postgresql/arel/visitors'
25
- end
27
+ require 'torque/postgresql/railtie' if defined?(Rails)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: torque-postgresql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carlos Silva
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-23 00:00:00.000000000 Z
11
+ date: 2018-08-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -37,9 +37,6 @@ dependencies:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
39
  version: '0.18'
40
- - - "<"
41
- - !ruby/object:Gem::Version
42
- version: '1.0'
43
40
  type: :runtime
44
41
  prerelease: false
45
42
  version_requirements: !ruby/object:Gem::Requirement
@@ -47,9 +44,6 @@ dependencies:
47
44
  - - ">="
48
45
  - !ruby/object:Gem::Version
49
46
  version: '0.18'
50
- - - "<"
51
- - !ruby/object:Gem::Version
52
- version: '1.0'
53
47
  - !ruby/object:Gem::Dependency
54
48
  name: rake
55
49
  requirement: !ruby/object:Gem::Requirement
@@ -179,6 +173,7 @@ extensions: []
179
173
  extra_rdoc_files: []
180
174
  files:
181
175
  - MIT-LICENSE
176
+ - README.rdoc
182
177
  - Rakefile
183
178
  - lib/torque-postgresql.rb
184
179
  - lib/torque/postgresql.rb
@@ -188,9 +183,14 @@ files:
188
183
  - lib/torque/postgresql/adapter/oid/enum.rb
189
184
  - lib/torque/postgresql/adapter/oid/interval.rb
190
185
  - lib/torque/postgresql/adapter/quoting.rb
186
+ - lib/torque/postgresql/adapter/schema_creation.rb
191
187
  - lib/torque/postgresql/adapter/schema_definitions.rb
192
188
  - lib/torque/postgresql/adapter/schema_dumper.rb
193
189
  - lib/torque/postgresql/adapter/schema_statements.rb
190
+ - lib/torque/postgresql/arel.rb
191
+ - lib/torque/postgresql/arel/join_source.rb
192
+ - lib/torque/postgresql/arel/select_manager.rb
193
+ - lib/torque/postgresql/arel/using.rb
194
194
  - lib/torque/postgresql/arel/visitors.rb
195
195
  - lib/torque/postgresql/attributes.rb
196
196
  - lib/torque/postgresql/attributes/builder.rb
@@ -201,14 +201,20 @@ files:
201
201
  - lib/torque/postgresql/auxiliary_statement.rb
202
202
  - lib/torque/postgresql/auxiliary_statement/settings.rb
203
203
  - lib/torque/postgresql/base.rb
204
+ - lib/torque/postgresql/coder.rb
204
205
  - lib/torque/postgresql/collector.rb
205
206
  - lib/torque/postgresql/config.rb
206
207
  - lib/torque/postgresql/i18n.rb
208
+ - lib/torque/postgresql/inheritance.rb
207
209
  - lib/torque/postgresql/migration.rb
208
210
  - lib/torque/postgresql/migration/command_recorder.rb
211
+ - lib/torque/postgresql/railtie.rb
209
212
  - lib/torque/postgresql/relation.rb
210
213
  - lib/torque/postgresql/relation/auxiliary_statement.rb
211
214
  - lib/torque/postgresql/relation/distinct_on.rb
215
+ - lib/torque/postgresql/relation/inheritance.rb
216
+ - lib/torque/postgresql/relation/merger.rb
217
+ - lib/torque/postgresql/schema_cache.rb
212
218
  - lib/torque/postgresql/schema_dumper.rb
213
219
  - lib/torque/postgresql/version.rb
214
220
  homepage: https://github.com/crashtech/torque-postgresql