torque-postgresql 1.1.1 → 2.0.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 (72) hide show
  1. checksums.yaml +5 -5
  2. data/Rakefile +5 -2
  3. data/lib/torque/postgresql.rb +0 -2
  4. data/lib/torque/postgresql/adapter.rb +0 -1
  5. data/lib/torque/postgresql/adapter/database_statements.rb +4 -15
  6. data/lib/torque/postgresql/adapter/schema_creation.rb +13 -23
  7. data/lib/torque/postgresql/adapter/schema_definitions.rb +7 -21
  8. data/lib/torque/postgresql/adapter/schema_dumper.rb +71 -11
  9. data/lib/torque/postgresql/adapter/schema_statements.rb +2 -12
  10. data/lib/torque/postgresql/associations.rb +0 -3
  11. data/lib/torque/postgresql/associations/association_scope.rb +18 -61
  12. data/lib/torque/postgresql/associations/belongs_to_many_association.rb +2 -1
  13. data/lib/torque/postgresql/associations/preloader.rb +0 -24
  14. data/lib/torque/postgresql/associations/preloader/association.rb +13 -9
  15. data/lib/torque/postgresql/auxiliary_statement.rb +12 -17
  16. data/lib/torque/postgresql/coder.rb +1 -2
  17. data/lib/torque/postgresql/config.rb +0 -4
  18. data/lib/torque/postgresql/inheritance.rb +13 -17
  19. data/lib/torque/postgresql/reflection/abstract_reflection.rb +19 -25
  20. data/lib/torque/postgresql/relation.rb +11 -16
  21. data/lib/torque/postgresql/relation/auxiliary_statement.rb +9 -15
  22. data/lib/torque/postgresql/relation/distinct_on.rb +1 -1
  23. data/lib/torque/postgresql/schema_cache.rb +19 -11
  24. data/lib/torque/postgresql/version.rb +1 -1
  25. data/spec/en.yml +19 -0
  26. data/spec/factories/authors.rb +6 -0
  27. data/spec/factories/comments.rb +13 -0
  28. data/spec/factories/posts.rb +6 -0
  29. data/spec/factories/tags.rb +5 -0
  30. data/spec/factories/texts.rb +5 -0
  31. data/spec/factories/users.rb +6 -0
  32. data/spec/factories/videos.rb +5 -0
  33. data/spec/mocks/cache_query.rb +16 -0
  34. data/spec/mocks/create_table.rb +35 -0
  35. data/spec/models/activity.rb +3 -0
  36. data/spec/models/activity_book.rb +4 -0
  37. data/spec/models/activity_post.rb +7 -0
  38. data/spec/models/activity_post/sample.rb +4 -0
  39. data/spec/models/author.rb +4 -0
  40. data/spec/models/author_journalist.rb +4 -0
  41. data/spec/models/comment.rb +3 -0
  42. data/spec/models/course.rb +2 -0
  43. data/spec/models/geometry.rb +2 -0
  44. data/spec/models/guest_comment.rb +4 -0
  45. data/spec/models/post.rb +6 -0
  46. data/spec/models/tag.rb +2 -0
  47. data/spec/models/text.rb +2 -0
  48. data/spec/models/time_keeper.rb +2 -0
  49. data/spec/models/user.rb +8 -0
  50. data/spec/models/video.rb +2 -0
  51. data/spec/schema.rb +141 -0
  52. data/spec/spec_helper.rb +59 -0
  53. data/spec/tests/arel_spec.rb +72 -0
  54. data/spec/tests/auxiliary_statement_spec.rb +593 -0
  55. data/spec/tests/belongs_to_many_spec.rb +240 -0
  56. data/spec/tests/coder_spec.rb +367 -0
  57. data/spec/tests/collector_spec.rb +59 -0
  58. data/spec/tests/distinct_on_spec.rb +65 -0
  59. data/spec/tests/enum_set_spec.rb +306 -0
  60. data/spec/tests/enum_spec.rb +628 -0
  61. data/spec/tests/geometric_builder_spec.rb +221 -0
  62. data/spec/tests/has_many_spec.rb +390 -0
  63. data/spec/tests/interval_spec.rb +167 -0
  64. data/spec/tests/lazy_spec.rb +24 -0
  65. data/spec/tests/period_spec.rb +954 -0
  66. data/spec/tests/quoting_spec.rb +24 -0
  67. data/spec/tests/range_spec.rb +36 -0
  68. data/spec/tests/relation_spec.rb +57 -0
  69. data/spec/tests/table_inheritance_spec.rb +416 -0
  70. metadata +103 -16
  71. data/lib/torque/postgresql/associations/join_dependency/join_association.rb +0 -15
  72. data/lib/torque/postgresql/schema_dumper.rb +0 -88
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: b95a55ebfe82e5b96582da09307f1d45d62ba922
4
- data.tar.gz: 38a068ec3fa7cc5aab2425a31e8ed37a49b15132
2
+ SHA256:
3
+ metadata.gz: 4164165e64b027d11997dde286684b27bd77c33634e3eb84c6f1c757b5d814a0
4
+ data.tar.gz: 8bf196d92b261661631ceb02f2ab7600a8a6cec5cacc43fa69b0c300afb65582
5
5
  SHA512:
6
- metadata.gz: b708c73cfcac1798474e35099570e4def16a6a51b2448ef34ce2ec5e97dd4c8d57f48fa51f18182f0405afa7eed1884b81846cb3b2e132b638c8711ee80dd72c
7
- data.tar.gz: 7bab6bd30e0b3898826b20cce99ff629192ea62d772864e10a3fc141e86e5f3f27a0f9e459addc29a8a27bcbb7df17920831d0f7e7b01ac823d65f600b699530
6
+ metadata.gz: 7e44fd4215ba1ef9d2aebf8d6a5c285266f0bb64544a2a74d36773aaaa8e57c5776c3260183352accf76f81e94edcba27ffa898145e4d0bb467f5097ce7e7467
7
+ data.tar.gz: 9c8acb15a0e78f33e8da372dcffc0e1a3e238631d01932056e5e48392801ec3706c3168a138944e5ebe7b80222f2f962e32af043a91c29235b6e824e02b70bbc
data/Rakefile CHANGED
@@ -14,13 +14,16 @@ RDoc::Task.new(:rdoc) do |rdoc|
14
14
  rdoc.rdoc_files.include('lib/**/*.rb')
15
15
  end
16
16
 
17
- desc 'Prints a schema dump of the test database'
18
- task :dump do |t|
17
+ desc 'Initialize the local environment'
18
+ task :environment do |t|
19
19
  lib = File.expand_path('../lib', __FILE__)
20
20
  spec = File.expand_path('../spec', __FILE__)
21
21
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
22
22
  $LOAD_PATH.unshift(spec) unless $LOAD_PATH.include?(spec)
23
+ end
23
24
 
25
+ desc 'Prints a schema dump of the test database'
26
+ task dump: :environment do |t|
24
27
  require 'byebug'
25
28
  require 'spec_helper'
26
29
  ActiveRecord::SchemaDumper.dump
@@ -6,7 +6,6 @@ require 'active_support'
6
6
 
7
7
  require 'active_support/core_ext/date/acts_like'
8
8
  require 'active_support/core_ext/time/zones'
9
- require 'active_support/core_ext/hash/compact'
10
9
  require 'active_record/connection_adapters/postgresql_adapter'
11
10
 
12
11
  require 'torque/postgresql/config'
@@ -28,6 +27,5 @@ require 'torque/postgresql/migration'
28
27
  require 'torque/postgresql/relation'
29
28
  require 'torque/postgresql/reflection'
30
29
  require 'torque/postgresql/schema_cache'
31
- require 'torque/postgresql/schema_dumper'
32
30
 
33
31
  require 'torque/postgresql/railtie' if defined?(Rails)
@@ -10,7 +10,6 @@ module Torque
10
10
  module PostgreSQL
11
11
  module Adapter
12
12
  include Quoting
13
- include ColumnDumper unless Torque::PostgreSQL::AR521
14
13
  include DatabaseStatements
15
14
  include SchemaStatements
16
15
 
@@ -43,16 +43,9 @@ module Torque
43
43
  end
44
44
 
45
45
  # :nodoc:
46
- if Torque::PostgreSQL::AR521
47
- def load_additional_types(oids = nil)
48
- super
49
- torque_load_additional_types(oids)
50
- end
51
- else
52
- def load_additional_types(type_map, oids = nil)
53
- super
54
- torque_load_additional_types(oids)
55
- end
46
+ def load_additional_types(oids = nil)
47
+ super
48
+ torque_load_additional_types(oids)
56
49
  end
57
50
 
58
51
  # Add the composite types to be loaded too.
@@ -80,11 +73,7 @@ module Torque
80
73
  SQL
81
74
 
82
75
  execute_and_clear(query, 'SCHEMA', []) do |records|
83
- records.each do |row|
84
- case row['typtype']
85
- when 'e' then OID::Enum.create(row, type_map)
86
- end
87
- end
76
+ records.each { |row| OID::Enum.create(row, type_map) }
88
77
  end
89
78
  end
90
79
 
@@ -5,10 +5,11 @@ module Torque
5
5
 
6
6
  # Redefine original table creation command to ensure PostgreSQL standard
7
7
  def visit_TableDefinition(o)
8
- create_sql = "CREATE#{' TEMPORARY' if o.temporary}"
9
- create_sql << " TABLE #{quote_table_name(o.name)}"
8
+ create_sql = +"CREATE#{table_modifier_in_create(o)} TABLE "
9
+ create_sql << "IF NOT EXISTS " if o.if_not_exists
10
+ create_sql << "#{quote_table_name(o.name)} "
10
11
 
11
- statements = o.columns.map{ |c| accept c }
12
+ statements = o.columns.map { |c| accept c }
12
13
  statements << accept(o.primary_keys) if o.primary_keys
13
14
 
14
15
  if supports_indexes_in_create?
@@ -17,36 +18,25 @@ module Torque
17
18
  end)
18
19
  end
19
20
 
20
- if supports_foreign_keys_in_create?
21
+ if supports_foreign_keys?
21
22
  statements.concat(o.foreign_keys.map do |to_table, options|
22
23
  foreign_key_in_create(o.name, to_table, options)
23
24
  end)
24
25
  end
25
26
 
26
- if o.as
27
- create_sql << " AS #{@conn.to_sql(o.as)}"
28
- else
29
- create_sql << " (#{statements.join(', ')})"
30
- add_table_options!(create_sql, table_options(o))
27
+ create_sql << "(#{statements.join(', ')})" \
28
+ if statements.present? || o.inherits.present?
31
29
 
32
- if o.inherits.present?
33
- tables = o.inherits.map(&method(:quote_table_name))
34
- create_sql << " INHERITS ( #{tables.join(' , ')} )"
35
- end
30
+ add_table_options!(create_sql, table_options(o))
31
+
32
+ if o.inherits.present?
33
+ tables = o.inherits.map(&method(:quote_table_name))
34
+ create_sql << " INHERITS ( #{tables.join(' , ')} )"
36
35
  end
37
36
 
37
+ create_sql << " AS #{to_sql(o.as)}" if o.as
38
38
  create_sql
39
39
  end
40
-
41
- # Keep rails 5.0 and 5.1 compatibility
42
- def supports_foreign_keys_in_create?
43
- if defined?(super)
44
- super
45
- else
46
- supports_foreign_keys?
47
- end
48
- end
49
-
50
40
  end
51
41
 
52
42
  ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaCreation.prepend SchemaCreation
@@ -7,17 +7,15 @@ module Torque
7
7
  # dates to be stored without having to store a seconds-based integer
8
8
  # or any sort of other approach
9
9
  def interval(*args, **options)
10
- args.each { |name| column(name, :interval, options) }
10
+ args.each { |name| column(name, :interval, **options) }
11
11
  end
12
12
 
13
13
  # Creates a column with an enum type, needing to specify the subtype,
14
14
  # which is basically the name of the type defined prior creating the
15
15
  # column
16
16
  def enum(*args, **options)
17
- args.each do |name|
18
- type = options.fetch(:subtype, name)
19
- column(name, type, options)
20
- end
17
+ subtype = options.delete(:subtype)
18
+ args.each { |name| column(name, (subtype || name), **options) }
21
19
  end
22
20
 
23
21
  # Creates a column with an enum array type, needing to specify the
@@ -34,23 +32,11 @@ module Torque
34
32
 
35
33
  attr_reader :inherits
36
34
 
37
- def initialize(name, *_, **options)
38
- old_args = []
39
- old_args << options.delete(:temporary) || false
40
- old_args << options.delete(:options)
41
- old_args << options.delete(:as)
42
- comment = options.delete(:comment)
35
+ def initialize(*args, **options)
36
+ super
43
37
 
44
- super(name, *old_args, comment: comment)
45
-
46
- if options.key?(:inherits)
47
- @inherits = Array[options.delete(:inherits)].flatten.compact
48
- @inherited_id = !(options.key?(:primary_key) || options.key?(:id))
49
- end
50
- end
51
-
52
- def inherited_id?
53
- @inherited_id
38
+ @inherits = Array.wrap(options.delete(:inherits)).flatten.compact \
39
+ if options.key?(:inherits)
54
40
  end
55
41
  end
56
42
 
@@ -1,22 +1,23 @@
1
1
  module Torque
2
2
  module PostgreSQL
3
3
  module Adapter
4
- module ColumnDumper
4
+ module SchemaDumper
5
+ def dump(stream) # :nodoc:
6
+ @connection.dump_mode!
7
+ super
5
8
 
6
- # Adds +:subtype+ as a valid migration key
7
- unless Torque::PostgreSQL::AR521
8
- def migration_keys
9
- super + [:subtype]
10
- end
9
+ @connection.dump_mode!
10
+ stream
11
+ end
12
+
13
+ def extensions(stream) # :nodoc:
14
+ super
15
+ user_defined_types(stream)
11
16
  end
12
17
 
13
18
  # Translate +:enum_set+ into +:enum+
14
19
  def schema_type(column)
15
- if column.type == :enum_set
16
- :enum
17
- else
18
- super
19
- end
20
+ column.type == :enum_set ? :enum : super
20
21
  end
21
22
 
22
23
  # Adds +:subtype+ option to the default set
@@ -36,7 +37,66 @@ module Torque
36
37
  column.sql_type.to_sym.inspect if column.type == :enum || column.type == :enum_set
37
38
  end
38
39
 
40
+ def tables(stream) # :nodoc:
41
+ inherited_tables = @connection.inherited_tables
42
+ sorted_tables = @connection.data_sources.sort - @connection.views
43
+
44
+ stream.puts " # These are the common tables managed"
45
+ (sorted_tables - inherited_tables.keys).each do |table_name|
46
+ table(table_name, stream) unless ignored?(table_name)
47
+ end
48
+
49
+ if inherited_tables.present?
50
+ stream.puts " # These are tables that has inheritance"
51
+ inherited_tables.each do |table_name, inherits|
52
+ next if ignored?(table_name)
53
+
54
+ sub_stream = StringIO.new
55
+ table(table_name, sub_stream)
56
+
57
+ # Add the inherits setting
58
+ sub_stream.rewind
59
+ inherits.map!(&:to_sym)
60
+ inherits = inherits.first if inherits.size === 1
61
+ inherits = ", inherits: #{inherits.inspect} do |t|"
62
+ table_dump = sub_stream.read.gsub(/ do \|t\|$/, inherits)
63
+
64
+ # Ensure bodyless definitions
65
+ table_dump.gsub!(/do \|t\|\n end/, '')
66
+ stream.print table_dump
67
+ end
68
+ end
69
+
70
+ # dump foreign keys at the end to make sure all dependent tables exist.
71
+ if @connection.supports_foreign_keys?
72
+ sorted_tables.each do |tbl|
73
+ foreign_keys(tbl, stream) unless ignored?(tbl)
74
+ end
75
+ end
76
+ end
77
+
78
+ # Dump user defined types like enum
79
+ def user_defined_types(stream)
80
+ types = @connection.user_defined_types('e')
81
+ return unless types.any?
82
+
83
+ stream.puts " # These are user-defined types used on this database"
84
+ types.sort_by(&:first).each { |(name, type)| send(type.to_sym, name, stream) }
85
+ stream.puts
86
+ rescue => e
87
+ stream.puts "# Could not dump user-defined types because of following #{e.class}"
88
+ stream.puts "# #{e.message}"
89
+ stream.puts
90
+ end
91
+
92
+ # Dump enum custom type
93
+ def enum(name, stream)
94
+ values = @connection.enum_values(name).map { |v| "\"#{v}\"" }
95
+ stream.puts " create_enum \"#{name}\", [#{values.join(', ')}], force: :cascade"
96
+ end
39
97
  end
98
+
99
+ ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaDumper.prepend SchemaDumper
40
100
  end
41
101
  end
42
102
  end
@@ -73,24 +73,14 @@ module Torque
73
73
 
74
74
  # Rewrite the method that creates tables to easily accept extra options
75
75
  def create_table(table_name, **options, &block)
76
- td = create_table_definition(table_name, **options)
77
- options[:id] = false if td.inherited_id?
78
- options[:temporary] = td
76
+ options[:id] = false if options[:inherits].present? &&
77
+ options[:primary_key].blank? && options[:id].blank?
79
78
 
80
79
  super table_name, **options, &block
81
80
  end
82
81
 
83
82
  private
84
83
 
85
- # This waits for the second call to really return the table definition
86
- def create_table_definition(*args, **options) # :nodoc:
87
- if !args.second.kind_of?(TableDefinition)
88
- TableDefinition.new(*args, **options)
89
- else
90
- args.second
91
- end
92
- end
93
-
94
84
  def quote_enum_values(name, values, options)
95
85
  prefix = options[:prefix]
96
86
  prefix = name if prefix === true
@@ -3,6 +3,3 @@ require_relative 'associations/association_scope'
3
3
  require_relative 'associations/belongs_to_many_association'
4
4
  require_relative 'associations/builder'
5
5
  require_relative 'associations/preloader'
6
-
7
- require_relative 'associations/join_dependency/join_association' \
8
- unless Torque::PostgreSQL::AR521
@@ -14,64 +14,40 @@ module Torque
14
14
  # When the relation is connected through an array, intercept the
15
15
  # condition builder and uses an overlap condition building it on
16
16
  # +build_id_constraint+
17
- def last_chain_scope(scope, *args)
18
- # 5.0 table, reflection, owner, association_klass
19
- # 5.1 table, reflection, owner
20
- # 5.2 reflection, owner
21
-
22
- reflection = args.size.eql?(2) ? args[0] : args[1]
23
- puts reflection.connected_through_array?.inspect
17
+ def last_chain_scope(scope, reflection, owner)
24
18
  return super unless reflection.connected_through_array?
25
19
 
26
- table = args[0] if args.size > 2
27
- keys = args.size.eql?(4) ? reflection.join_keys(args[3]) : reflection.join_keys
28
- owner = args.size.eql?(2) ? args[1] : args[2]
29
-
20
+ keys = reflection.join_keys
30
21
  value = transform_value(owner[keys.foreign_key])
31
- constraint, binds = build_id_constraint(reflection, keys, value, table, true)
22
+ constraint = build_id_constraint(reflection, keys, value, true)
32
23
 
33
- if Torque::PostgreSQL::AR521
34
- scope.where!(constraint)
35
- else
36
- klass = ::ActiveRecord::Relation::WhereClause
37
- scope.where_clause += klass.new([constraint], binds)
38
- scope
39
- end
24
+ scope.where!(constraint)
40
25
  end
41
26
 
42
27
  # When the relation is connected through an array, intercept the
43
28
  # condition builder and uses an overlap condition building it on
44
29
  # +build_id_constraint+
45
- def next_chain_scope(scope, *args)
46
- # 5.0 table, reflection, association_klass, foreign_table, next_reflection
47
- # 5.1 table, reflection, foreign_table, next_reflection
48
- # 5.2 reflection, next_reflection
49
-
50
- reflection = args.size.eql?(2) ? args[0] : args[1]
30
+ def next_chain_scope(scope, reflection, next_reflection)
51
31
  return super unless reflection.connected_through_array?
52
32
 
53
- table = args[0] if args.size > 2
54
- next_reflection = args[-1]
55
-
56
- foreign_table = args[-2] if args.size.eql?(5)
57
- foreign_table ||= next_reflection.aliased_table
58
-
59
- keys = args.size.eql?(5) ? reflection.join_keys(args[2]) : reflection.join_keys
33
+ keys = reflection.join_keys
34
+ foreign_table = next_reflection.aliased_table
60
35
 
61
36
  value = foreign_table[keys.foreign_key]
62
- constraint, *_ = build_id_constraint(reflection, keys, value, table)
37
+ constraint = build_id_constraint(reflection, keys, value)
63
38
 
64
39
  scope.joins!(join(foreign_table, constraint))
65
40
  end
66
41
 
67
42
  # Trigger the same method on the relation which will build the
68
43
  # constraint condition using array logics
69
- def build_id_constraint(reflection, keys, value, table = nil, bind_param = false)
70
- table ||= reflection.aliased_table
71
- value, binds = build_binds_for_constraint(reflection, value, keys.foreign_key) \
72
- if bind_param
44
+ def build_id_constraint(reflection, keys, value, bind_param = false)
45
+ table = reflection.aliased_table
46
+ value = Array.wrap(value).map do |value|
47
+ build_bind_param_for_constraint(reflection, value, keys.foreign_key)
48
+ end if bind_param
73
49
 
74
- [reflection.build_id_constraint(table[keys.key], value), binds]
50
+ reflection.build_id_constraint(table[keys.key], value)
75
51
  end
76
52
 
77
53
  # For array-like values, it needs to call the method as many times as
@@ -84,30 +60,11 @@ module Torque
84
60
  end
85
61
  end
86
62
 
87
- # When binds are necessary for a constraint, instantiate them
88
- if Torque::PostgreSQL::AR521
89
- def build_binds_for_constraint(reflection, values, foreign_key)
90
- result = Array.wrap(values).map do |value|
91
- ::Arel::Nodes::BindParam.new(::ActiveRecord::Relation::QueryAttribute.new(
92
- foreign_key, value, reflection.klass.attribute_types[foreign_key],
93
- ))
94
- end
95
-
96
- [result, nil]
97
- end
98
- else
99
- def build_binds_for_constraint(reflection, values, foreign_key)
100
- type = reflection.klass.attribute_types[foreign_key]
101
- parts = Array.wrap(values).map do |value|
102
- bind = ::Arel::Nodes::BindParam.new
103
- value = ::ActiveRecord::Relation::QueryAttribute.new(foreign_key, value, type)
104
- [bind, value]
105
- end.to_h
106
-
107
- [parts.keys, parts.values]
108
- end
63
+ def build_bind_param_for_constraint(reflection, value, foreign_key)
64
+ ::Arel::Nodes::BindParam.new(::ActiveRecord::Relation::QueryAttribute.new(
65
+ foreign_key, value, reflection.klass.attribute_types[foreign_key],
66
+ ))
109
67
  end
110
-
111
68
  end
112
69
 
113
70
  ::ActiveRecord::Associations::AssociationScope.singleton_class.prepend(AssociationScope::ClassMethods)