torque-postgresql 0.1.7 → 0.2.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 (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