torque-postgresql 2.2.4 → 2.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 95fa82a4869d180b12518b184191e6877b9e6cf3108fb5e68e55d6a836809389
4
- data.tar.gz: 45c6e24a30b3782ec26ff5caafe01430c24f137c460eb19b6f2a49e0b6609142
3
+ metadata.gz: c2a382953b6a3c1d87e05837454cdf523f4be237fdd66c85f0b155278eafa203
4
+ data.tar.gz: e72effb133a0ae945b85b1d46de72b16a098eb1d469f3720926b0267e7f3c11b
5
5
  SHA512:
6
- metadata.gz: cd7e925ab13b8ae3eb6f0d92fbb994f12c6c121998792263b0752eb9647c0d2e4f72dec8d3973c6e0365fe0c5194a2af5fba9189189743c5bca7b06a4e6dfa41
7
- data.tar.gz: 470bb4e8b0816318ca5ee1b99e1896a8a4f3297af46e653de4ddac5347cf40a781b530a4e2531cf41eae38f7205332e52ced09e5b857a618f965851a6d9d7162
6
+ metadata.gz: 554eb1ae3c30abd27acbbd9ce7e2f78d37e42c730ed811b5d617209cbb12a2c1bd34163f63ab25273f542e1cb6bfc36ee6d64484fd66f8a5b489e4aaea6ae628
7
+ data.tar.gz: d018ee26970f64a83e552f1929e55e281235054064771a851e5b4fc714e69a95e6247e95338deffe8b1732d6ae2dad1bc2b5602146a1c4fb4d763ad19fc13c97
data/README.rdoc CHANGED
@@ -128,6 +128,23 @@ reconfigured on the model, and then can be used during querying process.
128
128
 
129
129
  {Learn more}[link:classes/Torque/PostgreSQL/AuxiliaryStatement.html]
130
130
 
131
+ * Multiple Schemas
132
+
133
+ Allows models and modules to have a schema associated with them, so that
134
+ developers can better organize their tables into schemas and build features in
135
+ a way that the database can better represent how they are separated.
136
+
137
+ create_schema "internal", force: :cascade
138
+
139
+ module Internal
140
+ class User < ActiveRecord::Base
141
+ self.schema = 'internal'
142
+ end
143
+ end
144
+
145
+ Internal::User.all
146
+
147
+ {Learn more}[link:classes/Torque/PostgreSQL/Adapter/DatabaseStatements.html]
131
148
 
132
149
  == Download and installation
133
150
 
@@ -12,6 +12,26 @@ module Torque
12
12
  @_dump_mode = !!!@_dump_mode
13
13
  end
14
14
 
15
+ # List of schemas blocked by the application in the current connection
16
+ def schemas_blacklist
17
+ @schemas_blacklist ||= Torque::PostgreSQL.config.schemas.blacklist +
18
+ (@config.dig(:schemas, 'blacklist') || [])
19
+ end
20
+
21
+ # List of schemas used by the application in the current connection
22
+ def schemas_whitelist
23
+ @schemas_whitelist ||= Torque::PostgreSQL.config.schemas.whitelist +
24
+ (@config.dig(:schemas, 'whitelist') || [])
25
+ end
26
+
27
+ # A list of schemas on the search path sanitized
28
+ def schemas_search_path_sanitized
29
+ @schemas_search_path_sanitized ||= begin
30
+ db_user = @config[:username] || ENV['USER'] || ENV['USERNAME']
31
+ schema_search_path.split(',').map { |item| item.strip.sub('"$user"', db_user) }
32
+ end
33
+ end
34
+
15
35
  # Check if a given type is valid.
16
36
  def valid_type?(type)
17
37
  super || extended_types.include?(type)
@@ -22,6 +42,17 @@ module Torque
22
42
  EXTENDED_DATABASE_TYPES
23
43
  end
24
44
 
45
+ # Checks if a given schema exists in the database. If +filtered+ is
46
+ # given as false, then it will check regardless of whitelist and
47
+ # blacklist
48
+ def schema_exists?(name, filtered: true)
49
+ return user_defined_schemas.include?(name.to_s) if filtered
50
+
51
+ query_value(<<-SQL) == 1
52
+ SELECT 1 FROM pg_catalog.pg_namespace WHERE nspname = '#{name}'
53
+ SQL
54
+ end
55
+
25
56
  # Returns true if type exists.
26
57
  def type_exists?(name)
27
58
  user_defined_types.key? name.to_s
@@ -115,18 +146,41 @@ module Torque
115
146
  # Get the list of inherited tables associated with their parent tables
116
147
  def inherited_tables
117
148
  tables = query(<<-SQL, 'SCHEMA')
118
- SELECT child.relname AS table_name,
119
- array_agg(parent.relname) AS inheritances
149
+ SELECT inhrelid::regclass AS table_name,
150
+ inhparent::regclass AS inheritances
120
151
  FROM pg_inherits
121
152
  JOIN pg_class parent ON pg_inherits.inhparent = parent.oid
122
153
  JOIN pg_class child ON pg_inherits.inhrelid = child.oid
123
- GROUP BY child.relname, pg_inherits.inhrelid
124
- ORDER BY pg_inherits.inhrelid
154
+ ORDER BY inhrelid
125
155
  SQL
126
156
 
127
- tables.map do |(table, refs)|
128
- [table, PG::TextDecoder::Array.new.decode(refs)]
129
- end.to_h
157
+ tables.each_with_object({}) do |(child, parent), result|
158
+ (result[child] ||= []) << parent
159
+ end
160
+ end
161
+
162
+ # Get the list of schemas that were created by the user
163
+ def user_defined_schemas
164
+ query_values(user_defined_schemas_sql, 'SCHEMA')
165
+ end
166
+
167
+ # Build the query for allowed schemas
168
+ def user_defined_schemas_sql
169
+ conditions = []
170
+ conditions << <<-SQL if schemas_blacklist.any?
171
+ nspname NOT LIKE ANY (ARRAY['#{schemas_blacklist.join("', '")}'])
172
+ SQL
173
+
174
+ conditions << <<-SQL if schemas_whitelist.any?
175
+ nspname LIKE ANY (ARRAY['#{schemas_whitelist.join("', '")}'])
176
+ SQL
177
+
178
+ <<-SQL.squish
179
+ SELECT nspname
180
+ FROM pg_catalog.pg_namespace
181
+ WHERE 1=1 AND #{conditions.join(' AND ')}
182
+ ORDER BY oid
183
+ SQL
130
184
  end
131
185
 
132
186
  # Get the list of columns, and their definition, but only from the
@@ -14,6 +14,7 @@ module Torque
14
14
 
15
15
  def extensions(stream) # :nodoc:
16
16
  super
17
+ user_defined_schemas(stream)
17
18
  user_defined_types(stream)
18
19
  end
19
20
 
@@ -41,7 +42,9 @@ module Torque
41
42
 
42
43
  def tables(stream) # :nodoc:
43
44
  inherited_tables = @connection.inherited_tables
44
- sorted_tables = @connection.tables.sort - @connection.views
45
+ sorted_tables = (@connection.tables - @connection.views).sort_by do |table_name|
46
+ table_name.split(/(?:public)?\./).reverse
47
+ end
45
48
 
46
49
  stream.puts " # These are the common tables"
47
50
  (sorted_tables - inherited_tables.keys).each do |table_name|
@@ -58,7 +61,7 @@ module Torque
58
61
 
59
62
  # Add the inherits setting
60
63
  sub_stream.rewind
61
- inherits.map!(&:to_sym)
64
+ inherits.map! { |parent| parent.to_s.sub(/\Apublic\./, '') }
62
65
  inherits = inherits.first if inherits.size === 1
63
66
  inherits = ", inherits: #{inherits.inspect} do |t|"
64
67
  table_dump = sub_stream.read.gsub(/ do \|t\|$/, inherits)
@@ -84,6 +87,20 @@ module Torque
84
87
  triggers(stream) if defined?(::Fx::SchemaDumper::Trigger)
85
88
  end
86
89
 
90
+ # Make sure to remove the schema from the table name
91
+ def remove_prefix_and_suffix(table)
92
+ super(table.sub(/\A[a-z0-9_]*\./, ''))
93
+ end
94
+
95
+ # Dump user defined schemas
96
+ def user_defined_schemas(stream)
97
+ return if (list = (@connection.user_defined_schemas - ['public'])).empty?
98
+
99
+ stream.puts " # Custom schemas defined in this database."
100
+ list.each { |name| stream.puts " create_schema \"#{name}\", force: :cascade" }
101
+ stream.puts
102
+ end
103
+
87
104
  # Dump user defined types like enum
88
105
  def user_defined_types(stream)
89
106
  types = @connection.user_defined_types('e')
@@ -7,6 +7,21 @@ module Torque
7
7
 
8
8
  TableDefinition = ActiveRecord::ConnectionAdapters::PostgreSQL::TableDefinition
9
9
 
10
+ # Create a new schema
11
+ def create_schema(name, options = {})
12
+ drop_schema(name, options) if options[:force]
13
+
14
+ check = 'IF NOT EXISTS' if options.fetch(:check, true)
15
+ execute("CREATE SCHEMA #{check} #{quote_schema_name(name.to_s)}")
16
+ end
17
+
18
+ # Drop an existing schema
19
+ def drop_schema(name, options = {})
20
+ force = options.fetch(:force, '').upcase
21
+ check = 'IF EXISTS' if options.fetch(:check, true)
22
+ execute("DROP SCHEMA #{check} #{quote_schema_name(name.to_s)} #{force}")
23
+ end
24
+
10
25
  # Drops a type.
11
26
  def drop_type(name, options = {})
12
27
  force = options.fetch(:force, '').upcase
@@ -79,12 +94,37 @@ module Torque
79
94
 
80
95
  # Rewrite the method that creates tables to easily accept extra options
81
96
  def create_table(table_name, **options, &block)
97
+ table_name = "#{options[:schema]}.#{table_name}" if options[:schema].present?
98
+
82
99
  options[:id] = false if options[:inherits].present? &&
83
100
  options[:primary_key].blank? && options[:id].blank?
84
101
 
85
102
  super table_name, **options, &block
86
103
  end
87
104
 
105
+ # Add the schema option when extracting table options
106
+ def table_options(table_name)
107
+ parts = table_name.split('.').reverse
108
+ return super unless parts.size == 2 && parts[1] != 'public'
109
+
110
+ (super || {}).merge(schema: parts[1])
111
+ end
112
+
113
+ # When dumping the schema we need to add all schemas, not only those
114
+ # active for the current +schema_search_path+
115
+ def quoted_scope(name = nil, type: nil)
116
+ return super unless name.nil?
117
+
118
+ super.merge(schema: "ANY ('{#{user_defined_schemas.join(',')}}')")
119
+ end
120
+
121
+ # Fix the query to include the schema on tables names when dumping
122
+ def data_source_sql(name = nil, type: nil)
123
+ return super unless name.nil?
124
+
125
+ super.sub('SELECT c.relname FROM', "SELECT n.nspname || '.' || c.relname FROM")
126
+ end
127
+
88
128
  private
89
129
 
90
130
  def quote_enum_values(name, values, options)
@@ -31,9 +31,9 @@ module Torque
31
31
  )
32
32
  end
33
33
 
34
- # Add `inherits` to the list of extracted table options
34
+ # Add `inherits` and `schema` to the list of extracted table options
35
35
  def extract_table_options!(options)
36
- super.merge(options.extract!(:inherits))
36
+ super.merge(options.extract!(:inherits, :schema))
37
37
  end
38
38
 
39
39
  # Allow filtered bulk insert by adding the where clause. This method is
@@ -5,15 +5,27 @@ module Torque
5
5
  module Base
6
6
  extend ActiveSupport::Concern
7
7
 
8
+ ##
9
+ # :singleton-method: schema
10
+ # :call-seq: schema
11
+ #
12
+ # The schema to which the table belongs to.
13
+
8
14
  included do
9
15
  mattr_accessor :belongs_to_many_required_by_default, instance_accessor: false
16
+ class_attribute :schema, instance_writer: false
10
17
  end
11
18
 
12
19
  module ClassMethods
13
20
  delegate :distinct_on, :with, :itself_only, :cast_records, to: :all
14
21
 
15
- # Wenever it's inherited, add a new list of auxiliary statements
16
- # It also adds an auxiliary statement to load inherited records' relname
22
+ # Make sure that table name is an instance of TableName class
23
+ def reset_table_name
24
+ self.table_name = TableName.new(self, super)
25
+ end
26
+
27
+ # Whenever the base model is inherited, add a list of auxiliary
28
+ # statements like the one that loads inherited records' relname
17
29
  def inherited(subclass)
18
30
  super
19
31
 
@@ -24,6 +36,11 @@ module Torque
24
36
 
25
37
  # Define helper methods to return the class of the given records
26
38
  subclass.auxiliary_statement record_class do |cte|
39
+ ActiveSupport::Deprecation.warn(<<~MSG.squish)
40
+ Inheritance does not use this auxiliary statement and it can be removed.
41
+ You can replace it with `model.select_extra_values << 'tableoid::regclass'`.
42
+ MSG
43
+
27
44
  pg_class = ::Arel::Table.new('pg_class')
28
45
  arel_query = ::Arel::SelectManager.new(pg_class)
29
46
  arel_query.project(pg_class['oid'], pg_class['relname'].as(record_class.to_s))
@@ -36,18 +53,11 @@ module Torque
36
53
  # Define the dynamic attribute that returns the same information as
37
54
  # the one provided by the auxiliary statement
38
55
  subclass.dynamic_attribute(record_class) do
39
- next self.class.table_name unless self.class.physically_inheritances?
40
-
41
- pg_class = ::Arel::Table.new('pg_class')
42
- source = ::Arel::Table.new(subclass.table_name, as: 'source')
43
- quoted_id = ::Arel::Nodes::Quoted.new(id)
44
-
45
- query = ::Arel::SelectManager.new(pg_class)
46
- query.join(source).on(pg_class['oid'].eq(source['tableoid']))
47
- query.where(source[subclass.primary_key].eq(quoted_id))
48
- query.project(pg_class['relname'])
56
+ klass = self.class
57
+ next klass.table_name unless klass.physically_inheritances?
49
58
 
50
- self.class.connection.select_value(query)
59
+ query = klass.unscoped.where(subclass.primary_key => id)
60
+ query.pluck(klass.arel_table['tableoid'].cast('regclass')).first
51
61
  end
52
62
  end
53
63
 
@@ -40,6 +40,19 @@ module Torque
40
40
  end.to_h
41
41
  end
42
42
 
43
+ # Configure multiple schemas
44
+ config.nested(:schemas) do |schemas|
45
+
46
+ # Defines a list of LIKE-based schemas to not consider for a multiple
47
+ # schema database
48
+ schemas.blacklist = %w[information_schema pg_%]
49
+
50
+ # Defines a list of LIKE-based schemas to consider for a multiple schema
51
+ # database
52
+ schemas.whitelist = %w[public]
53
+
54
+ end
55
+
43
56
  # Configure associations features
44
57
  config.nested(:associations) do |assoc|
45
58
 
@@ -5,16 +5,26 @@ module Torque
5
5
  module Migration
6
6
  module CommandRecorder
7
7
 
8
- # Records the rename operation for types.
8
+ # Records the rename operation for types
9
9
  def rename_type(*args, &block)
10
10
  record(:rename_type, args, &block)
11
11
  end
12
12
 
13
- # Inverts the type name.
13
+ # Inverts the type rename operation
14
14
  def invert_rename_type(args)
15
15
  [:rename_type, args.reverse]
16
16
  end
17
17
 
18
+ # Records the creation of a schema
19
+ def create_schema(*args, &block)
20
+ record(:create_schema, args, &block)
21
+ end
22
+
23
+ # Inverts the creation of a schema
24
+ def invert_create_schema(args)
25
+ [:drop_schema, [args.first]]
26
+ end
27
+
18
28
  # Records the creation of the enum to be reverted.
19
29
  def create_enum(*args, &block)
20
30
  record(:create_enum, args, &block)
@@ -117,6 +117,12 @@ module Torque
117
117
  scopes = scoped_class.scan(/(?:::)?[A-Z][a-z]+/)
118
118
  scopes.unshift('Object::')
119
119
 
120
+ # Check if the table name comes with a schema
121
+ if table_name.include?('.')
122
+ schema, table_name = table_name.split('.')
123
+ scopes.insert(1, schema.camelize) if schema != 'public'
124
+ end
125
+
120
126
  # Consider the maximum namespaced possible model name
121
127
  max_name = table_name.tr('_', '/').camelize.split(/(::)/)
122
128
  max_name[-1] = max_name[-1].singularize
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Torque
4
+ module PostgreSQL
5
+ class TableName < Delegator
6
+ def initialize(klass, table_name)
7
+ @klass = klass
8
+ @table_name = table_name
9
+ end
10
+
11
+ def schema
12
+ return @schema if defined?(@schema)
13
+
14
+ @schema = ([@klass] + @klass.module_parents[0..-2]).find do |klass|
15
+ next unless klass.respond_to?(:schema)
16
+ break klass.schema
17
+ end
18
+ end
19
+
20
+ def to_s
21
+ schema.nil? ? @table_name : "#{schema}.#{@table_name}"
22
+ end
23
+
24
+ alias __getobj__ to_s
25
+
26
+ def ==(other)
27
+ other.to_s =~ /("?#{schema | search_path_schemes.join('|')}"?\.)?"?#{@table_name}"?/
28
+ end
29
+
30
+ def __setobj__(value)
31
+ @table_name = value
32
+ end
33
+
34
+ private
35
+
36
+ def search_path_schemes
37
+ klass.connection.schemas_search_path_sanitized
38
+ end
39
+ end
40
+ end
41
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Torque
4
4
  module PostgreSQL
5
- VERSION = '2.2.4'
5
+ VERSION = '2.3.0'
6
6
  end
7
7
  end
@@ -20,12 +20,13 @@ require 'torque/postgresql/associations'
20
20
  require 'torque/postgresql/attributes'
21
21
  require 'torque/postgresql/autosave_association'
22
22
  require 'torque/postgresql/auxiliary_statement'
23
- require 'torque/postgresql/base'
24
23
  require 'torque/postgresql/inheritance'
24
+ require 'torque/postgresql/base'# Needs to be after inheritance
25
25
  require 'torque/postgresql/insert_all'
26
26
  require 'torque/postgresql/migration'
27
27
  require 'torque/postgresql/relation'
28
28
  require 'torque/postgresql/reflection'
29
29
  require 'torque/postgresql/schema_cache'
30
+ require 'torque/postgresql/table_name'
30
31
 
31
32
  require 'torque/postgresql/railtie' if defined?(Rails)
data/lib/torque/range.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  module Torque
2
2
  module Range
3
3
  def intersection(other)
4
+ ActiveSupport::Deprecation.warn('Range extensions will be removed in future versions')
4
5
  raise ArgumentError, 'value must be a Range' unless other.kind_of?(Range)
5
6
 
6
7
  new_min = self.cover?(other.min) ? other.min : other.cover?(min) ? min : nil
@@ -11,6 +12,7 @@ module Torque
11
12
  alias_method :&, :intersection
12
13
 
13
14
  def union(other)
15
+ ActiveSupport::Deprecation.warn('Range extensions will be removed in future versions')
14
16
  raise ArgumentError, 'value must be a Range' unless other.kind_of?(Range)
15
17
 
16
18
  ([min, other.min].min)..([max, other.max].max)
@@ -0,0 +1,5 @@
1
+ module Internal
2
+ class User < ActiveRecord::Base
3
+ self.schema = 'internal'
4
+ end
5
+ end
data/spec/schema.rb CHANGED
@@ -10,7 +10,7 @@
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
- version = 2
13
+ version = 1
14
14
 
15
15
  return if ActiveRecord::Migrator.current_version == version
16
16
  ActiveRecord::Schema.define(version: version) do
@@ -20,6 +20,9 @@ ActiveRecord::Schema.define(version: version) do
20
20
  enable_extension "pgcrypto"
21
21
  enable_extension "plpgsql"
22
22
 
23
+ # Custom schemas used in this database.
24
+ create_schema "internal", force: :cascade
25
+
23
26
  # Custom types defined in this database.
24
27
  # Note that some types may not work with other database engines. Be careful if changing database.
25
28
  create_enum "content_status", ["created", "draft", "published", "archived"], force: :cascade
@@ -117,6 +120,13 @@ ActiveRecord::Schema.define(version: version) do
117
120
  t.datetime "updated_at", null: false
118
121
  end
119
122
 
123
+ create_table "users", schema: "internal", force: :cascade do |t|
124
+ t.string "email"
125
+ t.datetime "created_at", null: false
126
+ t.datetime "updated_at", null: false
127
+ t.index ["email"], name: "index_internal_users_on_email", unique: true
128
+ end
129
+
120
130
  create_table "activities", force: :cascade do |t|
121
131
  t.integer "author_id"
122
132
  t.string "title"
data/spec/spec_helper.rb CHANGED
@@ -22,7 +22,7 @@ cleaner = ->() do
22
22
  end
23
23
 
24
24
  load File.join('schema.rb')
25
- Dir.glob(File.join('spec', '{models,factories,mocks}', '*.rb')) do |file|
25
+ Dir.glob(File.join('spec', '{models,factories,mocks}', '**', '*.rb')) do |file|
26
26
  require file[5..-4]
27
27
  end
28
28
 
@@ -42,18 +42,19 @@ RSpec.describe 'Enum' do
42
42
  end
43
43
 
44
44
  context 'on schema' do
45
+ let(:dump_result) do
46
+ ActiveRecord::SchemaDumper.dump(connection, (dump_result = StringIO.new))
47
+ dump_result.string
48
+ end
49
+
45
50
  it 'can be used on tables' do
46
- dump_io = StringIO.new
47
51
  checker = /t\.enum +"conflicts", +array: true, +enum_type: :conflicts/
48
- ActiveRecord::SchemaDumper.dump(connection, dump_io)
49
- expect(dump_io.string).to match checker
52
+ expect(dump_result).to match checker
50
53
  end
51
54
 
52
55
  xit 'can have a default value as an array of symbols' do
53
- dump_io = StringIO.new
54
56
  checker = /t\.enum +"types", +default: \[:A, :B\], +array: true, +enum_type: :types/
55
- ActiveRecord::SchemaDumper.dump(connection, dump_io)
56
- expect(dump_io.string).to match checker
57
+ expect(dump_result).to match checker
57
58
  end
58
59
  end
59
60
 
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Schema' do
4
+ let(:connection) { ActiveRecord::Base.connection }
5
+
6
+ before do
7
+ connection.instance_variable_set(:@schmeas_blacklist, nil)
8
+ connection.instance_variable_set(:@schmeas_whitelist, nil)
9
+ end
10
+
11
+ context 'on migration' do
12
+ it 'can check for existance' do
13
+ expect(connection.schema_exists?(:information_schema)).to be_falsey
14
+ expect(connection.schema_exists?(:information_schema, filtered: false)).to be_truthy
15
+ end
16
+
17
+ it 'can be created' do
18
+ expect(connection.schema_exists?(:legacy, filtered: false)).to be_falsey
19
+ connection.create_schema(:legacy)
20
+ expect(connection.schema_exists?(:legacy, filtered: false)).to be_truthy
21
+ end
22
+
23
+ it 'can be deleted' do
24
+ expect(connection.schema_exists?(:legacy, filtered: false)).to be_falsey
25
+
26
+ connection.create_schema(:legacy)
27
+ expect(connection.schema_exists?(:legacy, filtered: false)).to be_truthy
28
+
29
+ connection.drop_schema(:legacy)
30
+ expect(connection.schema_exists?(:legacy, filtered: false)).to be_falsey
31
+ end
32
+
33
+ it 'works with whitelist' do
34
+ expect(connection.schema_exists?(:legacy)).to be_falsey
35
+ connection.create_schema(:legacy)
36
+
37
+ expect(connection.schema_exists?(:legacy)).to be_falsey
38
+ expect(connection.schema_exists?(:legacy, filtered: false)).to be_truthy
39
+
40
+ connection.schemas_whitelist.push('legacy')
41
+ expect(connection.schema_exists?(:legacy)).to be_truthy
42
+ end
43
+ end
44
+
45
+ context 'on schema' do
46
+ let(:dump_result) do
47
+ ActiveRecord::SchemaDumper.dump(connection, (dump_result = StringIO.new))
48
+ dump_result.string
49
+ end
50
+
51
+ it 'does not add when there is no extra schemas' do
52
+ connection.drop_schema(:internal, force: :cascade)
53
+ expect(dump_result).not_to match /Custom schemas defined in this database/
54
+ end
55
+
56
+ it 'does not include tables from blacklisted schemas' do
57
+ connection.schemas_blacklist.push('internal')
58
+ expect(dump_result).not_to match /create_table \"users\",.*schema: +"internal"/
59
+ end
60
+
61
+ context 'with internal schema whitelisted' do
62
+ before { connection.schemas_whitelist.push('internal') }
63
+
64
+ it 'dumps the schemas' do
65
+ expect(dump_result).to match /create_schema \"internal\"/
66
+ end
67
+
68
+ it 'shows the internal users table in the connection tables list' do
69
+ expect(connection.tables).to include('internal.users')
70
+ end
71
+
72
+ it 'dumps tables on whitelisted schemas' do
73
+ expect(dump_result).to match /create_table \"users\",.*schema: +"internal"/
74
+ end
75
+ end
76
+ end
77
+
78
+ context 'on relation' do
79
+ let(:model) { Internal::User }
80
+
81
+ it 'adds the schema to the query' do
82
+ expect(model.all.to_sql).to match(/FROM "internal"."users"/)
83
+ end
84
+
85
+ it 'can load the schema from the module' do
86
+ allow(Internal).to receive(:schema).and_return('internal')
87
+ allow(model).to receive(:schema).and_return(nil)
88
+
89
+ expect(model.all.to_sql).to match(/FROM "internal"."users"/)
90
+ end
91
+ end
92
+ end
@@ -73,37 +73,33 @@ RSpec.describe 'TableInheritance' do
73
73
  end
74
74
 
75
75
  context 'on schema' do
76
- it 'dumps single inheritance with body' do
77
- dump_io = StringIO.new
78
- ActiveRecord::SchemaDumper.dump(connection, dump_io)
76
+ let(:dump_result) do
77
+ ActiveRecord::SchemaDumper.dump(connection, (dump_result = StringIO.new))
78
+ dump_result.string
79
+ end
79
80
 
81
+ it 'dumps single inheritance with body' do
80
82
  parts = '"activity_books"'
81
83
  parts << ', id: false'
82
84
  parts << ', force: :cascade'
83
- parts << ', inherits: :activities'
84
- expect(dump_io.string).to match(/create_table #{parts} do /)
85
+ parts << ', inherits: "activities"'
86
+ expect(dump_result).to match(/create_table #{parts} do /)
85
87
  end
86
88
 
87
89
  it 'dumps single inheritance without body' do
88
- dump_io = StringIO.new
89
- ActiveRecord::SchemaDumper.dump(connection, dump_io)
90
-
91
90
  parts = '"activity_post_samples"'
92
91
  parts << ', id: false'
93
92
  parts << ', force: :cascade'
94
- parts << ', inherits: :activity_posts'
95
- expect(dump_io.string).to match(/create_table #{parts}(?! do \|t\|)/)
93
+ parts << ', inherits: "activity_posts"'
94
+ expect(dump_result).to match(/create_table #{parts}(?! do \|t\|)/)
96
95
  end
97
96
 
98
97
  it 'dumps multiple inheritance' do
99
- dump_io = StringIO.new
100
- ActiveRecord::SchemaDumper.dump(connection, dump_io)
101
-
102
98
  parts = '"activity_posts"'
103
99
  parts << ', id: false'
104
100
  parts << ', force: :cascade'
105
- parts << ', inherits: (\[:images, :activities\]|\[:activities, :images\])'
106
- expect(dump_io.string).to match(/create_table #{parts}/)
101
+ parts << ', inherits: (\["images", "activities"\]|\["activities", "images"\])'
102
+ expect(dump_result).to match(/create_table #{parts}/)
107
103
  end
108
104
  end
109
105
 
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: 2.2.4
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carlos Silva
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-04-11 00:00:00.000000000 Z
11
+ date: 2022-12-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -17,6 +17,9 @@ dependencies:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '6.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '7.0'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -24,6 +27,9 @@ dependencies:
24
27
  - - ">="
25
28
  - !ruby/object:Gem::Version
26
29
  version: '6.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '7.0'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: pg
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -155,7 +161,7 @@ dependencies:
155
161
  description: Add support to complex resources of PostgreSQL, like data types, array
156
162
  associations, and auxiliary statements (CTE)
157
163
  email:
158
- - carlinhus.fsilva@gmail.com
164
+ - me@carlosfsilva.com
159
165
  executables: []
160
166
  extensions: []
161
167
  extra_rdoc_files: []
@@ -231,6 +237,7 @@ files:
231
237
  - lib/torque/postgresql/relation/inheritance.rb
232
238
  - lib/torque/postgresql/relation/merger.rb
233
239
  - lib/torque/postgresql/schema_cache.rb
240
+ - lib/torque/postgresql/table_name.rb
234
241
  - lib/torque/postgresql/version.rb
235
242
  - lib/torque/range.rb
236
243
  - spec/en.yml
@@ -254,6 +261,7 @@ files:
254
261
  - spec/models/course.rb
255
262
  - spec/models/geometry.rb
256
263
  - spec/models/guest_comment.rb
264
+ - spec/models/internal/user.rb
257
265
  - spec/models/item.rb
258
266
  - spec/models/post.rb
259
267
  - spec/models/question.rb
@@ -281,13 +289,18 @@ files:
281
289
  - spec/tests/quoting_spec.rb
282
290
  - spec/tests/range_spec.rb
283
291
  - spec/tests/relation_spec.rb
292
+ - spec/tests/schema_spec.rb
284
293
  - spec/tests/table_inheritance_spec.rb
285
294
  homepage: https://github.com/crashtech/torque-postgresql
286
295
  licenses:
287
296
  - MIT
288
- metadata: {}
297
+ metadata:
298
+ source_code_uri: https://github.com/crashtech/torque-postgresql
299
+ bug_tracker_uri: https://github.com/crashtech/torque-postgresql/issues
289
300
  post_install_message:
290
- rdoc_options: []
301
+ rdoc_options:
302
+ - "--title"
303
+ - Torque PostgreSQL
291
304
  require_paths:
292
305
  - lib
293
306
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -327,6 +340,7 @@ test_files:
327
340
  - spec/models/course.rb
328
341
  - spec/models/geometry.rb
329
342
  - spec/models/guest_comment.rb
343
+ - spec/models/internal/user.rb
330
344
  - spec/models/item.rb
331
345
  - spec/models/post.rb
332
346
  - spec/models/question.rb
@@ -354,4 +368,5 @@ test_files:
354
368
  - spec/tests/quoting_spec.rb
355
369
  - spec/tests/range_spec.rb
356
370
  - spec/tests/relation_spec.rb
371
+ - spec/tests/schema_spec.rb
357
372
  - spec/tests/table_inheritance_spec.rb