torque-postgresql 2.2.4 → 2.3.0

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